Kommentare 0

HTTPS mitlesen (oder: Wie sehe ich, was meine Apps treiben?)

Im letzten Beitrag (alter Link, sorry) ging es um die Problematik auskunftsfreudiger Apps und der Umgang der Betriebssystemhersteller damit. Jetzt soll gezeigt werden, wie man den Datenverkehr einer App überwachen kann. Für dieses Tutorial sind Grundkenntnisse der Netzwerktechnik nützlich, man muss aber kein Profi sein.

Voraussetzungen:

  • Ein Rechner mit unixoidem Betriebssystem mit einem Paketfilter wie iptables (ich gehe von Linux aus).
  • Ein Gerät, welches überwacht werden soll. Das kann ein Smartphone sein, aber auch ein PC.
  • Internetzugang über WLAN oder Ethernet.

Schritt 1: wir klinken uns in die Kommunikation ein

Zuerst müssen wir dafür sorgen, dass sämtlicher Datenverkehr des zu überwachenden Gerätes über unseren Rechner laufen. Das geht am einfachsten, indem wir ihn als Router zwischen das Gerät und das Internet schalten. (Wer ein Gerät überwachen will, auf das er keinen Zugriff hat, für den ist ARP-Spoofing interessant).

Gehen wir von folgender Konfiguration aus:

  • IP-Adresse bestehender Router (das, was ihr jetzt als Standard-Gateway eingetragen habt): 192.168.1.1
  • IP-Adresse des mitlesenden Rechners („Sniffer“): 192.168.1.100
  • IP-Adresse des zu überwachenden Gerätes („Client“): 192.168.1.200

Zuerst aktivieren wir auf dem Sniffer Routing, damit er Pakete weiterleitet. Das geht mit „echo 1 > /proc/sys/net/ipv4/ip_forward“. Nun setzen wir beim Client den Standard-Gateway auf 192.168.1.100. Bei Android geht das in den WLAN-Einstellungen: Menütaste drücken – „Advanced“ auswählen – „Use static IP“ wählen.

Kurz testen, ob ihr noch ins Internet kommt. Sollte funktionieren.

Schritt 2: wir lesen HTTP mit

Jetzt wird es interessant: wir werden den HTTP-Verkehr mitlesen. Dazu installieren wir den Paketsniffer tcpdump („aptitude install tcpdump“ bei Debian und Ubuntu).

Diesen starten wir mit „tcpdump port 80 -s 0 -w /tmp/http.dmp“. „port 80“ bedeutet, dass wir nur HTTP mitlesen. Ohne diese Option würden wir eine Menge anderen Verkehr mit aufzeichnen, was das Log unübersichtlich machen würde. „-s 0“ ist wichtig: ohne diese Option werden nur die ersten 96 Bytes jedes Pakets aufgezeichnet. Wir wollen natürlich alle Daten. Mit „-w /tmp/http.dmp“ definieren wir schliesslich, dass wir die Aufzeichnung in der Datei „http.dmp“ im Verzeichnis „/tmp“ speichern möchten.

Starten, mit dem Browser eine Website aufrufen und die Datei sollte sich füllen:

http_get

Im Beispiel eine Anfrage an http://www.ahnungslos.ch. Die Datei im Texteditor zu betrachten macht natürlich nur begrenzt Freude, da wir alle unleserlichen Binärdaten wie Paketheader, Bilder etc. auch sehen und durchscrollen müssen. Die Dumps von tcpdump lassen sich jedoch mit Wireshark öffnen. Das ist für Windows und OS X erhältlich und bietet eine komfortable grafische Oberfläche. Tipp: Wenn man einen Request sieht und dessen Antwort sehen möchte: mit der rechten Maustaste anklicken und „follow TCP stream“ wählen. In einem neuen Fenster wird dann der Inhalt aller zur Verbindung gehörenden Pakete angezeigt.

Nun seht ihr schon viel, aber leider noch nicht alles. Falls ihr den Verkehr einer App wie Twitter mitlesen wolltet, habt ihr im Dump nicht viel gefunden.

