Blocking WordPress Pingback Verification DDoS

Recently one of the websites I host has come under a few reasonably sized DDoS attacks. The attacker has been (mis)using a WordPress feature, pingback verfications. The attacker sends requests to WordPress sites that have this feature enabled, the WordPress sites then send a HTTP request to the target site to verify the pingback. If your site is being attacked via this method your access logs will look similar to this:

52.28.2.139 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.0.1; http://www.muchohogar.com; verifying pingback from 185.103.252.170"
177.153.22.251 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.5.1; http://detox.suavidamaisfeliz.com; verifying pingback from 185.103.252.170"
119.9.131.80 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.5; http://ruedeseine.com; verifying pingback from 185.103.252.170"
130.185.250.98 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.4.2; http://devoclips.com; verifying pingback from 185.103.252.170"
149.210.165.225 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.5.1; http://sng-line.com; verifying pingback from 149.210.165.225"
84.21.137.236 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.3.1; http://www.web-promote.com; verifying pingback from 185.103.252.170"
104.196.107.216 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.4.2; http://homesophy.com; verifying pingback from 185.103.252.170"
89.225.228.230 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.5.1; http://89.225.228.230; verifying pingback from 185.103.252.170"
98.129.41.189 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.3; http://www.sscriticalcommunication.com; verifying pingback from 5.154.191.67"
130.211.134.65 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.5.1; http://130.211.134.65; verifying pingback from 185.103.252.170"
104.130.159.101 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.5; http://www.vmcfortmill.com; verifying pingback from 185.103.252.170"
59.124.159.107 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.5.1; http://myhome123.tw; verifying pingback from 185.103.252.170"
198.245.57.157 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.5.1; http://wpadmin.4mobile.cc; verifying pingback from 185.103.252.170"
136.243.152.43 - [-] - [06/May/2016:14:14:12 +0800] redacted.com "GET / HTTP/1.0" 200 162 "-" "WordPress/4.2.4; https://www.leginda.de; verifying pingback from 185.103.252.170"

This isn’t the first time sites I host have been hit with a DDoS that abuses the pingback feature from WordPress, but it is the first time I have seen this specific attack. The previous attacks looked different – they didn’t show the “verifying pingback from” part of the user agent. An example of those attacks can be found on the Sucuri and ISC SANS websites.

The first thing I noticed with this attack is that the IP address(es) the attacker is using to launch the attack is present in the user agent header, it can make blocking this very easy. As an example, the most recent attack I experienced generated over 1,000,000 GET requests over 5 minutes – approximately 900,000 of those requests were generated from a single IP address Fortunately I am subscribed to an on demand DDoS mitigation service (Prolexic) but the initial flood of requests that comes in is still enough to cause server issues until the attack is detected and mitigated. Here is a couple of ways you can minimise the impact on your server.

iptables

Running the following commands will block this specific attack:

iptables -N WordPress-PingVerify
iptables -I INPUT -p tcp --dport 80 -m string --to 70 --algo bm --string 'GET /' -j WordPress-PingVerify
iptables -A WordPress-PingVerify -p tcp --dport 80 -m string --to 80 --algo bm ! --string 'User-Agent: WordPress/' -j RETURN
iptables -A WordPress-PingVerify -p tcp --dport 80 -m string --to 300 --algo bm --string 'verifying pingback from' -j DROP
iptables -A WordPress-PingVerify -j RETURN

The above rules assume that the attack is destined to HTTP (port 80), if you are getting hit over HTTPS change the port 443 (or you can use multiport to specify both port 80 and 443).

As an alternative, you can use these rules to block ALL WordPress pingback requests – this will block not only the pingback verifications but pingbacks as well:

iptables -N WordPress-PingBacks
iptables -I INPUT -p tcp --dport 80 -m string --to 70 --algo bm --string 'GET /' -j WordPress-PingBacks
iptables -A WordPress-PingBacks -p tcp --dport 80 -m string --to 80 --algo bm ! --string 'User-Agent: WordPress/' -j RETURN
iptables -A WordPress-PingBacks -p tcp --dport 80 -j DROP
iptables -A WordPress-PingBacks -j RETURN

Here is an explanation of what these rules do:

iptables -N WordPress-PingVerify

This line will create a new chain named WordPress-PingBacks. This chain will have the rules for filtering out the requests from WordPress from your other HTTP traffic.

iptables -I INPUT -p tcp --dport 80 -m string --to 70 --algo bm --string 'GET /' -j WordPress-PingVerfy

