Wer die Ethernetleitung oder den Wireless-Router kontrolliert, kann angeschlossen Geräten neue Inhalte unterjubeln oder ihnen vorgaukeln, sie stünden am anderen Ende der Welt. Auch wenn diese sich zugeknöpft geben.
Auf meinem Schreibtisch steht seit etwa einem Jahr ein sogenannter Chumby ([2], Abbildung 1), ein kleiner radioweckergleicher Kasten, auf dem in konfigurierbaren Apps den ganzen Tag aktuelle Schlagzeilen, das Wetter, Börsenkurse und die neuesten Berichte aus der Welt der Programmierung durchtickern. Interessanterweise nervt der Zweitbildschirm, dessen Geschehen man aus dem Augenwinkel verfolgt, weniger als ein Widget auf dem Hauptschirm und hin und wieder erhasche ich so während der Arbeit die neuesten Klatschgesichten aus dem Silicon Valley oder werde Zeuge bahnbrechender Entwicklungen der Gadget-Industrie.
Abbildung 1: Der Chumby zeigt die neuesten Schlagzeilen auf ihackernews.com an. |
Vor einigen Wochen hielt es eine offensichtlich irrgeleitete Person in der Chumby-Zentrale aber anscheinend für notwendig, zwischen meinen voreingestellten Kanälen eine etwa 10 Sekunden lang dauernde Werbung für eine Autoversicherung zu schalten (Abbildung 2).
Abbildung 2: Die Reklamehexe hat sich ungefragt zwischen die Chumby-Kanäle gedrängt. |
Ich schaltete sofort auf DEFCON-2 [3] und untersuchte, ob die
Chumby-Einstellungen einen HTTP-Proxy erlaubten, mit dessen Hilfe
sich die unerwünschte Werbung abfangen und neutralisieren ließe, bevor
diese auf dem Chumby eintrifft.
Im Chumby-Forum erfuhr ich, dass ein Chumby von Haus aus keinen
HTTP-Proxy unterstützt, dass man
aber einen USB-Stick einstöpseln kann, auf dem in einer Datei
namens userhook0
im Root-Verzeichnis die Proxy-Einstellungen von
Abbildung 4 stehen. Mit diesem Stick gebootet schleust das Gerät dann
alle HTTP-Requests durch den Proxy-Server, der sich die URLs ansehen und
eventuell manipulieren kann.
Abbildung 3: Ein USB-Adapter verbindet den Chumby mit einem Ethernet-Adapter und dem USB-Stick mit dem gespeicherten User-Hook, der die Proxy-Einstellungen enthält. |
Abbildung 4: Steckt im Chumby ein USB-Stick mit einer Datei C |
Als Proxy-Server eignet sich Squid ([4]), aber wer gern bastelt, zimmert
sich wie in Listing 1 mit dem CPAN-Modul HTTP::Proxy schnell einen loggenden
Proxy zusammen. Zeile 21 startet den Proxy-Server, der auf Port 9999 des
Hosts 192.168.1.123 lauscht, die HTTP-Requests des Chumbys entgegennimmt,
und die Inhalte aus dem Internet holt. Der in Zeile 10 eingeschobene
request
-Filter sieht sich einen eintreffenden HTTP-Request an,
fieselt den URL heraus und gibt ihn mit print
aus. Mit diesem
Spion in der Leitung zeigt Abbildung 5, was der Chumby so treibt.
01 #!/usr/local/bin/perl -w 02 use strict; 03 use HTTP::Proxy; 04 use HTTP::Proxy::HeaderFilter::simple; 05 06 my $proxy = HTTP::Proxy->new( 07 host => "192.168.1.123", 08 port => 9999 ); 09 10 $proxy->push_filter( 11 request => 12 HTTP::Proxy::HeaderFilter::simple->new( 13 sub { 14 my( $self ) = @_; 15 print $self->proxy->request->uri(), 16 "\n"; 17 } 18 ) 19 ); 20 21 $proxy->start;
Abbildung 5: Der loggende Proxy schreibt die vom Chumby aufgerufenen URLs mit. |
Um nun der Chumby-Werbung den Teppich unter den Füßen wegzuziehen,
ändert Listing 2 die Methode push_filter
dergestalt um, dass sie
den URL des Requests umschreibt, falls der Chumby ursprünglich nach
eviladserver.com
verlangt hat. Statt nervender Werbung erscheint
dann ein Bild vom Sandy Beach auf meiner Lieblingsinsel Oahu auf Hawaii,
an dessen Brandung es erfahrene Bodysurfer in einer zusammenbrechenden
Welle sauber umherbeutelt.
01 #!/usr/local/bin/perl -w 02 use strict; 03 use HTTP::Proxy; 04 use HTTP::Proxy::HeaderFilter::simple; 05 use HTTP::Request::Common; 06 07 my $proxy = HTTP::Proxy->new( 08 host => "192.168.1.123", 09 port => 9999 ); 10 11 my $repl = "http://perlmeister.com/test/" . 12 "sandy-beach.jpg"; 13 14 $proxy->push_filter( 15 request => 16 HTTP::Proxy::HeaderFilter::simple->new( 17 sub { 18 my( $self, $headers, $req ) = @_; 19 20 if( $req->uri() =~ 21 /eviladserver\.com/ ) { 22 $_[2] = GET $repl; 23 } 24 } 25 ) 26 ); 27 28 $proxy->start;
Das HTTP::Proxy-Framework reicht in Zeile 18 drei Parameter in den
Filter-Callback hinein: In $self
eine Referenz auf das Filter-Objekt
selbst, in $headers
ein Header-Objekt und in $req
das Request-Objekt.
Stellt nun der Pattern-Match in Zeile 20 fest, dass die URL des
Requests auf eviladserver.com
zeigt, setzt Zeile 23 in $_[2]
das Request-Objekt der rufenden Funktion auf ein neues, das auf das
JPG-Bild mit dem hawaiianischen Strand auf perlmeister.com zeigt.
Ein kurzer Test mit Firefox und den in Abbildung 6 gezeigten Proxy-Settings
bestätigt die Umleitung in Abbildung 7.
Abbildung 6: Das Firefox-Menü "Network Settings" lässt den Browser auf den modifizierenden Proxy zeigen. |
Abbildung 7: Firefox mit Proxyeinstellung holt statt Werbung von eviladserver.com das voreingestellte Bild. |
Nun erlaubt es nicht jedes Gerät, dass Endnutzer einen Proxy einstellen. Im Chumby verwenden zum Beispiel manche Apps eine Library, die die Proxy-Einstellungen schlicht ignoriert. Hat man keinen Zugriff auf den Source-Code der auf dem Gerät laufenden Programme, greift der Fachmann zu Tricks in verschiedenen Netzwerkschichten, um die ausgesandten IP-Pakete wunschgemäß umzuleiten.
So verbindet sich ein Amazon Kindle zum Beispiel mit einem Wireless-Netzwerk, ohne auch nur nach einem Proxy-Server zu fragen (Abbildung 8). Was tun, falls das lokale Wireless-Netz nur über einen Proxy oder einen Tunnel ins Internet kann, oder man dem Amazon-Server eine andere IP vorgaukeln möchte?
Abbildung 8: Beim Verbinden des Kindle mit einem Wireless-Netzwerk lässt sich kein Proxy einstellen. |
Der Kindle holt sich beim Verbinden mit einem Wireless-Netzwerk eine
dynamische IP vom DHCP-Server ab und erhält von diesem auch gleich noch
die IP eines Default-Gateways, üblicherweise die des Routers. Setzt der
Kindle dann einen Webrequest ab, schickt er ein an den Webserver
addressiertes Paket an das Default-Gateway. Ist dies ein Linksys-Router
mit Tomato-Firmware ([6]), fängt es mit den in Abbildung 9 gezeigten
iptables
-Anweisungen die Pakete ab, denn auf dem putzigen Gerät läuft
Linux mit vollem Netzwerkstack. Die Regel prüft, ob ein eintrudelndes
Paket an den Port 80 eines Webservers geht, und leitet es in diesem Fall an
die Adresse des ebenfalls an den Router angeschlossenen handgeschriebenen
Proxyservers auf Port 9999 um.
Abbildung 9: Mit diesen iptables-Regeln schickt der Linksys-Router alle HTTP-Requests an den Proxy. |
Die erste Anweisung in Abbildung 9 verhindert, dass die Umleitung auch
mit Paketen zur Steuerung der Router-Adminoberfläche passiert. Sie schnappt
sich die eintrudelnden IP-Pakete, die an den Port 80 des Routers
gehen, denn die Option -d
(für Destination) ist auf die IP 192.168.20.1
des Routers gesetzt. In der PREROUTING-Phase setzt die Regel so die
Target ACCEPT, was heißt, dass die Pakete ohne Umschweife an den auf
dem Router wartenden Webserver gehen und keine der nachfolgenden
iptables
-Regeln Beachtung findet.
In der Tomato-Firmware lässt sich auch ein sshd
-Server starten, und loggt
sich der experimentierfreudige Bastler auf dem kleinen Gerät mittels
ssh root@192.168.20.1
ein und tippt das ebenfalls auf der Weboberfläche
verwendete Admin-Passwort, zeigt der Aufruf von ifconfig
, dass das
LAN-Interface auf den Namen br0
hört, während das WAN-Interface eth0
heißt.
Der auf dem LAN angeschlossene Rechner mit dem loggenden Proxyserver hört
auf die IP-Adresse 192.168.20.148
und demnach leitet die zweite
iptables
-Anweisung in Abbildung 9 alle Pakete, die nicht vom
Proxy kommen (-s ! IP
) und für Port 80 eines beliebigen
Servers bestimmt sind
an die IP des Proxy und dort auf Port 9999 weiter. Das Verfahren ist
unter der Bezeichnung "Transparent Proxy" oder auch "Intersepting Proxy"
bekannt ([5]).
Damit die vom Proxy nach getaner Arbeit wiederkommenden Pakete nicht
direkt an den ursprünglichen Sender zurück gehen, sondern über
den Router, schreibt
die dritte iptables
-Regel in Abbildung 9 die Pakete an den Proxy so
um, dass diese als Return-Adresse den Router angeben, und nicht etwa den
ursprünglichen Sender.
Die drei Regeln sind unter "Administration->Scripts" im Tab "WAN Up" einzuspeichern, damit der Router sie persistent in seinem NVRAM-Speicher ablegt und nach einem Reboot ausführt, sobald das WAN des Routers verfügbar ist.
Verbindet man den Kindle 3 dann mit dem bereitgestellten Wireless-Netzwerk des Routers und tippt auf dem unter "Experimental->Browser" erhältlichen Webbrowser einige URLs ein, sieht man im Proxy-Log, was der Kindle-Browser so an Abfragen absetzt.
Nutzt ein Sender allerdings eine SSL-Verbindung mittels einer https://-URL und implementiert die dazugehörigen Zertifikatsprüfungen korrekt, kann ein zwischengeschalteter Proxy die Kommunikation weder abhören noch manipulieren. Das wäre ein Man-in-the-Middle-Angriff, und eine SSL-Verbindung verhindert diesen effektiv.
Abbildung 10: Die Tomato-USB-Firmware ([7]) auf dem Linksys-Router definiert einen openvpn-Client, der angeschlossenen Wireless-Clients eine WAN-Addresse in einer anderen Geolocation verpasst. |
Abbildung 11: Diese Scripts unter der Rubrik "Administration" starten den openvpn-Client, wenn der Router bootet. |
Allerdings kann man zum Beispiel mittels eines VPNs die IP-Pakete so umlenken und mit NAT-Einstellungen umschreiben, dass der vom Gerät kontaktierte Server glaubt, das Gerät befände sich an einem Ort, an dem es gar nicht ist: Ein wirksames Verfahren gegen Websites, die sich dagegen sperren, ihre Inhalte an bestimmte Geolocations auszuliefern. Die erweiterte Tomato-Routerfirmware tomato-usb [7] verfügt deshalb über einen openvpn-Client, der sich relativ einfach mit VPN-Anbietern wie zum Beispiel ibvpn.com verbindet, die gegen eine monatliche Gebühr openvpn-Server in verschiedenen Ländern anbieten.
Den Usernamen und das Passwort für ibvpn.com schreibt das Startup-Script in
Abbildung 11 beim Booten des Routers in die temporäre Datei /tmp/ibvpn.conf
.
Da im Filesystem des Routers
abgelegte Dateien keinen Reboot überstehen, hilft man
sich im Tomatenland mit Shell-Skripts, die das im NVRAM-abgelegte
Skriptpanel beim Hochfahren des Routers dynamisch anlegt. Das erste
Kommando legt, wie in Abbildung 11 gezeigt, den Inhalt des Skripts
in der temporären Datei /tmp/vpn.sh
ab und das folgende
sh /tmp/vpn.sh &
führt den Shell-Code aus.
Das Skript selbst wartet mit einer while
-Schleife und sleep
-Anweisungen
solange, bis /var/notice/sysup
existiert. Hiermit signalisiert der
Router, dass das System erfolgreich hochgefahren wurde. Ist diese
Bedingung erfüllt, fährt service vpnclient1 start
den ersten openvpn-Client
hoch (Tomato-USB bietet sogar zwei),
der sich mit dem openvpn-Server verbindet. Ein erfolgreicher Handshake setzt
allerdings voraus, dass auf Tomato-USB unter dem Reiter "Keys" das
OpenSSL-Zertifikat des Servers und eventuell verwendete geheime
Schlüssel eingetragen wurden.
Der openvpn-Server verstellt im Erfolgsfall
mit einem push
-Kommando die Routingtabellen des Routers dergestalt, dass
ausgehende Pakete automatisch erstmal ans andere Ende des VPN-Tunnels gehen.
Von dort leitet sie dann der openvpn-Server weiter an den Zielwebserver, der
meint, er spräche mit dem openvpn-Server. Dies funktioniert auch für
SSL-Verbindungen tadellos. Diese merken vom weggezogenen Teppich rein
gar nichts, denn sie operieren viel weiter oben im Netzwerk-Stack.
Mehr praktische Tipps zur Konfiguration von VPNs finden sich in dem
empfehlenswerten Werk ""OpenVPN 2 Cookbook" ([8]).
Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2011/05/Perl
Chumby, http://chumby.com
"Defense Readiness Condition", http://en.wikipedia.org/wiki/DEFCON
Squid HTTP Proxy, http://www.squid-cache.org
"Squid Proxy Server 3.1, Beginner's Guide", Kulbir Saini, Packt Publishing, 2011
Tomato Firmware für Linksys-Router, http://www.polarcloud.com/tomato
Tomato USB-Firmware für Linksys-Router mit VPN software, http://tomatousb.org/
"OpenVPN 2 Cookbook", Jan Just Keijser, Packt Publishing, 2011
Michael Schilliarbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com. |