Kategorie ‘PHP’

It’s a spider – Web Crawler als Grundlage für Informationsbeschaffung

26. November 2009

Viele Skripte entstehen, wenn man sich viel mit Webbasierten Skriptsprachen wie PHP und Perl auseinandersetzt,
insbesondere solche Skripts, die der Informationsbeschaffung dienen.
Was die Web-Security betrifft können dies beispielsweise Programme sein, die Seiten auf verwundbare Muster
überprüfen, oder Informationen über das komplette System sammeln.

Ein nützliches Tool, um einen solchen Vorgang zu beginnen, nennt sich Web Crawler / Spider, also ein Skript,
welches sich von Seite zu Seite hangelt, und Informationen ausgibt.
Dies können komplexe Crawler sein, wie der Bot von namenhaften Suchmaschinen, oder kleinere, die lediglich einen
Internetauftritt analysieren.

Kürzlich habe ich einen kleinen Crawler geschrieben, der eine Internetseite nach URL’s durchsucht, und diese auflistet.
Hierbei lassen sich verschiedene Ebenen angeben, sozusagen die Suchtiefe, in die der Crawler vorstoßen soll.
Als praktisches Gimmick gibt es zusätzlich einen Ebenenabhängigen Filter, der die URL’s durch eine Whitelist, sowie eine Blacklist schickt, um so die Auswahl einzugrenzen.
Dieser Filter lässt sich nach Ebenen unterscheiden, sodass es zum Beispiel möglich ist, in Ebene 1 zunächst alle aktuellen Links ohne Einschränkung aufzulisten, und diese dann in Ebene 2 nach URL’s mit dem Inhalt “artikel” zu crawlen.

Hier zunächst der crawler als PHP Quellcode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?php
	// Crawler by Lidloses_Auge for http://novusec.com
	ini_set("max_execution_time",0);
	$urllist[0][0] = $argv[1];
	$ebene = $argv[2];
	$url[] = $urllist[0][0];
	$suchmuster = "/\"(https?:\/\/.*)\"/U";
	$lists = load_filter($ebene,"filter.ini");
 
	crawl($ebene,$lists[0],$lists[1]);
 
	function crawl($ebene,$white,$black) {
		global $urllist,$url,$suchmuster;
		for ($i = 0; $i < $ebene; $i++) {
			foreach($urllist[$i] as $urltodo) {
				$src = @file_get_contents($urltodo);
				preg_match_all($suchmuster, $src, $treffer, PREG_SET_ORDER);
				foreach($treffer as $trefferToDo) {
					if (!in_array($trefferToDo[1],$url) & filter($trefferToDo[1],$i,$white,$black)) {
						$url[] = $trefferToDo[1];
						$urllist[$i+1][] = $trefferToDo[1];
						echo "[Ebene=".($i+1)."/$ebene] ".$trefferToDo[1]."\r\n";
					}
				}		
			}
		}
	}
 
	function load_filter($ebene,$filterfile) {	
		$parseebene = 0;
		$filter = file($filterfile);
		foreach($filter as $filtertemp) {
			if (preg_match("/\/\*/",$filtertemp)) {
				$comment = 1;
				$filtertemp = substr($filtertemp,0,strpos($filtertemp,"/*"));
			}
			if (preg_match("/\*\//",$filtertemp)) {
				$comment = 0;
				$filtertemp = substr($filtertemp,strpos($filtertemp,"*/")+2);
			}
			if ($comment < 2) {
				if (preg_match("/\#\#/",$filtertemp)) $filtertemp = substr($filtertemp,0,strpos($filtertemp,"##"));
				if (preg_match("/\[(.*)\]/",$filtertemp)) preg_match("/\[(.*)\]/",$filtertemp,$type);
				if (preg_match("/\{/",$filtertemp)) $parseebene++;
				if (preg_match("/\}/",$filtertemp)) {
					$parseebene--;
					if (!is_array(${strtolower($type[1])}[${parseebene}-0])) ${strtolower($type[1])}[${parseebene}-0][] = "";
				}
				if ($parseebene > 0) {
					if (preg_match("/name\(\"(.*)\"\)/U",$filtertemp,$str)) ${strtolower($type[1])}[${parseebene}-1][] = $str[1];
					preg_match("/inherit\(\"(.*)\"\)/",$filtertemp,$inherit);
					if (strtolower($inherit[1]) == "all") $inherit[1] = $ebene-$parseebene;
					for ($i = $parseebene; $i < ($parseebene + $inherit[1]); $i++) {
						${strtolower($type[1])}[$i][] = $str[1];
					}
				}
			}
			if ($comment == 1) $comment = 2;
		}
		return array($whitelist,$blacklist);
	}
 
	function filter($check,$tempebene,$white,$black) {
		$var = true;
		if (!is_array($white[$tempebene])) $white[$tempebene][] = "";
		if (!is_array($black[$tempebene])) $black[$tempebene][] = "";
		foreach($white[$tempebene] as $wch) {
			foreach($black[$tempebene] as $bch) {
				if (!empty($bch)) $var = $var & (strpos(" ".$check,$bch) == 0);
			}
			if (!empty($wch)) $var = $var & (strpos(" ".$check,$wch) != 0);
		}
		return $var;
	}
