Trojaner-Alarm: PHP.Shell-38 via FTP eingeschleust

In meinem letzten Artikel habe ich damit begonnen, die ganze Geschichte um den mysteriösen Virenbefall auf meinen Webaccounts bei einem Hoster zu dokumentieren. Zur Vorgeschichte liest du also am Besten zunächst den verlinkten Artikel.

Mit unterschiedlichen Dateinamen und an unterschiedlichen Orten innerhalb der Sitestruktur meiner Webseiten war ein PHP-Skript abgelegt worden, welches eine einzelne Anweisung enthielt:

Den kompletten Salat werde ich jetzt nicht posten. Denn … viel mehr als ein chaotischer Haufen Zeichen ist zunächst nicht zu erkennen, oder etwa doch?

Die Skriptanalyse
Ich begann, mir das Ding mal anzusehen. „preg_replace“ ist ein gebräuchlicher PHP-Befehl, um innerhalb eines Strings (Zeichenkette), mit Hilfe von sogenannten regulären Ausdrücken Ersetzungen durchzuführen. Ein unheimlich mächtiges Werkzeug, welches ich auch gern benutze. Wobei ich gestehen muss, dass mir viele dieser „regulären Ausdrücke“ die mir bereits untergekommen sind, Schweißausbrüche bescheren. Es gibt unheimlich verfitzte reguläre Ausdrücke, die einem normalen Menschen in die Klapse bringen können, wenn er versucht hinter deren Sinn zu steigen.

„/.*/e“, … das ist der „Pattern“ in der obigen Anweisung, also der Ausdruck, nachdem gesucht wird. .* bedeutet nichts anderes als „alles“. Nimm alle Zeichen, die da gleich kommen werden, egal was es ist und egal wieviele es sind. Eigentlich totaler Blödsinn …. wenn da nicht das kleine „e“ stehen würde!

PREG_REPLACE_EVAL
Das kleine „e“ am Ende des Suchstrings macht aus dem normalen „preg_replace“ ein „preg_replace_eval“. Das wusste und kannte ich noch gar nicht. Das ding ist aber saugefährlich, denn das „eval“ nun wieder deutet darauf hin, dass der Zeichensalat, welcher im Script folgt „ausgeführt“ wird. Das ist quasi so, als würdest du auf deinem Rechner ein PRogramm starten … bzw. es ausführen. „e“ gilt seit PHP 5.5 als „DEPRECATED“, also veraltet, und wird demnach wohl bald mal ganz aus PHP fliegen, doch es verrichtet noch immer seinen Dienst.

Ok … damit steht fest, dass der „Zeichensalat“ offensichtlich ein ausführbarer Code ist, der „nur“ verschlüsselt vorliegt. Wie aber entschlüsselt man das Ding … ?

Dem Code auf der Spur
Nach dem Komma folgt diese wunderschöne Kette …

Gegenüber dem restlichen Zeichenchaos weist diese eine erheblich abweichende Regelmäßigkeit auf: auf das \x folgt immer eine hexadezimale Zahl. Das ist ASCII-Code! Da ich noch nicht zu den Vollnerds gehöre, welche die komplette ASCII-Tabelle im Schlaf herbeten können, bemühte ich kurz Google und schaufelte mir die ASCII-Tabelle auf den zweiten Monitor. Ich begann zu „dechiffrieren“ …

