Skip to content

XSS-Angriffe, Teil 8: Ein Portscan mit WebSockets oder Cross-Origin Requests

Schon mit ganz normalen JavaScript-Befehlen lassen sich ein Ping-Befehl und ein Portscanner für einen Host und einen IP-Adressbereich implementieren. Mit HTML5 erhielt JavaScript viele neue Funktionen, und die erleichtern auch den Portscan.

Die Attack and Defense Labs haben wie bereits des öfteren hier erwähnt das JavaScript-basierte Tool JS-Recon zur Suche nach Rechnern in lokalen Netz entwickelt, dass einen Portscan mit Hilfe von WebSockets oder Cross-Origin Requests durchführt. Auf dieser Implementierung und ihrer Beschreibung basiert auch die folgende Erklärung des Funktionsprinzips.

Ein Portscan mit WebSockets oder CORs

Für das Erkennen von offenen, geschlossenen oder gefilterten Ports werden nicht wie beim herkömmlichen JavaScript-Portscan Image-Objekte mit onLoad()- und onError()-Events und Timer verwendet, sondern die Änderungen der readyState-Statuswerte der WebSockets (Ausgangswert 0) oder Cross-Origin Requests (Ausgangswert 1) ausgewertet.

Der readyState zeigt den Status der Verbindung zu einer bestimmten Zeit an. Wird eine WebSocket- oder Cross-Origin-Request-Verbindung zu einem bestimmten Port einer IP-Adresse aufgebaut, wird der readyState auf seinen Ausgangswert gesetzt. In Abhängigkeit vom Status des Ports ändert sich der readyState-Wert nach einer bestimmten Zeit. Die Dauer der Wartezeit bis zum Statuswechsel kann genutzt werden, um zu erkennen, ob der Port, zu dem die Verbindung aufgebaut wurde, offen oder geschlossen ist oder gefiltert wird, siehe die folgende Tabelle.

Port-Status WebSocket (Ausgangswert readyState 0) COR (Ausgangswert readyState 1)
Offen (Anwendung Typ 1/2, s.u.) < 100 ms < 100 ms
Geschlossen ~ 1.000 ms ~ 1.000 ms
Gefiltert > 30.000 ms > 30.000 ms

Es gibt zwei Einschränkungen für diese Art von Portscan: Die Browser blockieren Verbindungen zu den Well Known Ports, so dass sie nicht gescannt werden können. Port 80 ist davon aber ausgenommen, so das nach Webservern gesucht werden kann. Und die Scans finden auf Anwendungsebene statt, so dass die Antwort von der Anwendung abhängig ist, die am gescannten Port lauscht. Das Ergebnis so eines Portscans ist aber hinreichend genau, um brauchbar zu sein.

Bei den Anwendungen sind vier mögliche Antworten zu unterscheiden:

  1. "Close on connect" - Die Protokolle sind nicht kompatible und die Anwendung schließt die Verbindung sofort nach dem Aufbau
  2. "Respond & close on connect" - Wie Type 1, aber die Anwendung schickt vor dem Schließen der Verbindung eine Default-Antwort.
  3. "Open with no response" - Die Anwendung hält die Verbindung offen und wartet auf weitere Daten oder Daten, die ihrem Protokoll entsprechen.
  4. "Open with response" - Wie Type 3, die Anwendung schickt nach dem Verbindungsaufbau aber eine Default-Antwort wie ein Banner oder eine Willkommens-Nachricht.

Das Verhalten von WebSockets und CORs für jeden dieser Typen zeigt die folgende Tabelle:

Anwendungstype WebSocket (Ausgangswert readyState 0) / COR (Ausgangswert readyState 1)
"Close on connect" < 100 ms
"Respond & close on connect" < 100 ms
"Open with no response" > 30.000 ms
"Open with response" < 100 ms (Firefox, Safari) ¦ > 30.000 ms (Chrome)

Vereinfach funktioniert der Portscan damit so:

  • Der readyState wird auf den Default-Wert gesetzt.
  • Ein Timer wird gestartet.
  • Ein Cross-Origin- oder WebSocket-Request wird an den vermuteten Rechner geschickt.
  • Es wird auf die Änderung des readyState-Werts gewartet.
  • Die Zeit bis zur Änderung des readyState-Werts verrät, ob der kontaktierte Port offen, geschlossen oder gefiltert ist und damit, ob der vermutete Rechner existiert (Port ist offen oder geschlossen) oder nicht (Port ist "gefiltert").

