How WordPress Gets Hacked in 2022 - Initial Reconnaissance

WordPress is the most popular open-source CMS in the world, as such it carries with it a massive target. For a bad actors it makes all the sense in the world to spend time and resources understanding the platform, especially its weaknesses and features. This article will build on this, and some research we're doing on our end to help quantify the tactics, techniques, and procedures (TTP) being used by bad actors in 2022.

This article also builds on analysis we saw in our previous thread on a hacked web server (part 1 and part 2) and another article we shared last year on XMLRPC and WP-JSON.

The fundamental difference in this post, from the past posts, is that this will be build on research we're doing via our honeypots. The insights, and opinions, below are derived from analysis we're actively doing to better understand the threat landscape.

Creating a Control Environment

The key to any research is establishing a solid control environment. One that we can monitor closely, but presents no danger to our environment allowing the attackers to move freely while we actively record their actions.

Here is what we configured:

Name Description
Date Created 07/22/2022
Time Created 14:24
Time Zone UTC
Host Cloud Provided VPS (Not GCE, AWS)
Tech Stack Linux, Apache, MariaDB, PHP
Application Stack WordPress
Application Security Lets Encrypt SSL only
Server Security None
Logging Trunc
Other Scripts Created a custom script to intercept all requests and record post requests.


We've been working with web application security for over 12 years so we went into this with a pretty good idea of what to expect. We know that the access vector has led hacks for a better part of a decade, and didn't expect that to change. We also knew that a close second to the access vector was software vulnerabilities, specifically those found in the extensible components of an application (think plugins and themes) more than core. What we weren't sure about was how fast it would occur, or if the order was still correct.

Two things should stand out in the configuration above. First, it's the configuration of logs to a third-party. This was critical to ensure that if we lost the server completely we limited the risk of losing the reliability, integrity, of the logs. Via our configuration we are given a high degree of confidence that the logs are in tact, regardless of what happens with the server. Second, it is imperative we understand what the attacker is sending to the server, that is why we created a script to record all POST requests. This will help confirm what we believe is being sent, and removes all doubt.

Let's dive into the research.

Time to First Contact

We know that the server was created on July 22nd, at 14:24 UTC. Coincidently, the very query that appeared as a bad actor came in at 03:28 on July 23rd (11 hours or so after creation). What is fascinating is what they queried first:

2022-07-23 03:28:25 - 199.15.251.34 [] /wp-login.php Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:96.0) Gecko/20100101 Firefox/96

2022-07-23 03:28:26 - 199.15.251.34 [] /?author=1 Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:96.0) Gecko/20100101 Firefox/96

2022-07-23 03:28:27 - 199.15.251.34 [] /author/administrator/ Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:96.0)  Gecko/20100101 Firefox/96

2022-07-23 03:28:29 - 199.15.251.34 [] /wp-json/wp/v2/users/ Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:96.0) Gecko/20100101 Firefox/96

2022-07-23 03:28:30 - 199.15.251.34 [] /?author=2 Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:96.0) Gecko/20100101 Firefox/96
	                    


If you're curious what is happening, the bad actor is querying users. When the user queries ?author=1 it is taking them to the Author page /author/administrator/. This tells the bad actor the name of the user. They then query the JSON API to see what other users might exist here: /wp-json/wp/v2/users/.

This is what they saw on our site by passing that slug to the URL:

[{"id":1,"name":"administrator","url":"https:\/\/[domainname].net","description":"","link":"https:\/\/[domainname].net\/author\/administrator\/","slug":"administrator","avatar_urls":{"24":"https:\/\/secure.gravatar.com\/avatar\/[id]?s=24&d=mm&r=g","48":"https:\/\/secure.gravatar.com\/avatar\/[id]?s=48&d=mm&r=g","96":"https:\/\/secure.gravatar.com\/avatar\/9ed94b19d58705577d8b6bf83653a97b?s=96&d=mm&r=g"},"meta":[],"_links":{"self":[{"href":"https:\/\/[domainname].net\/wp-json\/wp\/v2\/users\/1"}],"collection":[{"href":"https:\/\/[domainname].net\/wp-json\/wp\/v2\/users"}]}}]

We saw a total of 16 requests to /wp-json/wp/v2/users/ between July 22nd and July 27th from 10 unique IP addresses:

IP # of requests ASN
199.15.251.34 1 ELIA-60, US
20.213.77.180 4 MICROSOFT-CORP-MSN-AS-BLOCK, US
20.243.145.52 1 MICROSOFT-CORP-MSN-AS-BLOCK, US
199.15.251.34 1 ELIA-60, US
52.252.96.140 1 MICROSOFT-CORP-MSN-AS-BLOCK, US
135.181.7.82 1 HETZNER-AS, DE
20.92.234.205 1 MICROSOFT-CORP-MSN-AS-BLOCK, US
116.203.215.91 1 HETZNER-AS, DE
168.138.10.225 1 ORACLE-BMC-31898, US
137.184.140.67 1 DIGITALOCEAN-ASN, US


Side note: Interesting to see Microsoft Azure servers leading the pack here.

We then saw our very first Brute Force check using XMLRPC at 2022-07-23 08:38:35 here:

2022-07-23 08:38:35 - 31.216.62.146 {"<?xml_version":"\"1.0\"?><methodCall><methodName>system.multicall<\/methodName><params><param><value><array><data><value><struct><member><name>methodName<\/name><value><string>wp.getUsersBlogs<\/string><\/value><\/member><member><name>params<\/name><value><array><data><value><array><data><value><string>administrator<\/string><\/value><value><string>administrator<\/string><\/value><\/data><\/array><\/value><\/data><\/array><\/value><\/member><\/struct><\/value><\/data><\/array><\/value><\/param><\/params><\/methodCall>"} /xmlrpc.php Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96

