Sebastian schloss sich für den Insomnihack teaser CTF 2016 dem Team ENOFLAG an. In diesem Blogpost geht es um den ausgedachten Workaround für die smartcat2 (web0) Challenge.
Ich habe selbst smartcat1 nicht gelöst, da als ich beim Treffpunkt ankam, Denis @nobbd diese challenge bereits gelöst hatte und wir direkt mit smartcat2 weitemachten. Nachdem wir auch diese erfolgreich lösten, wurde uns mitgeteilt, dass wir nicht die intendierte Lösung genutzt haben, sodass wir gerne unseren Lösungsweg, nämlich den Bypass des Filters, beschreiben möchten.
Note to myself: Die Burp Instanzen öfters mal speichern und mehr Notizen machen, um bessere Writeups schreiben zu können. (Ich schreibe das aus meinem Gedächtnis heraus und habe wahrscheinlich (wichtige) Gedanken/Entscheidungen vergessen)
Smartcat2
Zunächst erstmal ein paar Worte zu der Challenge. Es war eine Webseite die uns erlaubte, eine IP Adresse zu pingen:
1 2 3 4 5 6 7 |
|
Wie wir bereits in smartcat1 gelernt haben, konnte man Kommands ausführen, in dem man diese mit Zeilenumbrüchen (\n
aka %0A
) separierte. Zum Beispiel würde dest=127.0.0.1%0Als
das Programm ls
ausführen. Wie auch immer, es gab eine Blacklist mit unerlaubten Zeichen:
1 2 3 4 5 |
|
Wir können keine Kommandos ausführen, welche Parameter benötigen, da Leerzeichen Teil der Blacklist sind. Der Standard-Bypass mit $IFS
funktioniert auch nicht, da $
ebenfalls auf der Blacklist ist. Wir können aber <
und >
anstatt der Pipe (|
) für die meisten Shell-Kommandos nutzen, um die Aus- bzw. Eingaben umzuleiten.
Die erste Sache die mich interessierte war, welche Shell genutzt wird. pstree
bzw. ps
oder ein ähnliches Kommando zeigte eine Menge sh
Prozesse, sodass wohl dies die Shell darstellte. Somit leider keine Bash-Magic anwendbar.
Nach einer Weile Rumspielen mit find
und cat
fanden wir den Hinweis, dass die Flagge sich im Ordner /home/smartcat
befindet. Allerdings sucht find
vom aktuellen Arbeitsverzeichnis aus (/var/www/cgi-bin/
) und wir können dieses nicht bearbeiten, oder doch?
Variablen nutzen
Was wir brauchten war etwas wie cd DIR
, aber Leerzeichen sind immernoch auf der Blacklist. Die Manpage von cd
brachte uns aber bei, dass If DIRECTORY is supplied, it will become the new directory. If no parameter is given, the contents of the HOME environment variable will be used.
(Wenn DIRECTORY gegeben ist, dann wird in diesen Ordner gewechselt. Ansonsten wird die Variable HOME
verwendet.) Mal schauen, ob wir den Wert der HOME
-Variable zu /home/smartcat
ändern können. Das Setzen von Umgebungsvariablen in der sh
ist so einfach wie das Ausführen von VARIABLE=VALUE
. Demnach haben wir zum Auflisten der Inhalte in /home/smartcat
die folgende Eingabe genutzt:
1
|
|
Super, wir sehen nun alle Dateien in dem Ordner. Diesen Ansatz können wir nutzen, um in beliebige Ordner zu wechseln und uns die Inhalte anzeigen zu lassen. Allerdings können wir flag2
nicht lesen, da uns die nötigen Leserechte fehlen, aber wir können das Programm readlfag
ausführen. %0Astrings<./readflag
führt uns zum nächsten Teil der Aufgabe:
1
|
|
Blacklist bypass
Wie man wahrscheinlich weiß, sind Blacklists immer schlecht und fast immer umgehbar. Wir brauchten einen Platz in das wir unseren Code abladen konnten, also einen Ordner mit Schreibrechten. Es stellte sich heraus, dass wir Schreib-, aber keine Ausführungsrechte auf /tmp
hatten. Wir überzeugten uns davon mit ls>/tmp/x
gefolgt von cat</tmp/x
.
Super, wir können also beliebige Dateien in /tmp
schreiben und ausführen. Aber wie füllt man diese Dateien mit Leben? Ich kam auf die Idee sog. here documents
zu nutzen:
1 2 3 |
|
1
|
|
Alles zwischen EOF
und EOF
wird dann in die Datei /tmp/file
geschrieben. Der nächste Schritt bestand also darin, irgendwie ein Programm hochzuladen oder zu schreiben, was auf dem Server die readflag
Binary ausführen und die Flagge anzeigen würde.
Während wir darüber nachdachten, wie wir Quelltext schreiben könnten, ohne Zeichen der Blacklist zu verweden, ließen wir ein HOME=/%0Acd%0Afind>/tmp/files
laufen, um eine Liste aller Dateien auf dem Server zu bekommen. Der Request lief ins Timeout, aber lange genug, um einige Dateien aus dem /bin
, /usr/bin
aufzulisten. Einige Tools die wir als nützlich einstuften:
- python2 / python3
- gcc / g++
- ftp / rsync / curl / wget
- gzip / gunzip / zip / unzip
Ich versuchte erst irgendwie gzip
oder zip
zu missbrauchen, um ein Leerzeichen in einer Datei zu komprimieren und zu hoffen, dass in der Ausgabe keine Zeichen der Blacklist vorhanden sind. Unglücklicherweise klappte das Entpacken auf dem Server nicht richtig. Genau das war der Augenblick in dem Denis die geniale Idee hatte Python2 und dessen print
Anweisung zu nutzen, um den Filter zu umgehen. In Python2 braucht man weder Klammern noch Leerzeichen, um etwas mit print
auszugeben.
1
|
|
Zusätzlich kann man Zeichen mit \xYY
kodieren. Wir schrieben ein Shellscript für die readflag
Binary:
1
|
|
… und kodierten alle Zeichen der Blacklist:
1
|
|
Danach nutzten wir unser here-document-cat um das Python-Script in /tmp/print.py
zu erzeugen, gefolgt durch die Ausführung mit: %0Apython</tmp/print.py>/tmp/getflag.sh
Wir wiederholten diesen Schritt für ein zweites Shellscript, welches unser vorheriges ausführte:
1
|
|
Letzendlich führten wir das zuletzt erstellte Shellscript aus, um die Flagge zu erhalten: %0Ash</tmp/runflag.sh>/tmp/ourflag
und %0Acat</tmp/ourflag
zum Lesen der Flagge: INS{shells_are _way_better_than_cats}
Insgesamt war es eine ziemlich colle Challenge :)
The team of internetwache.org
Kompletter Exploit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|