This line will check all traffic destined to the server on port 80. The string matching module will be used to check the first 70 bytes of the packet for the string “GET /” – this will match all normal HTTP GET requests. It will then be sent to the WordPress-PingVerify chain. Note that this rule uses -I – this will ensure that the rule is the first rule in the INPUT chain.

iptables -A WordPress-PingVerfy -p tcp --dport 80 -m string --to 80 --algo bm ! --string 'User-Agent: WordPress/' -j RETURN

This line will process all the packets that matched the previous rule. The string matching module is used again, this time the first 80 bytes of the packet are checked for the presence of of the WordPress user agent. If the packet does not match this rule the traffic is returned back to the INPUT chain so that your normal iptables are checked. If the User-Agent header has WordPress in it, we then move on to the next rule in the WordPress-PingVerify chain:

iptables -A WordPress-PingVerify -p tcp --dport 80 -m string --to 300 --algo bm --string 'verifying pingback from' -j DROP

This line will will use the string matching module again, this time checking the first 300 bytes of the packet. If that contains the string “verifying pingback from” it is now dropped. If you choose my second rule set, the string matching rule set isn’t used at all – all traffic will be dropped (as we already matched the WordPress user agent).

iptables -A WordPress-PingVerify -j RETURN

This line will then return any other traffic back to your standard INPUT rules for further processing.

nginx

You can add the following if statements to your nginx configuration file (usually in /etc/nginx/sites-enabled):

  if ($http_user_agent ~* 'verifying pingback') {
    set $pingbackcheck 1;
  }
  if ($uri = /) {
    set $pingbackcheck "${pingbackcheck}2";
  }
  if ($pingbackcheck = 12) {
    return 403;
  }

As nginx does not support multiple if conditions or nested if statements, the above configuration will do the following:

  1. If the User Agent header contains “verifying pingback” the variable $pingbackcheck will be set to 1.
  2. If the path of the request is “/” the variable $pingbackcheck will be set to ${$pingbackcheck}2. This means if the previous if statement matched as well the variable will now be “12”.
  3. If the variable $pingbackcheck is equal to 12 (so that both the above conditions were met), return a 403 forbidden page.

Using this you can reduce the load on your server greatly, there will be no need for the requests to hit the database or PHP.

Other Notes

As noted at the start, the attacker mainly used a single IP to generate all of these requests. As this type of attack has the IP used in the headers you can easily block it using the above iptables rules as a template – I don’t recommend doing this though as you may end up just playing a game of whack-a-mole with the attacker changing IP’s.

After the attacker used this attack for a period of 5 minutes or so it looks like they realised it wasn’t working. They followed up this attack by doing a SYN flood, UDP fragment attack and a CharGen reflection attack. The other attacks were not very big and easy to mitigate. See this screenshot for a break down of the attack types/speed:

Wordpress_Pingback_DDoS

If you run your own WordPress site I suggest checking the Surcuri site to validate that your WordPress site is not being used to attack other sites – you can do that from here. I recommend updating your WordPress setttings to disable pingbacks entirely – you can do this by going to your admin dashboard and going to Settings -> Discussion. Disable these two features:

  • Attempt to notify any blogs linked to from the article
  • Allow link notifications from other blogs (pingbacks and trackbacks) on new articles

If you would like any more information about this attack or have any questions please post a comment below.

Posted in iptables, Linux, Web.

4 Comments

  1. You have a couple of options. The easiest way is to just remove the rule that is pushing the traffic into the WordPress-Pingverify chain. Replace the ‘iptables -I’ part to ‘iptables -D’ instead so it looks like this:

    iptables -D INPUT -p tcp –dport 80 -m string –to 70 –algo bm –string ‘GET /’ -j WordPress-PingVerfy

    The other rules will not get used then.

  2. This seems to work for HTTP. But what if the victim server are running HTTPS. Can this method still be used or do I need to decrypt HTTPS packets on the firewall to perform filtering?

  3. You mention port 443, but GET requests will be encrypted, so surely this won’t work for HTTPS.

    Also, won’t there be a problem that the reflecting WordPress site will have connected and keep retrying sending the GET packet until your web server drops the connection, possibly after a minute or more. It doesn’t block the TCP handshake or close the socket and server process. So this could still be an effective layer 7 attack. I agree that these attacks are usually combined with other forms of DDoS, but a lot of them are short-lived “booters”.

    Apache could do it something like:
    RewriteCond %{HTTP_USER_AGENT} “^WordPress.*verifying pingback from
    (?!your.ip.add.ress)”
    RewriteRule ^.*$ – [F,L]

Leave a Reply

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