?>

Die Version ist in dieser Version auf den Konsolenbetrieb ausgelegt.
Um ihn für den Betrieb im Browser anzupassen, müssten lediglich die Zeilen:

1
2
$urllist[0][0] = $argv[1];
$ebene = $argv[2];

mit

1
2
$urllist[0][0] = $_GET['url'];
$ebene = $_GET['ebene'];

ersetzt werden.

Der Aufruf des Programms im Konsolenbetrieb lautet: php crawler.php
Also zum Beispiel:
php crawler.php http://novusec.com 2

Analog zum Konsolenbetrieb müssten dementsprechend die GET Werte gesetzt werden.

Der Crawler nutzt einen filter, der aus einer Datei eingelesen, und geparsed wird.
Dieser könnte wie folgt aussehen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[Whitelist]
{
	name("http://novusec.com") inherit("all")
	##name("tutorials")
	{
		name("injection")
		/*
		{
			name("regex")
		}
		*/
	}
}
[Blacklist]
{
	name("page")
	{
		name("category")
		name("sql")
	}
}

Wie leicht zu erkennen ist, beginnt die Whitelist mit [Whitelist] und die Blacklist mit [Blacklist].
Durch Klammerung unterscheiden sich die verschiedenen Ebenen, und mit dem Attribut “name”
lassen sich die Suchbegriffe festlegen.

In diesem Falle wird in der Whitelist auf Ebene 1 nach “http://novusec.com” gesucht, und in Ebene 2 nach “injection”.
Ursprünglich wurde noch eine dritte Ebene festgelegt, die sich jedoch mit der gewohnten Notation für mehrzeilige
Kommentare nicht mehr beim Suchvorgang auswirkt.
Einzeilige Kommentare habe ich mit zwei Rauten “##” realisiert, wie in diesem Beispiel in der ersten Ebene.

Suchbegriffe lassen sich auf untere Ebenen hin vererben, dies geschieht mit dem Attribut “inherit”.
Dadurch spart man sich Schreibarbeit, wenn man einen Suchbegriff in weiteren Ebenen verwenden möchte.
In diesem Fall wurde der Begriff “http://novusec.com” mit inherit(“all”) auf alle weiteren darunterliegenden Ebenen (sofern diese existieren) vererbt, und muss nicht extra aufgeführt werden. Ebenso ist es möglich eine Zahl anzugeben, sofern man den Begriff nur etwa auf eine weitere Ebene vererben will. Dies geschieht auch in Anführungsstrichen, also zum Beispiel inherit(“1″).

Analog zu der Whitelist gestaltet sich natürlich ebenso die Blacklist, bei der alle Begriffe aufgeführt werden, die NICHT in de Ergebnissen vorkommen sollen.

In diesem Falle möchte ich den Aufruf mit novusec.com auf 2 Suchebenen mit dem oben angegebenen Filter darstellen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
php crawler.php http://novusec.com 2
 
X-Powered-By: PHP/4.4.9
Content-type: text/html
 
