Um frühzeitig dahinter zu kommen, ob eine Spamwelle anrollt oder ein neuer Exploit ausgenutzt wird, ist es hilfreich, die Server-Logfiles zu Rate zu ziehen. Wenn auf einmal SQL-Statements oder Javascript-Code oder Verweise auf externe Scripte in Variablen-Werten auftauchen kann man davon ausgehen, dass da gerade jemand versucht, per SQL-Injection, XSS oder sonstwie das Blog zu cracken.
Im Falle von GET Variablen sieht man das noch ganz gut in den Standard-Server Logs, dagegen schweigen sich diese bei POST Variablen über den Inhalt derselben aus.

Will man also Einblick bekommen, mit welchen POST-Variablen das Blog so gefüttert wird, muss man selbst tätig werden. Dafür habe ich mir ein kleines Script gebastelt, das:

  1. Den Post-Request sowie ein paar Informationen, wo er herkommt und wo er hinsoll, in eine Datei schreibt
  2. Mir eine E-Mail mit diesen Informationen schickt

Angeregt wurde das ganze durch die Diskussion über die neuesten WordPress-Exploits bei village-idiot.org. Insbesondere der Ansatz, die Logging-Funktion in die wp-config.php einzubinden, fand ich dort - ich hatte es zunächst in die index.php eingebunden, die aber bei jedem Update aufs Neue geändert werden müsste. Da die wp-config.php in der Regel bei einem Update nicht geändert wird, überlebt die Logging-Funktion also auch künftige Updates.

Ich versuche das hier mal zu skizzieren. Benötigt werden Kenntnisse in PHP, ein Zugang zum Server, der das Ändern von Datei- und Verzeichnisrechten erlaubt und der Zugriff auf ein Verzeichnis ausserhalb der htroot (des Verzeichnisses, welches über das Internet per Browser erreichbar ist).
Das ist nichts für Anfänger!

Schritt 1: Die Log-Datei erzeugen

Auf dem Webserver, möglichst in einem Verzeichnis, das NICHT übers Web erreichbar ist, wird eine leere Datei erzeugt, die der Webserver beschreiben darf (bei mir funktioniert es mit den Dateirechten auf 644). Der Dateiname sollte nicht log.txt oder ähnlich lauten - vor allem nicht, wenn das Logfile in einem übers Web erreichbaren Verzeichnis liegt. In dem Logfile landen eventuell auch sensible Informationen. Wenn man einfach nur alle POST-Requests mitloggt, landen darin auch die Zugangsdaten zum Backend im Klartext. Was es bedeutet, diese in einer Datei, die übers Web erreichbar ist, vorzuhalten, brauche ich wohl nicht zu erklären. Ich sage nur: Ganz schlechte Idee.
Man sollte sich aber auch nicht darauf verlassen, dass die Datei in einem Verzeichnis ausserhalb der htroot sicher ist. Unsichere und/oder schlampig programmierte Scripte in einer anderen Installation auf dem gleichen Server können theoretisch auch den Zugriff auf solche "ausserhalb" liegenden Verzeichnisse ermöglichen. Also: Am Besten wäre, wenn die sensiblen Daten erst garnicht im Logfile auftauchen. Dazu später mehr.

Schritt 2: Datei mit der Logging-Funktion erzeugen

