Einführung
Kürzlich wurde bekannt, dass HP DVLabs mindestens zehn Schwachstellen im Belkin N300 Dual-Band Wi-Fi Range Extender (F9K1111) aufgedeckt hat. Als Reaktion darauf hat Belkin die Firmware-Version 1.04.10 veröffentlicht. Da dies das erste Update für den F9K1111 ist und es keine öffentlichen Auslöser für die Schwachstellen gab, hielten wir es für interessant, einen genaueren Blick darauf zu werfen.
Auspacken des Updates
Um unsere Analyse zu beginnen, haben wir das Firmware-Update vom Hersteller heruntergeladen. Zum Entpacken des Updates haben wir ein Firmware-Tool namens binwalk verwendet:
$ binwalk -Me F9K1111_WW_1.04.10_upg.bin
Das Ergebnis ist ein ziemlich normal aussehendes extrahiertes SquashFS-Dateisystem, das das Stammverzeichnis des Geräts darstellt (siehe unten).
Um nun den Bindiff durchzuführen, müssen wir ein wenig mit der Hardware interagieren, um die Dateien in den vorbereiteten Zustand zu versetzen.
Abrufen der Basis-Firmware
Um die Basis-Firmware zu analysieren, benötigen wir eine Möglichkeit, die Daten aus dem physischen Gerät auszulesen. Dazu müssen wir zunächst das Gerät aus seinem Gehäuse entfernen.
Rot und blau hervorgehoben sind mögliche Wege zum Abrufen der Firmware, der SPI-Flash-Chip bzw. die UART-Schnittstelle. Obwohl wir eine gewisse Aktivität auf dem UART gesehen haben, werden wir mit der Analyse des Basis-Images auf dem SPI-Flash-Chip fortfahren. Die Pinbelegung des Chips, mit dem wir es zu tun haben, MX25L1606e, ist von Macronix leicht erhältlich.
Nachdem wir uns dieses Blatt geschnappt und den Chip entfernt haben, können wir unseren GoodFET entsprechend der obigen generischen 8-poligen Pinbelegung verdrahten.
Nachdem wir die Pins 7 und 8 gebrückt haben, überprüfen wir, ob alles richtig angeschlossen ist mit
$ python goodfet.spiflash info
Als nächstes können wir goodfet.spiflash dump ausführen, um den Inhalt des Chips zu erhalten.
$ python goodfet.spiflash dump s
Abschließend können wir die resultierende Datei einer kurzen Prüfung unterziehen, um sicherzustellen, dass der Dump korrekt aussieht (d. h. zumindest einige lesbare Zeichenfolgen enthält).
Die resultierende Binärdatei kann wie bisher mit binwalk entpackt werden.
Diffing das Update
Wenn man die beiden entpackten Dateisysteme auf einen Windows-Rechner überträgt und in WinMerge ablegt, sieht man, dass sich nicht viel geändert hat.
Die Dateien compiler_data, version und FUNCTION_SCRIPT enthalten keine interessanten Änderungen (außer vielleicht für einige Daten, die für das Fingerprinting nützlich sein könnten). Auch die Änderung an util_system.asp ist nicht besonders interessant. Wir werden uns also im Wesentlichen die Änderungen von Belkin an webs, dem GoAhead Webserver, ansehen.
Analyse der Bahnen
Die HP-Initiative Zero Day hat die Schwachstellen mit den Namen der offenbar betroffenen Funktionen oder Eingaben benannt. Sie lauten wie folgt:
- formWpsStart pinCode Remote CodeExecution-Schwachstelle
- formWlanSetupWPS wps_enrolee_pin Sicherheitslücke bei Remotecodeausführung
- formWlanMP Sicherheitslücke bei der Remotecodeausführung
- formBSSetSitesurvey Sicherheitslücke bei der Remotecodeausführung
- formHwSet Sicherheitslücke bei der Remotecodeausführung
- formConnectionSetting Sicherheitslücke bei der Remote-Code-Ausführung
- formAccept Sicherheitslücke bei der Remotecodeausführung
- formiNICWpsStart Sicherheitslücke bei der Remote-Code-Ausführung
- formUSBStorage Sicherheitslücke bei der Remotecodeausführung
Nachdem wir also die gepatchte Version von webs in IDA geladen hatten, suchten wir in der Liste der Funktionen nach formHwSet und fanden nichts. In der Tat wurden viele dieser Funktionen nicht gefunden. Wenn wir Bindiff aufrufen, können wir sehen, dass 7 Funktionen während des Updates entfernt wurden:
Diese stimmen gut mit den Daten aus dem ZDI-Bulletin überein. Tatsächlich wurden alle in den ZDI-Hinweisen aufgeführten Funktionen mit Ausnahme von formWlanSetupWPS und formBSSetSitesurvey entfernt. Schauen wir uns die entfernten Funktionen einmal genauer an.
formUsbStorage
Die erste Funktion, die wir betrachten, ist formUsbStorage. Nachdem wir die Funktion kurz gelesen haben, ist das Problem ziemlich offensichtlich. Die POST-Variable sub_dir, auf die über die GoAhead-Webs-API-Funktion websGetVar zugegriffen wird, wird dann in einem Aufruf an system verwendet, was eine Befehlsinjektion ermöglicht.
Dieser Code könnte über ausgelöst werden:
wget --post-data="sub_dir=vectra;reboot" http://belkin.range/goform/formUSBStorage
formWlanMP
Ein ähnlicher Fehler ist im Formular actionformWlanMP zu finden. Verfolgt man die Aufrufe von websGetVar, ergeben sich einige Möglichkeiten.
Im Folgenden sehen wir, dass diese wenigen Möglichkeiten alle als Wege zur Injektion in den Systemaufruf funktionieren - wir haben uns für ateFunc entschieden.
Dieser Code könnte über ausgelöst werden:
wget --post-data="ateFunc=;reboot;" http://belkin.range/goform/formWlanMP
formHwSet
Hier gibt es eine weitere Befehlsinjektion, dieses Mal verwenden wir die Variable [sic] Anntena.
Dieser Code könnte über ausgelöst werden:
wget --post-data="Anntena=;reboot;" http://belkin.range/goform/formHwSet
formConnectionSetting
Hier haben wir eine Befehlsinjektion im Parameter timeOut in der Funktion formConnectionSetting.
Dieser Code könnte über ausgelöst werden:
wget --post-data="timeOut=1;reboot;" http://belkin.range/goform/formConnectionSetting
formBSSetSitesurvey
An diesem Punkt haben wir das Pferd der gelöschten Funktionen totgeschlagen. Werfen wir einen Blick auf die wichtigere der Funktionen, die Belkin nicht gelöscht hat - formBSSetSitesurvey. Hier ist ein Überblick:
Nachdem wir entsetzt zurückgeschreckt sind, können wir heranzoomen und sehen, dass die wichtigste Änderung darin besteht, dass Belkin eine Funktion namens strcat_escape hinzugefügt hat, die in dieser Funktion für Quellen aus websGetVar verwendet wird.
This strcat_escape function takes 3 buffers - dst, src, and tokens. The function uses nested loops to search the src string for existence of any of the tokens to be escaped, if found they are escaped before being copied into dst. In the pictured case token_of_none_quotation is passed as tokens which is defined as"\\\"'$()<>` #&*
Wir haben diese Funktion in C aus dem Web-Binary neu implementiert und können die erwartete Ausgabe sehen:
Diese (vermutlich korrekt) escapte Zeichenkette wird dann wie gewohnt über sprintf an das System übergeben.
Die Wirksamkeit dieses Pflasters hängt von einigen Faktoren ab:
- Die Funktion strcat_escape funktioniert vollständig wie vorgesehen
- strcat_escape verursacht nicht ungewollt Pufferüberläufe ;-)
- strcat_escape wird für alle Benutzereingaben verwendet, die im System landen
- Wir haben uns mit Belkin wegen einiger dieser Punkte in Verbindung gesetzt.
Schlussfolgerung
Wir alle wissen bereits, dass die Sicherheitsreife von eingebettetem Gerätecode ein Problem darstellt. Hier sehen wir, dass selbst bei Geräten, die 2014 veröffentlicht wurden, dies ein Problem bleibt.