1

I experienced that my server received a 99% CPU load and the site goes almost down.

Checked the access log file and there are tons of following entries:

203.115.XXX.XXX - - [13/Oct/2017:12:40:01 +0000] "POST /wp-admin/admin-ajax.php HTTP/1.0" 200 178
212.92.XXX.XXX - - [13/Oct/2017:12:40:01 +0000] "GET /wp-admin/admin-ajax.php HTTP/1.0" 200 1
218.29.XXX.XXX - - [13/Oct/2017:12:40:02 +0000] "GET /wp-admin/admin-ajax.php HTTP/1.0" 200 1
104.130.XXX.XXX - - [13/Oct/2017:12:40:02 +0000] "GET /wp-admin/admin-ajax.php HTTP/1.0" 200 1
176.123.XXX.XXX - - [13/Oct/2017:12:40:02 +0000] "POST /wp-admin/admin-ajax.php HTTP/1.0" 200 178
45.115.XXX.XXX - - [13/Oct/2017:12:40:03 +0000] "GET /wp-admin/admin-ajax.php HTTP/1.0" 200 1
212.92.XXX.XXX - - [13/Oct/2017:12:40:03 +0000] "POST /wp-admin/admin-ajax.php HTTP/1.0" 200 178
31.179.XXX.XXX - - [13/Oct/2017:12:40:04 +0000] "GET /wp-admin/admin-ajax.php HTTP/1.0" 200 1
92.240.XXX.XXX - - [13/Oct/2017:12:40:07 +0000] "GET /wp-admin/admin-ajax.php HTTP/1.0" 200 1
92.240.XXX.XXX - - [13/Oct/2017:12:40:07 +0000] "GET /wp-admin/admin-ajax.php HTTP/1.0" 200 1
61.5.XXX.XXX - - [13/Oct/2017:12:40:07 +0000] "POST /wp-admin/admin-ajax.php HTTP/1.0" 200 178
201.59.XXX.XXX - - [13/Oct/2017:12:40:07 +0000] "GET /wp-admin/admin-ajax.php HTTP/1.0" 200 1

Within a few hours, almost 800 single requests of the same IPs. This doesn't seem natural to me. Additionally according to analytics, there are not that many users on the page when this happens.

So it seems that the hit come from outside and impacting my servers power.

When blocking access to the admin-ajax.php file via htaccess, the cpu load is back to 1-3% and everything is fine.

My question:

Is there a way to block these spamming requests to the admin-ajax.php file which come from "outside" and only allow installed plugins/theme to access the admin-ajax.php file instead?

Update

It really seems like my site got spammed by some bots/servers.

Tried several things like Cloudflare, different hosting etc. The only thing which helped was using Sucuri as Website Firewall which blocks everything.

3 Answers 3

1

No there isn't a way, any more than there is a way to block "spammers" from accessing you home page. I mean you could put all kind of checks, but in the end you will break how sites are supposed to behave which will mean that someone somewhere will not get his content. If all you have is a blog maybe you just do not care as long as your friends and family can read it, but if you actually generate money with your site you might care more.

Instead of looking at logs you should ask yourself how come a request that should do nothing except for bootstraping wordpress is bringing down your site. If you run php 7+ and object cache the cpu cost of handling a "spammy" request should be close to zero. So either you should upgrade your server side to better gandle traffic, or you have a targeted attack against a specific plugin which tries to exploit its ajax handler, in which case identifying the target of the attack should be top priority. While an attack is unlikely, it still might make sense to change your log to show the payload of the request.

0

There is no magic bullet, I'm afraid. If you're too careful in blocking, you won't hit them, if you're not careful enough, you will end up blocking legitimate requests from users.

You could try to block them based on whether they send an Origin header or not. Browsers usually will, bot developers might not because they typically don't have to (and as someone who has written a few bots himself, at least I am pretty lazy when coding).

These seem to be using HTTP/1.0, while Browsers generally use 1.1 (and above).

Do they send User-Agents that look like legitimate Browser or do they just have "libwww-perl/5.76" or something similar?

I'd probably opt for a multi-criteria blocking mechanism. If it looks like a legitimate User-Agent but uses HTTP 1.0 and doesn't send an Origin header, it probably is a bot. You could go further, and only block after they've made one suspicious request (e.g. looking at what action they are trying to execute).

An advanced idea is to cross reference that with "did this IP have a regular page view before starting AJAX-requests?" or "did this IP ever request an image or a css/js file?", because bots most likely won't unless they are trying to be really stealthy or target your site specifically. That could get problematic if you do allow proxy servers to cache those resources (CloudFlare will do that automatically) and might be a bit too much effort for keeping them at bay, though.

2
  • I'm not using CloudFlare yet, but I also came along with their Rate Limiting functionality which might help in this case.
    – flowdee
    Commented Oct 13, 2017 at 13:33
  • It totally might, but again: set it too strict and your users suffer, set it too wide and it has no effect. And HTTP proxies are cheap, so it's not a financially prohibitive hurdle to require the bot to use a pool of hundreds of proxies with different IPs from different countries.
    – janh
    Commented Oct 13, 2017 at 13:38
0

While there is no reliable way to distinguish genuine AJAX calls from bot ones, in a situation like this you could block access using .htaccess

Plain no referer block (as suggested by @janh2):

RewriteEngine on
RewriteCond %{HTTP_REFERER} ^-?$
RewriteRule ^wp-admin/admin-ajax.php - [F,L]

or with ModSecurity and a custom message:

<Locationmatch "/wp-admin/admin-ajax.php">
SecRule REQUEST_METHOD "POST" "deny,status:401,id:972687,chain,msg:'wp-admin ajax request blocked, no referrer'"
SecRule &HTTP_REFERER "@eq 0"
</Locationmatch>

(Source: https://troyglancy.com/stopped-wordpress-brute-force-attacks-server/)

Again, not something you'd want to do if you weren't already experiencing problems as the referer header can be easily spoofed, but it might make a difference for you or anyone else with an active admin-ajax.php attack vector.

3
  • 2
    If mod_security isn't available, RewriteEngine on\n RewriteCond %{HTTP_REFERER} ^-?$\n RewriteRule ^wp-admin/admin-ajax.php - [F,L] (\n = line breaks) should do pretty much the same, though without a custom message.
    – janh
    Commented Oct 13, 2017 at 14:22
  • This doesn't solve the problem at all.
    – flowdee
    Commented Apr 16, 2018 at 7:46
  • @flowdee sorry to hear that, like I said it is only a partial solution as the referer field can be spoofed. however, I did notice the code in my answer had some curly quotes from a bad copy-paste, I replaced those with straight quotes, this would have prevented it from working.. so you could try it again.
    – majick
    Commented Apr 16, 2018 at 22:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.