28 = ‚(‚
65 = ‚e‘
76 = ‚v‘
Hier war mir schon klar, dass da „eval“ rauskommen würde. Was es auch tat. Mit der nächsten 28 ging wieder eine Klammer auf …
67 = ‚g‘
7A = ‚z‘
‚gzip?‘, ging es mir durch den Kopf. Doch ich staunte nicht schlecht als nämlich …
69 = ‚i‘
6E = ’n‘
66 = ‚f‘
Häh? …..
6C = ‚l‘
61 = ‚a‘
74 = ‚t‘
und 65 = ‚e‘ ?
„gzinflate“? Nie gehört. Ich vermutete nicht zu unrecht, dass hier quasi ein Packer a’la „Zip“ am Werkeln ist, aber ich befragt trotzdem Google und fand folgende Seite, welche auch gleich das von mir bereits vermutete base64-Gedöns beinhaltete:

Wie ich es mir schon dachte, könnte genau das auf „meinen Salat“ zutreffen. Ich wähnte mich wohl nicht zu Unrecht auf der richtigen Spur. Noch eine Info zu ‚gzinflate‘: Diese Funktion dekomprimiert eine Zeichenkette, die mit dem DEFLATE Kompressions Algorithmus komprimiert wurde.

Es war jetzt klar, dass der Rest der obigen Zeichenkette wohl das eben aufgezeigte „base64_decode“ beinhalten würde, was ich nach einer kurzen Stichprobe auch bestätigt fand.

Aus meinem mysterösen Skript wurde langsam etwas lesbares …

Die \x29 machen am Ende die Klammern wieder zu und \x3B ist das abschließende Semikolon, womit dann ein korrekter und funktionsfähiger PHP-Code entstanden ist.

Fassen wir kurz zusammen: Das mir untegejubelte Skript beinhaltet Base64-Kodierten, gepackten Code, der in maskierte Befehle eingebettet wurde, um sein Auffinden zu erschweren. Raffiniert!

Jetzt wusste ich zwar, was das alles sollte, aber was es genau sollte wußte ich immer noch nicht.

Und was kommt jetzt raus?
Für den Base64-Teil habe ich eine Webseite, die ich gern nutze: http://www.base64decode.org/. Ich kopierte alles zwischen den beiden einfachen Hochkommas in die Zwischenablage und von dort in das Eingabefeld auf Base64decode.org. Ich drückte den „Decode“-Button und … bekam wieder nur Zeichensalat raus.

Aber war ja auch klar. Das base64-decode war im Programmcode eingebettet in ein gzinflate! Ich musste nun noch zusehen, dass ich das Kauderwelsch „entpackt“ bekomme. Auch hier hilft Google zuverlässig. Auf der ersten Seite, die ich probierte, musste ich den kompletten Code eingeben .. also inklusive dem „eval“ … Das bescherte mir einen freundlichen Klaps der Firewall, die gleich mal zu machte. Letztlich gelangte ich auf den phpdecoder … dort steht u.a.

This tool will attempt to decode any PHP hidden code, including eval(base64_decode, eval(gzinflate, etc.

Very useful for webmasters trying to identify what a specific code is doing (from WordPress themes/plugins or Joomla templates).

Ähm … ja … genau das was ich suche. Ich schnappte mir meinen „Code“, verfrachtete ihn das Eingabefeld und ließ die Seite mal arbeiten … und ….
BINGO!

Hätte ich diese Seite gleich gefunden, wäre mir einiges an Arbeit erspart geblieben. Aber ich hätte wohl auch viel weniger Spaß an der Sache gehabt.

Was meine Augen jetzt erblickten, war im ersten Überfliegen ein komplettes Webinterface mit Formularen und AJAX und allem drum und dran, um nach Herzenzlust in meinen Files herumzustöbern. Das Tor zu meinen Internetseiten stand sperrangelweit offen. Der Super-GAU.
Ein kleiner Auszug sei erlaubt …. „lustig“, oder?

War das schon alles?
Als Leerstück behalte ich das Script natürlich im Original bei mir. Hier posten werde ich es nicht, obwohl man sich das Teil sicher auch sonstwo herunterladen kann. Ich forschte noch ein wenig weiter und stieß auf eine neue Bezeichnung für derlei Machwerk, die ich noch nicht kannte: RAT. RAT bedeutet Remote Administration Tool. Und genau das ist es ja auch strenggenommen: ein simples, aber wohl auch gut ausgefeiltes Administrationstool.

Ganz genau habe ich das Skript noch nicht auseinandergenommen. Aber die Webhistorie zeigt, dass mit derlei Backdoors, Trojanern, RATs und wie auch immer sie heißen mögen, sehr viel möglich ist auf fremden Webseiten. Glücklicherweise sind die jeweiligen Skripts bisher nie aufgerufen worden (wenn ich meine Logfiles richtig analysiert habe).

Ich wurde übermütig und wollte mir das Teil in Aktion ansehen. Ich speicherte den Code in einer normalen PHP-Seite und ludt es per FTP auf eine meiner Webseiten hoch. Ich wollte es, aber …. es ging nicht. Filezilla meldete irgendwelche Probleme. Ich versuchte es noch einmal. Und noch mal auf einem anderen Account. Immer wurde der Upload geblockt.

Keine Minuten später plumpsten zwei Emails in mein Postfach. Der Betreff: „Virenupload verhindert / virus upload prevented“. Aha — wow. So schnell erkannt, dachte ich. In den Mails dann sinngemäß folgender Text:

Es wurde versucht, einen Virus auf Ihren Account xxxxxxxxx hochzuladen. Das System hat diesen Upload verhindert. Ein kurzer Auszug aus dem Logfile mit entsprechender IP-Adresse:

Feb 4 19:20:00 yyyyyy proftpd[24183]: 85.13.xxx.xxx (85.13.xxx.xxx[85.13.xxx.xxx]) – USER xxxxxxx: Login successful.
Feb 4 19:20:00 yyyyyy proftpd[24183]: 85.13.xxx.xxx (85.13.xxx.xxx[85.13.xxx.xxx1]) – mod_clamav/0.11: Virus ‚PHP.Shell-38‘ found in ‚/www/htdocs/xxxxxxxx/seuche/seuche.php‘

Bitte beachten Sie, dass der Upload mit Ihrem FTP-Benutzer xxxxxxxx durchgeführt wurde. Ihre Zugangsdaten wurden also sehr wahrscheinlich von einem Virus oder Trojaner auf einem Ihrer Computer ausgelesen, auf dem die FTP-Zugangsdaten verwendet wurden oder gespeichert sind.
Wenn diese FTP-Zugangsdaten aber in einem CMS auf Ihrem Account gespeichert sind, könnten sie auch dort durch eine Sicherheitslücke ausgelesen worden sein.

Aus diesem Grund haben wir das Passwort des betreffenden FTP-Benutzers xxxxxxxx geändert.

Hammer, oder?
Der Upload per FTP wird jetzt ganz offensichtlich aktiv überwacht und bei Gefahr sofort mit dem Hammer drauf gehauen. Mal davon abgesehen, dass der Upload von gefährlichem „Schadcode“ geblockt wird, erfolgt jetzt zur Sicherheit des Accountinhabers sogleich eine Änderung des FTP-Kennworts. Dieses kann der User ja per Webinterface wieder ändern, aber der Angreifer steht erstmal blöd da, denn das neue Kennwort kann er nicht kennen. Angriff abgewehrt.

Das ging sogar noch weiter. Ich klinkte mich via Web-FTP ein und löschte die gesichterte „Virendatei“ wieder. Ich versuchte, den Upload einer ungefährlichen Datei, was kein Problem darstellte. Also probierte ich es gleich nochmal mit Filezilla und … keine Chance. Nicht mal ein Login war möglich. Auf keinem Account! Nicht bloß auf dem zum Spielen.

Eine Mail an all-inkl.com bestätigte meine Vermutung: durch den wiederholten Versuch, eine verseuchte Datei einzuschleppen, war meine IP-Adresse auf der Blacklist gelandet und wurde von vornherein abgewiesen. Noch eine neue Hürde, welche all-inkl da aufgebaut hat.

Vorläufiges Fazit
Letztlich bin ich froh, dass wohl kein Schaden entstanden ist. Ich werden noch meine anderen Accounts akribisch durchforsten. Was bleibt ist die Frage, warum all-inkl.com so lange nichts von den Viren gemerkt hat (seit 6. Dezember 2013!) und jetzt plötzlich mit brachialer Schutzgewalt zuschlagen kann. Ich fühle ich jetzt gleich sicherer mit meinen Webseiten. Doch – warum war dieses Sicherheitssystem vorher nicht da? Gehört das nicht zum Standard oder musste wirklich erst was passieren? Gute Frage, nächste Frage ….

Das war die Story um meine PHP.Shell-38 – Infektion. Woher der oder die Angreifer meine Zugangsdaten hatten ist bislang nicht geklärt. Ein infiziertes Filezilla erscheint mir jedoch die wahrscheinlichste Ursache zu sein, weshalb ich auch sofort die Kennwörter aus der Installation gekickt habe.

Übrigens noch was: der Zugriff am 6. Dezember 2013 war nicht der einzige Login der Angreifer. Am 22. Januar 2014 waren sie wieder da. Loggten sich ein, spielten den Gag bis zur Gif-Datei durch und verschwanden wieder. Das im Dezember gelegte Kuckucks-Ei wurde nicht angerührt.

Ich werde jedenfalls die kommenden Wochen ein wachsames Auge auf meine Logfiles haben. Das kann ich dir versichern … 🙂

2 Antworten

  1. Akareyon sagt:

    Moin und vielen Dank für die ganze Arbeit!

    Im Großen und Ganzen die selbe Geschichte bei mir. Mail von all-inkl, Achtung Virus. Logdatenanalyse sagt: Zugriff erst auf einen Unteraccount, dann auf den Hauptaccount. Zwei verschieden benamste GIFs über eine Handvoll Ordner verteilt, wo sie aber nicht wirklich vorhanden sind, und dann die systems.php mit dem preg_replace-Gezumpel im Unterordner des Hauptaccounts. Alles so zwischen kurz nach zehn bis halb elf am 6.12., nur von einer anderen IP aus, ansonsten Grabesstille. Wunder, oh Wunder. Mein Windows-Filezilla nehme ich heute Abend nochmal unter die Lupe…

  1. 5. Februar 2014

    […] Hier gehts zu Teil 2 – Trojaner-Alarm: PHP.Shell-38 via FTP eingeschleust […]

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.