[Ebene=1/2] http://novusec.com/feed/
[Ebene=1/2] http://novusec.com/comments/feed/
[Ebene=1/2] http://novusec.com/xmlrpc.php
[Ebene=1/2] http://novusec.com/wp-content/themes/inove/ie6.css
[Ebene=1/2] http://novusec.com/wp-content/themes/inove/js/util.js
[Ebene=1/2] http://novusec.com/wp-content/themes/inove/js/menu.js
[Ebene=1/2] http://novusec.com/xmlrpc.php?rsd
[Ebene=1/2] http://novusec.com/wp-includes/wlwmanifest.xml
[Ebene=1/2] http://novusec.com/wp-content/plugins/dmsguestbook/dmsguestbook.css
[Ebene=1/2] http://novusec.com/wp-content/themes/inove/wp-syntax.css
[Ebene=1/2] http://novusec.com/
[Ebene=1/2] http://novusec.com/links/
[Ebene=1/2] http://novusec.com/shoutbox/
[Ebene=1/2] http://novusec.com/about/
[Ebene=1/2] http://novusec.com/partner/
[Ebene=1/2] http://novusec.com/kontakt/
[Ebene=1/2] http://novusec.com/tools/
[Ebene=1/2] http://novusec.com/sqli-maxdome-de/
[Ebene=1/2] http://novusec.com/wp-content/themes/inove/img/hr.jpg
[Ebene=1/2] http://novusec.com/sqli-maxdome-de/#respond
[Ebene=1/2] http://novusec.com/author/player/
[Ebene=1/2] http://novusec.com/category/sql-injections/
[Ebene=1/2] http://novusec.com/sqli-bild-de-tarifvergleich/
[Ebene=1/2] http://novusec.com/sqli-bild-de-tarifvergleich/#respond
[Ebene=1/2] http://novusec.com/register_globals-ein-sicherheitsrisiko-auf-dem-weg-ins-exil/
[Ebene=1/2] http://novusec.com/register_globals-ein-sicherheitsrisiko-auf-dem-weg-ins-exil/#comments
[Ebene=1/2] http://novusec.com/author/lidloses_auge/
[Ebene=1/2] http://novusec.com/category/php/
[Ebene=1/2] http://novusec.com/xpath-injection-es-geht-auch-ohne-datenbank/
[Ebene=1/2] http://novusec.com/xpath-injection-es-geht-auch-ohne-datenbank/#respond
[Ebene=1/2] http://novusec.com/category/sonstiges/
[Ebene=1/2] http://novusec.com/php-honeypot-script/
[Ebene=1/2] http://novusec.com/php-honeypot-script/#comments
[Ebene=1/2] http://novusec.com/hp/
[Ebene=1/2] http://novusec.com/download/PHP_HoneyPot.rar
[Ebene=1/2] http://novusec.com/wp-content/winrar.png
[Ebene=1/2] http://novusec.com/greasemonkey-oneclickhoster-wait-bypass-script/
[Ebene=1/2] http://novusec.com/greasemonkey-oneclickhoster-wait-bypass-script/#comments
[Ebene=1/2] http://novusec.com/gm/oneclickhoster_wait.user.js
[Ebene=1/2] http://novusec.com/wp-content/greasemonkey.jpg
[Ebene=1/2] http://novusec.com/category/greasemonkey/
[Ebene=1/2] http://novusec.com/adblock-detection-without-javascript/
[Ebene=1/2] http://novusec.com/adblock-detection-without-javascript/#comments
[Ebene=1/2] http://novusec.com/http-response-splitting-crlf-oder-header-injection/
[Ebene=1/2] http://novusec.com/http-response-splitting-crlf-oder-header-injection/#comments
[Ebene=1/2] http://novusec.com/oneclickhoster-wait-bypass/
[Ebene=1/2] http://novusec.com/oneclickhoster-wait-bypass/#comments
[Ebene=1/2] http://novusec.com/category/javascript/
[Ebene=1/2] http://novusec.com/novusec-wieder-online/
[Ebene=1/2] http://novusec.com/novusec-wieder-online/#comments
[Ebene=1/2] http://novusec.com/category/exploits/
[Ebene=1/2] http://novusec.com/category/rfi-lfi/
[Ebene=1/2] http://novusec.com/category/text-tutorials/
[Ebene=1/2] http://novusec.com/category/video-tutorials/
[Ebene=1/2] http://novusec.com/category/xss/
[Ebene=1/2] http://novusec.com/banner/querverweis_88x31o.gif
[Ebene=1/2] http://novusec.com/wp-login.php
[Ebene=1/2] http://novusec.com/wp-content/plugins/wp-useronline/wp-useronline.php
[Ebene=2/2] http://novusec.com/xpath-injection-es-geht-auch-ohne-datenbank/feed/
[Ebene=2/2] http://novusec.com/exploiten-von-preg_replace-regex-injectionremote-code-execution/
[Ebene=2/2] http://novusec.com/exploiten-von-preg_replace-regex-injectionremote-code-execution/#comments
[Ebene=2/2] http://novusec.com/http-response-splitting-crlf-oder-header-injection/feed/

Wie deutlich zu erkennen ist, sind auf Ebene 1 sehr viel mehr URL’s aufgelistet, als bei Ebene 2.
Dies liegt an den strikten Filtereinstellungen für Ebene 2.
Es wurden auf Ebene 2 sämtliche URL’s mit dem Inhalt “injection” aufgelistet, und Begriffe wie “category” und “sql” ausgeschlossen.

In diesem crawler habe ich mich noch nicht besonders um eine ausführliche Fehlerbehandlung bemüht, daher können je nach Filtereinstellung eventuell ein paar Unstimmigkeiten auftreten.
Er soll eher als Beispiel dienen, wie ein crawler arbeiten könnte, mit nützliches Features, wie
dem ebenenabhängigen Filter.

Lidloses_Auge

Lidloses_Auge PHP

register_globals – Ein Sicherheitsrisiko auf dem Weg ins Exil

16. Oktober 2009

PHP ist eine Skriptsprache, die ständig in Bewegung ist,
und viele Neuerungen erfahren hat. Auch kann es passieren,
dass einige Funktionen und Einstellungen als unsicher angesehen
werden, und weniger häufig benutzt werden, oder sogar in späteren
PHP Versionen komplett von der Bildfläche verschwinden.
Eine Einstellung die auf dieses Schema passt, ist “register_globals”,
die in der PHP.ini aktiviert oder deaktiviert werden kann.

Diese Einstellung importiert, sofern sie aktiviert ist, alle Variablen
in einer bestimmbaren Reihenfolge(meist GET, POST, COOKIE, ENV, SERVER)
in den globalen Namensraum, sodass auf sie zugegriffen werden kann, wie
auf globale Variablen.
Im Grunde ist die Funktion ansich nicht unsicher, erleichtert aber ein
Auftreten von Sicherheitslücken bei unsicherer Programmierung.

