Samstag, 31. Juli 2010 |
Das in About Security #133 beschriebene JavaScript Ping lässt sich zu einem JavaScript Portscan erweitern, mit dem dann im lokalen Netz nach Webservern gesucht werden kann. Zuerst muss dazu festgestellt werden, ob eine HTTP-Verbindung zustande gekommen ist oder nicht. Dazu wird ein iFrame in Verbindung mit einem onLoad()-Event und einem Timer verwendet. Das src-Attribut des iFrames wird gesetzt und der Timer gestartet. Läuft auf dem gefundenen Host ein Webserver, wird der onLoad()-Event ausgelöst. Ist kein Webserver erreichbar, wird der Timer Event ausgelöst.
Nachdem so erst Hosts und danach Webserver ermittelt werden können, stellt sich die Frage, welcher Webserver oder welche Webanwendung genau gefunden wurde. Für das so genannte Fingerprinting wird wieder ein Image-Objekt mit einem OnLoad()-Event verwendet. Damit wird nach für Webservern/Webanwendungen typischen Bildern gesucht, wobei nur noch zwei mögliche Ergebnisse vorkommen können: Ein angefordertes Bild wird geladen oder es wird nicht geladen. Konnte das Bild geladen werden, werden seine Dimensionen mit den bekannten Werten verglichen. Stimmen sie überein, wird davon ausgegangen, dass der Webserver erfolgreich identifiziert wurde. Stimmen sie nicht überein oder konnte das Bild nicht geladen werden, wird mit dem nächsten Bild weitergemacht. Statt nach Bildern kann auch z.B. nach typischen CSS- oder JavaScript-Dateien gesucht werden. Typische Bilder sind z.B. für Microsofts IIS das 36x48 Pixel große Bild /pageerror.gif oder für Apache-Webserver das 20x22 Pixel große Bild /icons/c.gif. Für die Erkennung der webbasierten Konfigurationsoberflächen von Netzwerkgeräten wie z.B. Routern können meist spezifische Bilder der jeweiligen Hersteller verwendet werden ("Wo XYZ draufsteht, ist auch ein XYZ-Icon drin").
N E U ! Security
aktuell
Täglich aktuelle Security-Infos!
Das Prinzip ist also verblüffend einfach. Trotzdem wurde das Verfahren erst 2006 von den SPI Labs vorgestellt: 'Detecting, Analyzing, and Exploiting Intranet Applications using JavaScript'. Der Text und das dazu gehörende Beispiel sind leider nicht mehr online verfügbar, jedoch gibt es inzwischen andere JavaScript Portscanner im Web, z.B. bei GNUCITIZEN. An dessen Sourcecode lehnt sich das folgende Beispiel an. Eine verbesserte Version dieses Portscanners ist Bestandteil der AttackAPI von GNUCITIZEN.
PortScanner = {};
PortScanner.scanPort = function (callback, host, port, timeout) {
var timeout = (timeout == null)?100:timeout;
var img = new Image();
img.onerror = function () {
if (!img) return;
img = undefined;
callback(host, port, 'open');
};
img.onload = img.onerror;
img.src = 'http://' + host + ':' + port;
setTimeout(function () {
if (!img) return;
img = undefined;
callback(host, port, 'closed');
}, timeout);
};
Die Funktion scanPort() ist für den
eigentlichen Portscan
zuständig. Wie bereits beschrieben, wird ein neues Image-Objekt mit
onLoad()- und onError()-Event sowie einem Timer erzeugt, dessen
src-Attribut auf den zu prüfenden Host und Port gesetzt wird.
Außer Host, Port und gewünschtem Wert für den Timer wird
eine Callback-Funktion für die Ausgabe des Ergebnisses übergeben.
Bei Bedarf könnte auch nach einem bestimmten Bild gesucht werden, dann
müsste allerdings der onLoad()-Event passend erweitert werden.
Möchte man mehrere Ports eines Hosts mit einem Aufruf prüfen, ist eine weitere Funktion notwendig:
PortScanner.scanHost = function (callback, host, ports, timeout)
{
for (index = 0; index < ports.length; index++)
PortScanner.scanPort(callback, host, ports[index], timeout);
};
scanHost() wird u.a. mit einem Array mit den
zu prüfenden
Ports aufgerufen. Das Array kann beim Aufruf durch split(',')
aus einer z.B. über ein Formular übergebenen Liste durch Kommata
getrennter Ports erzeugt werden.
Soll nicht nur ein einzelner Host, sondern ein IP-Adressbereich gescannt werden, muss scanHost() lediglich für jede zu prüfende IP-Adresse aufgerufen werden. Werden die IP-Adressen als String in der Form a.b.c.d übergeben, muss daraus zuerst ein Array mit Integer-Werten erzeugt werden. Dies kann eine Funktion nach folgendem Muster übernehmen:
function erzeugeIPArray(ipString)
{
var stringArray = ipString.split('.');
// String in Array mit Strings aufteilen
var intArray = new Array();
// Array für Integer-Werte bereitstellen
var i;
for(i =0; i < stringArray.length; i++)
{
intArray[i] = parseInt(stringArray[i]);
// String in Integer-Wert umwandeln
}
return intArray;
}
Die IP-Adressen können nicht durch einfaches Heraufzählen durchgegangen werden. Stattdessen übernimmt folgende Funktion das Berechnen der nächsten IP-Adresse:
function erhoeheIP(dieIP)
{
var i;
var c;
for(i = 3; i>=0; i--)
{
if(dieIP[i] < 255 ¦¦ i == 0)
{
dieIP[i]++;
return dieIP;
}
else {
// Der Wert im aktuellen Segment i kann nicht erhöht werden,
// da dass zu einem Überlauf führen würde
// Daher muss im Segment davor weitergemacht werden
dieIP[i] = 0;
dieIP[i-1]++;
}
}
}
In der nächsten Folge wird dieses Beispiel weiter fortgeführt.
Wenn Sie Fragen oder Themenvorschläge haben, können Sie diese gerne an die angegebene E-Mail-Adresse senden oder im Security-Forum einbringen!
About Security – Übersicht zum aktuellen Thema "Sichere Webanwendungen – Cross-Site Scripting"