[BlueOnyx:10186] Re: Trojans and backdoors? - Suggested BlueOnyx improvement

Michael Stauber mstauber at blueonyx.it
Thu Apr 19 02:14:50 EDT 2012


Hi Ken,

> php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f 
> the-admin-username-here"

After a bit of experimenting I found this as well:

php_admin_flag mail.add_x_header On

It will add an "X-PHP-Originating-Script:" into the header of emails sent by 
PHP. Something like this:

X-PHP-Originating-Script: 502:mail.php

That then tells us that the email was sent by the script "mail.php" owned by 
the user with the ID 502. All in all that helps a little. But not much - that 
is for sure. Because if suPHP is off, that user might as well be "apache" and 
then we have to search all over the place again, as this script could be on 
any site.

There is an unofficial PHP patch which extends the mail() function with much 
more detailed forced headers that you can't turn off. These headers then give 
us the full path to the script in question and also tell us which remote IP 
address called the script that generated the mail. Which is very useful. But 
it requires a custom built PHP. And it discloses too much information about 
the environment of the server to any recipient of such emails. 

After trying a couple of different approaches I found something that is as 
simple as it is elegant. And no, it wasn't my own idea. It's a slightly 
modified approach that Philip Iezzi initially blogged about in 2009.

I comitted it to SVN, but it's not on YUM yet, as I want to give it some 
thorough testing before release:

See:	http://devel.blueonyx.it/trac/changeset/874/

What it does:

Two new files are added:

/usr/sausalito/configs/php/set_php_headers.php
/usr/sausalito/sbin/phpsendmail

The first one is a small PHP script with this in it:

<?php
putenv("_HTTP_HOST=".@$_SERVER["HTTP_HOST"]);
putenv("_SCRIPT_NAME=".@$_SERVER["SCRIPT_NAME"]);
putenv("_SCRIPT_FILENAME=".@$_SERVER["SCRIPT_FILENAME"]);
putenv("_DOCUMENT_ROOT=".@$_SERVER["DOCUMENT_ROOT"]);
putenv("_REMOTE_ADDR=".@$_SERVER["REMOTE_ADDR"]);
putenv("_SOWNER=". at get_current_user());
?>

The second one is a simple shell script. It logs PHP mail related activity to 
/var/log/maillog in a format like this:

Apr 19 01:35:01 5108r root: sendmail-wrapper-php: site=5108r1.smd.net, 
client=10.1.128.1, 
script=/home/.sites/28/site1/web/mailtest/mailtest/mail.php, uid=502, 
user=site1_admin

Next the php.ini files (either /etc/php.ini or your third party PHP's php.ini 
file) are modified and the following three lines are added or changed:

mail.add_x_header = On
sendmail_path = /usr/sausalito/sbin/phpsendmail
auto_prepend_file = /usr/sausalito/configs/php/set_php_headers.php

This also goes into the separate php.ini's of suPHP enabled sites.

Finally the following three lines are added to the Apache Vhost containers of 
any sites that have PHP or suPHP enabled:

php_admin_flag mail.add_x_header On
php_admin_value sendmail_path /usr/sausalito/sbin/phpsendmail
php_admin_value auto_prepend_file 
/usr/sausalito/configs/php/set_php_headers.php

So what does it all do?

The 'auto_prepend_file' parameter will trick PHP into prepending any executed 
PHP script with the code from /usr/sausalito/configs/php/set_php_headers.php. 
We use this 'auto_prepend_file' to get some extended information about the IP 
accessing the script, the path to the script, the scripts name and owner. This 
information is stored in the protected envelope variables.

When a PHP script now tries to send an email using the PHP mail() function, 
that function works as it normally does. The email is generated the same way 
as before. But instead of passing the command to send the email directly to 
/usr/sbin/sendmail, we take a little round about through the shell script 
/usr/sausalito/bin/phpsendmail, which has this code in it:

--------------------------------------------------------------------------------------------------
#!/bin/sh

# This is a wrapper that wraps around the PHP mail() function. 
# It logs some useful extra variables to /var/log/maillog.
# These give us a good indication about which PHP script is
# sending emails:

/usr/bin/logger -p mail.info sendmail-wrapper-php: site=${_HTTP_HOST}, 
client=${_REMOTE_ADDR}, script=${PWD}${_SCRIPT_NAME}, uid=${UID}, 
user=${_SOWNER}
/usr/sbin/sendmail -t -i $*
--------------------------------------------------------------------------------------------------

The first thing this script does, is to log the gathered information about the 
PHP script into /var/log/maillog. The last thing it does is to simply pass the 
email on to /usr/sbin/sendmail.

Last and least there is the PHP parameter 'mail.add_x_header' which we set to 
'On', too.

That includes a line like this in every email header that PHP's mail() 
function sends:

X-PHP-Originating-Script: 502:mail.php

The '502' in the above examle tells us that the numeric user ID of the owner 
of the script was '502'. After the colon we see the name (just the name - not 
the path!) of the offending script. In this case here 'mail.php'.

Now if we have such an email in front of us and would need to find out which 
site and user the email really came from on our server, we would need to take 
a look at /var/log/maillog like this:

cat /var/log/maillog|grep uid=502|grep mail.php

So we grep for the numeric user ID (502 in this case) and the name of the 
script (mail.php) that was listed in the "X-PHP-Originating-Script:" header of 
said email.

[root at 5108r php]# cat /var/log/maillog|grep uid=502|grep mail.php
client=10.1.128.1, 
script=/home/.sites/28/site1/web/mailtest/mailtest/mail.php, uid=502, 
user=site1_admin
Apr 19 01:10:18 5108r root: sendmail-wrapper-php: site=5108r1.smd.net, 
client=10.1.128.1, 
script=/home/.sites/28/site1/web/mailtest/mailtest/mail.php, uid=502, 
user=site1_admin
Apr 19 01:35:01 5108r root: sendmail-wrapper-php: site=5108r1.smd.net, 
client=10.1.128.1, 
script=/home/.sites/28/site1/web/mailtest/mailtest/mail.php, uid=502, 
user=site1_admin

Voila! 

Or if we wanted to see just the log entries of all PHP related email activity, 
we could use this command:

cat /var/log/maillog|grep sendmail-wrapper-php

The nice thing here is that the email header doesn't really disclose much 
useful information to anyone who should rather be left in the dark. But it 
helps us tremendously to find any offender we're looking for in the now 
slightly extended logging in /var/log/maillog.

The wrapper around Sendmail (/usr/sausalito/bin/phpsendmail) requires neither 
setuid nor any extended privileges and there is nothing in it that could be 
exploited.

The only "nasty" part is that we now use 'auto_prepend_file' to stick our 
small /usr/sausalito/configs/php/set_php_headers.php in front of every 
executed PHP script. However, just extending the envelope variables a bit 
(like it does) will hardly do any harm to scripts.

Unless someone has a better idea or finds a good reason why this might be a 
bad idea, I'll push the update out after some further testing.

-- 
With best regards

Michael Stauber


More information about the Blueonyx mailing list