Reverse Engineering des WPA-default Algorithmus des Alice (O2) Wlan Modem 1121
Dieser Text is eine Weiterführung meines Reverse Engineering des WPA-default Algorithmus von Alice (O2) Boxen posts.
Hier möchte ich nun schrittweise erklären wie ich an den Algorithmus zur Generierung des default WPA-Passworts des Alicebox 1121 gekommen bin.
Nachdem ich die 1121er Box - welche ich auf Ebay ersteigert hab - bekommen hatte, machte ich mich ans Werk zunächst so viele Informationen wie möglich über die Hardware zu erhalten.
Ich notierte mir zunächste alle Informationen die ich auf der Unterseite des Routers finden konnte. Insbesondere die Siemens Modell Kennung war interessant. Ich begann weitere Informationen im Internet zu suchen und wurde schnell im Alice-Wiki fündig. Interessant ist vor allem des letzte Link der über einen Telnet Zugang spricht. Auch habe ich auf der Seite erfahren, dass es sich bei dem SOC um ein Broadcom handelt. Dieser besitzt einen Mips32 kompatiblen Kern. Mit dieser Information kann ich den passenden Dissassembler suchen. Eine weitere Suche führt mich auf interessante Daten zur Hardware im OpenWRT Forum.
Somit habe ich zunächst diesen Zugang testen wollen. Alicebox per Ethernet-Kabel an mein Notebook angeschlossen und mal mit Nmap nach offenen Ports gesucht. Siehe da, ein offener Telnet Port. Also verbinden wir uns doch einfach mit:
telnet 192.168.1.1
Die Zugangsdaten für Telnet ergeben sich wie hier beschrieben wie folgt.
Telnet-Zugangsdaten:
Benutzername: admin
Passwort (besteht aus 3 Teilen): AliceXXXXXX123
Der mittlere Teil des Passwortes wird aus der LAN-MAC-Adresse des Alice Modems ausgelesen und ist somit für jedes Modem anders. Und zwar nur die ersten 24 Bit (Bits 23 bis 0). Das würde bei der frei erfundenen MAC Adresse "01-02-03-AB-CD-EF" die Zeichenkette "ABCDEF" ergeben.
Für genannte MAC-Adresse des Modem ergibt sich:
Benutzername: admin
Passwort: AliceABCDEF123
Also eingeloggt und eine -abgespeckte- Shell bekommen. Mit abgespeckt meinte ich, dass Befehle wie ls fehlten.
Das ist aber leicht durch einen alten Trick leicht zu umgehen. Anstatt ls schreibt man einfach
echo *
und schon kann man die Dateien und Verzeichnisse im aktuellen Ordner sehen.
Nun muss man nach einer Möglichkeit suchen interessante Daten zu übertragen. Also schaut man sich die durch Busybox verfügbaren Befehle an. Da die Helpfunktion nicht eingebaut wurde muss man also nach den Symlinks in den Binary-Pfaden /bin, /sbin, /usr/bin oder /usr/sbin schauen. Und siehe da, ein Binary namens ftpget.
Nachdem nun ein Weg gefunden wurde Daten auf die Box zu laden braucht man nun noch einen Weg Daten von der Box zu bekommen. Ich konnte zwar in den Binaries ein ftpput finden, jedoch ließ sich diese (wegen eines Bugs?) nicht sinnvoll nutzen. Deshalb musste eine Alternative her. Diese Alternative fand ich in netcat.
Damit netcat auf der Box läuft muss man netcat für mips32 statisch compilieren. Dafür hab ich mich für die CodeSourcery Toolchain für Mips entschieden und mit folgendem Shellscript eine netcat Binary erzeugt.
#/bin/sh export CC=mips-linux-gnu-gcc export CFLAGS='-muclibc -mips32 -static' export LDFLAGS=-static cd netcat-0.7.1 ./configure --host=mips-linux make
Die erstellte Binary muss jetzt mit einem lokal installierten FTP-Server auf die Box übertragen werden. Dazu meldet man sich per Telnet auf der Box an und zieht sich mit ftpget die Datei.
ftpget <ftpuser> <ftppass> <ftp-ip> /var/netcat /local/netcatsrc/netcat Firmware
Das /var Verzeichnis wurde gewählt weil es schreibfähig ist und genügend Platz bietet. Der Befehl Firmware wird benötigt damit die Binärdaten übertragen werden. Wichtig ist noch zu wissen, dass die Binary nach einem Systemstart wieder neu übertragen werden muss.
Jetzt kann ich mit netcat die Binaries von der Box an meinen Rechner übertragen. Als nächstes sucht man nach Kandidaten die für die Untersuchung in Frage kommen. Einen guten Anhaltspunkt erhält man wenn man nach Linux/Unix untypischen Binaries sucht. Embedded Systeme haben dazu noch den großen Vorteil, dass sie wenig Speicherplatz und somit auch wenig Kandidaten bieten.
Zunächst schaut man in den Startskripten des Systems nach. Hier ist zuerst die /etc/inittab interessant.
::sysinit:/etc/init.d/rcS ::respawn:-/bin/sh tty2::askfirst:-/bin/sh ::ctrlaltdel:/bin/umount -a -r
Dort steht nichts besonderes.. nur die übliche /etc/init.d/rcS welche wir uns als nächstes anschauen werden.
#! /bin/sh PATH=/sbin:/bin export PATH mount -t proc proc /proc /bin/mount -a #/sbin/inetd
Hm. Dort wird nichts interessantes mehr ausgeführt. Somit scheint der Prozess mit /bin/sh gestartet zu werden. Bash nutzt die /etc/profile um die Profilinformationen zu laden und wird bei jedem start von sh ausgeführt. Sie sieht wie folgt aus:
# /etc/profile: system-wide .profile file for the Bourne shells PATH=/bin:/sbin:/usr/bin KERNELVER=2.6.8.1 export PATH echo firsttime=`echo /var/udhcpd/udhcpd.lease*` if [ "$firsttime" = "/var/udhcpd/udhcpd.lease*" ]; then echo "Loading drivers and kernel modules... " echo # no-op # create directory in /var mounted for TMPFS
#snip cfm fi
Zunächst werden ein paar Umgebungsvariablen gesetzt, dann wird jedoch überprüft ob die Shell bereits gestartet wurde. In diesem Block werden dann ein paar Kernelmodule geladen und ein Befehl "cfm" gestartet. An sich gehört so etwas nicht in die /etc/profile aber so haben wir dann unseren Kandidaten gefunden. Mit netcat konnte ich nun die Datei /bin/cfm auf meinen Rechner laden um sie mit IDA pro zu analysieren.
Sucht man nach WPA oder Key findet man in der Binary leider nur Funktionen welche die Wlan-Hardware mittels wlctl konfiguriert. Deshalb hab ich in der Konsolenausgabe nach Anhaltspunkten gesucht.
Um an die Konsole zu kommen benötigt man ein UART fähigen Adapter. Es eignet sich dazu z.B. ein Arduino. Ich nutze für diese Zwecke einen Buspirate V3.6 (hier eine Einführung in die Benutzung des Buspirate mit UART). Der Anschluss für die serielle Schnittstelle ist in meinem Fall freundlicherweise ab Werk schon aufgelötet gewesen und sollte somit schnell zwischen dem Ethernetchip und RAM (vier herausragende Pins) auszumachen sein.
Bild von http://wiki.openwrt.org/toh/siemens/s1621-z220-a
Dabei sollte stets nur Ground, RX und TX und mit 115200 8N1 verbunden werden. Beim Boot erscheinen dann viele nützliche Informationen doch besonders fallen folgende Einträge auf:
defaultWPAKEY2=====================177647c793aac9 mac======177647c793aac9 dest2======MTc3NjQ3Yzc5M2FhYzk= dest======MTc3NjQ3Yzc5M2Fh defaultWPAKEY1=====================MTc3NjQ3Yzc5M2Fh
Die Struktur von dest und dest2 kam mir sehr bekannt und erinnerte mich stark an Base64 also probiert und siehe da, das Ergebnis entspricht genau dem defaultWPAKEY2. Es wird also ein Base64encode auf "mac" durchgeführt. Weiterhin fällt auf, dass kein anderer Eintrag so viele "======" Symbole besitzt. Sucht man nach diesem Eintrag in IDA und nach deren Referenzen fällt eine Funktion namens "trans" auf.
Schaut man etwas weiter oben, so fällt uns auch der Funktionsaufruf von Base64encode auf. Leider konnte ich aus dem "defaultWPAKEY2" noch auf kein Muster schließen und ich suchte nach Referenzen auf die "trans" Funktion. Dabei entdeckte ich zwei Aufrufe in der Funktion WlMngr::getAllVarsDefault(void).
Interessant ist der Aufruf von MD5encode. Ich startete eine Python-Konsole und probierte die MAC-Adresse des WLAN als Eingabe für MD5. Leider schien dies nicht das gewünschte Ergebnis zu sein. Als nächstes Probierte ich die MAC-Adresse des Ethernet Device und siehe da:
import base64 import hashlib mac = '001e40da925a' hashlib.md5(mac).hexdigest() '177647c793aac9ad5ed0dc9c7e99fe8a'
Die ersten 14 Zeichen der Hex-MD5 Ausgabe sind identisch. Also einen Base64encode auf das Ergebnis ausgeführt und schon haben wir den defaultWPAKEY1 gefunden.
base64.b64encode(hashlib.md5('001e40da925a').hexdigest())
'MTc3NjQ3Yzc5M2FhYzlhZDVlZDBkYzljN2U5OWZlOGE='
Da wir nur die ersten 16 Zeichen brauchen also ein
base64.b64encode(hashlib.md5('001e40da925a').hexdigest())[:16] 'MTc3NjQ3Yzc5M2Fh'
Das wars. Durch die Konsolenausgabe konnte man jetzt noch herausfinden, wie man von der Wlan-Mac-adresse (BSSID) auf die interne Ethernet-Mac schließen kann.
wl0: MAC Address: 00:1E:40:DA:92:5B
Base MAC Address : 00:1e:40:da:92:5a
Praktisch muss man nur das letzte Hexpaar der Wlan-Mac um 1 verringern und man hat den passenden Parameter.
Somit ist der Algorithmus für die Generierung des WPA-Default-Passworts in Python:
import hashlib, base64 wlan_mac = '00:1E:40:DA:92:5B'.replace(':', '').lower() dest = hashlib.md5('%012x' %(int(wlan_mac, 16)-1)).hexdigest() base64.b64encode(dest)[:16] 'MTc3NjQ3Yzc5M2Fh'
So einfach war das. In den nächsten Posts werde ich versuchen mich kürzer zu fassen.
Weiterhin habe ich ein Android Tool entwickelt, mit dem man die Sicherheit seines Netzwerks überprüfen kann. Das gleiche in Python für Linux Systeme (mit NetworkManager) ist in arbeit.
Alle Informationen sind ausschließlich für Forschungszwecke gedacht! Ich hafte nicht für etwaige Rechtsverstöße die mit den Informationen begangen werden.













