Sharing is Caring


Huge increase in WordPress xmlrpc.php POST requests

WordPress XMLPRC

WordPress xmlprc.php DDoS and brute-force attacks. How to identify, block, mitigate and leverage these xmlrpc.php scans, brute-force, and user enumeration attacks on WordPress sites… Secure WordPress xmlprc.php interface and reduce service disruption.

WordPress xmlrpc.php attack characteristics

WordPress <= 3.9.2 XML-PRC brute-force.

All attacked WordPress sites share the same characteristics: HTTP POST requests to /xmlrpc.php, all with an HTTP_USER_AGENT Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5), by random IP addresses (probably hacked and part of a botnet).

As shown below:

2014-07-07 09:16:59 77.94.248.174 POST /xmlrpc.php - 80 - 
  203.126.164.157 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  www.example.com 200 0 64 0 471 32901
2014-07-07 09:16:59 77.94.248.174 POST /xmlrpc.php - 80 -
  122.167.183.21 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  www.example.com 500 0 64 0 471 30108
2014-07-07 09:17:00 77.94.248.174 POST /xmlrpc.php - 80 - 
  39.51.10.73 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  www.example.com 200 0 64 0 471 32292
2014-07-07 09:17:00 77.94.248.174 POST /xmlrpc.php - 80 - 
  94.67.115.29 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  www.example.com 200 0 64 0 471 32105
2014-07-07 09:17:02 77.94.248.174 GET / - 80 - 
  203.126.164.157 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  www.example.com 500 0 64 0 145 30405
2014-07-07 09:17:02 77.94.248.174 GET / - 80 - 
  76.71.193.113 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  www.example.com 500 0 64 0 145 30155

Notice the POST payload is about 10 times bigger than the wp.getUsersBlogs bruteforce attacks mentioned further down below.

The attacks come at such high rates that the webservers sometimes return HTTP 500 Service Unavailable error messages for those websites. How to reduce this service disruption is explained in the next section. Attacked websites don’t run the same WordPress version. I’ve seen these attacks on WordPress versions 3.0.2 (*sigh* yep…) through 3.9.1.

About WordPress XML-RPC support
WordPress uses an XML-RPC interface. With WordPress XML-RPC support, you can post to your WordPress blog using many popular Weblog Clients. The XML-RPC system can be extended by WordPress Plugins to modify its behavior. All built-in XML-RPC methods use the action xmlrpc_call, with a parameter equal to the method’s name (e.g., wp.newPost). The action is performed after the user has been authenticated but before the rest of the method logic begins.

2014-07-07 10:46:23 77.94.250.138 POST /xmlrpc.php - 80 - 
  93.174.93.204 Mozilla/4.0+(compatible:+MSIE+7.0;+Windows+NT+6.0) - 
  www.example.net 200 0 64 0 417 359
2014-07-07 10:55:59 77.94.250.138 POST /xmlrpc.php - 80 - 
  93.174.93.204 Mozilla/4.0+(compatible:+MSIE+7.0;+Windows+NT+6.0) - 
  www.example.net 200 0 64 0 417 343
2014-07-07 11:01:28 77.94.250.138 POST /xmlrpc.php - 80 - 
  93.174.93.204 Mozilla/4.0+(compatible:+MSIE+7.0;+Windows+NT+6.0) - 
  www.example.net 200 0 64 0 417 406
2014-07-07 11:06:57 77.94.250.138 POST /xmlrpc.php - 80 - 
  93.174.93.204 Mozilla/4.0+(compatible:+MSIE+7.0;+Windows+NT+6.0) - 
  www.example.net 200 0 64 0 417 343

As you can see, this XML-RPC payload is much smaller, and it’s always the same IP address. The IP address is known to be a comment spammer, so I suspect this to be a different -spamming- attack. But I’ll keep an close eye on it.

How To Log XMLRPC.php POST Data to a Logfile

Log WordPress XML-RPC brute-force data to a logfile for analysis and inspection: on a number of WordPress blogs I run, I wanted to log the HTTP POST information send to xmlrpc.php. Just to see what is POST’ed.

