
Exploit für eine Command Injection Schwachstelle, die in der uhttpd-Binärdatei der TP-Link Tapo c200 IP-Kamera gefunden wurde.
CVE-2021-4045 ist eine Befehlseinschleusungs-Sicherheitslücke, die eine Remote-Code-Ausführung in der TP-Link Tapo c200 IP-Kamera ermöglicht. Sie betrifft alle Firmware-Versionen vor 1.1.16 Build 211209 Rel. 37726N aufgrund unzureichender Überprüfungen der Benutzereingaben in uhttpd, einer der Haupt-Binärdateien des Geräts. Eine vollständige Beschreibung finden Sie hier.
Dies ist eine erweiterte Version des PoC, der die Sicherheitslücke auf der CryptoParty Madrid 2022 demonstriert. Sie hat 2 Modi:
shell: Erzeugt eine Root-Shell auf dem Zielgerät

rtsp: Ermöglicht den Zugriff auf den Live-Videostream über RTSP

Die Funktion exec_and_read_json verwendet popen zur Ausführung von Befehlen:

exec_and_read_json wird von 2 unbenannten Funktionen verwendet, die ich set_language und wifi_connect benannt habe. Sie kümmern sich offensichtlich um die Sprach- bzw. WLAN-Konfiguration. wifi_connect scheint einfache Anführungszeichen (') zu parsen, set_language jedoch nicht. Das bedeutet, dass wir bei Kontrolle der Eingabe für die Funktion set_language erfolgreich eigene Befehle einschleusen können.

Die Funktion set_language wird von uh_slp_proto_request verwendet, der bereits erwähnten Funktion, die als Eingabe einige vom Benutzer empfangene, geparste Daten erhält.

Zum Parsen der Benutzerdaten prüft uh_slp_proto_request, ob es sich um ein gültiges JSON-Objekt handelt. Dann wird ein Zeichenkettenwert, identifiziert durch den Schlüssel "method", und ein Wörterbuchwert, identifiziert durch "params", abgerufen (zumindest nehme ich das an, da der Funktionsaufruf von Ghidra nicht aufgelöst werden konnte, aber so zu funktionieren schien). Abhängig von der gewählten Methode wählt uh_slp_proto_request die Funktion aus, die aufgerufen wird.
Indem wir also {"method": "setLanguage", "params":{}} senden, rufen wir erfolgreich die Funktion set_language auf und übergeben {} als Parameter language_json. Innerhalb von set_language wird das Objekt language_json dann in eine Zeichenkette umgewandelt und direkt in "ubus call system_state_audio set_language \'%s\'" zur Ausführung eingefügt.
Durch Senden von {"method": "setLanguage", "params": {"payload": "'; touch poc;'"}} wird ubus call system_state_audio set_language '{"payload": "'; touch poc;'"}' ausgeführt, das tatsächlich 3 Befehle enthält: ubus call system_state_audio set_language '{"payload": "', touch poc und '"}'. Der zweite Befehl ermöglicht uns eine vollständige Codeausführung.
uh_slp_proto_request wird nun von einer weiteren unbenannten Funktion verwendet, die alle Anfragen verwaltet und die ich main_server_function genannt habe. Wenn eine Anfrage gültig ist (die maximale Länge nicht überschreitet, je nach Serverkonfiguration http oder https verwendet usw.), prüft main_server_function, ob die URL /cgi-bin/luci oder /web-static enthält. Wenn nicht, wird uh_slp_proto_request aufgerufen.

Durch Raten und Senden einiger Anfragen an die Kamera können wir feststellen, dass die von uh_slp_proto_request verwendeten Daten normale POST-Daten sind. Wenn wir also eine POST-Anfrage an / mit der vorherigen Nutzlast senden, verarbeitet uh_slp_proto_request diese Daten, ruft set_language auf und unsere Nutzlast wird in den von exec_and_get_result ausgeführten Befehl eingeschleust.
Wie Sie sehen, habe ich nichts zur Authentifizierung erwähnt, da die Methode setLanguage ohne Anmeldung aufgerufen werden kann. Dies ermöglicht jedem Benutzer, mit nur einer einzigen, nicht authentifizierten Anfrage die vollständige Kontrolle über die Kamera zu erlangen.