In meinem Beitrag Kernthema am eigenen Leibe habe ich beschrieben, wie ich aus Gründen der Interoperabilität die Kommunikation zwischen meiner Buderus-Heizung und der Steuerungs-App „EasyControl“ entschlüsselt habe, und dass diese Erkenntnisse aufgrund einer “Verletzung des Urheberrechts” aus einem PHP-Hausautomations-Forum gelöscht werden mussten.

Ich habe nun eine Version ohne öffentlich sichtbaren Salt entwickelt und ihm einen Key-Generator zur Seite gestellt, so dass die gesamte Funktionalität erhalten blieb, auch wenn nun alles etwas umständlicher in der Handhabung ist. Was die genaue Rechtslage meines Ursprungscodings angeht – hier bin ich derzeit in der anwaltlichen Klärung.

Da ich bislang nur die Funktionalität mit einer direkten HTTP-Verbindung im lokalen Netz herstellen konnte und mich eventuelle erweiterte Funktionalitäten der Fernwartung interessierten, habe ich mir die für Heizungsfachbetriebe zugedachte App „EasyControl Pro“ näher angeschaut. Die außerordentlich schlechten Kritiken dass die App schlicht nicht funktioniert haben mich sogar motiviert vielleicht den/die kritisierten Fehler in der App zu finden, aber auf welch krasse Schnitzer ich hier stoßen sollte hatte ich nicht geahnt.

Know your DevTool

Die Einzelteile der App sind mit einem Tool wie z.B. iFunBox schnell identifiziert, man braucht nicht einmal einen Jailbreak. Einfach das iPhone anschließen, in das Verzeichnis der App wechseln und umschauen. Sie wurde mit dem Phonegap-Framework entwickelt, womit sich das selbe Coding auf vielen Mobil-Plattformen ohne große Modifikationen einsetzen lässt.

Allerdings sollte man bei dieser Variante der App-Entwicklung sein Coding und die Ressource-Verzeichnisse aufräumen bevor man sie publiziert, denn der Löwenanteil der App besteht aus Klartext. Menschenlesbar. Ohne Hürden einsehbar. So gesehen Open Source. Irgendwie ein Zustand diametral entgegengesetzt zu der Haltung, die sich aus dem Takedown meines Codings ablesen lässt.

Sharing is Caring

Die erste Überraschung wartet im Verzeichnis EasyControlPro/EasyControlPro.app/www/resource mit dem Dateinamen ApplesSharedSecretForIAP.txt. Hier findet man das sogenannte „Shared Secret“, mit dem die App gegenüber dem iTunes-Store Belege von Abo-Käufen verifiziert, die innerhalb der App durchgeführt werden – also z.B. das jährliche Abo für die Verwaltung von 50 Kundenheizungen in der App.

Ein Shared Secret heißt nicht so weil man es mit der Welt teilen sollte, sondern aus dem genau umgekehrten Grund: Es ist ein Geheimnis, dass nur die Kommunikationspartner kennen sollen, da ansonsten die Kommunikation kompromittiert werden kann. Die Lieferung frei Haus ist also schon einmal großes Tennis.

Debug me baby

Schaut man sich in dem Verzeichnis EasyControlPro/EasyControlPro.app/www/scripts um findet man eine Menge an JavaScript-Quellcode, der teilweise sehr aufschlussreiche Details bietet. So sind in der Datei e4e90f82.scripts.js freundlicherweise neun über das Internet erreichbare Testsysteme inklusive kompletter Login-Daten enthalten, die jeder Entwickler ohne KM200-Gateway nun zum Testen seines Codings nutzen kann. Danke für den netten Service!

Aus den Login-Daten der Testsysteme folgt auch schnell eine weitere Erkenntnis: Das XMPP-Passwort – mit sprechendem Variablennamen bezeichnet. Dies ist also das auf dem KM200 aufgedruckte Geräte-Passwort ohne die Minuszeichen zwischen jedem vierten Zeichen. Wichtig zu wissen, dazu später.

In die Ferne schweifen