Ein Beispiel für einen simplen utopischen Login Code verdeutlicht die Gefahr:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
echo "<form action = \"\" method=\"POST\"><input type=\"text\" name=\"user\"><br><input type=\"pass\" name=\"pass\"><br><input type = \"submit\" value = \"Senden\"></form>\n";
$dbname = "admin";
$dbpass = "098f6bcd4621d373cade4e832627b4f6"; // md5("test")
$user = $_POST['user'];
$pass = $_POST['pass'];
 
if ($user && $pass) {
	if ((preg_match("/^([a-zA-Z0-9]+)$/",$user)) && (md5($pass) == $dbpass) && $user == $dbname) {
		$logged_in = 1;
	}
	if ($logged_in == 1) {
	echo "logged in";
	/*
		...
		Some more action,which can be done while logged in
		...
	*/
	} else {
		echo "wrong login";
	}
}
?>

Hier ist eine simple kleine Login Routine abgebildet.
Zur Vereinfachung gibt es keine Queries und komplexere Abfragen,
sondern es werden lediglich Strings in Variablen verglichen,
und bei Erfolg der Wert “logged_in” auf 1 gesetzt.
Diese Art von Login ist im übrigen nicht zu empfehlen, und
macht dazu den Code noch äußerst unsauber.

Die Fahrlässigkeit besteht in diesem Falle darin, dass die Variable
“logged_in” nicht im Vorraus initialisiert wurde, sondern sofort im
Kontext verwendet wird, um die Authorisierung zu prüfen.
Bei aktiviertem “register_globals” könnte man nun wie folgt vorgehen:

Da alle Variablen in den globalen Namensraum importiert werden,
kann man via GET Parameter die Variable auf jeden gewünschten Wert setzen.
Ein Aufruf von “login.php?logged_in=1″ führt zu einem Import von “logged_in=1″.
Nun können beliebige Login Daten eingegeben werden, um in die Bedingung
“($user & $pass)” zu springen, und wir haben einen Login vorgetäuscht.

Beheben lässt sich das Problem mit einer initialen Zuweisung von “logged_in”
vor der eigentlichen Verwendung.

1
$logged_in = 0;

So kann der Wert durch den GET Parameter(wahlweise auch andere) nicht verändert werden.

Generell ist es aber von Vorteil die Einstellung “register_globals” komplett deaktiviert
zu lassen, und den Code entsprechend anzupassen, sodass diese Einstellung auch nicht
notwendig wird.

Lidloses_Auge PHP

HTTP Response Splitting – CRLF oder Header Injection

20. August 2009

Eine etwas in Vergessenheit geratene Art von Web- basierten Sicherheitslücken ist
der sogenannte “HTTP Response Splitting” Angriff. Er wird auch oftmals als
“HTTP Header Injection” oder “CRLF Injection” bezeichnet.

Einleiten möchte ich diesen Artikel mit einem kleinen Beispiel einer simplen Weiterleitung:

Angenommen wir haben folgendes kleines Script:

1
2
3
<?php
header("Location: ".$_GET['page']);
?>

Es tut nichts anderes, als die Seite weiterzuleiten auf den GET Parameter.
Ein Aufruf könnte z.B. so aussehen:

127.0.0.1/forward.php?page=http://www.google.de

Betrachtet man die jeweiligen Request und Answer Header wird dies in etwa (hier vereinfacht) so aussehen:

GET /forward.php?page=http://www.google.de HTTP/1.1
Host: 127.0.0.1
Keep-Alive: 300
Connection: keep-alive

HTTP/1.1 302 Found
Date: Wed, 19 Aug 2009 12:50:14 GMT
Server: Apache
Location: http://www.google.de
Content-Type: text/html

GET / HTTP/1.1
Host: www.google.de
Keep-Alive: 300
Connection: keep-alive

HTTP/1.1 200 OK
Date: Wed, 19 Aug 2009 12:51:41 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
Server: gws
Transfer-Encoding: chunked

Wie zu erkennen, wird zunächst ein Request an der Weiterleitungsskript gestartet, und die
gewünschte URL übergeben. Der Server Antwortet nicht etwa mit dem Statuscode 200 (OK)
sondern mit 302 (Found)
Dies impliziert eine temporäre Weiterleitung.

Am Location-Feld des ersten Antwort Headers erkennt man die gewünschte Adresse, auf die weitergeleitet
werden soll.
Dementsprechend wird ein zweites Request gestartet, in diesem Beispiel an Google, bei dem der Server
ganz normal mit einem 200 OK antwortet, und den Inhalt anzeigt.

Wir wollen unser Augenmerk nicht auf die Weiterleitung ansich legen, sondern auf die Tatsache, dass
wir Einfluss darauf haben, was im Location Feld vorzufinden ist.

