Stop Hack Attempts on WordPress xmlrpc.php

I recently noticed a lot of requests to this and other WordPress sites’ xmlrpc.php file. By “a lot”, I mean about 10-20 every second. It wasn’t particularly breaking anything (there aren’t any currently vulnerabilities there that I’m aware of), but it was increasing the load on my server.

My first step was to set an .htaccess rule to give a 403 response. That at least avoided hitting PHP with all those requests. But Apache still had to process them, so I wanted to take it a step further. I’m already using fail2ban, so I wanted to figure out how to stop these requests at that level instead of waiting until they reach Apache.

First, I needed to create a filter, telling fail2ban what kinds of requests I wanted to block. On my system (Ubuntu), I created a file at /etc/fail2ban/filter.d/apache-xmlrpc.conf. The file is fairly simple:

[Definition]
failregex = ^<HOST> .*POST .*xmlrpc\.php.*
ignoreregex =

This tells fail2ban how to parse the log files to find requests for xmlrpc.php, and where to find the IP address. You might need to adjust the regex if your log files are formatted differently.

Now that we’ve created the filter, we tell fail2ban to use it. We open /etc/fail2ban/jail.conf and add this rule:

[apache-xmlrpc]

enabled  = true
port     = http,https
filter   = apache-xmlrpc
logpath  = /srv/www/*/logs/access.log
maxretry = 6

Adjust the logpath parameter to point to your Apache access logs, and adjust maxretry to taste.

Restart fail2ban:

sudo service fail2ban restart

And you should soon find Apache handling far fewer requests. An added benefit to using fail2ban: legitimate requests to xmlrpc.php (e.g., trackbacks) should still get through.

Update (2013-08-28): This is, of course, a rough first step, and serves me well on my fairly low traffic server. If you’re looking for something more robust, definitely check out Todd’s comment below and read his blog post about protecting your WordPress server.

11 Responses to Stop Hack Attempts on WordPress xmlrpc.php

  1. Dustin says:

    I think you are the only person I’ve seen who has addressed this specific issue. I’ve had a specific domain of mine on my VPS disabled by my host because the loads on XML-RPC are off the charts. I thought it was a plugin, but no disabling was able to stop it. I finally found your post and added the offending IP ranges to my iptables list, then installed fail2ban. Thanks for the lead!

  2. Rob says:

    Thanks for this write up. Strangely enough, whenever I run fail2ban with these added settings my CPU usage for fail2ban-server jumps immediately to 100%. Not sure why, but simply making the filter active=false returns the state to normal.

    I am monitoring about 7 log files, but traffic is pretty light so they aren’t changing a lot. This is on an up-to-date Ubuntu precise (12.04.2 LTS).

    Thanks again.

  3. Andy Bailey says:

    thanks for putting this up, I have it on my mediatemple DV server but I’m not sure if it is working with the modified regex for the log files

    is there a way to check that fail2ban is preventing the POST to xmlrpc.php ?

    • Your fail2ban log should indicate which rules are being matched. For example, in my /var/log/fail2ban.log, I see:

      2013-08-17 02:41:24,501 fail2ban.actions: WARNING [apache-xmlrpc] Ban XXX.XXX.XXX.XXX
      
  4. Simon Woolf says:

    Hi,

    I had similar problems this morning, with a clutch of sites being hammered on xmlrpc.php from several different IP addresses.

    fail2ban is a great solution, but it wasn’t straightforward getting it to work in my environment (Centos 6 + cPanel)

    First, I had to download the source tarball, decompress and then run $python setup.py install (for some reason the yum install version wouldn’t start).

    Second when I started fail2ban (which i did via the client, ie: $fail2ban-client start), it warned me that the filter [apache-xmlrpc] had no actions.

    That didn’t look right, so I added an action to add rule to iptables to block the offending ip, and send me an email. Now this works like a dream.

    So the final config in jail.conf looks something like this:

    [apache-xmlrpc]

    enabled = true
    port = http,https
    filter = apache-xmlrpc
    action = iptables[name=apache-xmlrpc, port=http, protocol=tcp]
    sendmail-whois[name=SSH, dest=[email protected], sender=[email protected]]
    logpath = /home/*/access-logs/*
    maxretry = 4

    Note the very wildcarded log path – if you have a standard install of cPanel then you will need something like this too.
    I have 50+ accounts hosted on my server, and it takes fail2ban a few minutes to parse all the log files when it starts up – you will see pretty much 100% processor usage while it does that. But it soon settles down and behaves itself.

    TODO: I need to get fail2ban running as a service and set it to start on boot. Also the sharpeyed amonst you will note that I should probably filter out ftp or other service logs, as I’m uneccessarily parsing them with this regex.
    Finally, I haven’t added a rule to block https, simply because I don’t host any wordpress blogs over SSL at the present time, so this isn’t an issue for me.

    One final observation is that editing the .htaccess files to block xmlrpc.php with a 403 response was disastrous for me. The DDOS attempts continued at full force and the load just transferred from the php processor to apache, increasing, not decreasing the load. So I don’t recommend this option!

  5. Simon Woolf says:

    A further update – I’ve noticed that fail2ban is only banning IPs when it starts up – not all the time. Not sure why, wonder if you’ve noticed the same or not? Maybe I have something wrong in the config somewhere . . .

  6. Todd says:

    Simon and Rob,

    Although the intention is good here there is something that should be watched with this implementation and a couple of you have touched on those issues.

    The foremost issue is scanning the access.log which can be a bad thing. Depending on the traffic that the site gets this can become VERY CPU intensive and is not recommended. If you’re a hosting provider this is even more so not recommended. When the issue with the massive attacks on WP sites arose (April-June 2013) all major hosting providers, including us (small guys) immediately blocked all access to wp-login.php and I’m talking Go-Daddy, LiquidWeb, etc. This blocked access for legitimate purposes as well but it kept the servers up. Once things calmed down and like minds met we implemented more robust procedures.

    During a SYN Flood Attack for example your access log will quickly increase in size. The combination of the attack plus Fail2Ban scanning it can cause issues. In addition, Fail2Ban DOES scan logrotated files. Therefore, if you have had this server for a while and have a lot of rotated files it can make things worse.

    The “more” correct way to deal with this would be to hook into the WP login process (wp_authenticate) and write to a custom error log specifically designed for WordPress. Setup your Fail2Ban filters and only scan that log.

    When you say that Fail2Ban is not picking them up all the time are you referring to immediately after you attempt an invalid login? Fail2Ban can sometimes take a bit before it reads the entire log file. Do you have your IP whitelisted?

    We have a lot of information on Fail2Ban and detailed implementations for WordPress documented. If anyone would care to take a look here’s the link

    • Thanks for the helpful info, Todd. The performance concerns don’t particularly impact this humble site, but that’s very good to know when trying to apply this on a larger scale. I’ve updated the post above with a link.

  7. Pingback: Fail2ban installed | Shang-Yung Wang

  8. Pingback: How a DDOS attack makes me a better DevOp ;-) | Joachims Small World

  9. Tatiana says:

    What’s up to all, how is everything, I think every one is getting more from this web page, and your views are fastidious designed
    for new people.

    My webpage :: living a healthy life (Tatiana)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">