Webseitensicherheit – XSS

Kennen Sie den Begriff XSS für Cross Site Scripting?

Wenn nein, dann sollten Sie den Artikel unbedingt lesen, wenn Sie beispielsweise einen Webservice zur Speicherung Ihrer Kennwörter verwenden. Fragen Sie bei Ihrem Provider nach, um Ihr digitales Erbe zu schützen. Wir erklären Ihnen in diesem Artikel, was es ist und anhand von Beispielen zeigen wir, wie es grundsätzlich funktioniert.

Cross Site Scripting (XSS) ist einer der beliebtesten Angriffe, der jedem fortgeschrittenen Hacker bekannt ist. Er gilt als einer der riskantesten Angriffe für Webanwendungen und kann auch schädliche Folgen für den Betreiber von Webseiten haben.

Einführung in den XSS-Angriff

Ein Cross-Site-Scripting-Angriff ist eine Injektion von bösartigem Code, der im Browser des Opfers ausgeführt wird. Das bösartige Skript kann auf dem Webserver gespeichert werden und wird jedes Mal ausgeführt, wenn der Benutzer die entsprechende Funktion aufruft. Er kann auch mit den anderen Methoden durchgeführt werden, ohne dass ein Skript auf dem Webserver gespeichert ist.

Der Hauptzweck dieses Angriffs besteht darin, die Identitätsdaten des anderen Benutzers zu stehlen – Cookies, Sitzungs-Tokens und andere Informationen. In den meisten Fällen wird dieser Angriff genutzt, um die Cookies der anderen Person zu stehlen. Wie wir wissen, helfen uns Cookies dabei, uns automatisch anzumelden. Daher können wir uns mit gestohlenen Cookies mit anderen Identitäten anmelden. Dies ist einer der Gründe, warum dieser Angriff als einer der gefährlichsten Angriffe angesehen wird.

Der XSS-Angriff wird auf der Client-Seite durchgeführt. Er kann mit verschiedenen clientseitigen Programmiersprachen durchgeführt werden. Am häufigsten wird dieser Angriff jedoch mit Javascript und HTML durchgeführt.

Wie wird XSS durchgeführt?

Bei einem Cross-Site-Scripting-Angriff wird bösartiger Code oder ein Skript gesendet und eingeschleust. Bösartiger Code wird normalerweise mit clientseitigen Programmiersprachen wie Javascript, HTML, VB Script, Flash usw. geschrieben. Am häufigsten werden jedoch Javascript und HTML verwendet, um diesen Angriff durchzuführen.

Dieser Angriff kann auf unterschiedliche Weise durchgeführt werden. Je nach Art des XSS-Angriffs kann das bösartige Skript im Browser des Opfers reflektiert oder in der Datenbank gespeichert und jedes Mal ausgeführt werden, wenn der Benutzer die entsprechende Funktion aufruft.

Der Hauptgrund für diesen Angriff ist eine unangemessene Validierung der Benutzereingaben, durch die bösartige Eingaben in die Ausgabe gelangen können. Ein böswilliger Benutzer kann ein Skript eingeben, das in den Code der Website eingeschleust wird. Der Browser ist dann nicht in der Lage zu erkennen, ob der ausgeführte Code bösartig ist oder nicht.

Daher wird ein bösartiges Skript im Browser des Opfers ausgeführt oder ein gefälschtes Formular für die Benutzer angezeigt. Es gibt verschiedene Formen von XSS-Angriffen.

Die Hauptformen von Cross Site Scripting sind wie folgt:

Cross-Site-Scripting kann in einem bösartigen Skript auftreten, das auf der Client-Seite ausgeführt wird.

Auf gefälschten Seiten oder Formularen, die dem Benutzer angezeigt werden (wo das Opfer Anmeldedaten eingibt oder auf einen bösartigen Link klickt).

Auf Websites mit eingeblendeter Werbung.

Bösartige E-Mails, die an das Opfer gesendet werden.

