Weggezogener Teppich (Linux-Magazin, Februar 2012)

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.

DEFCON-2 durch Werbung

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, übernimmt das Gerät während des Bootvorgangs die dort eingestellten Proxy-Parameter.

Squid oder handgestrickt

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.

Listing 1: proxy-logger

    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.

Listing 2: proxy-adkiller

    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;

Manipulierender Proxy

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.

Der Widerspenstigen Zähmung

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.

Tomate mit sshd

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.

Sicher mit SSL

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]).

Infos

[1]

Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2011/05/Perl

[2]

Chumby, http://chumby.com

[3]

"Defense Readiness Condition", http://en.wikipedia.org/wiki/DEFCON

[4]

Squid HTTP Proxy, http://www.squid-cache.org

[5]

"Squid Proxy Server 3.1, Beginner's Guide", Kulbir Saini, Packt Publishing, 2011

[6]

Tomato Firmware für Linksys-Router, http://www.polarcloud.com/tomato

[7]

Tomato USB-Firmware für Linksys-Router mit VPN software, http://tomatousb.org/

[8]

"OpenVPN 2 Cookbook", Jan Just Keijser, Packt Publishing, 2011

Michael Schilli

arbeitet 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.