Skip to main content

Fetch the Flag CTF 2022: Logster – Lösungsbericht

Artikel von
feature ctf logster

10. November 2022

0 Min. Lesezeit

Danke, dass Sie mit uns Fetch gespielt haben! Glückwunsch an die Tausenden Spielerinnen und Spieler, die bei Fetch the Flag CTF dabei waren. Ein großes Dankeschön auch an die Snyker, die die Challenges entwickelt, getestet und dokumentiert haben!

Wenn Sie bei Snyks Fetch the Flag 2022 dabei waren und nach der Lösung für die Challenge Logster suchen, sind Sie hier richtig. Gehen wir die Lösung gemeinsam durch!

Beginnen wir mit der Erkundungsphase

In dieser Phase identifiziert ein Angreifer ein verwundbares Ziel und untersucht, wie es sich ausnutzen lässt. In unserem Fall erhalten wir einen Link zu einer Website. Für den Einstieg genügt ein einziger Zugangspunkt.

Logster-500-Lookup-Tool für eine Jnioromous-Shell mit einem Link zu logster.cctf-snyk.io

Zuerst prüfen wir den Link und rufen http://logster.c.ctf-snyk.io/ auf. Auf dieser Website können wir eine Website scannen.

Website-Scanner-Oberfläche mit einem Adressfeld, den Schaltflächen „More“ und „Scan“ sowie einem Bereich „Raw Headers“, der keine Daten anzeigt

Versuchen wir es mit https://www.cnn.com/. Die Header werden angezeigt:

Website-Scanner mit https://www.cnn.com/ im URL-Feld und einem Rohdaten-Headerprotokoll mit HTTP-200-Status

Aus der Challenge-Beschreibung („lookup“) und der Programmiersprache (Java) können wir schließen, dass es sich um Log4Shell handelt.

Starten wir das Tunneling!

Erstellen wir nun einen Express-Webserver, um benutzerdefinierte Header festzulegen, richten einen ngrok-Tunnel ein, um den Server lokal auszuführen, und machen ihn anschließend im Internet erreichbar. Danach scannen wir ihn und sehen uns das Ergebnis an!

Wenn Sie nicht wissen, wie Sie einen Express-Server einrichten, hilft Ihnen für diesen Schritt die offizielle Dokumentation.

Dunkler Code-Editor mit einem Express.js-Server, dessen Root-Route „Hello World!“ zurückgibt und auf Port 3000 lauscht.

Wir richten unseren Express-Server so ein, dass er auf Port 3000 läuft, und setzen mit ('PWN', 'pwn') einen benutzerdefinierten Header.

Starten wir ihn mit dem Befehl node express.js:

Terminal mit einer Fetch-the-Flag-Beispiel-App in Node.js und Express, die auf Port 3000 lauscht

Richten wir außerdem mit dem Befehl ngrok http 3000 den ngrok-Tunnel ein. In der offiziellen ngrok-Dokumentation erfahren Sie, wie Sie ihn auf Ihrem Rechner einrichten.

Terminal mit einer laufenden ngrok-Sitzung, die eine öffentliche HTTPS-URL an localhost:3000 weiterleitet, einschließlich Verbindungsstatistiken und Inspektions-URL.