Laut HTTP Spezifikation muss jedes Feld des Headers mit einem Carriage Return (CR) und einem
Line Feed (LF) enden. Dies ist ein Zeilenumbruch, der auch als \r\n oder %0d%0a geschrieben werden
kann.
Macht man sich diese Tatsache zunutze, kann man aus dem Feld, sofern man Einfluss darauf hat, ausbrechen.

Die Technik beim HTTP Response Splitting besteht im kompromittieren eines Proxy- oder Cacheservers,
der dem Webserver vorgeschaltet ist.
Hierzu generiert man 2 verschiedene Antworten, die vom Cache unterschiedlich interpretiert werden.

Ein kleines Beispiel:

127.0.0.1/forward.php?page=%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2027%0d%0a%0d%0aCRLF Injection

Da dies in dieser Form sehr kryptisch aussieht, möchte ich es kurz anders darstellen:

Content-Length: 0

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 27

CRLF Injection

Was bedeutet dies nun für unsere Request/Response Ausgabe?

GET /forward.php?page=download%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2027%0d%0a%0d%0aCRLF Injection

HTTP/1.1
Host: 127.0.0.1
Keep-Alive: 300
Connection: keep-alive

HTTP/1.1 302 Found
Date: Wed, 19 Aug 2009 12:50:14 GMT
Server: Apache
Location:
Content-Length: 0

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 27

CRLF Injection


Content-Type: text/html

Wie wir erkennen, existieren nun 2 Responses zu einem einzigen Request.
Die erste Antwort ist die vom Webserver generierte, mit dem Statuscode 302.
Die zweite Antwort haben wir vollständig selbst generiert, und bei Erfolg
sollte bereits jetzt eine weiße Seite mit unserem Content erscheinen.

Bis jetzt ist diese Methode Clientseitig, könnte also als XSS genutzt werden,
doch ist es möglich, das ganze noch weiterzuführen.

Wenn wir ein zweites Request über die gleiche Verbindung absetzen, z.b. auf:

127.0.0.1/index.php

So ordnet der Cache Server diesem zweiten Request die von uns generierte zweite Antwort zu,
sodass der Inhalt dessen in den Cache einfließt.

Dieses Verhalten wird auch als Cross-User-Defacement oder Web Cache Poisoning bezeichnet, und weiterhin
ist es möglich Second-Order-XSS einzuschleusen, also persistente serverseitige Attacken.

Es gibt zahlreiche Methoden, den Cache dazu zu bringen, die aufgerufene Seite zu cachen, auf die
ich hier nicht weiter eingehe.

Es ist wichtig zu erwähnen, dass ab den PHP Versionen 4.4.2 und 5.1.2 die header() Funktion
gefixed wurde, und es nicht mehr möglich ist, einen Header mit mehreren Zeilen zu senden.

Sofern Erfahrungen mit Cache Poisoning vorhanden sind,
wäre ich über Gesprächsthemen diesbezüglich nicht abgeneigt.

Einen schönen Sommertag wünscht Lidloses_Auge

Lidloses_Auge PHP

Information Gathering – Fingerprint Techniken

6. Juni 2009

. [ Show ] in English

Der Sicherheitsgrad eines Webservers lässt sich an vielen Faktoren messen, ein wichtiger Faktor sind hierbei die Informationen die preisgegeben werden.
Es gibt viele Informationen, die einem Angreifer wichtige Details zum aufgesetzten Server geben können, und bei vielerlei Dingen ist es sehr einfach Informationen zu bekommen, auch
Wenn diese zunächst uninteressant erscheinen.

Einige Quellen aus denen man Informationen beziehen kann sind folgende:

1. Server Banner:

Das Server Banner wird bei jeden HTTP Request mitgeschickt.
Ein Austausch von Nachrichten besteht aus Request und Answer.
Im Request fragt der Nutzer eine bestimmte Quelle auf dem Webserver an,
und versieht diese optional mit einigen Zusatzinformationen wie Cookie, Content-Type o.Ä. Diese stehen im sogenannten Header.
Diesen gibt es auch bei der vom Webserver gelieferten Antwort, in der zum einen
Das angefragte Dokument zu finden ist, und einige Informationen, wie je nach Optionen des Webservers mitgeliefert werden.

Ein Feld im Antwort-Header kann zum Beispiel das „Server“ Feld, oder auch „Server-Banner“ sein. Dieses könnte wie folgt aussehen:

Server: Apache/2.2.11 (Debian) mod_fastcgi/2.4.6

An den Inhalt des Headers kann man mit den Firefox Erweiterungen „Live HTTP Headers“ oder „Server Spy“ kommen. Es würde allerdings auch ausreichen manuell ein HTTP Request abzusetzen, etwa mit Telnet. Dort wird auch direkt der Antwort Header ausgegeben.
Welche Informationen wofür relevant sind werde ich später noch ausführen.

2. Verhalten des Webservers