Ein Portscan mit WebSockets für Port 80 der IP-Adresse ip könnte dann wie im folgenden Listing aussehen:

var ws;
var start_time;
var open_port_max=300;
var closed_port_max=2000;

function scan_port_ws(ip)
{
    start_time = (new Date).getTime();
    try
    {
        ws = new WebSocket("ws://" + ip + ":80");
        setTimeout("check_ps_ws()",5);
    }
    catch(err)
    {
        return;
    }
}

function check_ps_ws()
{
    var interval = (new Date).getTime() - start_time;
    if(ws.readyState == 0)
    // bisher keine Status-Änderung
    {
        if(interval > closed_port_max)
        {
            // Timeout erreicht, Port 80 wird gefiltert
        }
        else
        {
            // weiter warten
            setTimeout("check_ps_ws()",5);
        }
    }
    else
    // der readyState hat sich geändert
    {
        if(interval < open_port_max)
        {
            // Port 80 ist offen
        }
        else
        {
            // Port 80 ist geschlossen
        }
    }
}

Der Portscan für mehrere Ports läuft dann genau so wie im klassischen Beispiel ab: Der Reihe nach wird für jeden zu prüfenden Port ein Cross-Origin Request an den entsprechenden Port der zu testenden IP-Adresse geschickt bzw. eine WebSocket-Verbindung dorthin aufgebaut. Je nachdem, wie schnell sich der readyState-Wert ändert kann man darauf schließen, dass der kontaktierte Port offen, geschlossen oder gefiltert ist.

Und auch der Scan eines IP-Bereichs folgt dem klassischen Beispiel: Der Reihe nach werden für jede zu testende IP-Adresse die gewünschten Ports geprüft.

Sie haben jetzt mehrere Möglichkeiten kennen gelernt, wie mit JavaScript nach Rechnern im lokalen Netz gesucht werden kann. In der nächsten Folge sehen wir uns mal an, was ein Angreifer dort denn so findet, und was er dann anstellen kann.

Carsten Eilers


Übersicht über alle Artikel zum Thema

Cross-Site Scripting im Überblick, Teil 1: Reflektiertes XSS
Cross-Site Scripting im Überblick, Teil 2: Persistentes XSS
Cross-Site Scripting im Überblick, Teil 3: Der MySpace-Wurm Samy
Angriffe über Cross-Site Scripting: Der Sourcecode des MySpace-Wurms Samy
Cross-Site Scripting im Überblick, Teil 4: DOM-basiertes XSS
Cross-Site Scripting im Überblick, Teil 5: Resident XSS
XSS-Angriffe, Teil 1: Informationen einschleusen
XSS-Angriffe, Teil 2: Cookies und Tastendrücke ausspähen
XSS-Angriffe, Teil 3: Zugangsdaten ausspähen
XSS-Angriffe, Teil 4: Ein Blick in die History, und dann auf ins LAN!
XSS-Angriffe, Teil 5: Ein Portscan (nicht nur) im LAN
XSS-Angriffe, Teil 6: Ein verbesserter Portscanner
XSS-Angriffe, Teil 7: Hindernisse beim JavaScript-Portscan beseitigen
XSS-Angriffe, Teil 8: Ein Portscan mit WebSockets oder Cross-Origin Requests
XSS-Angriffe, Teil 9: Der Router im Visier
XSS-Angriffe, Teil 10: Weitere Angriffe auf den Router
XSS-Angriffe, Teil 11: Unerwünschtes Firmware-Update für den Router
XSS-Angriffe, Teil 12: Browser-basierte Botnets
XSS-Angriffe, Teil 13: Fortgeschrittene Angriffe
XSS-Angriffe, Teil 14: Das Browser Exploitation Framework BeEF

Trackbacks

Dipl.-Inform. Carsten Eilers am : Die IoT Top 10, #1: Unsichere Weboberflächen, Teil 5

Vorschau anzeigen
Die Beschreibung der gefährlichsten Schwachstellen in den Geräten des IoT geht weiter. In der Liste der Top IoT Vulnerabilities von OWASP sind wir immer noch bei Platz 1, dem &quot;Insecure Web Interface&quot;. Aber wenigstens sind wir beim zweiten