Telekom Speedport Hybrid: Logging mit rrdtool

Als internetsüchtiges Landei greift man ja jedem Strohhalm, den man zu fassen bekommt. Ich hatte vor gut zwei Jahren zusätzlich zu unserem „normalen“ DSL-Anschluss der (je nach Tagesform) 10-14MBit/s bring noch einen LTE-Anschluss geklickt.

Das Problem an der Sache: bei zwei Uplinks man muss den Traffic intelligent routen. Eigentlich soll alles über LTE abgewickelt werden, aber man definiert dann unzählige Ausnahmen um möglichst keinen teuren LTE-Traffic zu vergeuden. Manche Dienste lassen sich auch schwer anhand von IPs und Ports in Filter gießen. Selbst mit viel Gefummel und Gehirnschmalz reichen dann 30GB für zwei Werktätige im Homeoffice eigentlich nicht aus.

Zum LTE-Vertragende wurden Hybrid-Anschlüsse bundesweit verfügbar. Das ist genau was ich eigentlich will: höhere Geschwindigkeit ohne Volumenlimit und mehr Redundanz, das alles ohne Fummelorgie in pf bzw. iptables. Einzig der Rant von Clemens in der Freakshow hat mich davon abgehalten sofort zuzuschlagen. Sein Fazit: das Produkt ist gut, aber der Router ist scheiße.

Nun habe ich einen Speedport Hybrid im Haus und kann diese Meinung vollumfänglich bestätigen. Das Webinterface des Routers ist eine Beleidigung. Javascript-Foo ohne Ende, es nervt mit unwichtigen Dingen wie Telefonie und diversen „Sicherheitsfeatures“. Man kann zeitgesteuert WLAN und Internet abschalten (ein sehr deutsches Feature), dafür kommt man aber an wichtige Informationen wie verbrauchter Traffic oder CRC-Fehler nicht ran. Das Webinterface warnt den User, wenn von einem weiteren Client darauf zugegriffen wird und ist auch sonst in jeder Hinsicht ein Usability-Verbrechen.

Her mit Deinen Daten!

Es gibt ein verstecktes „Engineer“-Menü, das viele Daten bereitstellt, die ich gerne hätte: Paket-Zähler der Interfaces; Dämpfung, SNR, CRC-Fehler und Bitrate auf der DSL-Leitung, Empfangsqualität des LTE-Signals ect.

Telekom Speedport Engineer Menu

Diese Daten wollte ich haben und mit rrdtool visualisieren. Dann hätte ich einen „DSL-Wetterbericht“ und weiß, wie es meinem Anschluss geht. Leider muss man sich jedes Mal auf dem Webinterface einloggen und dann die Engineer-URL in den Browser pasten.

Das ganze kann man schlecht automatisieren, solche Trümmer wie Selenium wollte ich nicht gleich auffahren. Ich habe mir deswegen zwei Sachen näher angeschaut:

  1. Die Firmware. Vielleicht gibt es noch einen einfachen Weg: es könnten durchaus Klartextscripte (lua?) in der Router-Firmware zu finden sein, die Rückschlüsse auf die Datenquellen zulassen.
  2. Die Kommunikation beim Login und das involvierte Javascript.

Die Firmware des Routers gibt es bei der Telekom zum Download. Mit Tools wie dem Firmware Modification Kit und binwalk kann man in das Image reinschauen und findet folgendes vor:

Target File: Firmware_Speedport_Hybrid_v050124.01.00.057.bin
MD5 Checksum: 086f589676e2cf108e755c2f0ad34649

DECIMAL HEX DESCRIPTION
----------------------------------------------------
132615 0x20607 JFFS2 filesystem, big endian
31098175 0x1DA853F PNG image, 488 x 2, 8-bit colormap, non-interlaced
31098375 0x1DA8607 JFFS2 filesystem, big endian
45205479 0x2B1C7E7 gzip compressed data
53720703 0x333B67F gzip compressed data
56458441 0x35D7CC9 gzip compressed data
56493219 0x35E04A3 gzip compressed data
66090195 0x3F074D3 gzip compressed data

Interessant: das Image enthält mehrere Firmware-Images: neben der für den „normalen“ Router gibt es noch ein vxworks-Image für den LTE-Teil des Routers. Die anderen Images konnte ich nicht genauer zuordnen, „mein“ Image ist mit 30MB das größte und lässt sich einfach mit dd rauskratzen. Das Image ist ein JFFS2 Image und ich konnte es auch mit viel googeln und fluchen nicht mounten. An der Stelle musste ich erstmal aufgeben und einen anderen Weg suchen.

well … SECURITY!

Zwischen Router und Browser wird http gesprochen, man kann also einfach mit Charles oder Wireshark den Traffic analysieren. Früher hatten andere Speedport Router ein HTTPS-Webinterface. Das hatte aber nicht nur Vorteile:

Es spricht viel dafür, dass das HTTP-only Webinterface ein Resultat der oben geschilderten Probleme ist.

Ab in das JavaScript-Schlammbad!

Also Augen zu und durch! Der interessante Code steckt in http://speedport.ip/js/pages/login.js. Als Beifang springen zwei Dinge sofort ins Auge:

if(getVar(data, "isEngineerPassword")) {
    document.location.href = "/engineer/html/dsl.html";
    log.info("Login successful.");
}