You may also like:  Handig: GMER - Rootkit Detector and Remover

I made a quick ‘n dirty logger in WordPress’ xmlrpc.php file, it’s ugly… Open up xmlrcp.php, and add on line 2, after the PHP open tag <?php:


// Quick 'n dirty XMLRPC logger
$xmlrpc_log = "../database/xmlrpc_log.txt";
$text = "";
if ( $_SERVER['REQUEST_METHOD'] === 'POST' )
{
	foreach ( $_POST as $key => $value ) {
		$text .= $key ." : ". $value ."\r\n";
	}
	if( file_exists( $xmlrpc_log ) && is_writable( $xmlrpc_log ) )
	{
		// our XMLRPC "honeypot" logfile is writeable, let's continue
		$f = fopen( $xmlrpc_log,"ab" );
		fwrite( $f, $text );
		fclose( $f );
		clearstatcache();
	}
}

Now we wait…

XMLRPC-logger result
The result of the above XMLRPC-logger is quite interesting. It appears it could be a WordPress user blog enumeration scan. On one of the websites I enabled the logger, I noticed HTTP POST requests in the HTTP logfile:

2014-07-09 09:51:28 77.94.248.175 POST /xmlrpc.php - 80 - 
  84.40.123.39 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 500 202
2014-07-09 09:51:29 77.94.248.175 POST /xmlrpc.php - 80 - 
  182.186.89.187 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 503 592
2014-07-09 09:51:42 77.94.248.175 POST /xmlrpc.php - 80 - 
  77.31.97.165 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 502 249
2014-07-09 09:51:45 77.94.248.175 POST /xmlrpc.php - 80 - 
  162.198.57.86 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 499 343
2014-07-09 09:51:52 77.94.248.175 POST /xmlrpc.php - 80 - 
  213.233.104.10 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 515 265
2014-07-09 09:52:05 77.94.248.175 POST /xmlrpc.php - 80 - 
  112.135.143.66 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 501 390
2014-07-09 09:52:05 77.94.248.175 POST /xmlrpc.php - 80 - 
  109.93.159.232 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 503 234
2014-07-09 09:52:08 77.94.248.175 POST /xmlrpc.php - 80 - 
  111.68.38.156 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 503 686
2014-07-09 09:52:15 77.94.248.175 POST /xmlrpc.php - 80 - 
  181.188.88.148 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 64 0 501 374
2014-07-09 09:52:16 77.94.248.175 POST /xmlrpc.php - 80 - 
  96.36.130.121 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 501 265
2014-07-09 09:52:18 77.94.248.175 POST /xmlrpc.php - 80 - 
  176.73.72.206 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 501 218
2014-07-09 09:52:36 77.94.248.175 POST /xmlrpc.php - 80 - 
  196.29.199.46 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 502 358
2014-07-09 09:52:41 77.94.248.175 POST /xmlrpc.php - 80 - 
  121.54.54.50 Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) - 
  example.com 200 0 0 588 503 873

Notice that, in this case, the POST payload is much smaller, so this could be the result from a different type of attack. The logged POST data is:

<?xml_version"1.0" encoding="iso-8859-1"?>
<methodCall>
  <methodName>wp.getUsersBlogs</methodName>
  <params>
    <param>
      <value>
        <string>example_com</string>
      </value>
    </param>
    <param>
      <value>
        <string>nickie</string>
      </value>
    </param>
  </params>
</methodCall>
<?xml_version"1.0" encoding="iso-8859-1"?>
<methodCall>
  <methodName>wp.getUsersBlogs</methodName>
  <params>
    <param>
      <value>
        <string>example_com</string>
      </value>
    </param>
    <param>
    <value>
      <string>nicola</string>
    </value>
    </param>
  </params>
</methodCall>
<?xml_version"1.0" encoding="iso-8859-1"?>
<methodCall>
  <methodName>wp.getUsersBlogs</methodName>
  <params>
    <param>
      <value>
        <string>example_com</string>
      </value>
    </param>
    <param>
      <value>
        <string>nick</string>
      </value>
    </param>
  </params>
