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:
PHP-Code:
<?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:
Code:
$urllist[0][0] = $argv[1];
$ebene = $argv[2];
mit
Code:
$urllist[0][0] = $_GET['url'];
$ebene = $_GET['ebene'];
ersetzt werden.
Der Aufruf des Programms im Konsolenbetrieb lautet: php crawler.php
Also zum Beispiel:
Code:
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:
Code:
[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:
Code:
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