Am Verhalten, wie der Webserver auf Veränderungen reagiert lässt sich auch sinnvolles extrahieren. Es gibt zum Beispiel bestimmte Anzeichen an Darstellung und
Parsing Routinen an denen man Skriptsprache oder auch Versionen von Datenbanksystemen erkennen lassen.

3. Automatisiertes Fingerprinting

Mit dem Netzwerktool „nmap“ lassen sich automatisiert Fingerprinting Routinen ausführen, die detaillierte Informationen herausfinden können, bei denen man von Hand nicht unbedingt weiterkommt.

Was an also über den Webserver herausfinden möchte liegt am Benutzer selbst, doch gibt es eine Reihe von Standardinformationen, die man sich auf jeden Fall anschauen sollte.

1. Betriebssystem
2. Webserver
3. Scriptsprache
4. Datenbanksystem
5. Services + Ports
6. Weitere Websites auf Server

1. Betriebssystem

Es gibt einige Hinweise die auf das entsprechende Betriebssystem hindeuten können.
Als eine der wichtigsten Quellen steht hier der Webserver. Man kann diesen in den meisten Fällen aus dem Server Banner auslesen.
Steht hier etwa : „Microsoft-IIS/6.0“ kann man sich sicher sein auf ein Windows Betriebssystem gestoßen zu sein. Der Microsoft IIS Server läuft unter keinem anderen System als Windows.
Findet man allerdings nur ein „Apache“ vor kann man sich nicht 100% sicher sein, da hier nur die Minimal-Angabe eingeschaltet ist.
Die Webserver bieten 6 Optionen, mit denen sich die Ausgabe im Server Banner beeinflussen lässt. Diese nennen sich Server Tokens.

1. Prod (“Apache”)
2. Major (“Apache/2”)
3. Minor (“Apache/2.0”)
4. Min (“Apache/2.0.41”)
5. OS (“Apache/2.0.41 (Unix)”)
6. Full (“Apache/2.0.41 (Unix) mod_fastcgi/2.4.6”)

Man erkennt in diesen Beispielen die Ausgaben, die entweder nur vom Produkt, bis hin zu Versionsnummern und detaillierten Server Angaben über installierte Modifikationen reichen können. Ist hier „OS“ oder „Full“ eingeschaltet, ist die Suche nach dem Betriebssystem relativ schnell beendet.

Ein weiterer Weg ist, den Webserver zu Fehlermeldung zu zwingen in denen der Pfad der aktuellen Datei stehen kann. Dies kann durch Sonderzeichen geschehen, die der Webserver nicht verarbeiten kann. Mögliche Ausgaben können folgende sein:

Warning: Header may not contain more than a single header, new line detected. in C:\xampp\htdocs\info.php on line 2

Warning: Header may not contain more than a single header, new line detected. In
/var/www/info.php on line 2

Hier lässt der Pfad auf das Betriebssystem schließen, sofern es sich um den
absoluten Pfad handelt. Beim ersten ist dies Windows, beim zweiten ein auf Linux
basierendes Betriebssystem.

Eine automatisierte Möglichkeit bietet sich auch mit dem bereits angesprochenen
Tool nmap. Man startet also zunächst einen simplen Portscan mit:
Nmap –v –A Host
Findet man Ports vor wie 3389 oder den NetBIOS Port, ist dies mit großer
Sicherheit ein Windows Rechner, oder man verlässt sich einfach auf
die OS Fingerprint Option von nmap, die wir mit „-A“ eingeschaltet haben.

2. Webserver

Der Webserver lässt sich relativ schnell erschließen, sofern nicht besondere
Maßnahmen zur Verschleierung getroffen wurden.
Helfen wird uns wieder der Server Banner in dem bereits oben gezeigt wurde,
dass in den meisten Fällen der Name des Webservers bereits angezeigt wird,
selbst bei minimaler Darstellung.
Z.b. „Apache“
Sollte man nicht sofort Zugriff zu dem Server Banner haben, kann man auch
Versuchen den Webserver zu einer Fehlermeldung zu zwingen, etwa in dem man
Eine Seite aufruft die nicht existiert. In einigen Fällen wird der Webserver dann
zurückmelden, dass die aufgerufene Seite nicht existiert, und auch gleich den
Webserver mitsamt Version zurückgibt.
Eine weitere Methode ist auch hier das Port und Servicescanning wo wir auf die
Offenen Ports schauen sollten. Auch hier erscheint bei den laufenden Services
In manchen Fällen der Webserver.

3. Skriptsprache

Etwas schwieriger gestaltet sich das Herausfinden der aktuellen Skriptsprache,
denn nicht überall wo .php oder .html dransteht, muss es auch darin sein.

Dieses Versteckspiel wird möglich gemacht vom Zuweisen des Typs auf eine
Frei wählbare Endung, was in der httpd.conf geschieht und wie folgt aussehen
kann:

AddType application/x-httpd-php .php .php4 .html