</methodCall>
<?xml_version"1.0" encoding="iso-8859-1"?>
<methodCall>
  <methodName>wp.getUsersBlogs</methodName>
  <params>
    <param>
      <value>
        <string>example_com</string>
      </value>
    </param>
    <param>
      <value>
        <string>nicolas</string>
      </value>
    </param>
  </params>
</methodCall>
<?xml_version"1.0" encoding="iso-8859-1"?>
<methodCall>
  <methodName>wp.getUsersBlogs</methodName>
  <params>
    <param>
      <value>
        <string>example_com</string>
      </value>
    </param>
    <param>
      <value>
        <string>nico</string>
      </value>
    </param>
  </params>
</methodCall>
<?xml_version"1.0" encoding="iso-8859-1"?>
<methodCall>
  <methodName>wp.getUsersBlogs</methodName>
  <params>
    <param>
      <value>
        <string>example_com</string>
      </value>
    </param>
    <param>
      <value>
        <string>nicole1</string>
      </value>
    </param>
  </params>
</methodCall>
[...]

wp.getUsersBlogs is used to retrieve the blogs of the users.

Mitigate WordPress XML-RPC attacks and wp.getUserBlogs enumeration scans – How to Disable XML-RPC in WordPress

How to mitigate attacks and degraded web server performance…

You may also like:  Multiple critical vulnerabilities in PHP File Manager

Unfortunately you can’t just simply remove the WordPress xmlrpc.php file. It should be possible to mitigate against this wp.getUserBlogs enumeration scan with a filter, which we put in our THEME functions.php file. Basically it’s the same as the filter below to disable the pingback.ping function.

Here is an example of removing wp.getUsersBlogs method:

function saotn_remove_xmlrpc_getUsersBlogs( $methods ) {
  unset( $methods['wp.getUsersBlogs'] );
  return $methods;   
}
add_filter( 'xmlrpc_methods', 'saotn_remove_xmlrpc_getUsersBlogs');

But of course HTTP POST requests on xmlrpc.php will still come in.

Reduce web server load caused by XMLRPC.php attacks on websites

The performance of a web server might severely degrade when you host multiple WordPress sites that are under attack. Therefore we need to take action to reduce the disturbance caused by these attacks and the inconvenience for other sites. More than one action to take is possible and recommended.

Update WordPress – security release 3.9.2 fixes XML-RPC DoS

Update 2014-08-07: Both WordPress and Drupal released security updates to fix an XML-RPC DoS vulnerability in the XML-RPC implementation. WordPress 3.9.2, Drupal 7.31 and Drupal 6.33 fixes this severe XML-RPC Denial of Service (DoS).

Disable WordPress wp_cron in wp-config.php

A good starting point in reducing the service disruption is to disable WordPress’ WP_CRON functionality. The wp_cron.php file is executed after each HTTP request and thus it’s executed a lot. This is a drain on your database; it makes an extra database connection for each time it’s executed.

Open up your wp-config.php file and add:

define( 'DISABLE_WP_CRON', 'true' );

While you’re at it, verify WordPress’ WP_DEBUG is disabled too: define('WP_DEBUG', false);

Another good method to reduce server loads during an attack is to optimize WordPress wp_options table and autoload feature. This micro-optimization retrieves autoloaded options much faster using less resources.

How to Disable XMLRPC.PHP in WordPress Completely

You can disable the XML-RPC functionality in WordPress by adding to your theme’s functions.php file:

add_filter( 'xmlrpc_enabled', '__return_false' );

Disable only XMLRPC pingback functionality

Another action is to disable WordPress’ XMLRPC pingback function. You can achieve this by adding the following filter to your THEME’s functions.php file:

function saotn_remove_xmlrpc_pingback( $methods ) {
    unset( $methods['pingback.ping'] );
    return $methods;   
}
add_filter( 'xmlrpc_methods', 'saotn_remove_xmlrpc_pingback' );

Deny WinHttpRequest User-Agent in .htaccess

