Archive for the ‘Reverse Engineering’ Category
Arduino + ferngesteuerte Lampe
Ich bin ein blutiger Kacknoob was Elektrotechnik angeht. Dennoch habe ich seit Jahren vor, etwas in der Richtung zu tun (wer will denn auch Systeme erforschen, ohne verstehen zu wollen, wie die darunter liegende Hardware funktioniert?). Also habe ich mich mit meinen bisherigen Kenntnissen (die mir schon fast peinlich sind) daran gewagt, ein Stückchen Hardware einem Reverse Engineering zu unterziehen
(Wer die vielen Andeutungen nicht verstanden hat: ich entschuldige mich dafür, keine genaue Ahnung davon zu haben, was ich hier in dem Post von mir gebe )
Ich wollte mit einem simplen Target anfangen. Bei Reverse Engineering von Software ist sowas einfach, da man ja unzählige 30-Tage-Shareware Programme findet, die man einfach kostenfrei runterladen kann, um an ihnen rumzuexperimentieren. Bei Geräten sieht die Sache wieder ganz anders aus. Ich fand zufällig diesen Artikel. Leider habe ich das dort vorgestellte Gerät nicht Zuhause (obwohl ich sowas schon im Baumarkt gesehen habe). Daraufhin fiel mir sofort ein, dass meine liebe Mami eine Wohnzimmerlampe gekauft hatte die (zu ihrer eigenen Überraschung) mit einer Fernbedienung an und ausgeschaltet werden konnte.
Was ich nun vor hatte war folgendes: Analysieren wie das Gerät funktioniert. Nachbauen. Und anschließend eventuell was tolles damit machen.
Ich habe mir schon gedacht, dass es schwer wird ihr zu erklären, wieso ich ihre Fernbedienung brauche. Also habe ich es mir eines Abends einfach geborgt, ohne zu fragen. (Falls es bei meiner Analyse kaputt gegangen wäre, hätte ich das Teil einfach verschwinden lassen. Und wenn meiner Mutter aufgefallen wäre, dass es geklaut wurde, hätte ich einfach die polnischen Nachbarn beschuldigen können)
Vier Buttons um verschiedene Farben und Funktionen der Lampe zu steuern. Mir würde auch schon genügen, wenn ich das Teil an und ausschalten könnte.
Also ersteinmal das ganze aufgeschraubt:
Hey, das ist ja super! Das sieht sehr einfach aus. Ich wollte nun zu aller erst wissen, wie die Fernbedienung der Lampe mitteilt, dass sie angehen soll. Und da fiel mir schon etwas auf:
Auf den oben verlinkten Beitrag vertrauend, habe ich angenommen, dass dieses Gerät im 433.92Mhz Bereich arbeitet, um seine Befehle zu versenden. Also habe ich mir einen 434 Mhz Empfänger und Sender gekauft, in der Hoffnung, diese mit meinem Arduino ansteuern zu können (mit dem Empfänger wollte ich das Protokoll analysieren).
Einige Tage später kam meine Bestellung an. Zu meinem Entsetzen musste ich feststellen, dass der Empfänger viel “rauschen” empfang. Es war sehr schwierig die relevanten Daten zu finden (und diese haben so merkwürdig variiert, dass ich keine Muster erkennen konnte).
Da kam mir die Idee, mir einen Logic Analyzer zu besorgen (so kann ich dann sehen, wann und wie lange eine 1 und eine 0 gesendet werden, indem ich direkt an dem Gerät selbst messe). Ich wollte mir schon seit längerem Bus Pirate gönnen und dieser ist in der Lage als (laut offiziellen Informationen ein sehr schlechter) Logic Analyzer zu dienen. Nachdem mein Bus Pirate ankam, schloss ich ihn direkt an und begann mit dem reversen!
Ich musste nun meinen Bus Pirate an die Pins anlegen, an denen ich messen/sniffen wollte. Dafür habe ich erstmal das oben dargestellte Element mit der Aufschrift “LR1 433.92″ (welches anscheinend das hier ist, genauer gesagt das hier) auf der Rückseite gesucht:
Und nun einfach die Kabel angelegt (nachdem ich mir sicher war, dass es hier um höchstens 5V geht, was der Bus Pirate anscheinend vertragen kann).
Nun musste ich nur noch die Kabel halten, sowie den Button der Fernbedienung drücken, und gleichzeitig das Sniffen in der Software starten (da hierbei aufgrund mangelnder Speicher nur sehr kurz aufgezeichnet werden kann, muss das alles sehr schnell gehen). Mit nur 2 Händen ist das ziemlich schwer!
Nach einigen Versuchen (und einem 5 Minuten (!) anhaltenden Krampf in meiner Hand, währenddessen ich in der Wohnung gebrüllt habe “HAHAHA, ICH BIN BEHINDERT” … habe ich Magnesiummangel?) hatte ich endlich eine Aufnahme:
Wobei hier nur die oberste Zeile/Aufnahme relevant ist.
Nun konnte ich entweder so cool sein, und analysieren was hier genau einen Bit darstellt (und ob es eine 1 oder eine 0 repräsentiert) oder aber, ich könnte das ganze einfach dumm nachbauen (Anmerkung: ich bin dumm).
Ich habe mir aufgeschrieben, wie lange eine “1″ gesendet wird, und wie lange die darauffolgende 0 etc. Was dann ungefähr so aussah:
1 = 300 us
0 = 800 us
1 = 800 us
0 = 300 us
1 = 800 us
0 = 200 us
1 = 800 us
[...]
Das habe ich nun in Arduino implementiert, wobei ich dafür den 434 Mhz Sender benutzt habe:
#define DATA_PIN 10 int send_1[] = {300, 800, 800, 300, 800, 200, 800, 300, 200, 800, 300, 800, 800, 200, 800, 300, 800, 200, 800, 200, 800, 300, 800, 200, 300, 800, 800, 200, 300, 800, 300, 700, 800, 300, 800, 200, 300, 800, 300, 700, 300, 800, 300, 800, 200, 800, 300, 800, 200}; int state; void setup() { state = HIGH; pinMode(DATA_PIN, INPUT); Serial.begin(9600); Serial.println("Zu deinen Diensten!"); } void loop() { while(Serial.available() == 0); while(Serial.read() != -1); int a; for(a = 0; a < 8; a++) { int i; for(i = 0; i < 49; i++) { digitalWrite(DATA_PIN, state); digitalWrite(13, state); delayMicroseconds(send_1[i]); state = (state == HIGH) ? (LOW) : (HIGH); } digitalWrite(DATA_PIN, state); digitalWrite(13, state); delay(8); state = HIGH; } digitalWrite(13, LOW); delay(5000); }
Ganz einfach! Und funktionieren tut es. Damit ich irgendwas aufregenderes anstelle, habe ich einen Webserver bei mir auf dem Rechner aufgesetzt, welches per serieller Verbindung meinem Arduino befiehlt, das Licht an/auszumachen. Nun kann ich mit jedem internetfähigen Gerät, das Licht ausschalten. Hier beispielhaft mit meiner DSi:
Demnächst baue ich noch eine Klatsch-Funktion ein, sodass das Licht anspringt wenn man klatscht. Und falls ich den Spaß daran nicht so schnell verliere, wirds enden wie in einer Folge von The Big Bang Theory.
Wie auch immer. Ich hoffe, dass einige von euch trotzdem Spaß beim lesen hatten. Ich fühle mich jedesmal immer so doof, wenn ich noch am Anfang eines langen Weges stehe. Hofft mit mir, dass ich irgendwann in der Lage sein werde, spannendere Geräte zu analysieren!
Demnächst blogge ich wohl über das SFT09 Format, welches ich so gut wie fertig analysiert habe.
If you enjoyed this article please consider staying updated via RSS. Links to your own social media pages could be added here.
- Posted in Reverse Engineering
- 14 Comments
Disgu(i)sting
Ja, ich lebe noch.
Der letzte Blogeintrag ist fast schon ein viertel Jahr her. Ich hatte leider während der Semesterferien absolut keine Zeit für meine Hobbys. Ich musste zwangsweise etwas Energie in mein Real-Life investieren, und wer will das schon, richtig? Mir hat irgendwie auch die Motivation gefehlt irgendein Verschlüsselungssystem zu erforschen.
Gehen wir einen Tage zurück: Ich hatte keinen Zugang zum Internet und so langsam sind mir die Bücher ausgegangen, und so musste ich mir anders behelfen. Klar, ich könnte rausgehen in die Natur (haha!), aber ich hatte noch in meiner VirtualBox eine Applikation die darauf gewartet hat analysiert zu werden. Also wurde ich rückfällig, und saß dann gestern Abend wieder vor dem Rechner, um etwas zu analysieren. Das heutige Target nennt sich “Disguise” (na, war der Titel von dem Blogpost nicht einfallsreich?).
Diesmal war es etwas anders. Dieses Programm setzt zwar wieder auf Security-by-obscurity, aber einen Unterschied zu meinen vorherigen Targets hat es: es ist nicht direkt gebrochen, allein wenn man den Schlüssel und den Algorithmus gefunden hat.
In diesem Fall musste ich (un?)glücklicherweise tatsächlich eine Kryptoanalyse durchführen. Es ist meine erste echte Kryptoanalyse von einem unbekannten Verfahren gewesen, und wie das Leben so spielt, war es garnicht so schwer. Ich bin quasi in das Thema hineingerutscht.
Nun, was ist denn dieses Disguise? Auf der Webseite heißt es:
I share with you, with Disguise, a SECURE dual-keys proprietary multi-stage encryption algorithm to protect your PRECIOUS DATA.
(die Hervorhebungen sind originalgetreu übernommen)
Na sieh sich das mal einer an. Klingt doch super! Wäre da nur nicht dieses kleine winzige Wort “proprietary”, gäbe es keinen Grund für mich dieses Programm zu analysieren. Denn sonst hätte ich gedacht, dass das Verfahren etwas wie AES ist. Aber so weiß ich, dass der Programmierer vermutlich einen eigenen Verschlüsselungsalgorithmus entworfen hat. Und wer schonmal einen Kryptoexperten erlebt hat, der euch förmlich anbettelt, niemals einen eigenen Verschlüsselungsalgorithmus zu entwerfen, der wird spätestens in diesem Blogeintrag erfahren wieso.
Mittlerweile scheint es mir so, als könne man schlechte Verschlüsselung bereits an der GUI des Programmes entlarven. Vielleicht erinnert sich noch jemand an das hier. Jedenfalls, ist dieses Programm genauso hässlich:
Ekelhaft. Na vielleicht tut es ja seine Arbeit gut. Nämlich: Daten sicher verschlüsseln (hey, ihr seid auf meinem Blog, was glaubt ihr?)
Vorerst machen wir eine Blackbox Analyse. Ich werde mir also vorerst nicht den Programmcode anschauen. Ich werde eine Datei einspielen, und mir das Resultat anschauen.
Ich habe also testweise eine Datei verschlüsseln wollen. Und in dem Moment hatte mich das Programm nach zwei Daten gefragt. Es wollte von mir zwei so genannte “Signaturen” haben. Im Prinzip meint der damit nur ein Passwort. Ich sollte also zwei Passwörter eingeben. Allerdings durften diese nicht länger als 8 Zeichen sein. 8 Bytes? Das sind nur 64 Bit für einen Schlüssel. Allerdings will er zwei mal 8 Bytes. Wer weiß, was er mit diesen Passwörtern genau tut ?!
Ich werde im Laufe dieses Blogeintrages folgenden Plaintext als Eingabedatei “god.txt” verwenden (damit hier einige nicht rumheulen: es ist tatsächlich die erste txt Datei auf meinem Rechner, die mir unter die Finger kam; es hat keine weitere Bedeutung):
Is God willing to prevent evil, but not able? Then he is not omnipotent.
Is he able, but not willing? Then he is malevolent.
Is he both able and willing? Then whence cometh evil?
Is he neither able nor willing? Then why call him God?
Nach der Verschlüsselung hatte ich eine Datei “goddis.txt”, mit dem Inhalt:
Na das sieht doch ziemlich verschlüsselt aus. Was mir als erstes aufgefallen ist: die Ausgabedatei ist um 33 Bytes größer als das Original. Was hat der Algo da bloß getan? Beim Versuch andere Dateien zu verschlüsseln, ist jedesmal die Ausgabedatei um 33 Bytes größer.
Ich mache jetzt etwas ganz simples. Ich werde die Ausgabe Datei goddis.txt mal nach der statistischen Häufigkeit der Bytes untersuchen. Da bietet mir mein Hexeditor HxD eine passende Funktionalität. Die Ausgabe sieht so aus:
Es gibt da nicht viel zu sehen. Man erkennt bloß, dass einige Bytes garnicht vorkommen, wohingegen die letzten Bytes (0xF4 bis 0xF7) verglichen mit den anderen Bytes, ziemlich oft in der verschlüsselten Datei auftauchen. 0xF7 taucht sogar ganze 17 mal auf (das sind 6,32% der ganzen Datei).
Schauen wir uns das Resultat der Verschlüsselung von standardisierten Verschlüsselungsalgorithmen an. Hier in dem Fall ist es AES:
Die statistische Verteilung der Bytes sieht schon ziemlich zufällig aus. Das Byte 0×35 kommt hier am häufigsten vor, mit genau 6 Auftritten (das sind 2,49% der Datei). Zum Vergleich schauen wir uns noch eine rein zufällige generierte Datei an:
Es gibt in diesem Fall mehrere Bytes die das Maximum darstellen. Sie tauchen genau 4 mal auf, und machen damit 1,66% der Datei aus.
Verglichen damit steht Disguise sehr doof da. Es gibt einem das Gefühl, dass die Ausgabe nicht wirklich durchgewürfelt ist; und vielleicht haben wir sogar eine Möglichkeit, den Algorithmus zu brechen.
Genug Blackbox Analyse. Wir öffnen das Programm mit unserem Lieblingsdisassembler/debugger und schauen uns an, was das Programm tut. Da ich in diesem Beitrag mehr auf die Analyse des Verfahrens eingehen möchte, und nicht schon wieder auf das Reverse Engineering (dazu schaut ihr lieber hier nach), werde ich kurz beschreiben was ich alles über den Algorithmus herausgefunden habe:
Es gibt eine erste Runde die ich “Phase 1″ getauft habe. In dieser Phase wird ein “Pseudo”-Ciphertext generiert, der einfach wieder zurück zum Ursprungszustand versetzt werden kann. Danach folgt die Phase 2, wo dann die zweite Signatur angewendet wird, um es zu verschlüsseln. Und dann haben wir unsere verschlüsselte Datei.
Ein etwas tieferer Einblick: Zuerst wird aus der Signatur 1 (hier der Einfachheit zur Liebe: “sign123″) etwas generiert, was ich sig1c nenne. Dabei wird folgendermaßen vorgegangen: Wir lesen das aktuelle Byte aus (hier “s” = 0×73). Dieser wird reversed zu 0×37. Nun führt man eine OR-Verknüpfung mit dem Wert 0×08 durch (= 0x3F) und negiert anschließend das Ganze (= 0xC0). Das macht man mit allen Bytes der Signatur. Alles hinter der Signatur ist 0×00. Diese pseudo-Verschlüsselung wird genau 31 mal angewandt. Nun wird ein 0×00 Byte angeschlossen und dahinter wird ein konstanter Wert “03″ hinzugefügt. Das sind insgesamt 33 Bytes, welcher der Verschlüsselten Datei vorne angehangen werden (das erklärt schonmal dieses Mysterium!).
Aber mooooment. Ich sagte gerade, dass hinter dem sign123 nur noch 0×00 Bytes folgen. Wenn man genau dieses Verfahren auf 0×00 anwendet, dann kommt stets 0xF7 heraus. Das könnte eventuell die statistische Häufigkeit der 0xF7 in der Ausgabe Datei erklären.
Das erzeugte sig1c sieht nun so aus: C0 61 81 11 E4 D4 C4 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 F7 00 03
Das ist der Header, der jeder verschlüsselten Datei hinzugefügt wird (wobei die ersten 7 Bytes variieren, aufgrund der ersten Signatur; der Rest ist stets gleich!).
Der eine oder andere fragt sich nun: Wieso ist die Signatur nur 7 Bytes lang, obwohl das Programm 8 Zeichen haben will? Ich weiß nicht ob das so gewollt ist, aber das Programm liest nur 7 Bytes, und reserviert das 8te für das 0×00 Byte, um den String abzuschließen. Obwohl das total überflüssig ist. Wie wir nachher sehen werden, hat dieser kleine “Bug” mir Tür und Tor geöffnet.
Dieses sig1c-Verfahren wird auf die ganze Plaintext-Datei angewandt. Nun haben wir diesen Pseudo-Ciphertext, der wieder zurück zum Urprungszustand versetzt werden kann (es ist reversible/umkehrbar).
Auf diesen Zustand wird nun die Phase 2 angewandt. Dieser geht wie folgt:
Die Datei wird in 8-Byte Schritten eingelesen. Nun wird mit jedem Byte dessen mit dem aktuellen Byte der zweiten Signatur XOR verknüpft. (Bedenke: das letzte Byte der zweiten Signatur ist auch 0×00! Einfachheitshalber ist meine zweite Signatur “ABCDEFG”).
Beispiel von oben: Das erste Byte war 0xC0. Dieser wird mit 0×41 (“A”) geXORed. Es ergibt 0×81. Das Ergebnis des ersten Durchlaufes ist: 81 23 C2 55 A1 92 83 F7.
Nach jedem Durchlauf der 8 Byte, wird ein “shuffle” durchgeführt. Die Signatur2 wird verwürfelt. Allerdings hat sich der Programmierer hier sehr dumm angestellt (aber er hat anscheinend Ideen in die richtige Richtung gehabt!): Die Verwürfelung der Signatur ist nicht ständig das selbe. Es gibt 5 verschiedene Funktionen. Ein Counter wird jeweils modulo 5 geteilt, und jenachdem wird die jeweilige Funktion aufgerufen. Der Counter wird anfangs auf das 4te Byte des sig1c gesetzt (hier: 0×11 = 17).
17 modulo 5 ergibt 2. Es wird also die zweite Funktion zum shufflen der Signatur aufgerufen. Diese Funktion sieht in C so aus:
unsigned char op_value = signature2[3];
int i;
for(i = 0; i < 8; i++)
{
signature2[i] = signature2[i] ^ op_value;
}
es wird das 4te Byte der Signatur ausgelesen, und für die nachfolgenden Operationen verwendet. Nun wird jeder Wert der Signatur mit diesem Wert geXORed.
Das heißt quasi: Unsere aktuelle Signatur2 ist 41 42 43 44 45 46 47 00. Das dick markierte ist unser op_value. Zuerst XORed er also 0×41 mit 0×44. Dann 0×42 mit 0×44 usw. Irgendwann ist er aber bei sich selbst, er XORed also 0×44 mit 0×44. Wie jeder wissen sollte, ergibt das zwangsläufig immer 0×00. Das ist sehr fatal, wenn dieser Wert später in der Verschlüsselung Verwendung finden soll! Nach dem Shuffle haben wir eine Signatur2 die wie folgt aussieht: 05 06 07 00 01 02 03 44
Beachte: das letzte Byte ist 0×44, da hier 0×00 mit 0×44 geXORed wurde.
Nun, das ist der ganze Algorithmus. Nun machen wir uns daran, den Algorithmus anzugreiffen!
Wenn wir genau nachdenken, dann baut die Verschlüsselung darauf auf, dass der Pseudo-Ciphertext jeweils mit der zweiten Signatur XOR-verknüpft wird. Allerdings haben wir gerade gesehen, dass die zweite Signatur zwangsweise irgendwo eine 0×00 enthält. Irgendein Wert mit 0×00 geXORed ergibt wieder den Wert. Es passiert also nichts. Das heißt im Klartext: Ein Byte wird in dem Ursprungsformat bleiben, und nicht verändert.
Wenn ich mir jetzt in der fertig verschlüsselten Datei goddis.txt den nächsten 8-Byte Block anschaue, sehe ich das hier:
F2 F1 F0 F7 F6 F5 F4 B3
Wir erinnern uns, der Header bestand im zweiten Block nur aus 0xF7. Hier eine kleine bildliche Erläuterung:
Und da es ein XOR Verfahren ist, könnten die Pfeile auch eine Spitze auf beide Seiten haben. Denn ich kann auch Rückwärts von 81 durch XORen mit 0×41 wieder 0xC0 erhalten.
Ich sehe hier, dass beim XORen des zweiten Blockes, ein Fehler entsteht. Und zwar bleibt der 0xF7 bestehen, wie bereits erwähnt. Wenn wir nun die Ausgabe-Bytes (also F2 F1 F0 F7 F6 F5 F4 B3) wiederum mit 0xF7 alle XORen, haben wir die aktuelle Signatur2 (nämlich 05 06 07 00 01 02 03 44) errechnet. Aufgrund des 0×00 Byte-Bugs am Ende der Signatur, haben wir hier 0×44 (“D”) am Ende hängen. Wir wissen also, mit welchem Wert die Signatur geshuffled wurde. Wenn wir also alle signatur Bytes wieder mit 0×44 XORen, erhalten wir “ABCDEFG”. Tada!
Wir haben den zweiten Signatur-Key errechnet, dank der unzähligen Bugs im Algorithmus. Das hier vorgestellte Verfahren würde wohl in die Kategorie “Known Plaintext” fallen (beispielsweise wurde WEP dadurch gebrochen). Da wir in diesem Fall wissen, wie der Plaintext (hier eher Pseudo-Ciphertext) im Header aussieht (nämlich fast nur 0xF7er Bytes), können wir in jedem Fall den zweiten Signatur Key errechnen. Zur verdeutlichung:
Und mit diesem Key können wir nun sig1 entschlüsseln.
Wir haben allerdings ein Problem. Beim shufflen wird nicht immer XOR verwendet. Wir erinnern uns: es gibt 5 verschiedene Funktionen, um die Signatur zu shufflen. Eine davon verwendet ein “AND” zum verknüpfen, ein anderer ein “OR”.
Nehmen wir an, es wurde ein OR verwendet. Ich schaue mir diese shuffle Funktion an. Und als Operator wird das letzte Byte der Signatur verwendet. Allerdings ist das letzte Byte ja immer 0×00! D.h., beim shufflen werden alle Bytes der signatur mit 0×00 geORed. Das Resultat: es verändert sich nichts an der Signatur! Der nachfolgende 0xF7er Block wird mit der Original Signatur verschlüsselt. Wir XORen also wieder den Ciphertext mit 0xF7, und erhalten unsere original Signatur2. Das ist wieder ein trivialer Bug!
Anders sieht es aus, wenn “AND” zum shufflen benutzt wurde. Die passende Funktion dazu benutzt das 5te Byte der Signatur zum shufflen. Dieser könnte alles mögliche sein (alle printable ASCII Zeichen). Doch nicht verzagen, eddy fragen!
Bei einem AND können wir also nicht mit einer so einfachen Möglichkeit die Signatur2 errechnen. Aber wir können die aktuelle geshufflete Signatur für den 0xF7er Block errechnen, indem wir wieder diesen Ciphertext mit 0xF7 XORen. Und mit diesem Key rechnen wir ganz normal weiter.
Man sieht zwar noch meine Debug-Ausgaben, aber ich denke es ist ersichtlich, dass dieses Programm eine verschlüsselte Datei brechen kann, ohne zusätzliche Informationen, nur allein die verschlüsselte Datei! Wie toll ist das bitte? Hier der C-Quelltext (Bitte bitte entschuldigt den dreckigen Code! Es ist sehr schwer zu coden, und nebenbei die Analyse zu betreiben): disdis.c (hab jetzt absolut keine Lust die ganzen Debug Informationen zu entfernen…).
In diesem Blogpost liest man viele verschiedene Werte, und ich bin mir sicher, dass die meisten dem nicht folgen konnten und einfach nur verwirrt waren. Ich werde versuchen dazu ein paar Bilder mehr zu basteln (eventuell sogar eine Flash Animation?).
Wie auch immer; ich bin froh, denn: Der Verschlüsselungsalgorithmus ist gebrochen!
If you enjoyed this article please consider staying updated via RSS. Links to your own social media pages could be added here.
- Posted in IT Security, Reverse Engineering
- 5 Comments
Salzwasser Sauger
Düm Di Dum Düm, trararara DIIING. Ich wollte schon immer einen eigenen Introsong haben! Wer komponiert einen für mich? *liebschau*
Mir war gestern langweilig, also nahm ich ein Programm ausseinander! Ich wusste, dass meine Motivation nicht sehr stark war, deswegen wollte ich heute nur ein einfaches Programm operieren. Ich weiß leider nicht mehr von wem der Tipp kam, aber mir fiel eine gewisse Warez Seite ein, die ihre Angebote auf FTP-Server hochluden. Dafür wird ein eigens konstruierter Leecher verwendet. Auf der Webseite (die übrigens genauso hässlich ist wie das Programm) lädt man sich eine verschlüsselte “Mirror-File” herunter, die nur ein paar KB groß ist. Mit dem Leecher kann dieser nun geöffnet werden.
Wisst ihr nun, was ich mit hässlich meinte?
Die verschlüsselten Dateien haben die Endung “.swl”, deswegen rede ich hier von SWL-Dateien. Wie jeder Reverser weiß, wird zuerst das Programm auf die übliche Art benutzt. Wir klicken unten auf “Open”, es öffnet sich ein Dialogfenster und wir wählen unsere SWL-Datei aus. Nun lädt das Programm diese Datei, und zeigt uns den Inhalt an, sodass wir mit einem Druck auf “Download” das Herunterladen starten können.
So weit, so gut. Ich knackse kurz meine Finger, feuchte meine Lippen an, hole tief Luft, schaue auf die Uhr, merke mir die Zeit, gehe kurz auf die Toilette, hol mir von der Küche eine Tüte Erdnussflips und freue mich auf den Abend.
Als aller erstes will ich schauen, ob das Programm gepackt ist. Dafür verwende ich PEiD. Den entdeckten Packer lasse ich mir durch ein Stück Software automatisch entfernen, denn mir fehlt echt die Lust auf manual unpacking (und das Einlesen in das Thema erst!).
Nun kann ich es ganz bequem in meinen Debugger OllyDbg laden und anfangen. Ich mache mir natürlich Gedanken, wie ich am besten vorgehen soll, um das Geheimnis des Dateiformates zu befreien. Ich werde hier mal die übliche Vorgehensweise von mir schildern:
- Dateiformat in einem Hexeditor ansehen um eine ungefähre Idee davon zu kriegen, wie die Datei strukturiert sein könnte.
- Herausfinden, an welcher Codestelle der Dateiinhalt eingelesen wird
- Herausfinden an welchem Punkt der komplette Inhalt entschlüsselt wurde
- Zwischen diesen beiden Stellen an interessant aussehenden Stellen Breakpoints setzen
- Etwas im Code tracen (während der Ausführung) um ein Gefühl dafür zu bekommen, was (ungefähr) geschieht
- Nach Mustern im Code suchen, die mir Aufschluss darüber geben, WIE entschlüsselt wird (Algorithmus, Schlüssel, etc.)
- Wichtige CALLs dokumentieren und benennen um ein besseres Verständnis für den Codeablauf zu haben. Alles was nach einem Schlüssel aussieht, in einer Text-Datei vormerken.
- Vermutung aufstellen, und bestätigen durch eine Scriptsprache freier Wahl. Beispielsweise Rijndael im ECB Modus auf die Datei anwenden, und schauen ob das Resultat gut aussieht.
- Wenn das allgemeine Verständnis für die Verschlüsslung da ist, einen Decrypter schreiben.
Der erste Schritt ist sehr einfach und ziemlich interessant! In einem Fall war es mir sogar mal möglich, allein durch das Ansehen des Dateiformates im Hexeditor herauszufinden wie es verschlüsselt wurde (ein einfacher XOR mit dem ersten Byte der Datei). Aber hier siehts nicht so aus:
Fast die vollständige Datei sieht verkrüppelt aus. Sieht nach Verschlüsselung aus (wer hätte das gedacht?). Allerdings befindet sich am Ende eine Webadresse und eine lange Zahl. Die sehen ziemlich wichtig aus! Eventuell ist es der Schlüssel (oder der Schlüssel wird damit generiert, oder es wird an die Seite versendet und dieser gibt uns den Key, oder es ist ein IV, oder oder oder ….). Wir müssen unbedingt solche Vermutungen aufstellen, damit uns später in dem Flut von Assemblercode Muster auffallen. Wenn wir die Webadresse aufrufen, wird uns eingeredet, es wäre ein 404. Schade, vermutlich wird diese Zahl per POST gesendet, oder so ähnlich.
Mehr ist aus dem alleinigen Ansehen des Dateiinhalt nicht zu entnehmen. Also gehen wir zu Schritt 2 über. Wir müssen herausfinden, an welcher Codestelle die Datei geöffnet wird. So wissen wir die ungefähre Stelle von der Entschlüsselung. Nun, betrachten wir noch einmal, was passiert wenn wir auf “Open” drücken. Es erscheint ein ein Öffnen-Dialog. Wieso versuchen wir nicht genau an dieser Stelle das Programm zu stoppen? Dieser Öffnen-Dialog scheint so ziemlich einzigartig zu sein.
Viele Windowsprogrammierer kennen bereits die API GetOpenFileName. Damit erstellt man dieses schöne Öffnendialog-Fenster das vielen Windows-Usern bekannt ist. Genau dort will ich ansetzen. Also tippe ich unten in die Commandbar von OllyDbg “bp GetOpenFileNameA”. Jetzt kann ich mir sicher sein, dass ich genau dann breake, wenn das Programm die Datei auswählt. Ich lass das Programm laufen, und genau so kommt es!
Schritt 3 ist nicht unbedingt Notwendig, aber dennoch hilfreich. Nach dem Öffnen der Datei zeigt das Programm eine MessageBox. Aha! Dort können wir auch breaken. “bp MessageBoxA”. Halleluja!
In Schritt 4 sollen wir nun interessante Stellen suchen. Dafür bediene ich mich der String-Suchfunktion von Ollydbg. Ich scrolle etwas rum, und finde süße Dinge wie “TDCP_twofish”. Das sieht nach der DCPCrypt Bibliothek für Delphi aus. Und “twofish” ist der Name des Algorithmus! Und von “SHA1″ ist auch die Rede. Eine Hashfunktion, auch schön! Also breake ich an den Stellen, wo diese Strings referenziert werden.
In Schritt 5 und Schritt 6 kann man Stundenlang verweilen. Es macht Spaß zu sehen, wie der Entwickler das Programm entworfen und programmiert hat. Man versteht langsam, wieso er jenes und anderes getan hat. Wenn man verfolgt, was mit den Strings passiert die eingelesen werden, dann erlangt man ziemlich schnell Erfolge. Einer meiner Tricks, um zu verfolgen was mit dem Dateiinhalt geschieht, ist es den Anfang der Datei so zu ändern, dass daraus ein String entsteht (ansonsten wäre es ein binärer Inhalt). Beispielsweise ändere ich die ersten Bytes zu “INHALT” und füge ein 00-Byte hinzu. Nun wird mir Ollydbg immer diesen String anzeigen, wenn irgendwo der Dateiinhalt referenziert wird. Ich trace also gemütlich durch den Code und knabbere ein paar Snacks.
Nach einiger Zeit bringe ich in Erfahrung, dass anscheinend ein Hash von etwas gebildet wird. Der Hash ist 20 Bytes lang. MD5 kann es nicht sein, denn dieses hätte eine Länge von 16 Bytes. Aus Erfahrung weiß ich, dass es sich bei 20 Bytes eigentlich immer um SHA handelt. Aus den Strings entnehme ich folgende (für viele merkwürdig erscheinende) Zeile:
ASCII “abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq”
Wenn man nach dem String googlet, wird man zahlreiche Indizien dafür finden, dass diese merkwürdige Anreihung von Buchstaben etwas mit SHA zu tun hat. Da kann ich euch aufklären: Viele der kryptografischen Bibliotheken verwenden einen sogenannten “SelfTest” um sich selbst auf Funktionalität zu testen. Dabei wird der Hash von einem bekannten String erstellt, und mit der (vorgefertigten) richtigen Lösung verglichen. Sind beide gleich, funktioniert die Bibliothek. Und um SHA zu testen, wird (unter anderem) der oben genannte String verwendet. Ich setze also einen Breakpoint in den CALL wo dieser String gelinkt ist, in guter Hoffnung, dass die Library sich bei der initialisierung automatisch selbst testet.
Da ich weiß, dass hier DCPCrypt verwendet wird, bediene ich mich einer sehr guten Methode, um alle wichtigen CALLs zu benennen. Somit wären wir also im siebten Schritt. Ich suche nach Mustern im Code! Zuerst lade ich mir die aktuellste Version dieser Kryptobibliothek herunter. Ich sehe mir die Datei DCPsha1.pas an, um nach einem einfach aussehenden Muster zu suchen. Ich finde die folgende Codezeile:
class function TDCP_sha1.GetHashSize: integer;
begin
Result:= 160;
end;
Das sieht doch sehr schön aus! Eine kurze Funktion, die auch noch mit einer ungewöhnlichen Zahl arbeitet. Diese Funktion gibt die Hashgröße in Bits an, aber das braucht uns eigentlich nicht interessieren (160 Bits / 8 ergibt 20 Bytes, die Größe unseres Hashes!). Nun wollen wir uns überlegen, wie wohl diese obige Funktion in Assembler aussehen könnte. Wenn wir absolut keinen Plan davon hätten, könnten wir uns die Delphi IDE installieren und ein Beispielprogramm mit dieser Library kompilieren (mit zusätzlichen Debuginformationen) und uns dann im Debugger das Resultat anschauen.
Ich kann mir aber bereits denken, wie es in Assembler aussieht. Und zwar so:
mov eax, 0A0
ret
So ungefähr. Also suche ich einfach in Olly nach dieser ersten Zeile. Rechtsklick->Search for->command->”mov eax, 0A0″. Olly wird fündig!
Weiter unten sieht man noch einen Teil des SelfTest-Strings. Wir sind also tatsächlich im Code von SHA. Wir drücken nun die Doppelpunkt-Taste auf der Tastatur, und benennen diesen CALL mit “TDCP_sha1.GetHashSize”. Der ein oder andere wird sich nun fragen “Wieso wollen wir unbedingt diese Codestelle wissen?”. Der Grund ist einfach: Die restlichen Funktionen der SHA-Klasse müssen (eigentlich) in der gleichen Reihenfolge wie im Code hier zu finden sein! Im Sourcecode von DCPCrypt folgt nun “TDCP_sha1.SelfTest”. Und “oh Wunder!”, in OllyDBG sehen wir auch direkt nach der GetHashSize Funktion den SelfTest String. Es stimmt also!
Wir machen einen Rechtsklick auf GetHashSize. Find Refernces to->Selected Command. Von den Resultaten wählen wir das Unmarkierte. Wir finden uns an so einer Stelle wieder:
Das sieht leer und düster aus. Aber da wir bereits eine dieser Stellen auf unsere GetHashSize-Methode zurückführen können, haben wir eine Ahnung wie wir den Rest der Funktionen benennen können. Wir wählen den nächsten “dd dump.*****” in der Liste, klicken Enter und hüpfen zum nächsten CALL. Es ist der SelfTest. Also benennen wir diesen. Dann gehen wir zum nächsten dd-Eintrag und bennen ihn mit “Init”. Denn dieser wäre die nächste Methode im Source-Code gewesen. Am Ende erhalten wir eine wunderbar dokumentierte Liste:
An wichtigen Stellen setze ich hier ein Breakpoint. “Init”, “Update” und “Final”. So kann ich verfolgen, aus welchem String ein Hash erzeugt wird.
Ich lasse das Programm nun laufen, wähle meine verschlüsselte SWL-Datei und breake bei einem der Methoden. Ich kann den Registern entnehmen, welche Daten/Parameter/Argumente der Methode mitgegeben wurden. So entnehme ich ihm die Information, dass aus dem folgenden String ein SHA1-Hash gebildet wird:
0×010203 + “PWsaltwaterPW” + 0×030201
Es scheint ein konstanter Wert zu sein. Ein Passwort, dass in die EXE eingebrannt wurde. Vermutlich wird der Hash als Key für die Verschlüsselung verwendet. Der Hash der sich ergibt, ist also immer konstant folgender Wert: EB EA FB E3 B6 7F 8E 98 19 EE C8 AC 7C 7A 1C CF 3A FB 4D BA
Das ist cool! Ich muss den Schlüssel also nicht selbst berechnen! (Trotzdem irgendwie langweilig und monoton ….). Ich schreibe mir diesen Key also auf, damit es mir nicht verloren geht, und ich die ganze Suche von vorne starten muss.
Plötzlich fällt mir nach einigen Minute auf, dass ich die SWL-Datei nicht mehr öffnen kann. Das Programm teilt mir mit, dass die Zeit abgelaufen sei! Wie bitte? Die Webseite des Leechers sagt mir folgendes:
Achtung:
SWL-Dateien können nur innerhalb von 60 Minuten nach Empfang geöffnet werden. Es spielt aber keine Rolle, wie lange sie dann geöffnet bleiben.
Aha! Da wir gerade eben herausgefunden haben, dass das Programm einen konstanten Key verwendet, kann ich mir sicher sein, dass nicht der Server uns einen temporären Key liefert, zum entschlüsseln dieser Datei. Es ist also der Leecher selbst, der Clientseitig entscheidet, dass wir die Datei nicht mehr verwenden dürfen. Und genau dafür war wohl die URL und die Nummer am Ende der SWL-Datei. Ich patche also kurz die Codestelle, sodass ich alle SWL-Dateien unendlich lange verwenden kann. Das wäre schonmal aus der Welt!
Wenn wir uns an die String-Funde von gerade erinnern: Es war die Rede von Twofish! Also lassen wir unsere Vermutung von dem Krypto-ANALyzer in PEiD bestätigen. Und dieser ist genau unserer Meinung: Es wird der Twofish-Algorithmus verwendet. Wir gehen genauso vor, wie gerade. Wir suchen nach Mustern. Ich öffne ein paar SourceCodes von DCPCrypt, und suche nach schönen Zeilen, die einzigartig sind.
class function TDCP_blockcipher64.GetBlockSize: integer;
begin
Result:= 64;
end;
Also suche ich nach:
mov eax, 080
retn
und ich lande genau an der richtigen Codestelle. Nun gehe ich genauso vor, wie bei SHA1. Und am Ende habe ich so einiges dokumentiert:
Ich breake natürlich an allen interessanten Stellen (so gut wie allen oben genannten). Und ich finde heraus, dass DecryptCBC aufgerufen wird. Somit weiß ich mit sehr hoher Wahrscheinlichkeit dass der CBC-Modus benutzt wird. Nachdem ich bei “Init” und “InitStr” breake (leider auf dem Bild nicht zu sehen), sehe ich im EDX Register den Schlüssel. Und, wie hätte man es sonst erwartet, ist es der Hash den wir oben berechnet hatten!
Schritt 8 => Unsere Vermutung ist also, dass der Dateiinhalt per Twofish entschlüsselt wird. Und der Key ist der konstante Hash, den wir oben herausgefunden hatten. Nun holen wir uns irgendeine Scriptsprache, für die es eine fertige Twofish-Bibliothek gibt. Leider hat es das weder Python (jedenfalls keine funktionierende) noch Ruby. Aber PHP hat mcrypt. Also greiffe ich auf PHP! Ich hatte keine Lust auf PHP, und die Einarbeitung in MCrypt, also habe ich mir schnell von den Beispielcodes etwas zusammenkopiert. Den Decrypter braucht ja sowieso niemand.
Ich finde nur noch kurz heraus, wie die Daten im Plaintext strukturiert sind, damit man sie auslesen kann (alle Daten sind per 0×01 voneinander getrennt. Ganz easy!) und es entsteht (Schritt 9) ein Decrypter:
Schachmatt! SWL wurde geknackt!
Ein Teil dieses Blogeintrages wurde auf der Toilette verfasst. Normale Menschen lesen Zeitung auf dem Klo. Geeks bloggen. Vermutlich einer der Gründe wieso ich so viel Scheisse auf dem Blog produziere (Ah, ich liebe Wortspiele!)
If you enjoyed this article please consider staying updated via RSS. Links to your own social media pages could be added here.
- Posted in IT Security, Reverse Engineering
- 9 Comments
Tanz der Algorithmen
Ich fange mit meinen berühmt berüchtigten Worten an: Mir war mal wieder langweilig.
Um genau zu sein, hatte ich wieder Lust, geheime Systeme zu erforschen. Systeme, die ich nicht erforschen darf, und nicht soll. Wie mir mal ein weiser Türke anvertraute: Wir Türken haben einen großen Drang, genau das zu tun, was Verboten ist. Es liegt uns allen im Blut, um es mal mit den Worten des dritten Reiches zu sagen.
Ich blogge heute mal wieder etwas in Richtung Reverse Engineering von proprietären Systemen. Ich werde versuchen, etwas mehr Lehrreiches in mein Posting einzubringen. Also: Aufpassen!
Wie in meinem letzten Posting bereits angedeutet, geht es diesmal um Anti-Leech. Ich zitiere mal eine einzige Zeile, die ausreicht, um meine dunklen Augen zum Leuchten zu bringen:
With help of Anti-Leech you can protect your file links using an encrypted communication which will make it impossible for people to see where they actually download from and leave you in total control!
Ein müdes lächeln beschmückt mein Gesicht. Nicht, weil ich meinen Gegner unterschätze, sondern weil ich wirklich müde bin! Ein bisschen Recherche zeigt mir, dass bereits im Jahre 2005 ein Decrypter existierte. Der Programmierer hat anscheinend das Java Plugin von Anti-Leech decompiled, und nachgebaut. Aber ich möchte nocheinmal verlauten lassen, dass ich das alles nur just4fun mache (wen erinnern diese Worte auch, an das hier?). Und nicht, weil meine Arbeit für irgendjemanden wichtig ist.
Ich habe mir also erst einmal angeschaut, was dieses Anti-Leech denn genau ist: Es ist ein Browser-Plugin. Installiert man es, kann man spezielle Downloads, die per Anti-Leech geschützt sind, herunterladen. Der Sinn und Zweck ist, den Ort der Datei geheimzuhalten. Vermutlich ist der Grund, sich vor Abuse zu schützen. Die Dateien sind wohl illegal, und liegen auf Freehostern, die nichts davon wissen. Aber Anti-Leech kann noch mehr: detailierte Statistiken über Downloads, Passwortschutz und Traffickontrolle. Wer macht das ganze Zeug denn total irrsinnigerweise Clientseitig? Ein Server kann das alles, ohne dass der Besucher ein Plugin installieren muss, der auch noch einzig und allein auf Windows Betriebssystemen läuft. Kerckhoff würde lachen. Um mehr über Security by Obscurity zu erfahren, lese meinen alten Post über SFT.
Also habe ich mir das Plugin runtergeladen, installiert und erstmal probiert. Ich kenne nur eine Seite, die Anti-Leech noch benutzt. Mal schnell die Seite aufgerufen, einen Download gestartet, und gestaunt was passiert. Das Plugin erzeugt in meinem Firefox einen neuen Content, der mich den Downloadordner der Datei bestimmen lässt. Ein Button betätigen, und schon wird die Datei heruntergeladen. Die Datei selbst ist auch verschlüsselt, aber mit einem ganz anderen Programm. Dem FLP Loader. Laut meiner damaligen Twitter Nachricht, hatte ich das FLP Format bereits am 12ten Juli diesen Jahres dokumentiert. Die halbe Arbeit war also schon erledigt.
Der nächste Schritt wäre nun, zu prüfen ob das Plugin die einfachste aller Möglichkeiten verhindert: Mit einem Sniffer nachschauen, woher die Datei runtergeladen wird. Es kommt unerwartet: der Sniffer wird nicht erkannt. So einfach wäre die Sicherheit bereits gebrochen. Oder einfach, indem ich dem System ein Proxy schalte, oder einen Sniffer auf einem anderen Rechner im LAN (eventuell sogar auf dem Router?) installiere. Vermutlich auch, wenn ich die HTTP Aufrufe des Programmes einfach redirecte.
Wie auch immer, ich wollte was ganz anderes: Assembler! Eine Tatsache bestätigt meinen Ruf als Freak: Wenn ich Hunger bekomme, dann steigt meine Lust auf das Programmieren sowie das Hacken immens. Ich werde Hungrig nach beidem.
Und ich war hungrig. Man, war ich hungrig, ich hätte ein ganzes Sojapferd verdrücken können. Ich war ein Drogensüchtiger, der die Volumenregelung seines Musikplayers genauso dosiert wie das Volumen seiner Heroinspritze. Gangstas Paradise verführt mich in eine phantastische Welt voller sprechender Schlangen, wovon eines, eine Frau zu dem Genuss einer Frucht verleitet, woraufhin ein bärtiger Magier mich zum Leben auf der Erde verdammt, auf das meine ganze Rasse leide.
Phantasie hilft Zusammenhänge zu verstehen, in einer Welt voller Befehle und Zahlen. Also starte ich den Mainstreamdebugger schlechthin: Ollydbg. Wie Einstein schon einst feststellte, braucht man nur Stift, Papier und seinen Verstand um die Welt zu erforschen. Deswegen stelle ich mir eine schöne Welt vor, in der ich genau das tun kann:
Also fange ich an zu debuggen. Das blöde an diesem Programm ist: es ist ein Plugin. Eine DLL. Ich kann sie zwar in meinen Olly laden, aber ausführen kann ich sie nicht. Also debugge ich meinen Firefox Browser, switche per Kontextmenü zu der DLL und schaue mir vorerst ein paar Strings an.
RSA_private_decrypt returned error
Aha. Sieht ja sehr interessant aus. Vielleicht ein Asymmetrisches Verschlüsselungsverfahren? Das wäre nice, bisher hatte ich damit nichts zu tun! Um einen Blick für RSA Code zu bekommen, habe ich mich in diverse Spezifikationen eingelesen, und mir C Code dazu angeschaut. Mit dem Gedanken, dass ich Codeteile eventuell später beim Debuggen entdecke, und somit meine Vermutung bestätigen kann, dass es sich hier um RSA handelt.
Leider kam heraus, dass dies nicht der Fall ist. Ein paar Breakpoints, und einigen Analysen später, fand ich folgendes heraus: Der Client sendet eine ganz normale GET Anfrage an den Anti-Leech Server (der “normale” Link zur Download Datei, den jeder zu Gesicht bekommt). Allerdings mit einer speziellen Regelung. Es wird ein neuer Eintrag in den Header der HTTP Abfrage eingefügt:
X-AL-User-Agent: ALNN/1.0
AL steht sehr wahrscheinlich für “Anti-Leech”. Erst dann reagiert der Server mit der entsprechenden Antwort, die folgende Zeile im Header enthält:
X-AL-Location: scramble:[Verschlüsselter Inhalt]
Der Inhalt ist nur eine Zeile lang. meistens genau 60 Zeichen lang. Ich habe also als nächstes in den Strings nach dem besagten “scramble”, sowie “X-AL-Location” gesucht, und überall einen Breakpoint gesetzt, wo es nett aussieht. Um noch die Bereiche davor zu analysieren, habe ich einen Breakpoint auf CreateFile erstellt. So sollte es mir möglich sein, genau dann zu breaken, wenn die Datei fertig runtergeladen wurde.
Nun hatte ich eine ungefähre Vorstellung davon, wo genau sich die “geheime” Stelle im Code befindet.
Die Untersuchung der Descramble Funktion führte auf das folgende Ergebnis: Im verschlüsselten String befinden sich einige Stellen, die so aussehen wie: “%35″. Jeder Bereich, der mit einem Prozentzeichen begann, und zwei darauffolgende Zahlen beinhaltete, wurde von der Descramble Funktion seziert. Es ist eigentlich ganz simple. Solche Werte werden einfach (in diesem Fall) durch den ASCII Wert von “35″ ersetzt. So ergibt sich am Ende der normale Ciphertext. Nun gilt es herauszufinden, welcher Verschlüsselungsalgorithmus verwendet wurde, und welcher Schlüssel.
Und genau das ist es, was mir so viele Schmerzen im Arsch bereitet hat (um es mal schlecht übersetzt zu sagen). Die Verzweiflung bringt einen dazu, verrückte Sachen zu tun. Neben mir lag ein Stift, dessen Abdruck man einfach Wegwischen kann. Und vor mir war mein Kleiderschrank. Es kam wie es kommen musste:
Die Werbung für die Piratenpartei ist unbeabsichtigt!
Nun sah ich nur flüchtig über die Verschlüsselungsmethoden hinüber, und hatte ein paar Vermutungen:
Es ist:
-DES
-RSA
Da es niemals Lupus ist, konnte ich das schon rausstreichen.
Nachdem ich das Verschlüsselungsverfahren genauestens erforscht und dokumentiert hatte, war ich mir über eines sicher: Es konnte nicht RSA sein. Denn der Schlüssel berechnet sich auf eine Weise, die sehr untypisch (wenn nicht sogar unmöglich) für RSA ist. Mit MD5 aus einem konstanten Wert, dem IV sowie dem Datum, den wir per HTTP selbst mitsenden. Letzteres vermutlich auf Grund der Obfuscation. In Python könnte man es so beschreiben:
- const_iv = “\x14\x3f\x71\xfb”
- m = hashlib.md5()
- m.update(“/dlm_download.php/[FILENAME]&id=[ID]&dyn=[NUMBER]&changename=&netpumperquery=1&mirror=0″)
- m.update(“Sat, 31 Oct 2009 22:43:28 GMT”)
- a = hashlib.md5()
- a.update(m.digest())
- a.update(“\x4A\x29\xD1\x8B\xAD\x5B\x58\x79\x35\x8E\x21\x68\x84\xA6\x7C\xB4\x38\xDE\x5B\xF0\x96\x53\x98\xBF\xA3\x07\x91\xF6\x76\x59\x9F\x6D”)
- a.update(const_iv)
Wie man im Code sieht, existiert ein IV. Das heißt also, es ist kein ECB Modus.
So blieb nur noch DES, Triple-DES und Blowfish übrig. Der Grund für diese starke Eingrenzung liegt daran, dass ich bemerkt habe, dass es ein block cipher ist. Und zwar einer, mit der Blocklänge von 64 Bit. Eigentlich war ich mir bereits sicher, dass es kein Blowfish ist. Der Krypto ANALyzer von PEiD zeigte mir, dass in der Datei irgendwo die S-Box von DES existiert. Und genau diese wurde von dem Verschlüsselungsalgorithmus referenziert. Vermutung also: Es ist DES, oder Triple-DES. Ich kam mir mittlerweile wie Dr. House vor, der versucht, eine Krankheit zu identifizieren. Ironischerweise verspürte ich Schmerzen an meinem Bein. Das war ein Zeichen Gottes! (Oder es lag daran, dass mein Fahrrad kaputt war, und ich deswegen 3 Stunden zu Fuß laufen musste … Hm, nein sicher nicht, es war garantiert ein Zeichen!)
Um nun den Rest herauszufinden musste ich nur schauen, wie lang der Key ist. Wenn es nur 8 Bytes sind, dann ist es DES (sehr wahrscheinlich). Ansonsten (falls 16 oder 24 Bytes) ist es wohl Triple-DES. Nun, der Key ist aber 32 Bytes lang. Das passt weder zu DES, noch zu Triple-DES. Einige Strings gaben mir aber Hoffnung: Es wurde wohl die Crypto API von OpenSSL verwendet. Nun konnte ich dort nachschauen, ob eine nicht-standartisierte Funktion programmiert wurde, um längere Keys zu verwenden.
Die einzige Möglichkeit die sich erübrigt ist: DES_xcbc_decrypt. Dieser verwendet wohl einen Key, variabler Länge. Da aber dieser Modus von keiner Python Library implementiert wurde, sank meine Motivation auf 0, um einen Decrypter zu schreiben. Nach so vielen Wochen der Arbeit, sollte igendwann Schluss sein. Ich kann also nicht verifizieren, ob meine Vermutung stimmt. Das wäre der letzte Punkt gewesen, um die Doku von Anti-Leech komplett zu machen.
Somit beende ich meine Arbeit an diesem Verschlüsselungssystem, mit dem Gewissen, dieses Target (wenigstens größtenteils) auch besiegt zu haben Falls ich den Decrypter irgendwann fertigschreibe, nenne ich es “Leech-Toaster” (der obligatorische Dank an dieser Stelle an n4pster-3D*).
Grüße gehen natürlich auch an kugelfisch (wann kommen mal wieder neue Posts von dir?) dem ich unter anderem verdanke, dass ich mich überhaupt für proprietäre Formate und Protokolle interessiere
If you enjoyed this article please consider staying updated via RSS. Links to your own social media pages could be added here.
- Posted in IT Security, Reverse Engineering
- 6 Comments
Code makers and breakers (SFT geknackt)
Nun, wie soll ich anfangen? Soll ich wieder berichten, dass mir langweilig war? Nee, das kommt in jedem Blogpost vor (verdammt, jetzt habe ich es doch getan!).
Als ich gerade damit beschäftigt war die Software von der Firma, bei der ich zurzeit Praktikum mache, etwas sicherer vor Crackern zu machen, fiel mir auf, dass ich nicht so viel Ahnung davon habe. Hm, Software sicherer machen … hm das kann ich nicht so gut … aber die Sicherheit zu brechen, das macht Spaß!
Software sichern … hm … Ich mein, “sichern” im typischen Sinne kann man es ja nicht einmal. Es liegt in der Natur der Sache, dass ein ausführbares Programm analysierbar bleibt. Nur wie kann man es so erschweren, dass jeder Reverser die Lust verliert?
Auf der Suche nach der Antwort lud ich mir ein paar CrackMe’s runter, um unter dem Vorwand von “Anti Debugging Technik erlernen” etwas bei der Arbeit cracken zu können
Acht Stunden und unzählige fertige CrackMe’s später fuhr ich nach Hause … ich war immernoch hungrig nach mehr … mehr hardcore Assembler … mehr Geheimnisse entlüften … mehr Glückgsgefühle … mehr davon. Ich kramte auf meinem USB-Stick rum, und fand eine alte version des SFT-Loaders (“SFT Loader 2006″). Nach meinem letzten Beitrag über DLC, und über RSDF, dachte ich mir, es wäre doch praktisch meine Kenntnisse im Gebiet der Analyse von unbekannten Formaten auszuweiten. Diese SFT Dateien bieten einige Warez-Seiten an. Kennt das überhaupt noch jemand? Einige wenige Seiten scheinen das noch anzubieten. Wie auch immer, meinen Spaß hatte ich jedenfalls damit
In der SFT Datei sind (verschlüsselt) Host, Username, Passwort, Dateinamen und einige Optionen hinterlegt. Sodass dieses Programm es entschlüsseln, und dann von den FTP-Servern die Dateien herunterladen kann. Das wollte ich unbedingt mal analysieren, sollte doch sicher spaßig werden?
Gesagt getan. In einer Woche (á 8 Stunden) und noch etwas mehr, war ich fertig. Man, hat das lange gedauert. Ich habe mit einem Aufwand von 1-2 Tagen gerechnet, aber eine Codestelle im Programm hat meinen Kopf gefickt (ja, ich benutze sonst nie diesen Ausdruck, aber dieses Dateiformat hats echt verdient!). Beim reversen wurde mir immer wieder mal schwindelig und ich hielt meinen Kopf fest, damit sich meine Umgebung nicht mehr so merkwürdig bewegt! (und das ist kein Witz!)
Nun, das SFT Format ist viel cooler als DLC … nein, nicht sicherer. Sondern etwas komplexer … also spaßiger zu reversen
Wer nichts über die Struktur des Formats lernen möchte, der möge das hier überspringen und an das Ende des Artikels springen … dort findet ihr einen SFT Decrypter (Ja, ihr könnt mich hassen, dass ich das tue …)
Als aller erstes sollte klar werden, es ist wieder Security-by-Obscurity. Es gibt keinen Weg daran vorbei, wenn man versucht, auf dem Rechner des Users Daten zu verarbeiten, von dem der Nutzer aber nichts wissen soll. Der SFT-Loader MUSS zwangsweise irgendwann die Daten entschlüsseln. Was ich nun mache ist es, zu analysieren wie dieses Programm es genau macht. Wie generiert es sich seinen Schlüssel? Welche Algorithmen werden verwendet? In welcher Stelle der Datei befinden sich die Daten? Dazu bedient man sich des Reverse Engineering.
Kerckhoffs Prinzip besagt, dass die Sicherheit eines Verschlüsselungsverfahrens auf die Geheimhaltung des Schlüssels beruhen muss, nicht auf die des Algorithmus. In unserem Fall muss jedoch das Programm das Passwort ja wissen, um den Inhalt zu entschlüsseln. Irgendwoher muss es das Passwort ja kriegen. Sei es, indem es sich das selbst generiert (siehe weiter unten) oder ob es einen hardcoded key verwendet. Die Sicherheit ist die selbe, solange ich alles rekonstruieren kann.
Nun, zurück zum Dateiformat: jede SFT Datei hat einen Header. Die ist immer 0×40 (=> 64) Bytes lang. Sie fängt (immer?) mit “A” an, gefolgt von einem 0xFF Byte, und dann “2SFT04″. Es sollte klar sein, wofür “SFT” steht. Die “2″ ist mir noch nicht ganz klar. Die “04″ allerdings steht für die Dateiversion. Soweit ich weiß, ist dies die aktuellste Version des Formats. (Jedenfalls war es das 2006)
Danach folgen weitere 0xFFs bis die 0×40 Bytes voll sind. Nun ist der Header fertig, und der eigentliche Content folgt. Dieser ist mit zlib komprimiert. Einfach dekomprimieren (am einfachsten mit einem Python script) und schon hat man den dekomprimierten Inhalt. Dieser ist allerdings noch verschlüsselt. Der Algorithmus für die Verschlüsselung ist RC4. Wobei wie immer die Sicherheit des Algorithmus ziemlich egal ist, solange der Schlüssel irgendwo abgespeichert ist.
Der Schlüssel für RC4 ergibt sich aus dem SHA1 Wert des Headers. Dafür schneidet man den ersten Byte (also das “A”) des Headers heraus, fügt ans Ende zwei 0xFF hinzu und hasht es dann mit SHA1. Das Resultat ist unser Key. Gewöhnlicher Weise ist es immer die selbe:
7CBEB0CF896EC8DE4F54A2850E6C73B38E95EA06
Mit diesem Key entschlüsseln wir den Dateiinhalt. Und es erscheint uns der serialisierte (aber entschlüsselte) Inhalt der Datei.
Von hier an ist es nicht mehr viel. Man kann einfach den Inhalt splitten, und die einzelnen Werte auslesen. Die einzelnen Base64-Strings die dort zu finden sind, sind entweder mit dem SHA512 Hash von “SFT Loader Reloaded” oder “callstackapi”, (mit dem RC4 Algorithmus) zu entschlüsseln. Hierbei hatte ich ein paar Probleme, da meine python library einen Fehler drin hatte (man, ich musste den verdammten RC4 Algorithmus fast nachbauen um den Fehler zu finden … der Programmierer hat vergessen beim crypten i und j wieder auf 0 zu setzen, siehe The Pseudo-Random Generation Algorithm)
Nach einigem rumprobieren und surfen fand ich heraus, dass der Programmierer eine nicht-standardisierte Verschlüsselung verwendet, die nirgendwo dokumentiert ist. Das wäre natürlich der total Krampf im Arsch (ja, ich weiß dass es falsch übersetzt ist) den ganzen Algorithmus auch noch zu reversen. Aber glücklicherweise fand ich diese Komponente, welches wohl dieses Verfahren überhaupt erfunden hat. Sie nennt sich RCx und ist ein selbstprogrammierter Algorithmus, angelehnt an RC5. Also entweder wollte ich ein Delphi Programm schreiben (und diese Komponente verwenden), Strings entschlüsseln und an mein Programm pipen lassen, oder den ganzen Algorithmus selbst implementieren. Ersteres fiel weg, da ich keinem User aufzwingen möchte, Wine zu installieren. Also baute ich den Algorithmus nach. Nach rund 92 Zeilen Code, und 2 Tage debugging (Python hat wohl kein “Byte” als Dateityp, das war wie ein Tritt in die Weichteile) war meine kleine RCx Klasse fertig. Damit kann man wahrlich die einzelnen Werte endgültig entschlüsseln.
Vorerst knöpft man sich das “Header” Element vor (siehe Bild oben). Aus diesem ergibt sich ein String wie folgt:
SFT0#2#D7D05C8DEED489B6C6981D9A6E8D79315C8F2D41A7AC229B385C2A2B73A7959C65F07C7D7CE4F1D6CA7A79E0C2A4847E5587079ACF
SFT am Anfang zeigt uns wieder, dass es korrekt entschlüsselt wurde (mit dem erwähnten RCx Algorithmus). Die “0″ direkt danach gibt an, ob ein Passwort notwendig ist (in diesem Fall also nicht). Ich weiß nicht genau wofür die nachfolgende “2″ ist (Maximale Threads oder so ?) aber alles nach dem letzten “#” ist der Wert, den es zu entschlüsseln gilt. Dafür wurde ein (selbstentwickeltes?) XOR und Salt-System genutzt. Der Salt-Wert ist “callstackapi”. Hierdran wird einfach das eingegebene Passwort angehangen, oder ggf. nichts angehangen. Den XOR-Algorithmus kann man wie folgt beschreiben:
def YurryXOR(key):
raw_key = hashlib.sha512(key).digest()
raw_key = raw_key[:(len(raw_key)/2)]
result = []
key = key*10
for i in range(0, len(raw_key)):
result.append(chr(ord(raw_key[i]) ^ ord(key[i])))
return ”.join(result)
Kleine Erklärung: Der key ist das erwähnte callstackapi+password. Daraus wird ein SHA512 Wert generiert. Die letzte Hälfte wird rausgelöscht. Nun wird der nicht-gehashte Key mit dem gehashten geXORed. Und das Ergebnis ist unser Key.
de5a015215664d925bf3e9f97477caee4ef7a44f6a3d0ee08bf70f1f326e41c7
Sowas in der Art (btw, ich benutze für diese Demonstration diese Testdatei).
Das ist unser Yurry-Key (die habe ich nach meinem Schatz benannt. Haiiii schatziii <3 ). Mit dieser kann man ganz schmutzige Sachen machen (nein, nicht mit meinem Schatz du Perverser! Ich meine den Key!). Haben wir diesen erstmal, stehen uns alle Wege offen. Diesen Key können wir an unser Header-Element anwenden, und somit erhalten wir einen Wert, der exakt so aussieht wie das hier:
{1F945Z9B-3ZA9-4Q13-A5DB-KDKDKFLDSHGVFBV}
(Anfangs sind noch 20 zufällige Bytes, die angehanden wurden. Das ist wohl so eine Eigenschaft vom Algorithmus. Die kann man gefahrlos rauslöschen).
Das sieht aus wie eine Seriennummer, ist es aber nicht. Dieser Wert wird nur verwendet, um zu schauen ob der User das richtige Passwort eingegeben hat.
Mit dem gleichen Algorithmus und dem gleichen Key, ist es nun möglich alle anderen Elemente zu entschlüsseln (Host, Username, Passwort etc.)
Das wars auch schon. Man kann noch durch alle Dateinamen gehen, wenn man möchte. Ich denke, das werde ich bei Gelegenheit mal machen, und dem PyLoad Projekt ein SFT-Plugin schenken (auch wenn dies kein Dateiformat für One-Click-Hoster ist).
Nachdem letztens schon wieder ein Hacker Selbstmord begangen hat, ist mir der Fall Tron (ein Hacker der Verschlüsselungen geknackt hatte) wieder eingefallen. Um exakter zu sein, dass was er den Polizisten bei einer Hausdurchsuchung mal sagte: “Man kann das Anwenden
von mathematischen Formeln doch nicht unter Strafe stellen?!” (aus dem Buch “Tron – Tod eines Hackers”).
Ich schreibe später eventuell ein Reverse Engineering Paper hierdrüber, da dieses Target ziemlich lehrreich war!
Ein letztes noch: Es ging hier natürlich wiedermal nicht um das Endresultat, sondern um den Weg. Denn an Username&Passwort der SFT Datei, käme man auch durch Sniffer, Proxies oder ein paar Spielereien mit der Hosts-Datei. Wie J. J. Abrams bereits einmal sagte, es geht nicht um das Ende (die Auflösung des Ganzen). Sondern die Zeit, die man damit verbringt (Gemeint war die Serie Lost, aber passt auch hierzu!).
Verschließt eure Augen nicht vor der Wahrheit! Speichert eure sensiblen Daten nicht in einem undurchsichtigen proprietären Dateiformat. Das ist wie mit WEP. Indem nun jeder Witzbold in ein WEP-Netzwerk einbrechen kann, hat man den Leuten die Augen geöffnet: Verwendet nicht WEP! Und viele (wenn auch bei weitem nicht jeder) haben die Gefahr erkannt. Indem man aber nun einfach sturr und blind bleibt, und meint, weil WEP gebrochen wurde, wäre die ganze Sicherheit um WEP kaputt, irrt sich. Es war schon immer unsicher, nur wurde diesmal einfach nur bewiesen, dass es so ist. Und wer meint ich hätte mit diesen frei zugänglichen Informationen irgendetwas kaputt gemacht, ist naiv. Ich habe nur Informationen veröffentlicht, die jeder SFT User auf dem Rechner hat. Nur hat es wohl keiner vorher einer Analyse unterzogen. Wie dem auch sei:
oder: SFT-DECRYPTER + GUI (benötigt Java) von Seji
//edit 17.07.09 >>> kleines Update. Bugfixxes und ein paar Feature-Requests (Ordner und Dateiname anzeigen) wurden realisiert. Es werden nicht alle Dateinamen und Ordner angezeigt, sondern nur die ersten, habe gerade keine Lust das noch einzubauen. Dennoch viel Spaß
If you enjoyed this article please consider staying updated via RSS. Links to your own social media pages could be added here.
- Posted in IT Security, Reverse Engineering
- 62 Comments