Brute force attacks against WordPress have always been very common. In fact, Brute Force attacks against any CMS these days is a common occurrence, what is always interesting however are the tools employed to make it happen.
You create a website, because it’s super easy these days, publish the content and within a few weeks people try to repeatedly log in. These login attempts come from botnets, they are automated and their goal is simple “break into as many websites as they can by guessing their passwords.” Once they find one that matches, they take over of the site and use it to distribute malware, spam and similar activities.
Here is a small example, from our own honeypots, where we see hundreds of login attempts per day, trying various combinations:
user: admin, pass: admin user: admin, pass: 123456 user: admin, pass: 123123 user: admin, pass 112233 user: admin, pass: pass123 ..
The passwords may seem silly, but after going through the most common 200/300 dictionary passwords, they can get into many web sites.
XMLRPC wp.getUsersBlogs
Originally, these brute force attacks always happened via wp-login.php attempts, lately however they are evolving and now leveraging the XMLRPC wp.getUsersBlogs method to guess as many passwords as they can. Using XMLRPC is faster and harder to detect, which explains this change of tactics. This is not to be confused with our XMLRPC being used to DDOS websites, in this instance they are leveraging it to break into websites. Be sure to read up on the differences between Brute Force and Denial of Service attacks.
This attack is being made possible because many calls in the WordPress XMLRPC implementation required a username and password. It these attacks, we are seeing wp.getUsersBlogs being used (and ocassionally wp.getComments), but it could be other calls as well. If you provide a user and a password, it will confirm whether the combination is correct or not:
<methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value> <string>admin</string></value></param> <param><value><string>112233</string></value></param></params> </methodCall>
In the example above, the attackers tried the user admin with the password 112233.
Large Scale Brute Force
To examine the scale of this attack, we went back through our logs to get a better sense for the scale of the attacks. The past couple of weeks have been interesting. The attacks have increased ten-fold with almost 2 million attempts since the beginning of July coming from 17,000 different source attacking IPs. Some days we were seeing almost 200k attempts.
The only reason these numbers are not higher is because we’re killing the logs after block attempts, so all you are seeing is the gradual increase in attacks, but not the complete picture. This is what makes this entire thing very scary for website owners.
Another interesting point about this attack is the usernames being tried. Instead of relying only on “admin”, it tries to find the domain name and the real admin of the site to use it instead. These are the top user names tried:
179005 test 167147 admin 32030 sitedomain (domain modified to protect the innocent) 15850 sitedomain2 (domain modified to protect the innocent) 9590 realsiteadmin (user name modified to protect the innocent) 9564 realsiteadmin2 (user name modified ..)
So out of 2 million attempts, only 167k used the username “admin”. That shows that just disabling the admin user name, does not help if the attackers can easily find out the real user. One small reason we no longer subscribe to the argument of removing the “admin” user to be secure.
As for the passwords, they are using the most common passwords found in many dictionaries:
1dc13d admin 123123 admin1 admins 123456 12345678 7777777 letmein 121212 qweqwe iloveyou administrator holysh!t 55555 1q2w3e qwerty wordpress wpsite internet asdfghjkl 121314 lollipop killer pass lovers hello dragon admin123 office jerome fyfcnfcbz
Brute Force Protection
There are many ways to block brute force attacks. If you have a dedicated server, you can install OSSEC (open source) on it and let it automatically block the IP addresses that miss too many passwords. We automatically include brute force (password guessing) protection on our Website Firewall (CloudProxy), so if you are looking for a 1-click solution, you can leverage it.
There are obviously a number of application level tools (i.e., plugins) many will recommend within the WordPress ecosystem to help with Brute Force attacks. Here is the thing, none of the ones we tried will protect you from the XMLRPC calls, including our own plugin. It’s likely why we’re seeing the shift in attack methods. Blocking at the edge is going to be your preferred method until that gets fixed.
63 comments
At least in my tests, adding the .htaccess text below seems to stop the attack pretty much instantly.
Can you folks verify this as as well?
Order Deny,Allow
Deny from all
That should be correct Jim. Any of the XMLRPC plugins that disable XMLRPC via Apache should stop this in it’s tracks. I’m using iThemes Security for a similar method but basically this just lets Apache keep ANYONE from getting to the file. However, it does completely make the file not accessible to pingbacks, trackbacks and connections from remote tools like Livewriter and Jetpack, which is what is making people whine. Too bad. Its better than being hacked.
Would this interfere with something like InfiniteWP, which allows you to manage sites remotely?
We use InfiniteWP and also use the Disable XML-RPC plugin and they co-exist fine. https://wordpress.org/plugins/disable-xml-rpc/
It might. I know it causes issues with JetPack, which forced us to do a more granular block on xmlrpc.
It very well might. It all depends on how they are authenticating. You’d need to send them a quick email and find out. Would you please report back and let us know what they say?
I know that it should not affect iThemes Sync and it likely does not affect WP Pipeline either, due to how these use an internal plugin on each managed site.
I use InfiniteWP and blocked the access to XMLRPC using .htaccess, no problem for infiniteWP. I guess the use something else for interactions.
Yes, IWP connects directly to the plugin in the remote site using its own API. So, no need for XML-RPC 🙂
I would also be interested to know this. I use IWP but since blocking the file, I have not noticed any issue with IWP – though would be keen to know what they say.
Nope, it doesnt interfere. But I found that no matter if you disabled XML-RPC spammer are still able to do pingbacks. To solve this, you just need to disable pingbacks in posts and pages, from the Comments screen and thru phpmyadmin:
UPDATE wp_posts SET ping_status=’closed’ WHERE post_status = ‘publish’ AND post_type = ‘page’
UPDATE wp_posts SET ping_status=’closed’ WHERE post_status = ‘publish’ AND post_type = ‘post’
This simple approach will cover the holes that currently Akismet, Conditional Captcha, Wordfence nor iThemes Security cant.
All the best and good luck with those slippy attackers.
Jim, why do you add =”” after the file name?
The extra =”” is being added by this website’s blog software.
Correct, is simply:
xmlrpc.php> and not xmlrpc.php=””>
From my experience, the resulting 404 page that this deny rule causes can still cause high load on a server because of the amount of requests being made to the xmlrpc.php page. I have seen that a better method is to simply null route the xmlrpc.php page by using the following redirect rule in the .htaccess file of the targeted site:
RewriteRule ^xmlrpc.php$ “http://0.0.0.0/” [R=301,L]
This null routing causes less server resources to be used than a 404 http response.
THIS WORKS!!!
Max,
Thank you. Null routing seems to be the best method. My sever load was tremendous prior to seeing your Solution. Simply blocking access to the file was not enough.
Max, you are my new hero!
>50% CPU processing 404s down to <0.2% with your null routing magic.
Max, what if you’re using iThemes and you Turn Off the file? How does this differ from that? By denying access all together? And if using iThemes does it write something similar to the htaccess already?
I have a client getting massively attacked everyday and I’ve thrown everything I can at this, even the kitchen sink but nothing works. It’s so bad that I can’t even reboot the server now.
I use some filters inside my .htaccess to block access to file like xmlrpc.php as well. How about this WordPress filter? add_filter( ‘xmlrpc_enabled’, ‘__return_false’ );
The XML-RPC interface can be protected depends on the user agent: https://gist.github.com/sergejmueller/0c0999871b733a7db5c1
Login Security Solution has protected against brute force attacks via XMLRPC since April 2013, and has always been the most sophisticated and comprehensive login security plugin available, in my opinion.
I will have to try it 🙂 Thanks for the tip.
Ian, my site is being bombarded by “POST /xmlrpc.php HTTP/1.1” every few minutes. Login Security Solution won’t detect these attacks. Please check your raw log and let us know if that plugin detects it on your sites.
LSS doesn’t block the requests before they hit the web server (like a firewall would), so you’ll still see the attempts in your web server logs.
What it does is flags the IP if there are multiple failed attempts, and then when more attempts are detected, it will fail the authentication attempt, disconnect the database, and leave the HTTP connection open for a random amount of time (between 4 and 30 seconds, I think). It works that way in order to drain resources from the botnets.
Well, I simplified this matter while testing LSS.
I set the failed attempt notification as ‘1’, then I logged out and logged in with not valid credentials. I got a LSS warning email immediately. But it doesn’t work to detect XMLRPC attacks, there is no notification about such attack from the servers in the Netherlands which continues month after month.
Ian, I am sorry, you are right.
I just ran a script against my site, LSS was reporting that as a XMLRPC attack. Everything is fine with LSS. I guess those bots from the Netherlands got some poorly written code and it can’t be properly connected to my site.
Thanks for your tip.
No worries, I’m glad to hear you got it sorted out 🙂
I just tested it too and it’s working for me. I didn’t test the e-mail notifications, but I can see the failed logged attempts recorded in the `login_security_solution_fail` database table, and am noticing the artificial delays that LSS introduces.
So….. DDOSing yourself then. Seriously, this is a terrible idea. If a large enough botnet exists they can actually bring you to a grinding halt by your own security protocol.
One day I woke to find my mail box full with warnings from a wordpress plugin installed which blocks ip after four failed attempts. I guess there were around 35k attempts were made. I was surprised since I have a server config which kills all POST requests to wp-login.php – http://blog.applegrew.com/2013/05/securing-the-wordpress-login-page/. Then I figured the source was xmlrpc. Disabling that solved my problem.
On my wordpress website I use a question and answer challenge as part of registration and logging in – is this defeated by the xmlrpc method? I haven’t had a spam registration since I enacted this but it hasn’t stopped the automated brute force nonsense of course.
Daniel– why won’t existing brute force plugins work against XML-RPC? XML-RPC authentication uses wp_authenticate, so any functions hooked on to authenticate filter or wp_login_failed hook should still run
Most plugins rely on hooks for the failed login (specially the wp_login_failed), which is not called on XMLRPC.
I have reviewed all of the code and tested extensively from WP 3.9.1 back to 3.0 and wp_login_failed is bring triggered every time– what’s leading you to think that it would not be called?
I ran a test and found the ‘Limit Login Attempts’ plugin works the same on XMLRPC login attempts as on the WordPress login form.
Hi Daniel,
Could you explain how “Using XMLRPC is faster and harder to be detected” ?
Daniel, as an emergency workaround, what do you think about the password-protected wp-login? Let’s say, a bot finally breaks through xmlrpc.php and sends the site credentials back to the intruder. Yet he either some other attacking script won’t be able to normally login via wp-login.php because that page is password-protected. Thanks in advance.
The actual user name of the account used to post an article appears in the RSS feed for the blog unless you’ve given the user a display name and configured WP to use the display name instead of the actual user name. I use a random character string for the default admin account on my blogs and was still getting login attempts using the correct user name.
I still recommend that the default “admin” name be changed, but don’t solely rely on that for obfuscation.
Very good point, thank you
Over the last 3 days, I have noticed a massive amount of traffic hitting
my VPS client sites xmlrpc file. At one stage there were more than 100
bots per second. This flood successfully brought down two of our busy
ecommerce sites, leading to client calls (clients don’t really know what
a DDOS is and don’t care, they just want their site to work. Though
they were patient, this kind of issue can cast a shadow on your
service).
We tried a whole range of things to try to mitigate
the issue, SYNFLOOD in our CSF firewall (no effect), Wordfence plugin
(no effect), BRUTE protect plugin (no use).
Finally we blocked
the file using
Order
but the bots simply turned to thedeny,allow Deny from all
theme index file and continued their DOS attack.
Then we came up with a mod_sec rule which had more success:
SecRule
REQUEST_LINE "POST .*wp-login.*"
"pass,initcol:ip=%{REMOTE_ADDR},setvar:ip.maxlimit=+1,deprecatevar:ip.maxlimit=1/600,nolog,id:35011"
SecRule
IP:MAXLIMIT "@gt 10" "log,deny,id:350111,msg:'wp-bruteforce: denying
%{REMOTE_ADDR} (%{ip.maxlimit} connection attempts)'"
SecRule
REQUEST_LINE "POST .*xmlrpc.*"
"pass,initcol:ip=%{REMOTE_ADDR},setvar:ip.maxlimit=+1,deprecatevar:ip.maxlimit=1/600,nolog,id:35012"
SecRule
IP:MAXLIMIT "@gt 2" "log,deny,id:350112,msg:'wp-bruteforce-xmlrpc:
denying %{REMOTE_ADDR} (%{ip.maxlimit} connection attempts)'"
The
problem with disabling xmlrpc is that a lot of plugins and sites use it
legitimately. Removing it will break wordpress. Now I am investigating cloudflare and your cloudproxy service
If you are not using the wordpress API is there any reason not to just disable xmlrpc.php?
Seems either blocking access via htaccess or just setting the file permissions to 000 would easily eliminate this threat.
The latest WordPress update (3.91) has not mitigated this issue – I am still seeing huge DOS traffic at xmlrpc.php files across a range of sites.
There is a new brute force exploit for xmlrpc.php. Attackers are using XMLRPC API method wp.getUsersBlogs to brute force logins with dictionaries.
All *BIG* giant whitehats. Ah nice catch.
I recently received an email from my All In One WordPress Firewall and Security plugin on one of my sites informing me that someone had been locked out for too many failed login attempts. I was surprised, since I have my login pages hidden. When I looked at my raw access logs, I saw that they were using xmlrpc.php. My security plugin caught it, though. It is set to lock out anyone who uses the wrong login name after the first attempt.
Hello Dear,
Are you in debt? Do you need
an instant funding? Do you dream of owning a house, Car and good
Business? Do you need a loan ahead for the Christmas family vacation?
Have you been in search of a legitimate loan and been turned down
severally? If YES” Search no further.
We offer Personal/Commercial loans at 2% interest rate without collateral. get instant Approval even with bad credit.
Serious
and interested applicants should please contact us via email
today:lim.koh56@yahoo.com and be free from all your financial troubles.
NOTE:we will save you from payday loans that are making billions from the prey of the poor.
Best Regards.
Mr.Lim Koh
I find it interesting that the developers of wordpress have not closed the loop on this issue, this has been going on for YEARS and now its 2015 and once again there is an attack… When will they decide that the usage of this xmlrpc.php is just not a good thing, what good is it? Does Google rank your site based on pings? NO, in fact google basically does not care, so zero SEO factor, it seems like this code is dying, perhaps wordpress is not as useful as it once was.
The problem is… there are lots of widely used third party plugins and web services that make use of xmlrpc and thus, it cannot be dropped from core.
Maybe… the WP team could drop it if they develop an xmlrpc plugin to provide the same functionality. So, it would only be installed on required scenarios, but this is not a goal for now. There are more great changes to come, and until then, you can only submit it as a feature request in their forums 🙂
well failing that functionality, would it not be wise to hardcode an execution timeout?
Maybe yes. Below is the best site to post such a request:
https://github.com/Automattic/jetpack/issues
Let me know if you do it so I can second it 🙂
certainly, I just wonder why they cannot add a little user authentication before making a call to PHP
I have not had a problem, but then my wordpress blogs do not allow either outside comments or people to register in the first place, both are set to admin posting only. I’m guessing that eliminates the vast majority of the problems since there is only ONE acct and the login user name is not the same as the displayed names in posts, it’s also not “Admin” 🙂
Not granting public access by allowing people to log in eliminates that security issue.
I wrote this plugin to protect my servers, but still being able to use JetPack (which requires your xmlrpc.php to be available from JetPack’s/Automattic’s servers): https://wordpress.org/plugins/stop-xmlrpc-attack/
It will alter your .htaccess to block all requests to xmlrpc.php, except for requests originating from Automattic’s/JetPack’s IP address subnet. I polls ARIN on a regular basis to keep your .htaccess updated to any network changes…
// Maybe is not mine to say but why not edit the xmlrpc.php
// and at beginning add some ip recognition stuff like:
if (sha1($_SERVER[‘REMOTE_ADDR’]) == ‘0f9c22a8675fff9c3ad20d42e7e8579dde99477d’) {
// content of xmlrpc.php
} else {
print ‘ERROR 403’;
// or something else
}
// And for the multi user same but:
if ((one ip == sha1) || (second) || (etc.)) {}
// Just you have to know
print sha1(your ip);
// to start with…
edit: is not ‘print’ command is ‘echo’ …
Mine are being attacked this week… 🙁
Simply Use captcha
Put a double authentication via .htaccess, easy and effective.
did this. login attempts are still happening.
Username enum is coming from the guys at WPSCAN, at least thats how I enum site admins.
That’s one of the biggest issues (flaws) with WordPress as a tool for creating websites (as opposed to, say, ASP.NET) – you relegate too much control to WordPress and as a result you have little control and in most cases almost zero understanding of what’s going on – you just slap together a site using various plugins that you buy or get for free and you consider yourself a master website builder … until someone hacks into your “stronghold” and wipes out all the data.
If you’re building a website with ASP.NET such issues as you’re describing here rarely come up – you are free to implement login as you wish (including two form authentication or federated authentication (aka single sign-on)) because there are no set login pages (like the loginwp.php page) and with creating the login page and choosing the method of authentication yourself, you’re forced to learn more about securing your website via authentication and thus you’re less likely to become another victim of script kiddies.
XML-RPC server accepts POST requests only. what is the solution and plz be more clear on the explain because it hard for some person !! thanks for that …
Wouldn’t it be even better if in addition to install LSS you also installed a plug-in to rename (mask the name) of the wp-login and wp-admin files in order to make it more difficult to identify the site as a WP site or are there too many other ways to identify the site as a WP site?
We are seeing a lot of hits the past few days against /xmlrpc.php…. is there anything we should do?
I solve the problem with a free wordpress plugin ( Authentication and
xmlrpc log writer ) and enforcing on my server fail2ban. No more
problems. It also preserves the server performace killing multiple
authentications attemps on single xmlrpc call.
Comments are closed.