Dieser Angriff erfolgt, wenn der böswillige Benutzer die anfälligen Teile der Website findet und sie als entsprechende böswillige Eingabe sendet. Ein bösartiges Skript wird in den Code injiziert und dann als Ausgabe an den Endbenutzer gesendet.

Kommen wir zur Praxis!

Wir nutzen die Demoseiten von Google (xss-game.appspot.com), um die praktischen Beispiele zu veranschaulichen.

In der Demoseite erkennen wir ein Eingabefeld. Wir testen das Eingabefeld, ob es Abfragen abfängt. Ist die Eingabe nicht gestützt, so können wir Befehle dort eintragen, die der Webserver dann ausführt.

Bild 1

Dazu benutzen wir den TAG <script></script>. Sollte der Webserver den Tag akzeptieren, dann können wir dort weitere Befehle eintragen.

Nachdem wir den TAG gesetzt haben, drücken wir auf „Search“.

Bild 2

Wir sehen im Bild 2, dass der Script befehle (Tag) vollständig vom Webserver (siehe URL) übernommen wurde. Das bedeutet, dass er wohl auch weitere Befehle akzeptiert. Auch der Quellcode der Seite zeigt, dass die Variable „query“ ungefiltert zum Seitenaufbau verwendet wird.

if not self.request.get(‚query‘):

# Show main search page

self.render_string(page_header + main_page_markup + page_footer)

else:

query = self.request.get(‚query‘, ‚[empty]‘)

# Our search engine broke, we found no results 🙁

Somit ist die Seite verwundbar. Wir können hier auch einen Befehl zur Datenbankabfrage absetzen.

Der Einfachheitshalber setzen wir nur einen „alert(0)“ ein und die Seite reagiert auf den Befehl und führt einen alert aus.

Kommen wir zum zweiten Beispiel.

Simuliert wird ein Forum. So wie es in Internet vielfach vorkommt.

Was wir auf den ersten Blick sofort erkennen ist, dass der bereits existierenden Beitrag HTML Tags akzeptiert. Man kann es beispielsweise an der Formatierung der Schriftart erkennen.

Probieren wir aber erst den Tag <script>…</script>.

In diesem Beispiel wird das Skript JavaScript oder VB Script aber nicht ausgeführt. Somit suchen wir einen anderen Weg. Wie bereits erwähnt könnt uns hier ein HTML Tag weiterbringen.

Das bestätigt auch der Quellcode der Seite.

var posts = DB.getPosts();

