Skip to content

Cross-Site Scripting im Überblick, Teil 4: DOM-basiertes XSS

Bisher ging es mit reflektierten und persistenten XSS um Angriffe, die über die Webanwendung auf dem Server laufen. Thema der heutigen Folge ist das DOM-basierte XSS, dass ausschließlich im Client-Code im Webbrowser abläuft.

Was ist DOM-basiertes XSS?

Erstmals beschrieben wurde DOM-basiertes XSS 2005 von Amit Klein.

Der Angriff spielt sich ausschließlich im Webbrowser ab, im Unterschied zu Angriffen über reflektiertes oder persistentes XSS ist der Schadcode niemals Bestandteil der vom Server gelieferten HTML-Daten. Weder der Server noch ein IDS/IPS oder eine Web Application Firewall können ihn darin also erkennen.

Der Client-seitige Code einer Webanwendung ist immer dann für DOM-basiertes XSS anfällig, wenn sie Daten aus vom Angreifer kontrollierbaren Objekten wie zum Beispiel document.location, document.URL oder document.referrer oder in Zeiten von HTML5 und Web 2.0 auch irgend welche lokalen Eingaben ohne Prüfung auf eingeschleusten Code verwendet. Das folgende Beispiel folgt Amit Kleins Beispiel aus seinem Paper.

DOM-basiertes XSS im Beispiel

Eine Webseite enthält den folgenden Code:

Hallo
<script>
  var pos=document.URL.indexOf("name")+5;
  document.write(document.URL.substring(pos,document.URL.length));
</script>
,<br>

Herzlich Willkommen auf dieser Seite ...

Beim Aufruf dieser Seite wird der Benutzer mit seinem Namen begrüßt, zum Beispiel beim Aufruf von

http://www.beispiel.example/index.html?name=Carsten

mit

Hallo Carsten,
Herzlich Willkommen auf dieser Seite ...

Der übliche XSS-Test mit

http://www.beispiel.example/index.html?name=<script>alert('XSS')</script>

führt dagegen zum Öffnen der Alertbox.

Dieses Beispiel funktioniert nicht, wenn der Webbrowser den URL selbständig URL-kodiert, wie es zum Beispiel Mozilla und Firefox tun. Dadurch werden die < und > zu %3C bzw. %3E, was die spätere Codeausführung verhindert. Die Umkodierung verhindert aber keine Angriffe, die nicht auf < und > angewiesen sind.

Der Angriff ist möglich, weil der Browser beim Aufruf des präparierten URL einen HTTP-Request an www.beispiel.example sendet, die statische HTML-Seite mit obigen Code darin empfängt und dann beginnt, die HTML-Daten in das DOM zu parsen. Das DOM enthält das Objekt document, das die Eigenschaft URL besitzt, in der der URL der aktuellen Seite steht. Erreicht der Parser den JavaScript-Code, führt er ihn aus und ändert entsprechenden den enthaltenen Anweisungen die Seite. Der Code kopiert einen Teil des Inhalts von document.URL in die HTML-Seite. Im Beispiel also "Carsten" - oder eben den Schadcode "<script>alert('XSS')</script>". Das Ergebnis sieht im zweiten Fall folgendermaßen aus:

Hallo <script>alert('XSS')</script>,
Willkommen auf dieser Seite ...

Die fertiggestellte HTML-Seite wird dann geparst - und dabei der eingeschleuste Skriptcode ausgeführt.

DOM-basiertes XSS tarnen

Wie bereits oben erwähnt ist der Schadcode nie Bestandteil der vom Server gelieferten HTML-Seite. Nur die im Request mitgelieferten Query-Daten verraten ihn, aber auch das kann umgangen werden. Dazu wird der Schadcode als Fragmentbezeichner getarnt:

http://www.beispiel.example/index.html#name=<script>alert('XSS')</script>

Das #-Zeichen markiert den darauf folgenden Rest des URL als Fragmentbezeichner. Der enthält Referenzierungs-Informationen, die vom Browser nach dem Empfang der Ressource lokal ausgewertet werden. Die meisten Browser senden den daher Fragmentbezeichner nicht an den Server, der dadurch nur

http://www.beispiel.example/index.html

zu sehen bekommt.

Dieser Trick funktioniert nicht immer. Zum Beispiel ist eine solche Tarnung nicht möglich, wenn der Schadcode über den Benutzernamen oder das Passwort eines URL nach dem Muster http://Benutzername:Passwort@www.beispiel.example eingeschleust wird. Der Schadcode wird dann als Bestandteil des Authorization-Headers an den Server gesendet, wo er erkannt werden kann. Er wird aber auch bei diesem Angriff nicht vom Server in die Antwort eingebettet, das erledigt später der Browser beim Parsen der empfangenen Seite.

Parameter-Prüfungen unterlaufen

Wird der zum Einschleusen des Schadcodes verwendete Parameter vom Server geprüft, kann er unter Umständen durch die Verwendung eines anderen Namens getarnt werden:

http://www.beispiel.example/index.html?noname=<script>alert('XSS')</script>

Der JavaScript-Code sucht nur nach dem String name, dass da in diesem Fall ein no davor steht, stört ihn nicht.

Muss der Parameter name vorhanden sein, zum Beispiel weil sein Wert vom Server geprüft wird, kann er einfach an den URL mit dem Parameter mit falschen Namen angehängt werden:

http://www.beispiel.example/index.html?noname=<script>alert('XSS')</script>&name=Carsten

Den Server stört der ihm unbekannte Parameter noname nicht, er prüft wie vorgesehen den Wert des Parameters name. Der JavaScript-Code auf dem Client verwendet dagegen das erste Vorkommen von name - und das ist das in noname. Und damit kommt der XSS-Code in noname zum Zuge und wird ausgeführt.

Darf name nicht Bestandteil des zusätzlichen Parameters sein, kann er evtl. über einen Parameter mit anderen, zulässigen Namen getarnt werden:

http://www.beispiel.example/index.html?nix=name=<script>alert('XSS')</script>&name=Carsten

Der nicht verwendete Parameter nix kommt zuerst, als dessen Wert wird der für das Einschleusen verwendete Parameter samt Schadcode verwendet: name=<script>alert('XSS')</script>. Bei der Auswertung durch den JavaScript-Code gilt das oben schon geschriebene: In welchen Kontext das name steht, ist egal. Nur sein Vorkommen zählt.

In der nächsten Folge gibt es noch eine kurze Beschreibung des Resident XSS, danach werden verschiedene Angriffe über XSS beschrieben.

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