Skip to content

Latest commit

 

History

History

213.81.213.48-campaign

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Staged leafmailer install Campaign

A 12-HTTP-request, 53-second malware installation campaign, that, if made against a previously-compromised WordPress site, would have resulted in installation of a variant WSO web shell, and through that newly-installed WSO shell, a modified leafmailer.

IP Address 213.81.213.48

All HTTP requests come from 213.81.213.48. As far as my records go back (to 2009), 213.81.213.48 has never before accessed my website or WordPress honey pot.

213.81.213.48 → stip-static-48.213-81-213.telecom.sk

stip-static-48.213-81-213.telecom.sk → 213.81.213.48

inetnum:        213.81.213.0 - 213.81.213.255
netname:        ST-POPBA213-NET
descr:          Slovak Telekom
country:        SK
remarks:        In case of security problem notify abuse@telekom.sk
mnt-by:         SK-TELECOM-MNT
created:        2004-10-01T08:38:21Z
last-modified:  2012-12-03T13:37:13Z
route:          213.81.128.0/17
descr:          routes from Slovak Telecom AS6855
origin:         AS6855
mnt-by:         SK-TELECOM-MNT
created:        1970-01-01T00:00:00Z
last-modified:  2012-12-05T13:43:42Z

Remote OS and browser

nmap and p0f3 (for the SYN packet) both agree that 213.81.213.48 had a Linux computer running it.

This disagrees with the User Agent string that got sent with all requests:

Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36

p0f3 doesn't find a good guess for OS for the SYN-ACK packet.

nmap thinks 213.81.213.48's clock isn't synced, that it's about -21m38s off.

HTTP Requests

Timestamp Remote port number URL
2019-06-08T08:16:01.808-0600 45702 /wordpress/wp-content/plugins/revslider/temp/update_extract/revslider/db.php
2019-06-08T08:16:08.030-0600 45708 /wordpress/wp-content/plugins/revslider/temp/update_extract/revslider/db.php
2019-06-08T08:16:13.426-0600 45707 /wordpress/wp-content/plugins/revslider/temp/update_extract/revslider/db.php
2019-06-08T08:16:16.868-0600 45709 /wordpress/wp-content/plugins/revslider/temp/update_extract/revslider/db.php
2019-06-08T08:16:19.308-0600 45709 /wordpress/wp-content/plugins/revslider/temp/update_extract/revslider/db.php
2019-06-08T08:16:31.713-0600 45712 /wordpress/wp-content/plugins/revslider/temp/update_extract/revslider/db.php
2019-06-08T08:16:41.546-0600 45716 /wordpress/wp-content/plugins/revslider/temp/update_extract/revslider/.readme.php
2019-06-08T08:16:54.875-0600 45718 /wordpress/wp-content/plugins/revslider/temp/update_extract/revslider/.readme.php

The TCP port numbers seem a little odd, 45707 is out-of-order, 45709 re-used no other re-use.

p0f SYN packets show more activity at first.

HTTP Particulars

The "Acccept-language" header value of en-GB,en-US;q=0.9,en;q=0.8 seems odd coming from Slovakia.

Connection: keep-alive, but different ports?

Timestamp Cookie(s) HTTP Params
2019-06-08T08:16:01.808-0600 none none
2019-06-08T08:16:08.030-0600 none pass=nhzgrf
2019-06-08T08:16:13.426-0600 WSO auth cookie a=FilesMan, c=/var/www/html
2019-06-08T08:16:16.868-0600 WSO auth cookie a=FilesMan, c=/var/www/
2019-06-08T08:16:19.308-0600 WSO auth cookie a=FilesMan, c=/var/www/html/wordpress/wp-content/plugins/revslider/temp/update_extract/revslider
2019-06-08T08:16:31.713-0600 WSO auth cookie a=FilesMan, c=/var/www/html/, p1=uploadFile
2019-06-08T08:16:41.546-0600 WSO auth cookie none
2019-06-08T08:16:54.875-0600 WSO auth cookie a=FilesMAn, p=uploadFile, c=...

All these accesses come with stereotypical WSO HTTP parameters.

First request retrieves the WSO login page, second request sends "nhzgrf" a very common WSO password. Requests 3, 4, 5 get director listings of 3 directories. Request 6 uploads file .readme.php, a modified WSO web shell. Request 7 is of that modified WSO instance. Request 8 sends a file lead.php, to that modified WSO instance.

