Fetch the Flag CTF 2022: Lösung für Juggalo Central
Alexander Kraev
10. November 2022
0 Min. LesezeitDanke, dass Sie Fetch mit uns gespielt haben! Herzlichen Glückwunsch an die Tausenden von Spielerinnen und Spielern, die beiFetch the Flag CTF dabei waren. Ein großes Dankeschön auch an alle Snyker, die die Herausforderungen entwickelt, getestet und dokumentiert haben!
Wenn Sie bei Snyks Fetch the Flag 2022 dabei waren und die Herausforderung Juggalo Central nicht abschließen konnten, sind Sie hier richtig. Gehen wir die Lösung gemeinsam durch!
Schritt-für-Schritt-Anleitung
Zunächst gibt es einen Link zu einer Website mit dem üblichen Anmeldeformular und den beiden Feldern username und password. Außerdem gibt es eine Datei mit der Erweiterung .php. Sehen wir uns zuerst die Website an.
Die Website
Wie bereits erwähnt, enthält die Seite zwei Eingabefelder (und ein Clownbild). Zuerst habe ich den Seitenquelltext, die .css-Datei und sogar das Bild überprüft. Nichts davon war für mich brauchbar. Mir fiel auf, dass es zwei verschiedene Fehlermeldungen gab: eine, wenn ich einen üblichen Benutzernamen wie „admin“ verwendete, und eine andere bei einer zufälligen Zeichenfolge wie „qweasdzxc“.
Der Code
In index.php habe ich drei Funktionen gefunden: getFlag, searchUserByName und validateCredentails.
Die erste Funktion, getFlag, fragt eine Datenbanktabelle namens flag ab und gibt die erste gefundene Zeile zurück. Nach einigem Nachdenken kam ich zu dem Schluss, dass der gesuchte Schlüssel in dieser Tabelle gespeichert ist.
Die zweite Funktion, searchUserByName, sucht anhand der Eingabevariable $username nach einem Benutzer. Wenn es Treffer gibt, gibt die Funktion diese zurück. Dabei ist mir folgende Zeile aufgefallen:
Das bedeutet, dass diese Funktion nicht nur eine Zeile zurückgibt (ich gehe davon aus, dass Benutzernamen eindeutig sind), sondern alle Zeilen, falls mehrere Benutzer denselben Benutzernamen haben. Später stellte sich heraus, dass uns das nicht weiterhilft, denn in der nächsten Funktion passiert etwas anderes. Das kommt bei einem CTF manchmal vor.
Die dritte Funktion, validateCredentails, liest den Benutzernamen und das Passwort aus dem Body der POST-Anfrage und ruft searchUserByName auf, um zu prüfen, ob ein Benutzer mit diesem Benutzernamen existiert. Hier wurde mir auch klar, warum bei einem zufälligen Benutzernamen eine andere Fehlermeldung angezeigt wurde. Wenn der Benutzer einen nicht existierenden Namen eingab, gab die Funktion „Juggalo not found!“ zurück. Bei einem existierenden Benutzernamen mit falschem Passwort lautete die Fehlermeldung hingegen „Invalid credalo“.
Einen gültigen Benutzernamen finden
Jetzt suchen wir nach gültigen Zugangsdaten. Als ich etwas so Übliches wie „admin“ ausprobierte, erhielt ich die Fehlermeldung „Invalid credalo“. Dank der Codeanalyse aus dem vorherigen Schritt weiß ich nun, dass es einen Benutzer mit dem Wert „admin“ im Feld für den Benutzernamen gibt.
Der erste Versuch
Da wir nun einen gültigen Benutzernamen haben, sehen wir uns an, wie wir das Passwort knacken können. Die Fehlermeldung besagt, dass wir keinen Zugriff auf diesen Benutzer haben. Ursache dafür ist folgende Codezeile:
Auf der linken Seite der Bedingung wird das Passwort eines Benutzers aus der Datenbank abgerufen. Auf der rechten Seite stehen die ersten 20 Zeichen des MD5-Hashs, der zwei vom Benutzer angegebene Variablen enthält: username und password.
Mein erster Gedanke war, dass aufgrund dieser Bedingung jedes gültige Passwort aus 20 Zeichen bestehen muss. Kurz gesagt: Das war falsch.
Der zweite Versuch
Nachdem ich eine Weile über die Herausforderung nachgedacht hatte, kam mir eine andere Idee. In dieser Zeile wird der Vergleichsoperator != verwendet. Deshalb habe ich in der offiziellen PHP-Dokumentation nachgesehen, wie Vergleichsoperatoren in PHP funktionieren. Direkt neben dem Operator != stand eine Zeile, die ich nicht verstand:
Moment. Was ist „Type Juggling“? Nachdem ich das gelesen hatte, öffnete ich die Challenge-Seite erneut. Der Clown war immer noch da und beobachtete mich.
Der Hack
Wie sich herausstellte, gibt es in PHP ein Konzept namens „Type Juggling“. Nachdem ich mehr zu diesem Thema gelesen und online einige PHP-Tests durchgeführt hatte, kam ich auf folgende Bedingung:
Überraschenderweise ergab das „true“. Das liegt daran, dass PHP beide Operanden in numerische Werte umwandelt. Um nun das richtige Passwort für den Benutzer „admin“ zu finden, müssen wir lediglich einen MD5-Hash erzeugen, der zwei Bedingungen erfüllt: Er beginnt mit „0e“ und enthält danach nur Ziffern (oder mindestens 18 Zeichen, da substr verwendet wird).
Das Skript
Mit diesem Python-Skript lässt sich der richtige Hash finden:
Nach einer Minute konnte ich mich mit den Zugangsdaten aus diesem Skript auf der Website Juggalo Central anmelden.
Weitere Lösungen für Fetch the Flag
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 vorgegangen sind.