Das .html am Ende macht deutlich, dass in diesem Falle auch Dateien mit der
Endung html auf PHP Code geparsed werden und folglich auch eine
index.html?id=1 als Ersatz für index.php?id=1 dienen kann. In den meisten Fällen
ist aber den Endungen glauben zu schenken.
Wer ganz sicher gehen will schaut in den altbekannten http Header, aus dem wir
Auch diesmal nützliche Informationen ziehen können.
Ausgegeben werden könnte z.B. dies:

X-Powered-By: PHP/5.2.9

In dem Falle wissen wir sofort, dass es sich um PHP handelt. Dies ist aber nur
möglich, wenn die Option „expose_php“ auf „on“ gestellt ist.

Fehlermeldung die für eine Skriptsprache spezifisch sind, können auch ein starkes
Indiz sein. Eine Blackboxing Methode einen Fehler hervorzurufen, wäre das
Anhängen von Sonderzeichen wie ‘ ” %00 etc. an einen Parameter.
Ein möglicher Fehler wäre bei PHP dieser:

Warning: fopen(/test'.txt): failed to open stream: Permission denied in
/test.php on line 138

Über eine Suchmaschine kann man dann anschließend Informationen über die
auftretenden Fehlern beziehen.

PHP wandelt Variablennamen die mit einem Leerzeichen beginnen automatisch in
einen Namen ohne führende Leerzeichen um, also kann man mit folgendem
simplen Test ebenso auf PHP überprüfen:

index.php?page=10
index.php?+page=10

Wird in beiden Fällen das gleiche angezeigt, ist dies ein gutes Indiz für ein
Vorhandensein von PHP. ASP zum Beispiel reagiert in diesem Falle anders, und
wird ein anderes Dokument als zuvor anzeigen.
Techniken, die die Dateiendungen verschleiern, wie zum Beispiel Mod Rewrite
schützen nicht unbedingt vor der Informationsgewinnung. Ein Beispiel hat Player
in seinem Artikel beschrieben, wie man eine PHP Installation erkennen kann.
Zu finden ist dieser hier: http://novusec.com/php-easter-egg-sinnvoll-nutzen/

4. Datenbanksystem

Die Auswahl an großen Datenbanksystemen ist glücklicherweise nicht allzu groß
und es gibt einige Möglichkeiten herauszufinden, welches installiert ist.
Der Trick mit den Sonderzeichen greift in vielen Fällen auch hier sodass man zum
Beispiel folgende Fehlermeldungen bekommen könnte:

You have an error in your SQL syntax; check the manual that corresponds to
your MySQL server version for the right syntax to use near '3' at line 1

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL
result resource in /var/www/test.php on line 92

Unclosed quotation mark before the character string

Während die ersten beiden Meldungen auf MySQL hinweisen, ist die dritte eine
Meldung des Microsoft SQL Servers. Die Meldungen können außerdem auf eine
SQL Injection hindeuten. Dies funktioniert nur, solange die Option
„display_errors“ auf „on“ geschaltet ist.

Der Portscanner „nmap“ erledigt auch für die Informationsgewinnung über
Datenbanken gute Dienste. Scannt man einen Webserver und findet den offenen
Port 3306, dann ist dies ein laufender MySQL Server. MSSQL benutzt wiederum
Andere Ports und Oracle Datenbanken ebenso andere.

5. Services + Ports

Sofern die Website mitsamt ihren Implementierungen abgesichert ist, gibt es über
Die Seite selbst wenig Möglichkeiten für einen Angreifer Schaden anzurichten.
Die auf dem Server installierten Services können jedoch auch zur Gefahr werden.
Der Befehl:

nmap –v –A Hostadresse

liefert bei installiertem nmap eine detaillierte Auflistung über offene Ports und
dessen Services. Die Programme können Schwachstellen enthalten wie Buffer
Overflows oder Format Strings, die unter Umständen sogar aus der Ferne
angegriffen werden können, und dem Angreifer die vollständige Kontrolle über
den Server bieten, solange die Prozesse SUID root sind, also dem root Konto
gehören.
In großen Exploitdatenbanken kann man anschließend nachschauen, ob zu einem
Gefundenen Service ein Exploit existiert.

6. Weitere Websites auf dem Server

Wird man auf einer Seite nicht fündig, kann man einen Umweg über die Websites
gehen, die auf dem gleichen Server wie die Zielseite liegen.
Das Stichwort ist hierbei „Reverse-IP“ oder „Reverse-DNS“.
Einige Seiten bieten solch einen Dienst an, und zeigen die Seiten mit gleicher IP
an. Manche Seiten sind weniger zuverlässig als andere, dies ist von der Domäne
abhängig die für die Suche zurate gezogen wird.

Beispiele für Reverse-DNS Dienste sind:

http://www.myipneighbors.com/
http://www.domaintools.com/reverse-ip/
http://www.protect-x.com/reverse/

Dies stellt nur einen groben Überblick an Informationen dar, die man beziehen kann, doch können diese Informationen essentiell für ein weiteres Vorgehen sein.
Wer tiefer in die Materie einsteigen möchte sollte sich mit dem Stichwort „Fingerprinting“ umsehen.

Lidloses_Auge PHP , , , , ,

Include in Variable

6. Juni 2009

. [ Show ] in English

Heute hat mich jemand gefragt, ob es möglich ist, das Resultat eines Includes in eine Variable zu schreiben.
Da diese Methode fast garnicht verwenden, aber trotzdem in manchen fällen Interessant sein kann, möchte ich Sie euch einfach mal zeigen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
//startet Buffer
ob_start();
 
//Seite wird in Buffer geladen
include("http://NovuSec.com/");
 
//Der Buffer wird in die Variable geschrieben
$MyIn=ob_get_contents();
 
//Nun wird der Buffer wieder gelöscht
ob_end_clean();
 
//Doch der inhlt bleibt in der Variable und kann verwendet werden
echo $MyIn;
 
?>

Grundsätzlich kann genau so gut file_get_contents() verwendet werden.

Player PHP

PHP Easter Egg sinnvoll nutzen

16. Mai 2009

. [ Show ] in English

Wenn man folgenden Code

?=PHPE9568F36-D428-11d2-A769-00AA001ACF42

an eine Homepage hängt und eine Index.php vorhanden ist, wird ein PHP Logo dargestellt.
z.B.

http://novusec.com/?=PHPE9568F36-D428-11d2-A769-00AA001ACF42

Wie man sehen kann, wird das PHP Logo dargestellt.
Wenn jedoch keine Index.php vorhanden ist, wird auch kein PHP Logo dargestellt.

Wie können wir dieses Easter Egg nun Sinnvoll nutzen?
Auf manchen Homepages werden durch den Mod-Rewrite die Dateiendungen verschleiert. Sprich, man kann nicht mehr erkennen ob es sich um eine HTML-Dateien oder doch um eine PHP-Datei handelt.
Wenn wir nun den Code an die Homepage anhängen und das PHP-Logo erzeugt wird, wissen wir, dass es sich um PHP handelt.

Player PHP, Text Tutorials

PHP_SELF

22. April 2009

. [ Show ] in English

[+] Einleitung
Ich möchte euch heute gerne die Gefahren und Gegenmaßnahmen von php_self erläutern.

[+] Was ist PHP_SELF?
php_self ist eine globale Variable, die den aktuellen Ordner und die Datei des Scriptes ausgibt.
Aufgerufen wird es wie folgt:

1
echo $_SERVER['PHP_SELF'];

[+] Anwendungsmöglichkeiten
php_self wird meistens in Formen verwendet um einen Request an das aufgerufene Script zu senden. z.B:

1
<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">

bei den Seitenaufruf: http://site.de/login.php
sieht die Ausgabe wie folgt aus:

1
<form method="post" action="/login.php">

[+] Angriff
Wie man sich an dieser Stelle denken kann, ist es möglich HTML/Javascript auszuführen.
Die frage ist nur wie?
einen Parameter können wir nicht dranhängen, denn es werden nur Ordner und der Dateiname ausgegeben,
daher müssen wir hinter login.php ein Slash einfügen um zu Simulieren, dass es ein Ordner ist.
Danach den Tag schließen und anschließen kann man HTML/Javascript ausführen.
Der Aufruf sieht dann so aus:
http://site.de/login.php/">< script>alert(document.cookie)

[+] Schutz

1
<form method="post" action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>">

Durch die Funktion htmlentities werden alle Eingaben in HTML Code umgewandelt,
daher ist es nicht mehr möglich fremden Code auszuführen

Player PHP, Text Tutorials, XSS

Screenshot

29. Januar 2009

. [ Show ] in English

Mittels GDLib, gibts es eine möglichkeit Screenshots zu erstellen.
Falls jemand die GDLib nicht kennt, hier ein kleiner ausschnitt aus Wikipedia

Die GD Library, kurz GD oder GDlib, ist eine von Thomas Boutell und anderen entwickelte Open Source-Programmbibliothek zur dynamischen Erzeugung und Manipulation von Grafiken. Die GD Library ist in C geschrieben, es gibt jedoch Schnittstellen zu anderen Programmiersprachen wie Perl oder PHP.

Quelle: http://de.wikipedia.org/wiki/GD_Library

Dazu zeigei ich euch auch gleich den Sourcecode:

1
2
3
4
5
<?php
$im = imagegrabscreen();
imagepng($im, "Screenshot.png");
imagedestroy($im);
?>

Problem bei der ganzen sache ist, dass ihr dazu einen Windows Server braucht, da diese funktion unter Linux nicht unterstütz wird.
Man könnte aber folgendes machen:
Ihr setzt bei euch Xampp auf und installiert die GDLib, dann könnt Ihr das Script local laufen lassen.
Wenn ihr dazu noch euren port 80 Freischaltet, kann man auch von außen drauf zugreifen.
jetzt müsst Ihr nun dafür sorgen, dass jemand draufklickt.

Ist halt nicht besonderes, aber man kann dadurch manche sachen rauskriegen. z.B. welches Antivierenprogramm das potentielle opfer hat ;)

Player PHP