We don’t want shady user-agents requesting information on our website. Since this attack on mulitple sites has in common that the User-Agent is always Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5), I believe it’s wise to block this User-Agent on the website under siege.

Add to your .htaccess file:

RewriteCond %{HTTP_USER_AGENT} .*WinHttp.WinHttpRequest.* [NC]
RewriteRule .* - [F,L]

Remove WordPress spam comments and disable WordPress comments

It is recommended to check your WordPress database for spam comments, and to delete spam comments if they are present. The larger your WordPress MySQL database is, the bigger the disturbance. When your WordPress website is under attack, quickly disable WordPress comments on all posts, for the same reason. You can re-enable them later.

You may also like:  Arbor whitepaper: Anatomy of a Botnet

WordPress .htaccess protection from XMLRPC-, comment- and trackback spam

when the visitor isn’t coming from your website as referer

It has always been important to protect your WordPress site from comment- and trackback spammers, and to block spammers manually if necessary. Especially if they don’t come from your website (e.g. don’t have your domain name as referer). To block all POST requests on xmlrpc.php, wp-comments-post.php and wp-trackback.php, without your domain name as referrer, add to your .htaccess file:

RewriteCond %{REQUEST_METHOD} POST [NC]
RewriteCond %{REQUEST_FILENAME} (xmlrpc|wp-comments-post|wp-trackback)\.php [NC]
RewriteCond %{HTTP_REFERER} !^http://www.example.com [NC]
Rewriterule .* - [F,L]

A fast and easy method is to secure WordPress with a captcha on comment- and log in forms.

IIS requestFiltering, protect and deny access to xmlrpc.php, wp-comments-post.php and wp-trackback.php

The <denyUrlSequences> element contains a collection of <add> elements that specify sequences of URL characters that IIS will deny, which helps prevent URL-based attacks on the Web server. Access to xmlrpc.php on IIS web servers can be denied with a requestFiltering rule. Just add a denyUrlSequences:

<security>
  <requestFiltering>
    <denyUrlSequences>
      <add sequence="xmlrpc.php" />
      <add sequence="wp-comments-post.php" />
      <add sequence="wp-trackback.php" />
    </denyUrlSequences>
  </requestFiltering>
</security>

When request filtering blocks an HTTP request because of a denied URL sequence, IIS 7 will return an HTTP 404 error to the client and log the following HTTP status with a unique sub status that identifies the reason why the request was denied.

Yes, the point of XMLRPC.php is for remote communiation, but we don’t want that now during these attacks.

The Internet Storm Center report

The Internet Storm Center (ISC) also reports on this WordPress brute force attack via wp.getUsersBlogs.

WordPress 3.9.2 security release fixes XML-RPC DoS

Update 2014-08-07: WordPress and Drupal security updates fixes XML-RPC DoS

XML-RPC Brute-force amplification attacks through WordPress xmlrpc.php

Just a small note: Sucuri writes about ongoing amplified brute-force attacks through the WordPress xmlrpc.php file. Attackers managed to find a way to send a brute-force attack, trying multiple (tens or hundreds) username/password combinations within one request. This way, an XML-RPC brute-force attack might stay under the radar of ordinary Web Application Firewalls or rate-limiting settings.

featured image (photo) credit: pedro mg via photopin cc

About the Author J. Reilink

My name is Jan. I am not a hacker, coder, developer, programmer or guru. I am merely a system administrator, doing my daily thing at Vevida in the Netherlands. With over 10 years of experience, my specialties include Windows Server, IIS, Linux (CentOS, Debian), security, PHP, websites & optimization.

follow me on:

Did you find this post excellent, helpful or informative?



Has this post saved you time, helped you solve a problem? Or do you think Saotn is just awesome? Then why not support us and make a small, one-time, donation?

