Auf der GPN14 haben die squareroots ein Capture the Flag veranstaltet. In diesem Artikel schildere ich die Lösungen zu den Challenges, die ich gelöst habe und zu denen ich im Nachhinein noch genug Spuren auf meinem Rechner habe, um etwas über sie zu erzählen. Nachts und schnell gelöst, handelt es sich hier natürlich nicht um vorbildlichen Code…

Time is up

In einer der Challenges unter dem Namen „Time is up“ war die Datei mit dem Flag über knapp 800 .rar-Teildateien verteilt, die man alle einzeln über ein Downloadportal herunterladen musste. In diesem Downloadportal musste man vor dem Download jeder einzelnen Datei ein CAPTCHA eingeben, das oft, aber nicht immer, sehr schwer war und in unter 5 Sekunden gelöst werden musste.

Die Lösung hierzu stammt nicht nur von mir, sondern zum größten Teil auch von NoMoKeTo.

Ausgangspunkt der Challenge war eine Textdatei mit den Links zu den einzelnen Dateien in willkürlicher Reihenfolge, die man ebenfalls über besagtes Download-Portal herunterladen musste. Dies haben wir von Hand erledigt und in ein Python-Skript gefüttert, das ich im folgenden beschreibe.

Das erste Python-Skript, download.py, lädt in einer Schleife für jede Datei die Downloadseite und ein CAPTCHA. Die Downloadseite wird auf den Dateinamen der herunterzuladenden Datei durchsucht, damit wir keine Mühe auf .rar-Teildateien verschwenden, die wir bereits bei einem vorherigen Ausführen heruntergeladen haben.

Anschließend wird das CAPTCHA versucht zu lösen (siehe unten) und zurück an den Server gesendet. War das CAPTCHA falsch, laden wir uns einfach ein neues und versuchen es erneut, bis es klappt. War das CAPTCHA richtig, wird die betreffende Datei gespeichert.

Nun zum interessanten Teil, unserem CAPTCHA-OCR. Die CAPTCHAs bestehen immer aus vier bunten und gedrehten Großbuchstaben oder Zahlen verschiedener Schriftarten auf insgesamt zehn verschiedenen Hintergründen.

CAPTCHA CAPTCHA CAPTCHA CAPTCHA

In einem ersten Trainingsschritt (collectbgs.py) haben wir so lange CAPTCHAs heruntergeladen, bis wir jeden Hintergrund mindestens 50 mal gesehen haben, wobei wir zwei CAPTCHAs als mit dem gleichen Hintergrund erkennen, wenn mindestens die Hälfte der Pixel farblich übereinstimmt. Anhand dieser Bilder extrahieren wir nun den puren Hintergrund, indem wir für jeden Pixel die Farbe setzen, die in den mindestens 50 Bilder an dieser Stelle am häufigsten vorkommt.

CAPTCHA CAPTCHA CAPTCHA

Um nun ein einzelnes CAPTCHA zu lösen (captchasolver.py), finden wir zuerst mit der bereits geschilderten Methode heraus, welchen Hintergrund das CAPTCHA verwendet und subtrahieren diesen (bzw. färben alle Pixel schwarz, die sich vom Hintergrund unterscheiden), womit wir den reinen Text erhalten.

Wir suchen nun nach leeren Spalten in unserem so behandelten CAPTCHA um die Zwischenräume zwischen den vier Buchstaben zu finden und so die einzelnen Buchstaben zu isolieren. Nun müssen wir noch die Buchstaben erkennen.

Wir zählen dazu drei Werte des Buchstabens: Die Anzahl Pixel, die der Buchstabe ausfüllt, die Anzahl der schwarzen Pixel, die am Rand des Buchstabens liegen und die Anzahl der weißen Pixel, die komplett vom Buchstaben eingeschlossen sind, also z.B. in den Bäuchen eines B oder in einem O.

Nach einer halbstündigen manuellen Trainingsrunde hat sich dieses Zahlentripel als charakteristisch genug herausgestellt, um zumindest bei einigen der in den CAPTCHAs verwendeten Schriftarten eine hohe Trefferquote zu erzielen. Dadurch, dass vier Buchstaben korrekt erkannt werden mussten und das Skript bei manchen Schriftarten keine Chance hatte, war die Trefferquote insgesamt eher gering, aber ausreichend um in einer halben Stunde alle 796 Dateien herunterzuladen und das Flag zu finden.

Auszug aus einer Trainigsdatei für einen der Hintergründe:

{
    "186-145-0": "Y",
    "198-164-13": "N",
    "141-110-62": "O",
    "110-88-1": "1"
}

Was hätten die CAPTCHAs tun müssen, um unserem Skript zu entgehen? Nun, Linien quer durch die Buchstaben hätten die Trennung der Buchstaben erschwert, exotische Schriftarten hätten die Erkennung über das Zahlentripel nicht erlaubt und bei Einsatz von Fail-to-ban wären wir verloren gewesen. Andererseits: Manche der CAPTCHAs waren so ekelhaft, dass ich sie auch als Mensch nicht geschafft habe zu lösen und so betrachtet war unser Skript wohl ähnlich gut wie ein Mensch, was mal wieder zeigt: CAPTCHAs sind keine effektive Methode, um Menschen von Skripten zu unterscheiden und stattdessen verursachen Sie Frustration beim User. Do not use them. Danke.

Der Source Code unserer Skripte zum nachlesen findet sich in diesem GitHub Gist, aber ist wahrscheinlich alles andere als portabel und auf andere Dinge übertragbar (was auch ein wenig so gedacht ist).

Colorful life

In einer „Programming“-Challenge gab es eine Website, auf der man ein Bild präsentiert bekommen hat, das mit einer zufälligen Farbe ausgefüllt war, und musste in extrem kurzer Zeit in ein Formular die Rot-, Gelb- und Grünwerte dieser Farbe eingeben. Folgendes JavaScript, auf der Entwicklerkonsole ausgeführt, löst das Problem.

var img = document.getElementsByTagName('img')[0]; 
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
var pixelData = canvas.getContext('2d').getImageData(1, 1, 1, 1).data;
document.getElementsByName('r')[0].value = pixelData[0];
document.getElementsByName('g')[0].value = pixelData[1];
document.getElementsByName('b')[0].value = pixelData[2];
document.forms[0].submit()

Weird Garbage

Bei der Challenge „Weird Garbage“ war ein Server gegeben, der -- über Telnet angesprochen -- jeweils eine Zeile Brainfuck zurückgegeben hat.

Ausgeführt, gibt dieses Brainfuck jeweils drei Zeichen aus. Der Trick war, sich alle diese Zeichentripel zu besorgen und dann in die richtige Reihenfolge zu bringen, wobei man eigentlich nur den ersten Teil („sqr“) identifizieren musste, um dann den nächsten Teil zu finden, der mit den letzten beiden Zeichen begann („qrt“).

Where is Kurt Krabbel?

Eine „Misc“-Challenge bestand in einem Screenshot des Foursquare-Profils von „Kurt Krabbel“, der verschiedene Orte in Mannheim aufgesucht hat. Das besondere an Mannheim ist, dass die Innenstadt nicht nur in Quadraten aufgebaut, sondern sogar benannt ist. Die Adressen, die Kurt aufgesucht hat, sind in chronologischer Reihenfolge in den Quadraten H1, A1, C5, K1, L14, A5, B3 zu finden und das Flag setzte sich aus den Buchstaben davon zusammen: MD5(hacklab).