Offenbar gibt es ein Standardpasswort für Servicezwecke. Entweder ist das Passwort statisch oder es lässt sich aus der Telekom verfügbaren Daten ableitet (IMEI oder Seriennummer …).

[Update] Ich habe in einem meiner vielen Telefonate mit der Telekom Störungsstelle einem Mitarbeiter die Information abgerungen, dass es nur ein hart codiertes Engineer-Password gibt … 🙁 [/Update]

Die Statusseite unter http://speedport.ip/html/login/status.html?lang=de ist ohne Login zugänglich und könnte den notwendigen Input liefern.
Insgesamt ist das schon gruselig, dass mein Provider meinen Router umkonfigurieren kann und ich nicht in der Lage bin es zu verhindern.

Ein weiteres interessantes Fundstück findet sich hier:

if (showpass) {
    encryptpwd = sjcl.hash.sha256.hash(encryptpwd + loginpwd);
}
else {
    encryptpwd = sjcl.hash.sha256.hash(encryptpwd + loginpwd);
}

Offensichtlich findet beim Hersteller der Firmware kein Code-Review statt.

Die Speedport Login Prozedur

Damit trotzdem niemand das Router-Passwort mitlesen kann, unternimmt das Webinterface einen unglaublichen Eiertanz. Das Vorgehen ist vermutlich aus einem Crypto-Playbook, so ähnlich funktioniert auch der Login bei einigen Musikstreamingdiensten.

Zuerst sendet der Browser das hier zum Router:

POST /data/Login.json?lang=en HTTP/1.1
Content-Type: application/x-www-form-urlencoded

csrf_token=nulltoken&showpw=0&challengev=null

Mit diesem Request wird challengev angefordert, der Router liefert darauf hin 52 zufällige Bytes zurück:

[{
	"vartype": "status",
	"varid": "status",
	"varvalue": "ok"
}, {
	"vartype": "value",
	"varid": "challengev",
	"varvalue": "0f875ca2feb96b8AbFFf9e2e39AD9fAdFC13e59aE19BCc8A7f67"
}]

challengev muss im weiteren Verlauf der Sitzung immer als Cookie mitgesendet werden. Das eigentliche Passwort wird dann mit challengev in eine Hashfunktion geworfen und das Resultat daraus in sjcl.codec.hex.fromBits().

challenge_val = getVar(rep.serverData, "challengev");
encryptpwd = challenge_val + ":";
var showpass = $("#showpw_router_password").attr("checked");

if (showpass) {
    encryptpwd = sjcl.hash.sha256.hash(encryptpwd + loginpwd);
}
else {
    encryptpwd = sjcl.hash.sha256.hash(encryptpwd + loginpwd);
}
encryptpwd = sjcl.codec.hex.fromBits(encryptpwd);

Sendet man das richtige Passwort…

POST /data/Login.json?lang=en HTTP/1.1
Content-Type: application/x-www-form-urlencoded

password=8c40880088c6fc2ee7fd47e38c02f2c794cf80dc41e60f677c256a796e5aca93&showpw=0&csrf_token=nulltoken

… bekommt man in der Antwort eine Session-ID:

HTTP/1.1 200 OK
Set-Cookie: SessionID_R3=332X22U33mY; path=/; HttpOnly;

[{
	"vartype":"status",
	"varid":"login",
	"varvalue":"success"
},
{
	"vartype":"status",
	"varid":"status",
	"varvalue":"ok"
},

]

Die Speedport-Firmware macht sich dann noch die Mühe mit den ersten 16 Zeichen von challengev sowie dem Passwort einen symmetrischen Schlüssel mittels PBKDF2 abzuleiten. Das alleine dauert in einer V8 Engine mehr als eine Sekunde und ist der Hauptgrund für die Verzögerung beim Login:

var mypbkdf2 = new PBKDF2(sha256loginpwd, loginsalt, 1000, 16);
mypbkdf2.deriveKey(function(percent_done){}, function(key){
		// ....
	    loginDK = key;
	    setCookie("challengev", challenge_val);
	    setCookie("derivedk", loginDK);
    });

Mit den insgesamt nur drei Cookies kann man dem Speedport endlich seine Daten abringen:

challengev=0f875ca2feb96b8AbFFf9e2e39AD9fAdFC13e59aE19BCc8A7f67; derivedk=28f3bdb0eafc8a6732b42d0bb3bd29ce; lang=en; SessionID_R3=332X22U33mY

Wie ich später bemerkt habe, ist derivedk für die Abfrage der JSON Statusdaten aus dem Engineer-Menu nicht notwendig.

l33tport

Ich habe das ganze in node.js nachgebaut und als „l33tport“ veröffentlicht. Das Script führt den Login durch und lädt die Statusdaten als JSON runter. Damit bin ich erstmal am Ziel: ich kann die Rohdaten selbst verarbeiten. Erstes Ergebnis ist der oben erwähnte „DSL-Wetterbericht“:

DSL Wetterbericht

Mit dem Script als Basis sind natürlich noch ganz andere Dinge vorstellbar: ein alternatives, benutzbares Web-UI für den Router, integration des Routers in Hausautomation, eine „richtige“ App… Wie immer sind der Phantasie keine Grenzen gesetzt.

Update (24.05.2015): rrdtool Beispiele

Das Github-Projekt enthält jetzt ein paar Beispiele, wie man die rrdtool-Datenbanken erstellt, dort via cron Daten reinpumpt und wie man daraus bunte Graphen erstellt.