Here's a short, 3.993 second WSO (Web Shell by oRb, a.k.a. "FilesMan") installation. It includes only eight HTTP requests, including a cold WordPress login. The attacking IP address, 77.72.82.12, has probably never accessed my web server before.
The username/password used was first "discovered" by 5.39.27.194, which apparently only does WordPress password guessing. There's a hidden (to me) connection between 5.39.27.194 and 77.72.82.12.
77.72.82.12 reverse lookups as hostby.ups-gb.co.uk
hostby.ups-gb.co.uk does not have an A record
whois
says 77.72.82.12 is owned by a UK company:
organisation: ORG-UPSL4-RIPE
org-name: United Protection (UK) Security LIMITED
address: 141-149 Lower Bryan Street, Hanley, Stoke On Trent, Staffordshire, England, ST1 5AT
address: United Kingdom
mnt-by: UPUKS-MNT
created: 2017-01-24T19:50:55Z
last-modified: 2017-10-30T14:45:58Z
The routing is a little odd:
descr: NFOrce Entertainment BV - route 77.72.82.0/24
origin: AS43350
mnt-by: MNT-NFORCE
created: 2017-02-01T14:01:04Z
last-modified: 2017-02-01T14:01:04Z
traceroute
goes through cogent1-gsa.r2.dbc.nl.as43350.com, which geoiplookup
says is in Netherlands,
but geoiplookup
has 77.72.82.12 as in the UK.
It appears that some trans-Atlantic cables go from USA to Netherlands directly,
but many more go directly to Great Britain.
p0f3
identifies 77.72.82.12 as "Windows 7 or 8"
[2018/08/30 14:58:19] mod=syn|cli=77.72.82.12/53502|srv=162.246.45.144/80|subj=cli|os=Windows 7 or 8|dist=12|params=fuzzy|raw_sig=4:116+12:0:1460:8192,8:mss,nop,ws,nop,nop,sok:df,id+,ecn:0
Fairly easy to deobfuscate, it only required changing "eval" to "print", then running the program to get the next level of obfuscated code. I did that several times to get a copy of WSO 2.5.
Everything else is unobfuscated at the level that my WordPress honey pot sees things.
Timestamp of request | Action requested of WordPress |
---|---|
2018-08-30T03:39:13.440-0600 | Cold call to WordPress login page. No cookies, no HTTP parameters. |
2018-08-30T03:39:13.835-0600 | Attacker sends WordPress "cookie check" cookie back, no WordPress user or password. |
2018-08-30T03:39:14.171-0600 | Attacker sends WordPress login as admin/1234qwer, proper WordPress HTTP parameters |
2018-08-30T03:39:14.444-0600 | Attacker sends request for WordPress admin dashboard. WordPress logged-in-cookies set correctly |
2018-08-30T03:39:15.036-0600 | Sends request for theme editor page |
2018-08-30T03:39:15.668-0600 | Request to edit 404.php file from theme twentytwelve in browser. |
2018-08-30T03:39:16.171-0600 | Compromised 404.php file contents sent to theme editor to save. |
2018-08-30T03:39:16.977-0600 | Invocation of /blog/wp-content/themes/twentytwelve/404.php , which should get a WSO login page |
2018-08-30T03:39:17.434-0600 | Invocation of /blog/wp-content/themes/twentytwelve/404.php with HTTP "pass" parameter set incorrectly |
This isn't the most direct way of compromising a file on a WordPress site,
but it also isn't exactly the sequence of calls that a human-driven browser would make, either.
For example, wp-login.php
has links to JavaScript and CSS files that this attacker did not ask for,
but a real browser would.
I don't think a human-driven browser could jump in to editing a file in a theme without some intermediate
pages getting displayed, either.
There's also no real need to make a "cold call" of wp-login.php
: it's entirely possible to
set login name/password and the required cookies in a single invocation of wp-login.php
.
The final HTTP request called 404.php
directly, as opposed to asking for a nonexistent URL
and letting Apache or WordPress invoke 404.php
.
Unfortunately, the attacker put an ASCII carriage return (control-M, "\r")
at the beginning of the HTTP parameter name: "\rpass" instead of "pass".
This seems like some kind of Windows-text-editor problem that leaked through.
It also kept the attacker from logging in to my WSO honey pot.
The WSO password it sent: "ryfgddj".
Unfortunately, entities access URLs with "twentytwelve/404.php" quite often, 29133 times between 2014-03-10 15:04:20-06 and 2018-09-01 23:40:43-06. I don't think that looking at accesses of "twentytwelve/404.php" would bear fruit.
Since the attacker logged in on it's first try, examining the user ID and password seems important.
admin/1234qwer first logged in to my WordPress honey pot:
2017-11-24T21:55:39-07:00 5.39.27.194 admin 1234qwer
This may not be first successful login with this password. I've lost some data along the way, due to running a honey pot off-and-on for some years. Disks fill up, I forget to load Apache log files, etc etc.
"1234qwer" as a WordPress password guess is pretty common. It got tried 221 times between 2017-11-21T02:05:19.42-07:00 and 2018-08-31T09:21:52.347-06:00, by 92 different IP addresses, in combination with 127 different user names. Some of the user names are obviously mistakes ("{domain}" probably constitutes a failed template expansion). "admin" got used 75 of the 221 times. My WordPress honey pot allows user name enumeration through the "see all posts by this author" misfeature. Many, but not all ("paul-mureithi", "stratigery") are the result of random user IDs composed by the user name enumeration misfeature emulation.
Four "cycles" of guessing passwords:
- cycle 1: 101 passwords, stopping at "adminadmin", a successful login
- cycle 2: same sequence of passwords, but stops at "1234qwer", also a successful login
- cycle 3: same sequence of passwords, but stops at "1234qwer"
- cycle 3: different sequence of 22 passwords, stops at "adminadmin"
The mean time between login attempts is 0.231 seconds, median is 0.219 seconds. The distribution of inter-login-intervals doesn't look meaningful. The short inter-attempt interval confirms this was completely automated.
The cycles begin and end with an HTTP GET method request. All other requests use the HTTP POST method.
My WordPress honey pot accepts any password as legitmate with a probability of 0.00050 (1 in 2000). It also keeps track of any passwords it has deemed legitmate in the past. Previously, on 2017-11-21T16:26:28-07:00, the WordPress honey pot had granted 91.200.12.75 access with user name "admin", password "adminadmin". So 5.39.27.194 got to "adminadmin" in its list of passwords to try, and the honey pot let it in.
Cycle 2 took place about 3.5 hours later. During that cycle of guessing, the WordPress honey pot got the random number that means "allow this password", and let 5.39.27.194 in on "1234qwer". At a guess, Cycle 3 is double-checking the odd results (to bottom feeding WordPress password guesser) that Cycles 1 and 2 gave. 5.39.27.194 got to "1234qwer" before "adminadmin", and got logged in on that. Cycle 4 got to "adminadmin" before it tried "1234qwer".
This looks like another unfortunate interaction between WordPress honey pot design, and real life. It might be better to have a specific password for a honey pot. Potentially, nobody will guess it unless it's something really lame like "1234", so that's a drawback. Also, the honey pot wouldn't harvest as many potential passwords. Perhaps a WordPress honey pot that doesn't accept any password, merely logs guessing IP address, from port, time and password would be in order just to capture password guessing lists.
This IP address seems to be doing only WordPress password guessing. 5.39.27.194 only used 110 distinct candidate passwords. A few got tried 4 times, but many only got tried a single time. "1234qwer" got tried 4 different times. I put 5.39.27.194's password guessing history in a file.
The IP address 5.39.27.194 has performed at least 209 accesses
between 2017-11-24T18:28:51-07 and 2017-11-30T11:57:15-07
All of the accesses asked for /wp-login.php
URIs, except the following.
Timestamp | URI |
---|---|
2017-11-24 18:29:14-07 | /wp-admin/ |
2017-11-24 21:55:39-07 | /wp-admin/ |
2017-11-28 08:49:31-07 | /wp-admin/ |
2017-11-30 11:57:15-07 | /wp-admin/ |
Each of those corresponds to a successful WordPress "login" to my honey pot.
User agent string: " Mozilla/5.0 (Linux; U; Android 2.2) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"
which disagrees with p0f3
assessement of "Windows 7 or 8"
Password guessing cycle timings:
- 2017-11-24T18:28:52.018-0700 to 2017-11-24T18:29:14.445-0700
- 2017-11-24T21:55:30.406-0700 to 2017-11-24T21:55:39.005-0700
- 2017-11-28T08:49:23.093-0700 to 2017-11-28T08:49:31.748-0700
- 2017-11-30T11:57:09.182-0700 to 2017-11-30T11:57:15.101-0700
p0f3
recorded these TCP SYN packets from 5.39.27.194:
Timestamp | From port | distance (hops) | Guessing cycle |
---|---|---|---|
2017-11-24 18:28:51-07 | 58756 | 17 | Cycle 1 |
2017-11-24 18:29:14-07 | 61183 | 17 | ??? |
2017-11-24 21:55:29-07 | 64280 | 17 | Cycle 2 |
2017-11-28 08:49:22-07 | 62903 | 17 | Cycle 3 |
2017-11-30 11:57:08-07 | 62547 | 17 | Cycle 4 |
Ephemeral port numbers for Windows 7 and up are supposedly 49152 to 65535. Linux supposedly uses 32768 to 61000 by default. The 4 TCP "from" port numbers greater than 61000 would support a Windows 7 or 8 OS, as opposed to Linux.
It isn't out of the question to see only 5 TCP port numbers for 200+ HTTP requests. The attacker used HTTP/1.1 on all requests.
I unfortunately don't log from port in my attempted logins file, so I can't tell what the port 61183 comes from.