Wie ich bereits herausgefunden hatte wurde die Fernwartungsfunktion über XMPP implementiert. Zum Beobachten des Datenstroms bedienen wir uns einmal mehr des genialen Tools Wireshark. Wir sehen, dass die App eine Verbindung zu einem zentralen Server (wa2-mz36-qrmzh6.bosch.de) im Internet aufbaut und Kontakt hält. Ist nun ein KM200 ebenfalls per XMPP mit diesen Server verbunden, werden von diesem Server XMPP-Nachrichten der App zum KM200 und zurück vermittelt, vorausgesetzt man hat sich korrekt beim Server authentifiziert. Der Inhalt der Nachrichten ist HTTP-over-XMPP, mit dem von mir bereits ergründeten Inhalt: REST-URLs mit verschlüsselter JSON-Payload.

So gibt es also bei der Variante mit XMPP zwei Sicherheitsstufen:
Zum einen muss sich die App mittels dem obsoleten SASL/DIGEST-MD5-Verfahren gegen den vermittelnden Server authentifizieren um auf das KM200 zugreifen zu können, zum anderen wird die Payload des KM200 verschlüsselt übertragen.

Gib’s mir halt so

Authentifizierung ist ja immer so eine Sache. Das bereits genannte SASL/DIGEST-MD5-Verfahren nutzt eine Variante der Challenge-Response-Authentifizierung, welche sicherstellt, dass kein Passwort übertragen werden muss. Das funktioniert hier soweit auch gut – sofern man korrekte Login-Daten angibt. Denn erhält die EasyControlPro aufgrund nicht gültiger Login-Daten ein FAILURE statt eines SUCCESS bei der Authentifizierung, dann startet die App einen weiteren Versuch der Authentifizierung mit dem Verfahren PLAIN. PLAIN bedeutet das was es heißt – Login-Name und Passwort werden im Klartext übertragen, lediglich base64-Codiert. Ein solcher Login-Versuch sieht dann z.B. so aus:

<auth mechanism="PLAIN" xmlns="urn:ietf:params:xml:ns:xmpp-sasl">AGNvbnRhY3RfMTIzNDU2Nzg5AEM2dTlqUHVlX2FiY2RlZmdoaWprbG1ub3A=</auth>

Decodiert man nun die Payload mit base64 bekommt man folgenden String:

contact_123456789C6u9jPue_abcdefghijklmnop

Ich habe bei diesem Versuch den den Login-Namen 123456789 und das XMPP-Passwort, welches dem Geräte-Passwort entspricht (siehe oben) abcdefghijklmnop eingegeben. Man sieht sehr schön, wie dem Login von der App-Seite ein contact_ vorangestellt wird und dem Passwort ein „geheimes“ Prefix: C6u9jPue_.

Mit diesen Informationen, die komplett ohne Dekompilierung der App, also nur über § 69d UrhG gewonnen wurden, kann nun jedermensch mit einer XMPP-Bibliothek eine eigene Implementierung einer hoffentlich besseren App starten, da § 69e UrhG hier in keiner Weise entgegensteht. Go, go, go!

Gefahr im Anzug oder Frack?

Es stellt sich aber auch die Frage, ob der Fallback auf eine PLAIN-Authentifizierung eine Sicherheitslücke darstellt. Meine Meinung:

Oh ja!

Ein Angriffs-Szenario ist z.B. die klassische Man-in-the-Middle-Attacke. Mit einem gefälschten DNS-Eintrag werden Login-Daten von einem Fake-Server abgefischt und der nächste Verbindungsaufbau der App durchgelassen – der Nutzer merkt hiervon nichts. So kommt man in den Besitz von genau den Teilen der Login-Credentials, die fest mit dem Gerät verheiratet sind und sich – im Gegensatz zum Benutzer-Passwort – nicht mehr ändern lassen! 

Die XMPP-Verbindungen sind damit latent unsicher und extrem (D)DoS-Anfällig. Die Wahl von ECB statt CBC als Blockchiffre-Modus bei der Payload-Verschlüsselung macht – unabhängig von der Kenntnis des hier genutzten Salt – diese Verschlüsselung schneller angreifbar.

No offense, honest feedback

Mein Tip an die Bosch Thermotechnik GmbH: Bitte hier schnell aufräumen, die App entlausen – und mal die Community ‚ranlassen. Das hier gefährlicheres als die aufgezeigte hauseigene Implementierung herauskommt kann ich mir nur schwerlich vorstellen.