Kopieren Sie den Weiterleitungslink, fügen Sie ihn auf der Website ein und starten Sie den Scan. In der ngrok-Konsole (http://localhost:4040/) sehen wir, dass der Header den Inhalt aus unserer Datei express.js wiedergibt.

ngrok-Inspect-Konsole mit einer Liste von GET-Anfragen mit 200-OK-Antworten und detaillierten HTTP-Headern

Versuchen wir, einen Header mit einer Log4Shell-artigen Payload festzulegen. Öffnen wir wieder unsere Datei express.js und ändern den Header in ('${java:version}', 'pwn'):

Dunkler Code-Editor mit einer Express.js-App: Eine Root-Route gibt „Hello World!“ zurück und lauscht auf Port 3000

Starten Sie den Server neu und führen Sie einen weiteren Scan der Website durch. Wir erhalten einen 500 Internal Server Error. In den Protokollen sehen wir, dass der Headername ein gültiges HTTP-Token sein muss.

Server-Anfrageüberwachung mit einer ausgewählten GET-Anfrage, einem 500 Internal Server Error und einer Meldung zu einem ungültigen HTTP-Token

Express erlaubt keine ungültigen Header – $ und {} sind keine zulässigen Zeichen. Daher müssen wir diese Einschränkung umgehen. Dazu erstellen wir einen Socket-Server, der bei jeder eingehenden Verbindung eine benutzerdefinierte Antwort zurückgibt.

Der Socket-Server sieht so aus: Er lauscht am Socket und sendet bei jeder Verbindung die Antwort zurück – in diesem Fall einschließlich der Java-Version. Wir versuchen, diesen benutzerdefinierten Header einzuschleusen und prüfen, ob er ausgewertet wird.

JavaScript-Code in index.js, das einen Netzwerkserver erstellt, eine HTTP-200-Antwort sendet und auf Port 3000 lauscht

Starten wir den Server mit dem Befehl node index.js und ändern den ngrok-Tunnel mit dem Befehl ngrok tcp 3000 in einen TCP-Tunnel. Um die TCP-Tunnelfunktion nutzen zu können, müssen Sie ein Konto bei ngrok erstellen.

Terminal mit einer aktiven ngrok-Sitzung, die TCP-Datenverkehr von 0.tcp.eu.ngrok.io:14584 an localhost:3000 weiterleitet.

Kopieren Sie den Forwarding-Link ohne TCP und fügen Sie ihn auf der Website ein. Setzen Sie am Anfang https:// ein und scannen Sie den Link. Wir sehen, dass der benutzerdefinierte Header ausgewertet wurde. Dabei wurde ein Lookup ausgeführt und die Java-Version zurückgegeben. Der Lookup funktioniert also.

Oberfläche für Website-Scans mit einem URL-Feld, den Schaltflächen „Mehr“ und „Scannen“ sowie den Ergebnissen der rohen Header einschließlich Status 200.

Nun müssen wir einen Log4Shell-Exploit einrichten.

Was ist Log4Shell?

CVE-2021-44228, auch bekannt als Log4Shell, ist eine nicht authentifizierte Remote-Code-Execution-Schwachstelle (RCE), die fast alle Versionen von Apache Log4j 2 betrifft. Am 9. Dezember 2021 verbreitete sich die Nachricht über diese Zero-Day-Schwachstelle in Infosec-Communitys – zusammen mit einem öffentlich verfügbaren Proof of Concept (POC).

Wenn Sie mehr über die Log4Shell-Schwachstelle erfahren möchten, sehen Sie sich unsere kostenlose Lektion auf Snyk Learn an.

Der POC

Für die nächsten Schritte verwenden wir diesen öffentlich verfügbaren POC. Dieses Repository enthält alles, was wir für den Angriff benötigen.

Klonen Sie das Projekt mit Git und wechseln Sie zur Klasse Evil.java. Wir müssen sie anpassen, um die eigentliche Payload für diese Challenge zu erstellen. Wir möchten alle Dateien im Stammverzeichnis auflisten. Dazu erstellen wir ein File-Objekt, rufen eine Dateiliste ab und geben alle Dateinamen aus.

Dunkler Code-Editor mit Evil.java: einer Java-ObjectFactory, die Dateien im Stammverzeichnis auflistet und „You have been pwned!“ zurückgibt.

Erstellen wir unser Docker-Image mit folgendem Befehl:

docker build -t log4shell-vulnerable-server-exploit .

Starten wir den ngrok-TCP-Server mit folgendem Befehl:

ngrok tcp 9999
ngrok-Terminal mit einer Online-Sitzung, die tcp://7.tcp.eu.ngrok.io:18771 an localhost:9999 weiterleitet

Und den ngrok-HTTP-Server mit dem Befehl: ngrok http 8888

ngrok-Terminal mit einer aktiven Sitzung, die eine öffentliche HTTPS-URL an http://localhost:8888 weiterleitet

Wir müssen den Docker-Container mit folgendem Befehl remote ausführen:

Terminalbefehl zum Ausführen eines Docker-Containers mit Portzuordnungen, einem HTTP-Server-Host und dem Namen eines Log4Shell-Schwachstellentests

Zuerst müssen wir jedoch den LDAP-Server auf den richtigen Forwarding-Link verweisen lassen. Kopieren Sie den Link des HTTP-Servers, der auf Port 8888 läuft, und fügen Sie ihn ein.

Außerdem benötigen wir die Adresse des TCP-Servers auf Port 9999 in der Socket-Datei index.js. Hier senden wir einen Header mit einer echten Log4Shell-Payload. Wir stellen die zuvor angepasste Evil-Klasse bereit.

JavaScript-Code mit einer Serverantwort, die eine ngrok-TCP-Adresse und den Text „Evil“ einbettet, gefolgt von „hello“.

Starten wir den Socket-Server mit dem Befehl neu: node index.js

Führen wir diesen Befehl noch einmal aus:

Terminal-Screenshot mit einem Docker-Befehl, der einen für Log4Shell anfälligen Server mit den freigegebenen Ports 8888 und 9999 startet.

Auf Ihrem Terminal sollte dieselbe Ausgabe erscheinen:

Terminal mit einem Docker-Befehl zum Starten eines Exploits für einen anfälligen Server; LDAP- und HTTP-Server lauschen auf den Ports 9999 und 8888.

Wenn Sie zur Website zurückkehren, sollten Sie die Dateiliste des Stammverzeichnisses sehen. Und dort ist die Flag!

Screenshot mit dem Titel „Raw Headers“ mit einer Debug-Ausgabe, die Serververzeichnisse und -dateien auflistet, darunter package.json und node_modules.

Wir müssen die Payload ein letztes Mal anpassen, um die Flag anzuzeigen. Kehren wir zur Evil-Klasse zurück. Mit diesem Codeausschnitt können wir die Flag auslesen und den Dateiinhalt ausgeben.

Dunkel gestalteter Code-Editor mit der Datei Evil.java: eine Java-ObjectFactory, die /flag liest und „you have been pwned!“ zurückgibt

Damit die Änderungen übernommen werden, müssen wir den Docker-Container erneut ausführen. Bei einem weiteren Scan wird der Inhalt der Flag-Datei angezeigt!

Screenshot mit rohen Headern, in dem Debug-Protokolle und eine hervorgehobene SNYK-Token-Zeichenfolge zu sehen sind.

Logster – Zusammenfassung

Die Einfachheit dieses Exploits und die weite Verbreitung der Bibliothek haben Sicherheitsexperten seit Bekanntwerden der Schwachstelle in Alarmbereitschaft versetzt. Zunächst wurde empfohlen, auf Version 2.16 zu aktualisieren. Leider wurde dann in dieser Version ein Denial-of-Service-Exploit entdeckt. Empfohlen wird daher ein Upgrade auf Version 2.17.

Ausführliche Empfehlungen zur Behebung finden Sie in unserem Log4Shell-Leitfaden zur Behebung. Dieser wird fortlaufend aktualisiert, sobald neue Informationen verfügbar sind.

Ich hoffe, Ihnen haben Logster und die anderen Challenges beim CTF Spaß gemacht :) Möchten Sie erfahren, wie wir alle anderen Flags gefunden haben? Auf unserer Seite mit den Fetch the Flag-Lösungen erfahren Sie, wie wir dabei vorgegangen sind.