A small donation supports us in research time, hosting costs, and growth.
PayPal Donate
Please buy me a cup of coffee ($2.5) to support these articles and posts.
Or use this link to enter your own donation amount. Thank you!


  • Claush

    I’v been hit with the same today on several wordpress blogs – same user agent and hit on xmlrpc.

    Appreciate your quick temp fixes to hold the attacks down – hope you update if you get more information on the matter.

  • Hi Claush,

    Thank you for your comment. Great to hear the quick temp fixes were enough to reduce the impact. Keep an eye out on your HTTP log files for new User-Agent strings.

    I’ll update the post when (if) more information comes available.

  • nick s

    We’re seeing a different xmlrpc.php attack alongside this one: not massively distributed, like the WinHttp.WinHttpRequest.5 attack, but instead coming out of 17 Google cloud IPs with no UA at all: http://pastebin.com/j2mY4suD

  • Interesting Nick, thanks. I’ll see what I can come up with in our archived web server logs tomorrow.

  • I’ve updated this post with some new information

  • Pingback: WordPress Sites Seeing Increased Malware, Brute Force Attacks This Week : Web & Search Engine Optimizers : RippleSmith Web Optimization Services()

  • zxq9

    Any resolution or news?

    This month I’m starting to get a trickle (thousands, not millions) of requests to xmlrpc.php from Chinese servers. I’m puzzled by the lack of volume, unless my host is doing something to mitigate known bad traffic for me (which is rather likely, actually). Is there any new news on xmlrpc issues in WordPress that’s come out in the last few weeks? It could just be probes looking for vulnerable versions, of course, and that might explain the lack of volume.

    Thanks for the detailed post.

  • I’m afraid I don’t have any news on this matter. I still see xmlrpc.php POST request coming by on websites on the web servers I administer, but not at such rates as when I made this blog post. If it’s doable you could try to log some of the xmlrpc requests to a log file, and it’s very well possible your hosting provider has evasive filters in place.

  • sanjay

    Thank you very much for this solution

  • Pingback: Una batalla ganada al spam | Rompiendo dicotomía()

  • Pingback: Stopping WordPress /xmlrpc.php Apache requests with UFW on Ubuntu – the mergy notes()

  • Mike

    In case you are not aware (sorry if you already know this), but XMLPRC is used for posting content remotely. The xmlrpc.php file is what WordPress uses to allow you to post remotely.

    As you know, one of the things we all love about WordPress is how easy it is to create new websites and to manage the content. These are the very same reasons why hackers also love WordPress.

    If you are not posting comments to your website remotely, one of the quickest way to get yourself out of this situation is to rename the xmlrpc.php file to some fictitious name. Make sure you change the file type to anything other than “.php.” This way, you will remove the possibility that the server may accidentally run the code.

    If you are doing posts remotely, here’s some code you can add to your .htaccess file:

    order deny,allow
    deny from all
    allow from 123.456.789.123 allow {where “123.456.789.123” is the IP address of the computer that can use xmlrpc.pgp}

    WordPress has a bunch of security holes and we have been victimized many times. I a solution that so far has helped me secure our sites more than anything else we have tried.

    Here is the link ==> http://jvz8.com/c/9278/20094

    Hopefully, WordPress will not open up new holes with the next WP update.

  • Thanks for posting this although for me the attacks still seemed to be coming somehow.
    What worked for me was to add the following line to the .htaccess file:
    Redirect 301 /xmlrpc.php http://127.0.0.1

    I found the information here:
    http://www.linuxbabu.net/2014/07/wordpress-xmlrpc-php-attack/

    This stopped the attack with the added bonus that the attackers are now attacking themselves as 127.0.0.1 redirects back to the requester.

  • Hi Robin, thank you for your comment, nice addition!

    Most actions against this xmlrpc.php abuse are aimed at having at least some XMLRPC functionality left on your site. If you redirect all requests on /xmlrcp.php to the attackers localhost (which is fun), you can also simply remove the xmlrpc.php file or prohibit the requests, either with

    RewriteCond %{REQUEST_FILENAME} xmlrpc\.php [NC]
    Rewriterule .* - [F,L]

    or

    RewriteCond %{REQUEST_URI} ^/xmlrpc\.php [NC]
    RewriteRule .* - [L]