How to: Protect WordPress from brute-force XML-RPC attacks
Table of Contents
The WordPress XML-RPC API has been under attack for many years now. Back in August 2014, WordPress released version 3.9.2, fixing a possible denial of service issue in PHP’s XML processing. There are brute-force amplification attacks, reported by Sucuri, and so on. So, how do you protect WordPress from xmlrpc.php attacks, but still being able to use (some of) its functionality like Jetpack? This post gives you some insight.
The problem: during a brute-force attack, HTTP requests keep coming in, knocking down web servers due to the sheer number of HTTP requests for /xmlrpc.php, and the increasing number of running PHP processes. This often consumes all available CPU and memory: a typical xmlrpc.php attack characteristic.
You want to protect your website and somehow block requests to xmlrpc.php. But you also want to use (some of) its functionality, like WordPress Jetpack. How?
One option is to Whitelist WordPress.com IP addresses for xmlrpc.php access through web.config in Windows Server IIS.
WordPress xmlrpc.php whitelist for WordPress.com, Automattic & Jetpack IP addresses
In a WordPress support ticket Jeremy Herve (@jeherve) provides some information about the required IP addresses in use for WordPress, Jetpack and other services.
If your hosting provider doesn’t want to allow all connections to Jetpack, you can use these IPs:
So you need to whitelist these IP addresses. One big advantage of using a whitelist, is that you automatically block all other IP’s.
Add your own IP to the list if you need access too.
XML-RPC (xmlrpc.php) whitelist in Windows Server IIS web.config
You can use the following web.config snippet to whitelist IP addresses and ranges (netblocks) for access to the xmlrpc.php file. The location tag means the rules only apply to the path mentioned. In this case the file xmlrpc.php .
Another solution is to block access to xmlrpc.php completely in IIS. In your web.config file add in the appropriate place:
This blocks requests to /xmlrpc.php URL’s completely, meaning you cannot use a plugin like Jetpack, or other functionality that relies on XML-RPC.
For a full list of the WordPress API functions available to developers via XML-RPC, take a look at this page on the WordPress codex.
Apache .htaccess mod_authz_host equivalent
To use on a Linux web server with Apache 2.2. A mod_authz_host .htaccess equivalent for the above web.config, for you to use, is as follows:
When using Apache 2.4, you need to use a slightly different syntaxis for the Apache module mod_authz_host:
You can find out why this difference in .htaccess files is important in my WordPress .htaccess best security practices post. Go on, I won’t stop you and this post can wait 🙂
What if WordPress/Jetpack IP addresses change?
Unfortunately you need to regularly check http://whois.arin.net/rest/org/AUTOM-93/nets to see if IP blocks have changed.
Other options do exist. I hope this’ll help you in keeping your site safe!
Want to say thanks?
If I’ve helped you out and you want to thank me, why not buy me a coffee?
Thank you for your support. ♥
WordPress 500 internal Server Error xmlrpc.php fix part 2
I had this issue previously and it appeared resolved. But it has returned after upgrading my WordPress installation to 3.x.
So I tried the simple thing of just disabling all my plug-ins but that didn’t do it this time.
I had to do that (disable my plug-ins as described here) and all this too!
I hope this helps some of you. Please make sure you have a complete backup of our MYSQL dbase AND your blog in case you hose something! I am a nut about backups and you should be too.
1. Using either FTP or CPanel, navigate to your WordPress root directory.
2. You should find the file “xmlrpc.php” there. Make a back up copy of it, just in case. Download it and then.
3. Open xmlrpc.php in an editor
4. Go to the end of the file.
5. Put your cursor after the final ?>
6. Delete anything there, including spaces, or blank lines.
7. Save the edited xmlrpc.php back to your WordPress root directory. [I also changed the permissions on this file to allow the Owner to ‘Execute’ too!]
If you don’t have one (php.ini) then create a text file and name it “php.ini” (without the quotes 😉 ) and with a single line of code in it:
[If you have one just add that line.]
This file has to be placed into the root directory OR /wp-admin/ within your WordPress installation.
It caused me problems being in the /wp-admin/ directory so I deleted it from there and place it in the root of my blog /mysite/blog/
So keep that in mind!
Also if you are creating the file locally and then uploading it make sure you change the file to a .ini and it does not still have the .txt extension on it.
Then you might want to find your .htaccess file
[It is a hidden file! So if you are using an FTP client make sure you set your ‘filter’ with the ‘-a’ option to ‘see hidden files’ and directories.]
Add this line to the beginning of the file:
AddType x-mapp-php5 .php
AddHandler x-mapp-php5 .php
And lastly I did this
Run the following database query to change the data type on the post_parent column:
ALTER TABLE wp_posts CHANGE post_parent post_parent BIGINT;
So after a few hours of aggravation I can now publish posts with loads of content from Window Live Writer again!
UPDATE: This guy here has a new solution for 1&1 users that works well!
11 thoughts on “WordPress 500 internal Server Error xmlrpc.php fix part 2”
I’ve recently started a blog, the information you provide on this site has helped me tremendously. Thank you for all of your time & work.
I am a server admin. I’ll be linking back to this from my own blog.
Damn, that sound’s so easy if you think about it.
You did it again, thanks.
Awesome. I hope you will not stop posting new articles. I read all your posts.
Terrific, that’s exactly what I was hunting for! You just spared me alot of work
Thank you, I’ve just been searching for info about this topic for a long time and yours is the best I have discovered so far.
Any time I edit the htaccess file I get a 500 error. Help?
Leave a Reply Cancel reply
This site uses Akismet to reduce spam. Learn how your comment data is processed.
Huge increase in WordPress xmlrpc.php POST requests
Table of Contents
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.
Over the course of the last days, I notice a huge increase in HTTP POST requests on the WordPress xmlrpc.php file. This could be a new type of XML-RPC bruteforce or (D)DoS attack. The attacks are targeted at different WordPress versions, so let’s do some investigation.
WordPress xmlrpc.php attack characteristics (WordPress Mozilla/4.0+(compatible;+Win32;+WinHttp.WinHttpRequest.5) , by random IP addresses (probably hacked and part of a botnet).
Did you 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.
A note: 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.
The Internet Storm Center (ISC) also reports on this WordPress brute force attack via wp.getUsersBlogs.
As you can see, the XML-RPC payload is much smaller here, and it originates from the same IP address.
The IP address is known to be a comment spammer, so I suspect this to be a different kind of spamming attack. But I’ll keep an close eye on it.
Before we can tell anything about this attack (these attacks), we need to log some data first. We then can analyze the gathered data.
How to log XMLRPC.php POST data to a log file
Log WordPress XML-RPC brute-force data to a log file 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.
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 :
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:
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:
wp.getUsersBlogs is used to retrieve the blogs of the users.
Mitigate WordPress XML-RPC attacks and wp.getUserBlogs user enumeration scans: how to disable XML-RPC in WordPress
Here is how to mitigate XMLRPC and user enumeration attacks, and to resolve degraded web server performance.
Unfortunately you can’t just simply remove the xmlrpc.php file. It is used in many places within WordPress. However, it’s possible to mitigate against this wp.getUserBlogs enumeration scan with a filter.
This filter needs to be put your 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:
But of course HTTP POST requests on xmlrpc.php will still come in. Unfortunately, you just can’t protect PHP with PHP.
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.
So first we disable WP_CRON. Open up your wp-config.php file and add:
While you’re at it, verify that WordPress WP_DEBUG is disabled too: define( ‘WP_DEBUG’, false );
Another good method to reduce server load during an attack is to optimize WordPress wp_options table and autoload feature. This micro-optimization retrieves autoloaded options much faster using less database resources.
How to disable XMLRPC.PHP in WordPress completely
Secondly, you can disable the XML-RPC functionality in WordPress by adding to your theme’s functions.php file:
But again, HTTP requests still come in to your server, degrading performance or causing a denial of service. Let’s do something about that in the next section.
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:
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:
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
Just add a denyUrlSequences :
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 communication, but we don’t want that now during these attacks.
Bonus: 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 easily re-enable them later.
Bonus: 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:
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.
Throttle xmlrpc.php attacks on WordPress with nginx
xmlrpc.php is a bundled WordPress script, created with the best intentions to allow API style traffic. Unfortunately, it’s also a target for malicious bots to try and mount DDOS attacks on WordPress sites.
After having a web site brought down by this, I had a search around, and found plenty of articles about throttling with Apache, and plenty about blocking with Nginx, but none about throttling with Nginx, so I decided to post my experience with finding a solution.
The trouble with blocking is throwing out the baby with the bathwater; I still want valid traffic such as Jetpack, and pingbacks to keep functioning as normal, hence my fixation on throttling rather than blocking.
I have chosen Nginx over Apache for it’s superior memory management and ease of configuration.
What‘s the problem with xmlrpc.php?
There is a very tricky DDOS floating around where this WordPress script is stormed with a large number of POST attacks, bringing down smaller web servers. If you can get a look at your Nginx access log, it might look something like this:
One of the peskier aspects of this attack is that often there is no described agent or other feature that might make it easy to block with something like Wordfence, and blocking the source IP address is not ideal as it can keep changing, and is often shared with other legitimate services.
Option 1: How to block all use of xmlrpc.php with Nginx
This is relatively widely posted around the web, but I will include it anyway. This should be added to your Nginx config, in the server context.
Adding this is the sledgehammer approach but might be what you want if you are undergoing a storm and need to stop it fast. Or, you may not care about other RPC services anyway.
Option 2: How to throttle xmlrpc.php with Nginx
This will require modifying two areas of your Nginx setup, the http context, and addition of a location context to your relevant server context.
Step 1: Modifying the http context
Always use caution when editing your web server files, and create a backup copy before changing anything.
First, we have to define a limit request zone and rate.
First example: limit to one request every two seconds, which is what I use and should be good for small web servers. We are calling this zone “one”.
Second example: limit to one request every second, which may be good enough for your needs. We are still calling this zone “one”.
For the full syntax breakdown of this command to determine your own variations, see the Nginx reference for limit_req_zone at Nginx.org here.
Step 2: Modifying the server context
Here we add a location block with some different content for our request zone. Here we use the burst parameter to say how long a “queue” we will allow before returning an error 503 (Service Temporarily Unavailable).
Create a backup copy of your file with the server context, which sometimes can be the same one as yout http context file, then add something similar to the following.
For a full explanation of the limit_req command to find what settings are right for your site, see the Nginx.org reference page here.
Restarting the webserver
Once you have modified your files, if you can, check syntax with:
..and if all is well, restart your web server.
A Piece of My Mind, One Byte at a Time
More WordPress XMLRPC Brute Force Attacks
If I never see this file again, it might be too soon.
We’re seeing an uptick in requests to xmlrpc.php, the API endpoint for WordPress. The wp.getUsersBlogs method is being hit across a large number of domains; I managed to grab a series of request payloads:
There aren’t any abnormal HTTP headers in these requests, just the appropriate Content-Length, and Connection: Close. wp.getUsersBlogs is used to retrieve a list of blogs for the provided user (http://codex.wordpress.org/XML-RPC_WordPress_API/Users). Below is a sample response:
] $ curl – vd ‘ wp.getUsersBlogs
‘ www . cryptobells . com / xmlrpc . php
Note the application-layer 403 response in the response body. The HTTP daemon, however, will respond with a 200 OK, which means that log analyzers and simple WAF rules would be useless in identifying a malicious behavior pattern, such as a distributed series of requests to the XML-RPC endpoint, each with a different credential set. By analyzing the response body, a distributed series of requests could be used to effectively brute force a user’s credentials, without triggering traditional brute force rules that rely on HTTP response codes (for example, wp-login.php returns a 200 on failed login, but 301 when presented with correct credentials).
Administrators wanting to disable this potential attack vector can disable the wp.getUsersBlogs method, similar to how pingbacks were being disabled after the well-known XMLRPC DDoS earlier this year (http://wptavern.com/how-to-prevent-wordpress-from-participating-in-pingback-denial-of-service-attacks):
The will result in a separate API failure (event when presented with proper credentials):
I’m very unfamiliar with how common plugins like Jetpack play with this part of the XML-RPC endpoint, so I doubt that recommending this action be taken on a broad scale would be wise, but for the paranoid, it’s a good way to lock down the core application.
Update [7/24/2014]: Sent this over to the ISC team (https://isc.sans.edu/diary/+WordPress+brute+force+attack+via+wp.getUsersBlogs/18427), and it got picked up by Trustwave (http://cryptobells.spiderlabs.com/2014/07/honeypot-alert-wordpress-xml-rpc-brute-force-scanning.html) and Threatpost (http://threatpost.com/wordpress-sites-seeing-increased-malware-brute-force-attacks-this-week/107378 – does that screenshot look familiar? 😉 ). We noticed far fewer occurrences of this in the days that followed, but that doesn’t negate the threat. Login Security Solution advertises defense against XML-RPC authentication, but with such a massive horizontal scale, that still wouldn’t have made a difference.
Update [8/11/2014]: WordPress 3.9.2 was released a few days ago that included an XML-RPC vulnerability fix, but this did not patch what we’ve noted here- the vulnerability patched was completely unrelated (BreakSec has a great write-up on the fix).
30 thoughts on “ More WordPress XMLRPC Brute Force Attacks ”
My site is being bombarded by “POST /xmlrpc.php HTTP/1.1” every few minutes. Login Security Solution plugin won’t detect these attacks in my case.
As noted above, Login Security Solution is not effective against a large number of differing IPs. Have you tried using ngrep, or writing the contents of the POST payload to a file, to see what the actual content of the requests is? Have you considered disabling the getUsersBlog API method? How about disabling XML-RPC entirely if you’re not using a remote publishing client or Multisite?
Hi, thanks for your help.
To make a clear picture, I ran a script from your second screensot against my side. Login Security Solution plugin has detected it as a XML-RPC attack. The server response is 200.
Speaking about those endless “POST /xmlrpc.php HTTP/1.1″from elsewhere, the server response is 406. It seems their script, probably, is poorly written.
Your advice about writing the contents of the POST payload to a file to see the actual content of the requests is the excellent idea.
I keep googling that technique, can’t find it yet.
Could you please provide me with you input?
There are a few tools you can use to grab POST payloads. I’ve developed (well, still developing- it’s almost done!) a cloud proxy WAF that analyzes all HTTP traffic; this can be used to analyze HTTP traffic from our custom web interface. You can check out the project at https://freewaf.com/. We used ngrep (http://ngrep.sourceforge.net/) to capture packet payloads for this post. Syadmins of the North also had a cryptobells post detailing this, giving an example of a quick function to log data posted to xmlrpc.php; see their post at http://www.saotn.org/huge-increase-wordpress-xmlrpc-php-post-requests for more info on that.
I just tested Syadmins of the North’s script.
It’s easy to run and read a log file.
I can read my curl command in the log file while testing it, but those foreign:
“POST /xmlrpc.php HTTP/1.1” 406 226
That logger and Login Security Solution can’t catch it. Hopefully, its payload is totally corrupted and won’t bring any harm.
One more thing, when I deny those IP’s I get:
“POST /xmlrpc.php HTTP/1.1” 403 18200
See the total size of data: 18200, it was 226 before denying it.
God knows what those script kiddies are doing 🙂 but their servers seem very powerful.
They are on Ecatel Ltd. in the Netherlands and googling their activities makes them look like a cuckoo’s nest 🙂
Thanks again for your support.
Robert, I am still here. 🙁
Never mind my 18200 bytes mention.
It’s just my host’s state of the art 403 page.
Robert, please never mind that 18200 bytes mention.
It’s my host’s state of the art 403 page.
Yes, you’re right about the response size 🙂
As for the 406, it’s a code returned by the host- not something clients are sending. 406 is Not Acceptable, which relates to what Accept headers the client presents (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html). 226 is the response length. If the server is returning an error (with a status >= 400), it follows that application-level logging will not pick up the payload. Nothing you can do about that; since it’s not hitting your application, it doesn’t present a security risk. 🙂
I am currently seeing a massive flood of wp.getUsersBlogs hits on my server that I’m monitoring.
Would you care to share some logs, packet captures, or other analytics?
I am not keen on ModSecurity, but I have these lines below attempting to curb the brute forcers… I wish I knew how to write the bf_counter and block the ip in the firewall but again I’m new to ModSec…
SecRule REQUEST_URI “xmlrpc.php” “deny,status:411,id:5000227,chain,msg:’xmlrpc DoS attempt’”
SecRule HTTP_User-Agent “WinHttp.WinHttpRequest.5”
while this is going on, I’m watching,
sudo tail -f /etc/httpd/logs/modsec_audit.log
below is an example of what I’m capturing in the modsec_audit.log. As you can see, they are using the xmlrpc api method wp.getUsersBlogs. If you reference the method in the WordPress Codex, the two values “test” and “sydney” represent username and password.
[23/Aug/2014:14:27:18 –0400] Go6GSUWntUYAAEPaTlIAAAEG [attackers-ip] 57504 [target-server-ip] 80
POST /xmlrpc.php HTTP/1.1
HTTP/1.1 404 Not Found
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Content-Type: text/html; charset=UTF-8
Message: Access denied with code 411 (phase 2). Operator EQ matched 0 at REQUEST_HEADERS. [file “/usr/local/apache/conf/modsec2.user.conf”] [line “877”] [id “5000228”] [msg “xmlrpc DoS attempt”]
Action: Intercepted (phase 2)
Stopwatch: 1408818438112841 626398 (1127* 1964 -)
Producer: ModSecurity for Apache/2.5.13 (http://www.modsecurity.org/).
Server: Apache/2.0.63 (Unix) mod_ssl/2.0.63 OpenSSL/0.9.8e-fips-rhel5
I was thinking a good way to stop this is to create a ModSecurity rule that blocks the ip after x failed attempts, however, I am new to ModSec so I can only seek assistance.
poprocks, I hope this helps. I am willing to provide more log information and testing.
looks like the xml was stripped out of that comment, here is a link to a pastebin:
This all looks pretty standard, exactly what I first reported several weeks ago 🙂
See the following pastebin for a rule that denies based on the sort of activity. An IP will be banned for fifteen minutes after 3 failed attempts: http://pastebin.com/BKPDxGLe
There is a new brute force exploit for xmlrpc.php. Attackers are using XMLRPC API method wp.getUsersBlogs to brute force logins with dictionaries.
Well, recently Brute force Attacks has immensely increased, becoming a dangerous factor for all WordPress users, but it is a thing, which is fight-able, I mean, by using security methods, we can move brute force attacks out of the window. Although, it can be difficult for newbies, who just got started with WordPress, but he/she can learn by reading posts online and then can implement security.
In my view, implementing only three tricks works very well, Changing Login Slug, A content Delivery network (CDN) and a Security Plugin, which bans IP address after a few Login attempts.