WordPress enumerations
Over the years the blogging platform WordPress has ended up being incredibly popular and as a result a huge number of websites are running some version of WordPress these days. As of 2021 some stats put the number of WordPress installs at over 40% of all websites. In any case it's beyond any doubt that a huge number of websites use WordPress and given this huge popularity WordPress has become a target. So I'm looking through my logs the other day and as usual I get a lot of requests that are basically just automated WordPress vulnerability scans from various sources:
I've seen these sorts of things a number of times and I know what they are doing but I didn't know what the name people used for this type of attack was. This post is mostly just for the sake of my memory but it might be useful for other people to know what's going on.
When you see something like:
GET /wp-login.php
GET /wordpress/wp-login.php
GET /wp/wp-login.php
You are seeing a fairly straightforward attempt to probe if the site is running off WordPress. Less obvious is when you see a number of sequential requests like this:
GET /?author=1
GET /?author=2
GET /?author=3
What you are seeing here is a probing of what users are installed, this is known as user enumeration.
Unfortunately in some versions of WordPress this request will resolve to a 301 redirect that contains information about the user names corresponding to the ID. This information is then useful for trying to attempt to brute force passwords and other attacks. Unfortunately this redirect is enabled by default. Even more unfortunately the admin username is in this list and usually has the ID number 1.
It's fairly well known how to automate such a scan and that's what we are seeing here in these logs.
When you go to other services like YouTube and go to videos you'll notice in the URLs they use unique hashes instead of numbers for the videos. The reason is to make it hard to enumerate all the URLs that are available. I wish WordPress did something like this by default since this would stop a few this like this.
Now there's a few other interesting things in the logs too that I've seen lately
GET /wp-json/wp/v2/users
This is an endpoint that basically gives out all the information about the users in a JSON format. If this is enabled then there is no need to enumerate anything, you get everything in one go in a nicely formatted JSON response. Unfortunately before WordPress 4.7 this by default gave back all users, including users that have never made a post. This is especially annoying because people might have admin users that are deliberately not posting on the site.
Overall I find these WordPress defaults to be highly annoying since they make it easier for attackers to brute force the passwords on sites.
What I'd like to do about this
I run a statically generated site so these requests aren't something I'm personally worried about here. I also recommend to people that they statically generate the pages ahead of time for their WordPress sites if they can then serve these up because this is more secure and more performant than having WordPress also serving the webpages.
What I'd really like to do is use asyncIO1 to tarpit all these responses, a bit like this or this.
The only reason I haven't done this already is because I'm statically serving this site and setting up this tarpit would increase the hosting resources and maintenance I need for running this site.
-
Please note it is very important that you use AsyncIO to make this sort of tarpit because you'll have sockets open for a very long time. If you did this with other approaches you might just end up DOS-ing your own website by consuming all your system resources on holding sockets open if those sockets are running on something resource heavy like threads. Also please note that if you tarpit these responses like this you are awesome. ↩