The "WSO auth cookie" consists of a cookie with the name md5($_SERVER['HTTP_HOST'), and the corresponding value of the MD5 hash of the password. In this case, md5("stratigery.com") and md5("nhzgrf").

It looks like the attacker(s) thought they were using a previously installed WSO web shell. They installed their own WSO web shell, .readme.php. They thought they used .readme.php to download a leafmailer instance, which they named lead.php. The initial login (second HTTP request) to what they thought was a WSO shell named db.php set a WSO login cookie, which got sent with every request after that, and would have made a real .readme.php act as if a login had occurred.

Why install a WSO instance, using a WSO instance? You could guess something like they thought the original WSO would phone home with the URL of what they installed, but that's not a mod one finds in WSO instances. There's some phone-homes, appearing in WSO 2.5.1 and 2.8 at least, but those just email the URL of the WSO instance invoked, nothing more.

Request timing

The inter-request intervals are between 2.44 and 13.33 seconds. This seems a little long for a program to do the request, but quite fast for a human driver. If a program made the requests, why get the login page first?

Variant WSO Shell

The variant web shell is WSO 2.5 with a prepended set of functions conveniently labled "Mod" in comments.

Deobfuscation

The obfuscation appears visually similar to that of ring.php, a medium-functionality web shell that comes with the "login_wall" compromised plugin. The downloaded file has comments, function and variable names that look like a WordPress plugin. Instead of outputing an in-line image tag, both ring.php and this web shell's original file decode what appears to be a base64-encoded PNG image into PHP source code, then eval it.

The de-obfuscation algorithm is completely different in that it does not use a parameter of the POST invocation to Xor-decode the base64-decoded bytes. It just does a base64_decode and a gzinflate on the result.

By changing eval to print in the code of .readme.php, and running it, we obtain the source code of the web shell.

Analysis

It's pretty much a WSO 2.5 instance, with a few extra capabilities based on invocation with special HTTP parameters.

  1. Disables "safe mode", and allow large file downloads by writing to php.ini in the shell's directory.
  2. Check if the file wp-config.php exists when invoked with an HTTP parameter named "checkwp".
  3. Change a string in the WSO 2.5 instance if an HTTP parameter named "joke" exists. Looks like this is intended to change the MD5 hash used to validate WSO passwords.
  4. Copy the WSO instance to a new file name when invoked with an HTTP parameter named "newname".

The authors of the modifications made WSO slightly more capable, and in a way that's easily remotely invokable. One could just add "?joke=TheNewPassword" and call this WSO to get it to change passwords.

Modified Leafmailer

Installed using newly-installed WSO, .readme.php, by invoking it with classic WSO HTTP parameters, "a", "c" and "p1" "a" has the value "FilesMAn" and "p1" has the value "uploadFile", so if .readme.php had actually gotten installed, it would receive a file named lead.php.

lead,php is substantially identical to an earlier honey pot capture of leafmailer. The PHP is almost entirely identical, except this new leafmailer omits the "phone home" present in my earlier capture. It also includes comments, which the previous leafmailer omitted. I'm sympathetic to the comment removal, as the comments are of the "dumbass" style:

/**
 * The Subject of the message.
 * @var string
 */
public $Subject = '';

Comments that do nothing to enhance a human's code comprehension are worse than useless. Every single comment in this leafmailer repeats the variable or function name in conjunction with a stock phrase. This does nothing to help a human comprehend the code.

Subsequent accesses

It seems like the ultimate goal of this campaign is to use the LeafMailer that would be installed in lead.php. Looking in my web server's history for URLs ending in "lead.php" I find 3 sets of accesses:

Timestamp IP Address URL
2018-09-13 05:14:03-06 193.192.193.153 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/lead.php
2018-09-13 05:15:54-06 193.192.193.153 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/lead.php
2018-09-13 05:16:04-06 193.192.193.153 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/lead.php
2018-09-14 17:25:00-06 89.249.73.162 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/lead.php
2018-09-14 17:25:14-06 89.249.73.162 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/lead.php
2018-09-14 17:25:18-06 89.249.73.162 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/lead.php
2018-09-14 17:25:38-06 89.249.73.162 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/lead.php
2018-09-14 17:26:01-06 89.249.73.162 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/lead.php/
2018-09-14 17:26:12-06 89.249.73.162 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/lead.php
2019-04-04 08:33:27-06 195.206.105.37 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/lead.php

None of is relevant to this campaign, occuring well before it happened. The final lead.php attempted access leads us to a previously unnoticed campaign.

Similar Campaign

Apparently I missed a similar campaign from 195.206.105.37, occuring 2019-04-04 08:31:17-06 through 2019-04-04 08:32:04-06

Timestamp URL
2019-04-04 08:30:39-06 /wordpress//wp-content/plugins/wp-mobile-detector/cache/db.php
2019-04-04 08:30:39-06 /favicon.ico
2019-04-04 08:30:42-06 /wordpress//wp-content/plugins/wp-mobile-detector/cache/db.php
2019-04-04 08:30:49-06 /wordpress//wp-content/plugins/wp-mobile-detector/cache/db.php
2019-04-04 08:30:59-06 /wordpress//wp-content/plugins/wp-mobile-detector/cache/db.php
2019-04-04 08:31:13-06 /wordpress//wp-content/plugins/wp-mobile-detector/cache/db.php
2019-04-04 08:31:17-06 /wordpress//wp-content/plugins/wp-mobile-detector/cache/.readme.php
2019-04-04 08:31:33-06 /wordpress//wp-content/plugins/wp-mobile-detector/cache/.readme.php
2019-04-04 08:31:37-06 /wordpress//wp-content/plugins/wp-mobile-detector/cache/.readme.php
2019-04-04 08:31:41-06 /wordpress//wp-content/plugins/wp-mobile-detector/cache/.readme.php
2019-04-04 08:31:47-06 /wordpress//wp-content/plugins/wp-mobile-detector/cache/.readme.php
2019-04-04 08:32:04-06 /wordpress//wp-content/plugins/wp-mobile-detector/cache/.readme.php
2019-04-04 08:33:02-06 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/db.php
2019-04-04 08:33:04-06 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/db.php
2019-04-04 08:33:27-06 /wordpress//wp-content/plugins/revslider/temp/update_extract/revslider/lead.php

p0f believes that the attacker(s) ran "Firefox 10.x or newer" on "Windows 7 or 8". That's believable, a single User Agent got used, "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0"

I can believe that a human drove these requests based on the attacker retrieving /favicon.ico, which automated programs rarely do, and the intervals between requests, which are quite long, minimum of 2 seconds, most of the intervals much longer.