Hacky Easter

DATEV eG
DATEV TechBlog
Published in
9 min readMay 20, 2021

Von: Stefan Hager

Was machen Hacker, wenn sie Puzzles spielen wollen? Sie spielen bei CTFs mit. CTF, das steht für “Capture The Flag” und beschreibt üblicherweise irgendein Problem, an dessen Überwindung ein kleines Textfile steht, eine Flag, die zum Beispiel so aussieht:

pwnctf{C0ngratz-You-w0n!_Now_to_the_n3xt-flag!}.

Um dorthin zu gelangen, muss man vielleicht einen Webserver kompromittieren (natürlich einen speziell für das CTF bereitgestellten), forensische Recherche eines Files betreiben oder eine Schwäche eines eigentlich unknackbaren Verschlüsselungsalgorithmus ausnutzen. Alles unter Einsatz von Tools, die häufig auch in der täglichen Arbeit von Pentestern oder digitalen Forensikern zu finden sind.

Hacky Easter ist ein solcher CTF-Event, allerdings mit einer niedrigen Einstiegshürde — die Challenges fangen niederschwellig an und sind auch für nicht Computer-affine Menschen lösbar, bevor sie deutlich schwerer werden.

Zur Veranschaulichung, und vielleicht auch um den Appetit bei Euch für das nächste CTF-Event zu wecken, habe ich ein Beispiel aus jeder der Schwierigkeitskategorien mit einer ausführlichen Lösung.

Challenge: Basement Cat

Schwierigkeitsstufe: n00b (die einfachste)

Der Text der Challenge ist:

Hi, me iz Basement Cat!

Here iz flag: 5jsnZDgv9EfFeoGXZrFurdz7MWAnK2WaPfszFadr

Freundlicherweise gibt es einen kostenlosen Hinweis, der die Hausnummer auf dem Bild (58) als wichtig angibt, und den Hinweis auf Cyber Chef.

Wer Cyber Chef nicht kennt: das ist ein Tool der NSA, welches sehr viele Module bereithält, um verschiedenste Codes zu knacken, und per Browser bedienbar ist.