for (var i=0; i<posts.length; i++) {

var html = ‚<table class=“message“> <tr> <td valign=top> ‚

+ ‚<img src=“/static/level2_icon.png“> </td> <td valign=top ‚

+ ‚ class=“message-container“> <div class=“shim“></div>‘;

html += ‚<b>You</b>‘;

html += ‚<span class=“date“>‘ + new Date(posts[i].date) + ‚</span>‘;

html += „<blockquote>“ + posts[i].message + „</blockquote„;

html += „</td></tr></table>“

containerEl.innerHTML += html;

 

Wir können unschwer erkennen, dass hier ein HTML-Befehl zusammengesetzt wird und unsere Eingabe post[i].message ungeschützt übernommen wird. Darum scheitern auch die Scriptsprachen.

Das bedeutet, dass wir uns einem HTML-Tag zusammenstellen müssen, der einen Befehl ausführt. Wir wollen auch in diesem Beispiel nur einen „alert“ erzeugen.

Wir laden beispielsweise eine Datei, die nicht existiert und erzeugen einen Fehler. Das alles im HTML-Format.

<img src=’aaa‘ onerror=’alert()‘>

Den Befehl „onerror“ wählen wir deshalb, weil er ein JavaScript ausführen kann, wenn er auftritt. Und wie wir bereits wissen, könnten wir dann auch auf Datenbank zugreifen.

Beispielsweise könnte im weiterführenden Sinnen der Code

var sql = „INSERT INTO users (name, password, level) VALUES (‚Admin‘, ‚aa3432fe34f32‘, 500)“;

lauten oder wir aktualisieren das Kennwort eines Administrators. Weiterhin könnte ich den Code bei Webseiten ändern, da moderne Content Management Systeme (z.B. WordPress) den Code aus Datenbankinhalten zusammensetzen.

Fazit ist, dass die Seite verwundbar ist.

Somit haben wir einmal mit HTML-Tags und einmal mit JavaScript-Tags eine Seite gehackt.

 

Kommen wir zum dritten Beispiel.

Bild 4

Wir sehen eine Seite, die keine Eingabefelder hat. Es gibt drei Tabulatoren. Jeder Tabulator zeigt ein Bild.

Bild 5

Somit können wir zunächst kein Script irgendwo einsetzen. Sollten wir aufgeben?

Natürlich nicht! Wir erkennen, dass sich der sogenannten „payload“ in der URL verändert, wenn ich den Tabulator wechsle. Er gibt also an, welches Bild geladen wird.

Sehen wir uns den Quellcode an.

function chooseTab(num) {

// Dynamically load the appropriate image.

var html = „Image “ + parseInt(num) + „<br>“;

html += „<img src=’/static/level3/cloud“ + num + „.jpg‘ />“;

$(‚#tabContent‘).html(html);

 

window.location.hash = num;

 

// Select the current tab

 

Und wieder kann man erkennen, dass ein HTML Befehl zusammengebaut wird. Wir müssen also den Wert „num“ manipulieren. Der Wert „num“ ist hinter …frame# in der URL zu finden, wie wir unschwer erkennen können.

Wir kennen das schon aus dem zweitens Beispiel. Wenn wir einen Fehler erzeugen, dann können wir mithilfe der Funktion „onerror“ ein JavaScript ausführen.

Wir können dies realisieren, indem wir das src-Attribut mit einem einfachen Anführungszeichen schließen und dann ein onerror-Attribut mit einer Warnfunktion wie in der vorherigen Ebene hinzufügen und den ‚.jpg‘-Teil mit doppelten Schrägstrichen kommentieren.

Fügen wir also 1′ onerror=’alert();// der URL hinzu und laden die Seite neu. Schon wird unsere Javascript Funktion „alert(0)“ vom Browser ausgeführt.

Siehe sehen, dass man einen Webserver auch manipulieren kann, wenn kein Eingabefeld vorhanden ist. Angriffe können auch über die URL stattfinden.

 

Kommen wir zum vierten Beispiel

Wir haben ein Eingabefeld und einen Knopf, der den Count-down startet.

Die URL hat keinen manipulierbaren „payload“.  Vielleicht können wir auch diesmal ein Skript ins Eingabefeld absetzen. Sehen wir uns den Quellcode an.

</head>

<body id=“level4″>

<img src=“/static/logos/level4.png“ />

<br>

<img src=“/static/loading.gif“ onload=“startTimer(‚{{ timer }}‘);“ />

<br>

<div id=“message“>Your timer will execute in {{ timer }} seconds.</div>

</body>

Bedauerlicherweise können wir kein Skript (<script>… …</script>direkt im Eingabefeld ausführen. Eingaben dieser Art werden diesmal „gefiltert“.

Wir sehen aber, dass sich Übergabeparameter in der URL befinden. In unserem Fall “?timer=10“.

 

Bild 6

Wir können deutlich erkennen, dass es eine „Timer“ Funktion gibt.

Wir können versuchen, die Timer-Funktion auszutricksen, um beliebigen Code auszuführen, da sie direkt in die Seite eingefügt wird und sie beim Seitenaufbau integriert ist. Weiterhin erkennen wir, dass der Wert des Eingabefeldes direkt in die URL übernommen wird.

Im vorherigen Beispiel konnten wir die URL manipulieren.

Wir schreiben also ins Eingabefeld folgendes:

10’**alert(0));//

im Bild 7 sehen Sie, was passiert. Unsere Eingabe wird übernommen.

Bild 7

Warum funktioniert das? Der Wert, den wir von der Indexseite übergeben haben, wird direkt in den Funktionsparameter am Timer eingefügt.

<img src=“/static/loading.gif“ onload=“startTimer(‚{{ timer }}‘);“ />

Wir können also das hier ausgeführte Javascript manipulieren. Wenn wir den folgenden Parameter übergeben:

10’**alert(0));//

Das Javascript wird versuchen, 10**alert(0) auszuwerten, bevor es die startTimer-Funktion aufruft. Um das Ergebnis von 10**alert(0) auszuwerten, muss es außerdem den von der Funktion alert() zurückgegebenen Wert erhalten, was den Browser veranlasst, die alert-Funktion auszuführen.

Sie können also sehen, dass wieder Eingaben im Eingabefeld dafür verantwortlich waren, dass wir die Seite manipulieren und Scripte ausführen konnten.

 

Kommen wir zu einem weiteren Beispiel:

Bild 8

URL und Seite wirken „normal“ und sicher.

Wir haben nur einen „Link“.

Bild 9

Der Link führt uns zu einer Seite, in der wir ein Eingabefeld haben. Wie Sie nun bereits wissen, setzen wir hier sofort an.

Doch davor probieren wir den Link „Next“ aus.

Hier kommen wir zu einer dritten Seite.

Bild 10

Sieht rechte einfach aus.

Setzen wir in Seite 2 doch eine E-Mail-Adresse ein und sehen weiter.

Bild 11

Und klicken auf „Next >>“.

Bild 12

Bedauerlicherweise werden unsere Eingaben nicht sichtbar zum Aufbau der dritten Seite verwendet.

So kommen wir also nicht weiter. Wir sehen aber, dass sich die URL verändert, wenn wir auf „Next >>“ auf der Seite 2 klicken. Vielleicht sollten wir dort ansetzen.

Auf der Anmeldeseite (Seite 2) können wir eine E-Mail-Adresse eingeben (oder etwas anderes, es wird ja nicht ausgewertet) und auf den Link next klicken, der uns zu der Seite führt, die durch den nächsten Parameter übergeben wird (z. B. ?next=confirm). Wir können diesen Parameter überlisten, indem wir Javascript-Code einfügen, der die Warnfunktion ausführt.

Wie wir sehen können wir mit „Next>>“ den „payload“ verändern.

In das Eingabefeld tragen wir „javascript:alert(0)“ ein.

Warum funktioniert das? Die Bestätigungsseite akzeptiert auch den nächsten Parameter und verwendet ihn, um den Benutzer an den angegebenen Wert weiterzuleiten, wie wir im Quellcode sehen.

<script>

setTimeout(function() { window.location = ‚{{ next }}‘; }, 5000);

</script>

Nachdem die Zeit abgelaufen ist, werden wir zum Link weitergeleitet:

javascript:alert(0)

Dieser wird vom Browser als Bookmarklet verstanden und führt den Code aus.

Somit ist auch diese Seite angreifbar.

 

Für alle, die das Google-Spiel probieren, hier ist die letzte Lösung:

Als „payload“ muss man

//www.google.com/jsapi?callback=alert

anhängen.

Lesen Sie hierzu auch die rfc3986, um das Thema zu durchleuchten.

Als Fazit können wir also folgendes festhalten.

Webseiten sind möglicherweise angreifbar. Wir müssen unbedingt auf die Eingabefelder achten.

Sind dem Angreifer noch mehr Details der Webseite bekannt, so kann er Skripte verfeinern und entsprechende gezielte Angriffe starten.

Es ist auch keine Schande, wenn eine Webseite für XSS anfällig ist. Sie befinden sich in guter Gesellschaft. Sony, Amazon, firstpass und viele mehr sind durch solche Angriffe bereits in Mitleidenschaft gezogen worden.

Deshalb unser Rat an dieser Stelle. Legen Sie Ihre Kennwörter nicht bei einem Internetprovider im Netz ab. Wer weiß, ob er nicht das nächste Opfer ist.

 

 

 

Post by Digitales Erbe

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert