It does not seem to exist any logging of the PHP function calls, but it does exist a way to hook and log any HTTP POST request the website receives, and logging includes POST data. That way you get logs even before fopen is called, so you easily find out the compromised file. The strategy is:
- enable POST data logging
- wait for the malicious files to appear
- look in the logs to find the compromised PHP scripts
Now each point in detail.
1) Enable POST data logging
First of all you need a PHP script that logs HTTP POST data when called. It isn't really hard to write one from scratch, but it's even easier to use an existing one that I slightly modified to make it more readable and secure:
<?php
if ( isset($_POST) && is_array($_POST) && count($_POST) > 0 )
{
$log_dir = dirname( __FILE__ ) . '/logs/';
$log_name = "posts-" . $_SERVER['REMOTE_ADDR'] . "-" . date("Y-m-d-H") . ".log";
$log_entry = gmdate('r') . "\t (local time: " . date('r') . ")\t" . $_SERVER['REQUEST_URI'] . "\n";
foreach ($_POST as $k => $v)
{
if ( $k == "pwd" || $k == "passwd" || $k == "password" || $k == "pass" || $k == "secret" )
{
$v = "*******";
}
$log_entry .= $k." => ".$v."\n------\n";
}
$log_entry .= "\n///////////// END OF POST DATA /////////////\n\n\n";
$fp=fopen( $log_dir . $log_name, 'a' );
fputs($fp, $log_entry);
fclose($fp);
chmod($log_dir . $log_name, 0600);
}
?>
Create two directories in your website root folder, such as postdata/logs
, save the script as postdata/logger.php
and set owners and permissions as appropriate for your server:
root@myserver:/home/user/htdocs/www.example.com# mkdir -p postdata/logs
root@myserver:/home/user/htdocs/www.example.com# vi postdata/logger.php
root@myserver:/home/user/htdocs/www.example.com# chown -R user postdata
root@myserver:/home/user/htdocs/www.example.com# chmod -R a-rw postdata
root@myserver:/home/user/htdocs/www.example.com# chmod -R u+r postdata
root@myserver:/home/user/htdocs/www.example.com# chmod u+w postdata/logs
Now let's tell PHP it must run that script before anything else. You can do so by adding
php_value auto_prepend_file /home/user/htdocs/www.example.com/postdata/logger.php
to your website .htaccess
file, but, since I'm running PHP-FPM which ignores .htaccess
, I add that configuration to my PHP-FPM pool instead:
echo 'php_value[auto_prepend_file] = /home/user/htdocs/www.example.com/postdata/logger.php' >> /etc/php/7.1/fpm/pool.d/user.conf
and then I restart the PHP-FPM daemon.
2) Wait for the malicious files to appear
This is usually just a matter of monitoring your server. Be it by having Munin
to automatically warn you when something seems wrong, or by manually using tools like find
to look for recently changed files, or mailq
and so on. For example
$ find . -mtime -1 -iname \*.php
will list all PHP files that have been modified in the last 24 hours. Please note that automatic updates your CMS might do are legit and they do modify PHP files, so those may count as false positives.
3) Look in the logs to find the compromised PHP scripts
cd /home/user/htdocs/www.example.com/postdata/logs
less posts-10.7.33.101-2018-05-01-00.log
If logged POST data look weird, that's probably a posting to the compromised script. You can find the script name in the first line of the log file:
$ head -n 1 posts-10.7.33.101-2018-05-01-00.log
Mon, 30 Apr 2018 22:28:40 +0000 /wp-content/plugins/one-page-navigator/admin/bsf-core/irclzkpf.php
Bingo! That was the malicious script in my case. I'm not sure there aren't any other malicious or original but compromised scripts in the website, but I just leave step 1 in place and all the rest is a piece of cake.
Please note that removing/editing that script is not enough, because by now the attacker has already used it to compromise other scripts in the site. However it's quite easy to find those by looking for base64_decode
function calls or \\x.*\\x.*\\x.*\\x.*\\x.*\\x
charater sequences. I think even the scan function of WordFence can find them, just in case you're running Wordpress like me.
And, while we are at it, please note that the POST data log files will contain any user credentials in plain text, except a few common cases of password fields, so my version of the logger script uses chmod
to restrict access to the log files, but that falls short of any decent security measure. Take your own steps to limit access to the POST data log files and delete them right away as soon as you are finished with them.