Weil das Mitlesen von Klartextprotokollen wie HTTP so einfach ist, wickeln viele Apps ihre Kommunikation über das verschlüsselte HTTPS ab. Aber für jedes Problem gibt es eine Lösung, also dran bleiben!

Schritt 3: kurze Theorielektion

HTTPS ist mit SSL gesichertes HTTP. SSL bietet zwei für uns relevante Sicherheitsfunktionen: Verschlüsselung (Daten werden für Dritte unlesbar übertragen) und Authentifizierung (Client kann prüfen, ob der Server ist, wer er zu sein ausgibt).

Um HTTPS mitlesen zu können, müssen wir also zwei Voraussetzungen schaffen:

  1. Wir müssen an den Schlüssel kommen oder den Schlüssel selbst erzeugen.
  2. Wir müssen der App glaubhaft machen, wir seien der Server, mit dem sie kommunizieren will.

Die Authentifizierung läuft über Zertifikate. Der Server hat ein Zertifikat mit einem privaten Schlüssel und den öffentlichen Schlüssel dazu (siehe hier). Das Serverzertifikat enthält den Hostnamen und ist von einer Zertifizierungsstelle signiert. Dies kann intern eine eigene Stelle sein, oder für den öffentlichen Gebrauch ein Anbieter wie Verisign. Beim Verbindungsaufbau prüft der Client, ob das Zertifikat zum Hostnamen passt und vertrauenswürdig ist. Betriebssysteme und Browser enthalten dazu eine Liste vertrauenswürdiger Zertifizierungsstellen.

Da wir den Schlüssel nicht knacken können, müssen wir uns zwischen Server und Client hängen. So können wir eine Anfrage gegenüber dem Client mit unserem Zertifikat verschlüsseln. Gegenüber dem Server verhalten wir uns wie ein normaler Client. Zwischen drin haben wir die Daten im Klartext und können sie mitlesen.

Schritt 4: unsere eigene Zertifizierungsstelle

Damit wir selbst Zertifikate ausstellen können, müssen wir ein Root-Zertifikat erstellen. Also ein Zertifikat, mit dem wir andere Zertifikate signieren können. Dazu benötigen wir openssl. Das sollte bei jeder Distribution dabei sein, sonst nachinstallieren.

Zuerst müssen wir in der Datei „/etc/ssl/openssl.cnf“ ein Verzeichnis angeben, in welchem die Zertifikate abgelegt werden:
dir = /root/fakeCA
Die Verzeichnisse erstellen wir gemäss den Vorgaben:
cd /root
mkdir fakeCA
chmod 700 fakeCA
cd sslCA
mkdir certs private newcerts

Es werden noch zwei Dateien benötigt, diese legen wir an mit:
echo 1 > serial
touch index.txt

Nun können wir das Zertifikat erstellen:
openssl req -new -x509 -days 3650 -extensions v3_ca -keyout private/cakey.pem -out fakeca_public.pem
-config /etc/ssl/openssl.cnf

Damit erstellen wir ein Zertifikat mit einer Gültigkeit von 10 Jahren. openssl fragt ein Passwort für den privaten Schlüssel sowie Informationen wie Ort, Land etc. ab. Da können wir beliebige Werte eintragen, sollten aber auf Umlaute verzichten.

Jetzt haben wir zwei neue Dateien: „private/cakey.pem“ (privater Schlüssel) und „fakeca_public.pem“ (öffentlicher Schlüssel). Später brauchen wir beide Schlüssel in einer Datei. Wir führen sie deshalb zusammen mit „cat private/cakey.pem fakeca.pem > fakeca.pem“. Wem das zu mühsam ist, kann die bereits erstellte fakeca.pem (Download) verwenden. Das Passwort dazu ist „ahnungslos“. Wie immer hat Faulheit seinen Preis: wer dieses Zertifikat auf seinem Gerät installiert, dessen Datenverkehr kann von allen Lesern dieses Tutorials mitgelesen werden. 😉