function logpost(mailme='0') {
	//
	$log_abspath = '/absoluter/pfad/zum/log/verzeichnis/';
	$log_filename = 'der.logfile.name';
	//
	$req = $_SERVER['REQUEST_METHOD'];
	$req_file = $_SERVER['SCRIPT_NAME'];
	$req_ip = $_SERVER['REMOTE_ADDR'];
	if ( $req == 'POST' ) {
		if ( strpos($req_file, 'wp-login') === false ) {
			$log = date('d.m.Y, H:i:s').':';
			$log .= "\t".'Post-Request: ';
			foreach ($_POST as $key => $value) {
				$log .= $key.':'.$value.' ';
			}
			$log .= "\t".'Request-Time: '.strftime('%d.%m.%Y, %T',$_SERVER['REQUEST_TIME']);
			$log .= "\t".'Request-Uri: '.$_SERVER['REQUEST_URI'];
			$log .= "\t".'Remote-Adress: '.$req_ip;
			$log .= "\t".'User-Agent: '.$_SERVER['HTTP_USER_AGENT'];
			$log .= "\t".'File-Name: '.$req_file;
			$log .= "\n\n";
			// logfile oeffnen und schreiben und schliessen:
			$handle = fopen($log_abspath.$log_filename,'a+');
			fwrite($handle,$log);
			fclose($handle);
			// mailme?
			if(mailme == 'email')
				$mailheader = 'From: watchdog@deineblog.adresse'."\r\n".'X-Mailer: PHP/'.phpversion();
				mail('deine@email.adresse','Blogname: POST-LOG',$log,$mailheader);
			}
		}
	}
}

So. In dem Script müssen die Zeilen mit den Pfadangaben und Mailadressen natürlich auf die eigene Konfiguration angepasst werden.

Die if-Abfrage if ( strpos($req_file, 'wp-login') === false ) { ... } sorgt dafür, dass Anfragen an die wp-login.php nicht mitgeloggt werden, somit also keine Zugangsdaten in dem Log (oder der Email) auftauchen. Allerdings bekommt man so auch nicht mit, wenn die wp-login.php attackiert wird. Wer das auch mitbekommen möchte, muss diese Abfrage rausnehmen und sollte das Logfile zeitnah ansehen und leeren.

Das Script auf dem Webserver als .php Datei speichern und den Pfad merken, denn der wird im nächsten Schritt benötigt.

Schritt 3: Einbinden und Aktivieren in der wp-config.php

Am Ende der wp-config.php, vor dem schliessenden ?> Tag, wird das Script per include() eingebunden und bei Bedarf mit dem Funktionsaufruf aktiviert. Dabei kann der Parameter "email" verwendet werdem um zu bestimmen, ob eine E-Mail versendet wird oder nicht:

(...)
include('pfad/zur/scriptdatei/scriptname.php');
logpost('email'); // leer lassen, wenn keine e-mail erwuenscht: logpost();

Bitte darauf achten, dass in der wp-content.php keine Leerzeichen oder Zeilenumbrüche vor oder nach den <?php und ?> Tags stehen - ansonsten gibt es Fehler und Warnungen mit "blah blah Headers already sent".

Das Logfile sollte regelmässig gelesen und geleert werden. POST Parameter können sehr viel Daten enthalten und das Log so recht schnell ziemlich aufblasen. Ausserdem (siehe Kommentar) besteht die Gefahr, dass durch einen gezielten Angriff mit grossen POST Request-Daten das Log so aufgeblasen wird, dass die Speicherlimits vom Hostingvertrag überschritten werden, und man entweder die Website abgeklemmt bekommt oder nachzahlen darf!

Weitere Überlegungen, die in das obige Script noch nicht mit einbezogen sind:
- Man könnte sich die User und Passwortdaten verkürzt ausgeben lassen (PW****)
- Um ein Aufblasen der Log-Datei zu verhindern, könnte man die Werte der POST-Variablen mit strlen(); checken und bei Überschreiten einer bestimmten Länge verkürzt ausgeben.

Disclaimer

War ja klar, dass der kommt, nicht wahr? :-)
Also, ich übernehme keinerlei Haftung für das Script und eventuelle Schäden, die dadurch ausgelöst werden. Ich bin kein professioneller Programmierer und das Script ist lediglich in meiner Installation getestet. Auf die Gefahren die mir bewusst sind, habe ich im Beitrag hingewiesen, aber wahrscheinlich gibt es noch viel mehr, die mir nicht bewusst sind - ich denke es gibt einen guten Grund, warum POST requests nicht in den Standard-Serverlogs mitgeschrieben werden.
Wer sich unsicher ist, was das alles soll, sollte die Finger davon lassen. Alle anderen sollten das auch nicht ständig aktiviert lassen, sondern nur bedarfsweise, wenn man eben mal sehen möchte, was da so alles an das Blog herangetragen wird.