Interesting enough, between the first query and the last we only saw 6 requests to XMLRPC using <string>administrator<\/string> before it stopped at 2022-07-23 11:42:11. We say it stopped because it seems like another attacker joined the scanning process. We assume it was another attacker because unlike the first that was rotating their IP, this one decided to do it all from their stationary machine at: 20.213.77.180. This IP is on the MICROSOFT-CORP-MSN-AS-BLOCK, US network, most likely an Azure machine (non web server), and was more interested in wp-login / wp-admin.

This user was particularly interesting because he first started by inundating XMRLPC with requests like this:

2022-07-23 11:48:11 - 20.213.77.180 [] //xmlrpc.php Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4240.193 Safari/537.36

Unlike the previous articles he wasn't passing anything across in the POST request, or misusing multicall, so they weren't doing much other than stressing the server (or maybe they just made a mistake in their configuration).

On the 23rd alone this user sent 2,783 requests to the same machine and it started at 11:48:10 on July 23rd and ended at 12:03:12, all with empty POST requests (that was about 50% of the total requests we have seen since (through July 27th).

At 12:03:13 he began a different attack, and this was specifically a brute force attempt targeting wp-login.php and wp-admin respectively.

The very first BF attempt sent this request:

2022-07-23 12:03:13 - 20.213.77.180 {"log":"administrator","pwd":"admin","redirect_to":"https:\/\/[domain].net\/\/wp-admin\/","testcookie":"1"} //wp-login.php Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4240.193 Safari/537.36

You can see how they are passing the administrator for the username and admin as the password. Great reminder never to use simple passwords like Admin, or Password (which was the fourth try in their scan). If that is not enough of a reason, here are a few of the passwords we recorded:

123456
12345
administrator@123
administrator123
administrator
admin
passpass
pass
password



And here is a reminder we are not as unique as we think we are:

passw0rd
passwd
password01!
password01
p@$$w0rd
p0o9i8u7
p455w0rd
p4ssw0rd
p4ssword
pa$$w0rd
pa$$word
pa55w0rd
pa55word



If you find yourself thinking of the absurdity of a user using password may I direct your attention to exhibit A (July 24, 2022):



All in all the number of XMLRCP requests abusing multicall was a bit underwhelming, but it is of interest to bad actors. We recorded 231 requests targeting it, and 229 different IPs making the request.

Coincidently, in contrast to the XMLRPC requests targeting multicall, there were only 7 IPs targeting XMLRPC with an empty POST request for a total 4,825 requests. Here are those IPs:

IP # of requests ASN
20.213.77.180 2,783 MICROSOFT-CORP-MSN-AS-BLOCK, US
20.243.145.52 831 MICROSOFT-CORP-MSN-AS-BLOCK, US
87.250.224.194 1 YANDEX, RUS
52.252.96.140 109 MICROSOFT-CORP-MSN-AS-BLOCK, US
20.92.234.205 100 MICROSOFT-CORP-MSN-AS-BLOCK, US
168.138.10.225 1,000 ORACLE-BMC-31898, US
35.231.214.30 1 GOOGLE-CLOUD-PLATFORM, US


Interesting, Microsoft Azure servers coming in strong again. Wonder if it's easy enough to speculate that it is the same user?

What The Initial Recon Tells us About Attacks Against WordPress in 2022

We are the first to admit that this is not the most comprehensive test, and not statistically significant, but it is interesting none the less. We're thinking a lot of the empty XMLRPC requests, and another interesting possibility, might be that they are sending the multicall payload via the input requests. We've updated our logger to account for this so we'll be able to confirm things shortly.

It's great to see that not much has changed, and access continues to be the leading vector being abused by bad actors, but we were surprised to see very limited scans for known vulnerabilities. In the three days since going live, almost all the focus has been on access, specifically targeting wp-admin / wp-login.php. This is dramatically different to the what we saw in 2014 / 2015 / 2106 where it was a shotgun approach to scanning for high impact vulns like TimThumb, MailPoet and so many others. More time will show whether this behavior changes. Maybe it was just this specific attackers modus operandi.

We do find ourselves very curious how the attackers found it in the first place. It brings us back to some of the conversations around attackers monitoring certificate creation via the Certificate Transparency (CT) logs. But that is highly speculative.

What we do have a high degree of confidence is that all WordPress users should expand their basic hardening controls for WordPress to focus on blocking access to the JSON API and XMLRPC by default. Here are some recommendations on what you can do without a plugin using .htacess at the root of your domain:

<Files xmlrpc.php>
order deny,allow
deny from all
allow from xxx.xxx.xxx.xxx
</Files>

# BLOCK REQUEST TO WP REST API
# Block/Forbid Requests to: /wp-json/wp/
# WP REST API REQUEST METHODS: GET, POST, PUT, PATCH, DELETE
RewriteCond %{REQUEST_METHOD} ^(GET|POST|PUT|PATCH|DELETE) [NC]
RewriteCond %{REQUEST_URI} ^.*wp-json/wp/ [NC]
RewriteRule ^(.*)$ - [F]
						


Lastly, we'll be reporting on Part II as we analyze this further. We have since updated the password within the standard deviation of what they're trying so that we can track what they do next. Stay tuned!



Posted in   Security_Research   WordPress     by noc_team

Improve Your Websites Speed and Security