(Erreichbar unter https://gchq.github.io/CyberChef/)

Wenn man “58” in das Suchfeld unter Operations eingibt, erscheint auch sofort das richtige Modul für das gewünschte Rezept: “From Base58”.

Base 64 ist vielen bekannt; Binärblobs oder jegliche anderen Daten lassen sich per Base64 in darstellbare und leicht kopierbare Zeichen umwandeln — 64 davon, um genau zu sein. Weniger bekannt sind andere Verfahren, wie Base 58 — was letzten Endes funktioniert wie Base 64, aber mit einem eingeschränkten Zeichensatz.

Und hier ist dann auch unsere erste Flag: he2021{meow_nice_to_meet_you}

Klar muss man den Umweg über Cyber Chef nicht nehmen; die meisten Flags lassen mehrere Lösungswege zu. Aber hier ist es eine einfache Lösungsmethode.

Challenge: Ghost in a Shell 1

Schwierigkeitsstufe: easy

Der wichtige Text der Challenge lautet:

Connect to the server, snoop around, and find the flag!

Dann machen wir das mal.

ssh 46.101.107.117 -p 2106 -l inky

password is: mucky_4444

Note: The service is restarted every hour at x:00.

Ok, bis hierher ziemlich Standard. Ein Restart der Challenge ist oft nötig, weil natürlich auf dem Server alles probiert wird, um an die Flag zu kommen — vielleicht auch Dinge, welche die Challenge oder den Server unbrauchbar machen.

Die Challenge ist als “easy” klassifiziert, das heißt, wahrscheinlich müssen wir uns nicht zu root machen, sondern können das Puzzle lösen mit dem, was wir vorfinden.

Loggen wir uns also mal ein und schauen, was wir finden.

ssh 46.101.107.117 -p 2106 -l inky

inky@46.101.107.117’s password:

c1299694a3cd:~$ ls

images notes.txt text

“notes.txt” hat viel Prosa über das Spiel Pac-Man. Auf Anhieb nichts, was uns gerade weiterhilft. Im Verzeichnis text sind ebenfalls noch ein paar Beschreibungen der Geister — aber wahrscheinlich bewusst platzierte Irrwege. Das Verzeichnis images ist auf den ersten Blick auch nicht spannend, aber die Bilder schauen wir uns trotzdem an: Nichts, was sofort ins Auge sticht. Die Files haben auch keine beachtenswerte Größe (ein Hinweis auf etwas, was darin versteckt ist zum Beispiel). Was bleibt?

Versteckte Files vielleicht?

c1299694a3cd:~$ ls -la images

total 304

drwxr-xr-x 1 root root 4096 Apr 3 05:23 .

drwxr-xr-x 1 root root 4096 May 18 11:00 ..

drwxr-xr-x 1 root root 4096 Apr 3 05:23 …

(lines omitted)

Siehe da, ein verstecktes Verzeichnis: …

Und Pac-Man isst ja Punkte. Die Verzeichnisse . und .. finden sich überall in Linux (UNIX, AIX, etc) und bezeichnen das Directory, in dem man sich gerade befindet ( . ) und das diesem Directory übergeordnete Verzeichnis ( .. ). Da unser Directory mit den drei Punkten auch mit einem Punkt anfängt, ist es für Linux ein verstecktes Verzeichnis. Wenn wir es auslesen — wieder mit Sicht auf versteckte Files — finden wir diesmal eine Datei namens … — nur können wir die nicht einfach auf der Instanz auf dem Server öffnen. Aber wir können ja erstmal nachsehen, was es für eine Art Datei ist. Viele Kommandos stehen nicht zur Verfügung, also gehen wir mit dem Holzhammer an die Sache ran und schauen uns die ersten Bytes an — bis auf das „?PNG“ am Anfang viel Binärmüll, aber wir haben unsere Antwort — das ist der Fileheader eines PNG-Bildes.

c1299694a3cd:~$ head images/…/…

�PNG

Dann kopieren wir uns das lokal, damit wir das Bild anschauen können:

scp -P 2106 inky@46.101.107.117:~/images/…/… ./ghost.png

Die Flag ist nun mit einem QR-Code-Leser herausgefunden: he2021{h1dd3n_d0td0td0t!}.

Challenge: Cafe Shop

Schwierigkeitsstufe: medium

Ein simpler Webshop, wie es scheint — aber wir sollen ein Produkt bestellen, dass es so nicht auf der Speisekarte gibt. Als erstes sollten wir schauen, was die Produkte gemeinsam haben, und an welcher Stelle wir manipulieren können.

Mit Hilfe eines transparenten Proxies — in dem Fall Burp — lassen sich Requests und Replies auf einfache Weise ansehen und manipulieren.

“Vanilla Cafe” erzeugt einen POST Request mit dem Parameter “id=11865457+Vanilla+Cafe” — wobei hier die “+”-Zeichen einem Leerzeichen gleichzusetzen sind. Zumindest der Produktname kommt ja vor, aber die Zahl 11865457 macht erstmal noch keinen Sinn. Auch die anderen beiden Einträge, “Cherry Cola” und “Beef Jerky” haben eine achtstellige Zahl davor.

Zeit, sich den Hint der Challenge nochmal anzusehen.

“They also serve hash browns, for $256.”

Die Schlüsselworte „Hash“ und 256 sind hier wichtig. Kryptographische Hashes spielen in vielen Challenges eine Rolle. Ein aktueller davon ist sha256. Nach ein bisschen rumprobieren haben wir den Ansatz gefunden:

echo -n “11865457 Vanilla Cafe” | sha256sum

f15bffb719f26892f17eea53dc7e3459cafe021bc0db2dce72429667d7aaee96 -

echo -n “42640575 Cherry Cola” | sha256sum

36bc94f7d7c3398319f2c01a9a9c583aed66d3a5e325aafa0652ceb2bdc271cf -

echo -n “80427209 Beef Jerky” | sha256sum

ed734b4fc622d543774121dcfb573cf53d7ddef85ebebeef9fd7cbd8bf4363c9 -

Jeder Hash des Klartexts “<ID> <Produktname>” enthält zumindest einen Teil des Produktnamens im Hash! Also 0xcafe aus “Vanilla Cafe”, oder 0xbeef aus dem “Beef Jerky”. Bei Cola müssen wir ein bisschen tricksen, um “o” und “l” darzustellen: aber der “Cherry Cola”-Hash enthält 0xc01a, eine Leet-speech Variation der Buchstaben.

Wir müssen also einen Hash finden, der für “<8-stellige Nr> Decaf Cola” einen sha256-Hash erzeugt, der sowohl 0xdecaf als auch 0xc01a enthält. Ein paar schnelle Zeilen in Python später haben wir das Ergebnis:

i 18621173 — h 2c7d9c65c1ba091c01aa2be99ca03aa188fbe7b4347ffb1d30f925decafee44f

18621173 Decaf Cola

Setzen wir nun mit Burp die id auf den Wert “id=18621173+Decaf+Cola”, erhalten wir wieder einen QR-Code:

Die Flag ist he2021{h3xpr3ss_urs3lf}.

Challenge: Memeory 3.0 — The Finale

Schwierigkeitsstufe: hard

Die erste Aufgabe in der Kategorie “hard” ist, wie es scheint, Memory gegen den Server auf der anderen Seite zu spielen. Davon gab es in den letzten Jahren schon einfachere Variationen, die Version 3 ist bislang die schwerste: sie ist unmöglich per Hand zu lösen. Für 50 Paare hat man ganze 30 Sekunden Zeit, und man darf sich nur drei Fehler leisten. Auch muss man das zehnmal hintereinander schaffen, um zu bestehen.

Der Name “Memeory” ist natürlich passend gewählt zu den Bildern auf den Memory-Karten: Memes.

Hier fängt es aber schon an, ein wenig kniffliger zu werden: die Bilder sind für Menschen als identisch erkennbar, aber nicht ganz so simpel für einen Computer — denn die Bilder sind um 90°, 180° oder 270° gedreht, und mal heller oder dunkler. Der Ansatz, die Bilder herunterzuladen und lokal zu verarbeiten um Entscheidungen zu treffen, muss also innerhalb 30 Sekunden greifen.

Möglichkeiten gibt es einige: man kann auch die Transparenz des Deckblatts verringern, um die Bilder darunter sehen zu können — aber das Zeitlimit macht einen Erfolg für das manuelle Lösen trotzdem unmöglich.

Mein erster Ansatz war, eine Python-Bibliothek namens imagehash zu verwenden; diese ermöglicht das Erkennen von ähnlichen Bildern. Nach ein paar Fehlversuchen habe ich mir dann aber eine andere Lösungsvariante überlegt. Es gibt nur eine begrenzte Anzahl Bilder, diese werden rotiert oder/und in ihrem Helligkeitswert verändert. Ab und zu liefert der Server auch einfach mal ein komplett schwarzes Bild aus, das sollte auch berücksichtigt werden.

Bei jedem Aufdecken eines Bilds wird vom Server zufällig entschieden, wie es verändert wird — also ob gedreht oder nicht, etc. In 30 Sekunden kann man jedes Bild nur wenige Male requesten — zumindest mit dem einfachen Script, welches ich dafür geschrieben habe. Aber wozu kann man denn Dinge parallelisieren und in Threads laufen lassen?

Auf die Weise konnte ich 32 Variationen jeden Bildes innerhalb des Zeitlimits herunterladen. Diese wurden dann auf Unikate reduziert und ein md5-Hash des Files gebildet. “Pah, md5! Und das als Security-Mensch! Schäm Dich!” höre ich aus den hinteren Reihen. Der Hash hier hat keinerlei Security-Funktion. Auch wenn Collisions möglich wären, bleiben sie dennoch unwahrscheinlich.

Warum also md5 und nicht, sagen wir, sha-256? Zeit. Meine Annahme war, dass es schneller sein würde, mit md5-Hashes zu arbeiten — mehr nicht. Wahrscheinlich funktioniert das auch mit komplexeren Hashes, aber… in dem Fall ist die Methode nicht sicherheitsrelevant, wie gesagt.

Die Hashes aller Bilder, die ein und dasselbe Meme auf verschiedene Weise zeigen, wurde in eine Liste eingetragen. Die Listen wiederum in eine persistente, von der Session unabhängige list of lists.

Dann kann das Spiel beginnen. Nach dem Eröffnen einer neuen Session wurden alle Bilder heruntergeladen, Hashes ermittelt und nach Paaren gesucht: zwei unterschiedliche Hashes innerhalb eines List-Items bedeutet ein Match der Bilder.

Diese wurden vom Script dann als die angeklickten Bilder an den Server übermittelt, und auch intern als angeklickt intern. Was übrig blieb, war das schwarze Bild und irgendwas anderes, aber das war dann innerhalb der Fehlertoleranz des Spiels (drei Fehlklicks erlaubt).

Nach zehn Runden kam dann die Flag als Belohnung:

ok, here is your flag: he2021{0k-1–5u44end3r-y0u-w1n!}

Es gibt noch so viele andere Challenges, über die ich schreiben könnte. Zum Beispiel die Trilogie (easy — medium — hard), in der man scheinbar simple Binaries exploiten musste, um Shell-Kommandos abzusetzen. Oder den Webservice, der aus einem Request einen Ciphertext als Shortlink macht und aufgrund seines Algorithmus anfällig für Padding-Oracle-Attacken ist. Die Challenge, bei der man Server Side Template Injection — Angriffe ausführen musste, um ans Ziel zu kommen, und so weiter.

Wie jedes Jahr hat Hacky Easter viel Spaß gemacht, und ich habe eine Unmenge an Dingen gelernt: Schwächen in Protokollen, Angriffsmethoden, und nicht zuletzt wie ich meinen Angriffscode optimiere, damit er nicht nur funktioniert, sondern das auch noch performant innerhalb von Zeitlimits.

Vielleicht konnte ich Eure Lust darauf etwas wecken. Die Natur von CTFs ist es, dass Write-Ups und Lösungen erst nach Ablauf veröffentlicht werden dürfen; aber der nächste CTF kommt bestimmt, und die nächsten Wochen habt ihr unter https://21.hackyeaster.com/ noch Zeit, Euch die einzelnen Challenges anzuschauen und sie zu lösen — allerdings ohne Wertung im Scoreboard. Viel Spaß!

--

--

DATEV eG
DATEV TechBlog

DATEV eG steht für qualitativ hochwertige Softwarelösungen und IT-Dienstleistungen für Steuerberater, Wirtschaftsprüfer, Rechtsanwälte und Unternehmen.