Schritt 5: h@x0rZ-T00lz

Um uns in die Kommunikation einzuklinken verwenden wir sslsniff. Es agiert als transparenter Proxy: möchte ein Client eine Verbindung über HTTPS aufbauen, erstellt es im Hintergrund ein Zertifikat auf den richtigen Hostnamen und antwortet damit. Die erstellten Zertifikate signiert es mit dem von uns erstellten Rootzertifikat. Die Daten leitet es anschliessend weiter an den Server, mit dem der Client ursprünglich kommunizieren wollte. Es merken weder Server noch Client, dass wir dazwischen sind.

Zuerst installieren wir es, entweder über die Paketverwaltung der Distribution oder wir kompilieren es direkt aus den Sourcen. Ich empfehle den Weg über die Paketverwaltung, da es wegen der vielen Abhängigkeiten etwas mühsam zum kompilieren ist.

Jetzt können wir es starten mit:
sslsniff -a -c /root/fakeCA/fakeca.pem -s 4433 -w /tmp/https.log

sslsniff

Es verwendet unser Zertifikat und wartet auf Port 4433 auf Anfragen.

Hinweis: sslsniff hat so gut wie keine Fehlerbehandlung. Fehler quittiert es mit einem „Segmentation fault“. Falls ihr den bei der ersten Anfrage habt, habt ihr euch wahrscheinlich beim Passwort vertippt.

Schritt 6: Weichen stellen

In diesem Schritt sorgen wir dafür, dass Anfragen vom Client an HTTPS auf sslsniff umgeleitet werden. Dazu verwenden wir den Paketfilter. Bei iptables ist es dieser Befehl:
iptables -t nat -A PREROUTING -p tcp --destination-port 443 -j REDIRECT --to-ports 4433
Die Parameter bedeuten folgendes:

  • -t nat“: Tabelle für Network Address Translation verwenden
  • -A PREROUTING“: Regel anwenden, bevor eine Routing-Entscheidung getroffen wurde
  • -p tcp –destination-port 443“: Regel gilt für TCP Port 443 (HTTPS)
  • -j REDIRECT –to-ports 4433“: Pakete umleiten auf lokalen Rechner, Port 4433
  • Die Regel löschen kann man übrigens mit „iptables -F -t nat“.

Schritt 7: Vertrauen ist gut…

