Track down a rogue php email script
I've been asked again how to track down a php script abused by spammers on a
standard LAMP platform running apache and mod_php. So here it goes.
The scenario
It's 2007, a good 10 years of poor php applications and exploits on the record, but still lots of people are running VPS with apache and mod_php poorly configured, no suExec, no chroot... you got the picture. In the standard LAMP platform apache is configured to run as www-data or similar, so all the vhosts look the same and if someone abuses a script it's almost impossible to tell which vhost, but most important which script (altho in some cases a bit of guesswork is enough).
The solution
The easiest way to find which script is sending out spam emails is a combination of php settings and wrapper scripts. The php's mail function invokes sendmail so what one can do, which is also common practise to avoid such problems, is to write a sendmail wrapper. Sendmail here has to be read as either the sendmail daemon or a wrapper that all MTAs ship for compatibility with quite a few applications expect to be available in path.The wrapper can be in any language you like, and at its core it should simply read the message from stdin and call the real sendmail binary to send the email. Around that you can add all the kind of logging necessary to find out the path and name of the script invoking it, generally dumping the environment variables will be more than sufficient. You also need to set sendmail_path in your php.ini to point to the wrapper.
But if you're running mod_php the env var will be pretty much empty, or not enough to track down the rogue script. The solution is to use the auto_append_file php's setting. From the manual:
auto_append_file string Specifies the name of a file that is automatically parsed after the main file. The file is included as if it was called with the require() function, so include_path is used. The special value none disables auto-appending.So by creating an auto_append.php, or however you want to call it, and defining it in php.ini as described above, you can have code executed along with any php script and use it to populate the environment variable with useful information. An example:
putenv(’HTTP_HOST=’. $_SERVER[’HTTP_HOST’]); putenv(’SCRIPT_NAME=’ . $_SERVER[’SCRIPT_NAME’]); putenv(’REMOTE_ADDR=’ . $_SERVER[’REMOTE_ADDR’]);Doing so makes it straightforward to find out the fault.