4Chan-CAPTCHA knacken
(nullpt.rs)- Ein Projekt, das ein TensorFlow.js-Modell entwickelt hat, um 4Chan-CAPTCHAs automatisch im Browser zu lösen; es erreichte die Zielmarke von mindestens 80 % und das Wunschziel von über 90 % Genauigkeit
- Die CAPTCHA-Sammlung ließ sich wegen
ttl,cd, Cloudflare Turnstile und zunehmend längerer Wartezeiten in der Request-API nicht einfach per Massenscraping erledigen - Kommerzielle menschliche Lösungsdienste und manuelles Labeling scheiterten an Fehlern und Throttling; mit etwa 2.500 echten Hintergründen und 50–150 Bildern pro Zeichen wurden rund 50.000 synthetische Daten erzeugt, um genügend Trainingsumfang zu erreichen
- Das Modell nutzte eine CNN+LSTM-Architektur und CTC-Encoding; nach dem Training mit Keras/TensorFlow wurde es über Python 3.10, Keras 2 und das
.h5-Format nach TensorFlow.js konvertiert - Im echten Browser dauerte das erste Laden etwa 1 Sekunde, spätere Ausführungen wirkten praktisch sofort; bei mehreren hundert echten CAPTCHAs zeigte es eine Erfolgsquote von über 90 %
Ziel und veröffentlichter Code
- Ziel war es, ein Modell zu bauen, das 4Chan-CAPTCHAs zuverlässig im Browser löst und zugleich als Übung für Machine Learning und TensorFlow-Training dient
- Die Messlatte lag bei mindestens 80 % Genauigkeit, idealerweise über 90 %, was am Ende erreicht wurde
- Der zugehörige Code ist auf GitHub unter 4chan-captcha-playground veröffentlicht
Funktionsweise des 4Chan-CAPTCHA
- 4Chan verlangt vor dem Erstellen von Beiträgen oder Antworten die Eingabe eines CAPTCHA
- Ein normales CAPTCHA ist ein Bild mit 5–6 alphanumerischen Zeichen, die der Nutzer vollständig korrekt eingeben muss
- Beim Slider-CAPTCHA wird ein Hintergrundbild, das wie zufällige Zeichenfragmente aussieht, mit einem Vordergrundbild mit transparentem Ausschnitt ausgerichtet, sodass der CAPTCHA-Text sichtbar wird
Einschränkungen beim Sammeln von CAPTCHAs
- Beobachtet man eine neue CAPTCHA-Anfrage, sendet der Browser eine Anfrage an
https://sys.4chan.org/captcha?framed=1&board={board} - Entfernt man
framed=1, wird stattpostMessage()im HTML rohes JSON zurückgegeben- Das JSON enthält unter anderem
challenge,ttl,cd,img,img_width,img_height,bg,bg_width ttlscheint die Zeit zu sein, nach der das CAPTCHA nach etwa 2 Minuten abläuftcdwird als Cooldown interpretiert, der bis zur nächsten CAPTCHA-Anfrage abzuwarten ist
- Das JSON enthält unter anderem
- Bei aufeinanderfolgenden Anfragen wächst
cdimmer weiter- Die ersten paar Anfragen sind alle 5 Sekunden möglich
- Danach steigt der Wert auf 8 Sekunden und verdoppelt sich anschließend ungefähr weiter
- Schließlich erreicht er bei 280 Sekunden eine Obergrenze
- Nach Erreichen des 280-Sekunden-Timers werden die CAPTCHAs schwieriger
- Es erscheinen Bilder mit mehreren horizontalen Linien und ovalen Störelementen
- Die Datenqualität sinkt, bleibt aber weiterhin nutzbar
- Vor CAPTCHA-Anfragen muss Cloudflare Turnstile bestanden werden
- Viele Proxys und einfache Skripte zu verwenden, war nicht praktikabel
- Das Sammelskript kopiert Cloudflare-Cookies aus dem Browser und nutzt sie; nach Ablauf werden sie manuell ersetzt
- Auf diese Weise wurden einige hundert CAPTCHAs gesammelt, aber das reichte nicht fürs Training, und es fehlten auch die korrekten Labels
Grenzen menschlichen Labelings
- Die Ausrichtung der Slider-CAPTCHAs zeigte mit dem heuristischen Skript
trainer/captcha_aligner.pyeine Erfolgsquote von 100 % - Es wurde
trainer/labeler.pygeschrieben, um CAPTCHAs an einen kommerziellen CAPTCHA-Lösungsdienst zu senden, bei dem echte Menschen die Antworten eingeben - Die ersten Dutzend eingesendeten CAPTCHAs wurden größtenteils mit mindestens einem falschen Zeichen gelöst
- Mit der Funktion „100% Recognition“ des Dienstes wurde eingestellt, Ergebnisse nur dann zu erhalten, wenn mehrere Bearbeiter dieselbe Antwort liefern
- Die Einstellungen waren
n = 2,x = 2,y = 3 - Zunächst wird an 2 Personen gesendet; stimmen sie nicht überein, werden bis zu 3 weitere hinzugefügt, bis zwei Antworten übereinstimmen
- Die Einstellungen waren
- Mit dieser Einstellung wurden etwa 80 % der CAPTCHAs gelöst, davon waren etwa 90 % korrekt, aber rund 10 % enthielten Fehler
- Es gab Fälle, in denen mehrere Bearbeiter denselben Fehler machten
- Zusätzlich kam ein Userscript zum Einsatz, mit dem man selbst oder mit Hilfe von Bekannten CAPTCHAs löste und Bild sowie Antwort speicherte
- So kamen einige hundert weitere Bilder in den Trainingssatz
- Wegen Throttling bei wiederholten Anfragen und steigender CAPTCHA-Schwierigkeit wurde dieser Ansatz eingestellt
Erzeugung synthetischer Daten
- Da 4Chan und der zugehörige CAPTCHA-Code nicht Open Source sind, konnte derselbe Code nicht lokal ausgeführt werden
- Stattdessen wurden synthetische CAPTCHAs erzeugt, die die echte CAPTCHA-Struktur annähern
- CAPTCHAs wurden in zwei Teile zerlegt: Hintergrund und Zeichen
- Der Hintergrund wurde gewonnen, indem in echten Bildern große Konturen gefunden und die Zeichenbereiche entfernt wurden
- Nach dem Entfernen der Zeichen blieb nur der verrauschte Hintergrund übrig
- Einzelne Zeichen wurden durch manuelles Labeling gewonnen
- Zeichen wurden mit VoTT getaggt
- Ein einfaches Skript extrahierte die Zeichen und führte Nachbearbeitung durch
- Pro Zeichen standen 50–150 isolierte Bilder zur Verfügung
- 4Chan-CAPTCHAs enthalten nur
0, 2, 4, A, D, G, H, J, K, M, N, P, R, S, T, W, X, Y- Vermutlich ist diese Auswahl dazu gedacht, Mehrdeutigkeiten zu vermeiden
- Die extrahierten Zeichen und Hintergründe wurden kombiniert und gemäß beobachteten Zeichenplatzierungsmustern zu synthetischen Bildern zusammengesetzt
- Da die Eingabezeichen bereits gelabelt waren, konnten auch die Antworten der synthetischen CAPTCHAs automatisch erzeugt werden
Modellarchitektur und Vorverarbeitung
- Für die Trainingsdaten wurden vorab ausgerichtete Slider-CAPTCHAs, normale CAPTCHAs und synthetische CAPTCHAs gemischt
- Das Trainingsskript brachte alle Bilder auf 300x80 Pixel und wandelte sie in reines Schwarzweiß um
- Das Modell ist eine LSTM-CNN-Architektur, die anhand mehrerer Artikel zum Lösen von CAPTCHAs zusammengestellt wurde
- Es verwendet 3 Convolution-/Max-Pooling-Layer
- Es verwendet 2 LSTM-Layer
- Ein vierter Convolution-Layer wurde ebenfalls getestet, verbesserte die Leistung aber nicht
- Da die Ausgabelänge variabel 5 oder 6 Zeichen beträgt, wurde CTC-Encoding verwendet
- Für die Implementierung kamen Keras und TensorFlow zum Einsatz
Problem mit der Argumentreihenfolge von tf.image.resize()
- Einige ältere ausgerichtete Slider-CAPTCHAs passten nicht zur Auflösung 300x80 oder zum Seitenverhältnis
- Damit das Trainingsskript unterschiedliche Eingaben verarbeiten kann, wurde
tf.image.resize()verwendet - Anfangs wurde angenommen, dass das Größenargument ein Tupel
(width, height)ist, tatsächlich verlangttf.image.resize()jedoch die Reihenfolge(height, width) - Durch diesen Fehler wurden die Bilder auf unlesbare Weise vertikal gestreckt, etwa zu 80x300
- Selbst nach mehr als 32 Epochen Training ergab sich auf gesehenen Bildern kaum Leistung
- Für neue CAPTCHAs lieferte das Modell nahezu zufällige Vorhersagen
- Durch Visualisierung der verarbeiteten Eingabebilder wurde das Problem erkannt; nach der Korrektur verbesserte sich die Trainingsleistung deutlich
Trainingsumfang und Ergebnisse
- Der finale Datensatz bestand aus etwa 500 manuell gelösten Bildern und rund 50.000 synthetischen Bildern
- Die synthetischen Bilder wurden durch zufälliges Sampling aus etwa 2.500 Hintergrundbildern und 50–150 Bildern pro Zeichen erzeugt
- Der Datensatz wurde zufällig gemischt und im Verhältnis 90/10 in Trainings- und Evaluationssatz aufgeteilt
- Auf einer NVIDIA RTX A4000 Laptop GPU dauerte das Training pro Epoche etwa 45 Sekunden
- Am Ende der ersten Epoche lag der Loss bei etwa 19, und die Vorhersagen waren fast alle falsch
- Am Ende der vierten Epoche war der Loss auf 0,55 gefallen, und 5 von 5 zufälligen Testvorhersagen waren korrekt
- 8–16 Epochen waren ein guter Kompromiss zwischen Zeitaufwand und Endleistung
- Um die 8. Epoche stabilisierte sich der Loss
- Nach 16 Epochen nahmen die Verbesserungen stark ab
- Mit
trainer/infer.pywurde die Inferenz in Python getestet, und auch auf ungesehenen Bildern waren die Ergebnisse vielversprechend
TensorFlow.js-Konvertierung und Ausführung im Browser
- Das Userscript wurde mit TensorFlow.js und TypeScript geschrieben
- Der CAPTCHA-Ausrichtungsalgorithmus und der Bildvorverarbeitungscode aus Python wurden neu implementiert
- Der zugehörige Code befindet sich im Verzeichnis
user-scripts/des Repositorys - Das Modellformat von Python TensorFlow/Keras ist nicht mit dem von TensorFlow.js erwarteten Format kompatibel
- Das offizielle Konvertierungsskript musste verwendet werden, dabei traten jedoch zwei Probleme auf
- Der offizielle TensorFlow-to-TFJS-Konverter funktionierte unter Python 3.12 nicht, und die Fehlermeldung war nicht eindeutig
- Mit Python 3.10 via PyEnv gelang die Konvertierung
- Das Konvertierungsskript konnte Keras-3-Modelle in das TensorFlow.js-Format umwandeln, aber TensorFlow.js konnte das konvertierte Modell tatsächlich nicht lesen
- Das zugehörige Problem wurde über einen Forumspost identifiziert
- Die Lösung war die Verwendung von Keras 2
- Das Legacy-Paket
tf_keraswurde installiert - Für das Training wurde die Umgebungsvariable
TF_USE_LEGACY_KERAS=1gesetzt - Das Modell wurde im Legacy-Format
.h5exportiert und das Eingabeformat im Konvertierungsskript angegeben - Am Code war nur eine einfache Änderung an einer Zeile nötig
- Das Legacy-Paket
Leistung bei echten 4Chan-CAPTCHAs
- Auch bei echten 4Chan-CAPTCHAs funktioniert das Modell gut
- Das erste Laden des Modells dauert etwa 1 Sekunde
- Danach fühlt sich die Ausführung praktisch sofort an
- Aus der Erfahrung mit mehreren hundert echten CAPTCHAs im Browser lag die Erfolgsquote bei über 90 %
- Fälle, in denen ein Zeichen selbst falsch erkannt wurde, waren selten; bei ungenauen Ergebnissen fehlte meist ein einzelnes Zeichen vollständig
- Mehr Training mit echten Daten oder Anpassungen am CAPTCHA-Layout des Generators könnten weitere Verbesserungen bringen
- Die Genauigkeit dieses Modells war deutlich höher als die kommerzieller menschlicher CAPTCHA-Lösungsdienste
4-Zeichen-CAPTCHAs und Fazit
- Nach Abschluss des Projekts, während der Artikel geschrieben und bearbeitet wurde, begann 4Chan zeitweise 4-Zeichen-CAPTCHAs auszuliefern
- Das Modell wurde nur mit 5- und 6-Zeichen-CAPTCHAs trainiert, zeigte bei 4-Zeichen-CAPTCHAs aber eine vergleichbare Leistung
- Im Verlauf des Projekts wurde viel über Machine Learning und Computer Vision gelernt, und das ursprüngliche Ziel eines browserbasierten CAPTCHA-Lösungsmodells wurde erreicht
1 Kommentare
Meinungen auf Hacker News
Der vermurkste Teil bei der Integration von Keras und TensorFlow.js wirkt typisch für TensorFlow.
Wenn ich TensorFlow benutze, hatte ich immer eher das Gefühl, dass unter einem Dach grob zusammengehörige Tools versammelt sind, statt eines integrierten, geschmeidigen Produkts.
Eigentlich kann man sogar sagen, dass sich alle Open-Source-Bibliotheken und -Tools von Google so anfühlen.
Die Antwort auf „Warum wurde 2019 entschieden, Keras in TensorFlow zusammenzuführen?“ lautete: „Das war nicht meine Entscheidung. Das war eine Entscheidung der TF-Führung im Jahr 2018; ich war damals ein L5 Individual Contributor, und das war eine L8-Entscheidung.“
Ich brauchte ein CAPTCHA, um Kommentarformular-Spam auf meiner Website[0] zu verhindern, und habe dafür eine interessante Methode wiederverwendet, die ich früher einmal gesehen hatte.
Es ist keineswegs perfekt und auch nicht schwierig, aber der Bauprozess hat mir wirklich gefallen.
[0] https://www.hybridlogic.co.uk/contact
https://vivirenremoto.github.io/doomcaptcha/
Es gibt einen Grund, warum man sich von verzerrten textbasierten CAPTCHAs wegbewegt hat.
Wir sind inzwischen fast an dem Punkt, an dem Computer sie besser lösen als Menschen.
https://www.usenix.org/system/files/conference/woot14/woot14... ist ein Paper zu diesem Thema, das ich ziemlich interessant finde.
Trotzdem lassen sich erstaunlich viele textbasierte CAPTCHAs mit einem Shell-Skript aus ein paar Zeilen lösen, das mit ImageMagick in Graustufen umwandelt, Dilatation und Erosion anwendet und das Ergebnis dann an Tesseract übergibt.
Aber es gibt auch Websites wie https://2captcha.net, daher ist ein CAPTCHA am Ende eher eine Vorrichtung, die ein kleines Mindestmaß an Aufwand verlangt.
In die Lösung in diesem Artikel sind erhebliche Zeit, Können und Mühe geflossen, und das Ergebnis lässt sich zudem nicht gut verallgemeinern; bei einer anderen Art von CAPTCHA müsste man wieder von vorne anfangen.
Die meisten Spammer können das nicht reproduzieren, und wer es kann, verdient wahrscheinlich legal Geld oder nimmt sich lohnendere Ziele vor.
Solche CAPTCHAs funktionieren weiterhin gut, um die Kosten erfolgreichen Spams über den erwarteten Ertrag zu heben.
Könnte man ein Forum bauen, in dem jedes Mitglied ein 15-minütiges Videointerview mit einem Moderator führen muss? Ich weiß, dass das „nicht skaliert“, aber als witzige Scherz-Vorrichtung scheint es machbar.
Sie sind keine Lösung, eher eine kleine Festung, die nach und nach veraltet.
Dem Link zufolge dauert reCAPTCHA v3 10–15 Sekunden und kostet 1,3 Dollar pro 1000 CAPTCHAs.
Bei vielen Aufgaben, bei denen man CAPTCHAs umgehen möchte, etwa beim massenhaften Scrapen großer Websites, werden diese Kosten tatsächlich ziemlich hoch und schwer tragbar.
mCaptcha.org ist eines davon, und es gibt auch andere Implementierungen.
Klassische CAPTCHAs werden, sobald sie auch nur ein wenig wirksam sind, in puncto Barrierefreiheit schnell zum Albtraum.
Falls dich solche Themen interessieren: Ich habe 2014 auch eine Analyse des Silk-Road-CAPTCHA zusammengestellt: https://github.com/mieko/sr-captcha
4chans Reaktion wirkt angemessen.
Da es sich ohnehin leicht mit neuronalen Netzen lösen lässt, geht es darum, die Aufgabe für Menschen zu vereinfachen.
Selbst wenn man heute ein sehr schwieriges CAPTCHA entwirft, ist es eher unwahrscheinlich, dass es für Maschinen schwerer wird, und ziemlich wahrscheinlich, dass es nur Menschen stärker nervt.
https://4chan.org/pass
Er wird bereits als Option angeboten, um ohne CAPTCHA zu posten.
Wenn CAPTCHAs völlig wirkungslos sind, folgt daraus, dass man CAPTCHAs und kostenloses Posten abschafft und alle, die posten wollen, einen 4chan Pass kaufen müssen.
Vor Kurzem wurde eine 15-minütige Schreibverzögerung eingeführt, und die macht wirklich wütend.
Ich musste 4chan in Cookie AutoDelete auf die Allowlist setzen.
Statt so zu tun, als gäbe es ein CAPTCHA, wäre es vielleicht besser, tatsächlich das Timing und Verhalten der Nutzer zu analysieren.
Ehrlich gesagt habe ich den Eindruck, dass so etwas ohnehin schon passiert.
Wenn man es ganz meta angeht, könnte man auch eine KI darauf trainieren zu beurteilen, ob der Akteur auf der Gegenseite ein Mensch ist oder nicht.
Im Grunde würde man damit einen umgekehrten Turing-Test erfinden: Wenn die KI eine Antwort nicht von der eines normalen Menschen unterscheiden kann, gilt sie als Mensch.
Der Unterschied ist, dass sie nicht von Marketing-Menschenantworten unterschieden wird.
Schon allein dieser Gedanke macht mir jetzt etwas übel, ich muss mich hinlegen.
Noch bevor sie ein CAPTCHA ausliefern, identifizieren sie zuerst TLS-Fingerprints, IP, HTTP/2, Requests, die JavaScript-Umgebung, Fähigkeiten beim Font- und Bild-Rendering sowie den Browser selbst.
Aus diesen Informationen berechnen sie einen Trust Score und entscheiden, ob sie überhaupt ein CAPTCHA anzeigen.
Erst danach ergibt es Sinn, die CAPTCHA-Eingabe zu analysieren, aber zu diesem Zeitpunkt sind bereits 90 % der Bots erwischt.
Die Menge an Informationen, die ein Browser ohne jede Erkennung an einen Server weitergeben kann, ist absurd groß; wahrscheinlich ist unser jeweiliger digitaler Fingerabdruck eindeutiger als ein echter Fingerabdruck.
Der ursprüngliche Paradefall für das Knacken von 4chan-CAPTCHAs ist für mich immer noch, wie Yannick Kilcher GPT-J mit dem „Raiders of the Lost Kek“-Datensatz feinabgestimmt hat.
Vielleicht einer der coolsten Einsätze eines Large Language Model, die je als Video gezeigt wurden: https://youtu.be/efPrtcLdcdM?si=errY0PrEhnX9ylDw
Rekordverdächtig.
Wegen Dingen wie „der offizielle TensorFlow-to-TFJS-Modellkonverter funktioniert nicht mit Python 3.12 und ist auch nicht ordentlich dokumentiert“ oder „TensorFlow.js unterstützt Keras 3 nicht“ habe ich vor ein paar Jahren fast aufgegeben, als ich nur ein bisschen mit Machine Learning herumprobieren wollte.
Viel zu oft waren aktuelle Tutorials bereits veraltet, es gab überall zufällige Fallstricke, und es war schockierend, wie viele „Getting Started“-Guides stillschweigend voraussetzen, dass man bereits Experte ist.
Es ist besser, die Grundlagen mit einem alten Lehrbuch zur bayesschen Statistik zu lernen und danach zu einem großen Framework wie PyTorch überzugehen.
Am Anfang sollte man CNN-, RNN- und Transformer-Architekturen sowie alle Teile der Trainingspipeline selbst schreiben.
Einschließlich Data Loader, aber CUDA-Matrix-Kernels kann man auslassen.
Von Wrappern um Wrapper anderer Leute, wie LangChain, sollte man lieber Abstand halten.
Die Dokumentation ist oft nicht nur veraltet, sondern bei Grundlagen sogar schlicht falsch.
Hugging Face ist großartig, wenn man die Basics kennt und Standard-Wrapper reparieren kann, wenn sie kaputtgehen.
Das ist so ähnlich, als würde man ein paar Stunden damit verbringen, zu lernen, wie man den Deckel einer Klärgrube öffnet.
Wenn man Links zu CAPTCHA-Lösediensten folgt, kann man die Profile der Leute lesen, die diese Arbeit machen.
Es wird damit beworben, dass es ethischer sei, als in einer gefährlichen Fabrik zu arbeiten.