Wir haben es fast geschafft! Ihr solltet jetzt mit dem Browser auf dem Client eine Website über HTTPS besuchen können (zB. https://www.google.com). Wenn alles funktioniert, werdet ihr von einer Warnung begrüsst: „das Sicherheitszertifikat dieser Website ist nicht vertrauenswürdig“. Wenn ihr auf „Zertifikat anzeigen“ klickt, seht ihr, dass das Zertifikat zwar auf google.com erstellt wurde, jedoch von der unbekannten CA fakeCA.lan. Der Browser vertraut nur Zertifikaten, die von einer CA signiert wurden, die er für vertrauenswürdig hält. Das ist normalerweise sinnvoll, denn sonst könnte sich jeder als google.com oder facebook.com ausgeben.

Im Browser können wir zwar auf „ignorieren“ klicken, aber die meisten Apps bieten diese Option nicht an. Wenn sie dem Zertifikat nicht vertrauen, bauen sie keine Verbindung auf. Wir müssen unser Zertifikat also der Liste vertrauenswürdiger Zertifizierungsstellen hinzufügen. Zum Glück verlassen sich alle (jedenfalls alle von mir getesteten) Apps auf die Liste des Betriebssystems. Wir müssen also nicht für jede App etwas einstellen.

Eine Anleitung, wie ihr das Zertifikat auf eurem Gerät installiert, findet ihr im Internet. CACert bietet eine Anleitung für viele Betriebssysteme (Beispiel). Anstatt dem Zertifikat von CACert importiert ihr einfach das fakeCA-Zertifikat. Hinweis: ihr importiert nur den öffentlichen Schlüssel. Falls ihr eine .crt-Datei (statt .pem) benötigt, könnt ihr sie mit openssl konvertieren. Ausser ihr verwendet Android, da ist es etwas komplizierter. Android bietet nämlich keine Möglichkeit, eigene Zertifikate zu installieren (ausser Clientzertifikate für VPN).

Die Liste der vertrauenswürdigen Zertifikate findet ihr bei Android unter „/system/etc/security/cacerts.bks“. Sie ist im „Bouncy Castle“-Format. Um sie zu editieren, braucht ihr die entsprechende Klasse und Java. Das ist auf hier gut erklärt.

Ich konnte zwar das Zertifikat hinzufügen und die neue Datei auf das Gerät zurückkopieren, jedoch kamen die Fehler immer noch. Irgendwie wurde sie nicht eingelesen oder beim Neustart überschrieben.

Ein radikaler Weg war die Lösung: eine update.zip vom CyanogenMod heruntergeladen, die cacerts.bks hinein kopiert und diese update.zip dann installiert. Achtung: Signaturprüfung deaktivieren vor dem Flashen, die Signatur stimmt natürlich nicht mehr, nachdem man die Datei verändert hat.

Wer sich die Arbeit zum Bearbeiten der cacerts.bks sparen will, kann hier (Download) meine Datei herunterladen. Sie enthält die Standard-Zertifikate von Android sowie die fakeCA.

Nach der Installation: nochmals testen. Jetzt sollte keine Warnung mehr erscheinen. Wir sind soweit!

Schritt 8: Big Brother

Nach all der Vorbereitungsarbeit können wir endlich den Verkehr einer App überwachen. Dazu installieren wir eine „verdächtige“ App. Je mehr Berechtigungen sie verlangt, desto besser. Falls sslsniff inzwischen nicht mehr läuft, starten wir ihn wieder. Ich lasse jeweils parallel dazu tcpdump auf Port 80 laufen, da nicht alle Apps über HTTPS kommunizieren.

Viber verschickt gerade meine (falsche) Telefonnummer sowie den Typ und die Softwareversion meines Smartphones:

viber

Hintergrundrauschen: Google möchte meinen Standort wissen und verschickt dazu die ESSIDs der WLANs in Reichweite (da kein GPS-Empfang im Haus):

google_loc

Spontacts verwendet Flurry für die Statistikerhebung, Datenübertragung per HTTP:

spontacts

Fazit

HTTPS abzuschnorcheln ist nicht ganz trivial, es ist jedoch auch keine Hexerei.

Wenn wir es können, kann es auch der Admin eurer Firma. Vielleicht hat er schon lange per Gruppenrichtlinie sein Zertifikat auf eurem Computer installiert und liest euer Facebook-Login mit. 😉 Manchmal wird tatsächlich HTTPS auf der Firewall der Firma aufgemacht, denn sonst könnte man die Daten nicht auf Viren scannen. Nur weil der URL mit https:// beginnt und der Browser keine Warnung anzeigt, heisst es nicht, dass niemand mitliest.

Mit den Daten, die ihr von eurer App mitgelesen habt, könnt ihr übrigens noch kreativeres anstellen als nur „Adressbuchexporteure“ zu überführen: ihr könntet zB. einen eigenen Client für WhatsApp schreiben.

Wenn ihr schon allen Netzwerkverkehr über euren Rechner leitet, könnt ihr ihn nicht nur mitlesen, sondern auch verändern. Damit lässt sich viel Spass haben. Wie wäre es, wenn ihr die Bilder der abgerufenen Websites umdrehen würdet, bevor ihr sie ausliefert?

Welche Erkenntnisse habt ihr gewonnen? Einen Datendieb überführt oder einfach den Kollegen einen Streich gespielt? Hinterlasst doch einen Kommentar!

Gastblogger Manuel Krummenacher twittert als @mkrtech und auf Google+ über die technische Welt und wie er sich darin zurecht findet. Heute ist er als erster Gastautor auf ahnungslos.ch aktiv.

Schreibe eine Antwort