Skip to content

Latest commit

 

History

History
268 lines (213 loc) · 9.24 KB

File metadata and controls

268 lines (213 loc) · 9.24 KB

Object Oriented Malware Dropper

Ultimately, this attack would install obfuscated "v2.0-1" extensible backdoor, nothing new there.

The real innovation is in the PHP dropper code. Whoever wrote this caught the Object Oriented sickness. class DomainFramer2 is a miracle of Object Oriented Overdesign.

The other interesting thing is one of the two cookies passed along in the HTTP request. The uninteresting cookie of the pair is a WSO login cookie, where the name of the cookie is md5($_SERVER['HTTP_HOST']) and the value is the MD5-hash of a predetermined password. WSO web shells have code to check if that cookie exists and is correct, otherwise, it only sends the requestor a login page.

The second cookie has both name and value of "7a017e28704d15b0d8efe38606806610" This lexically equals what PHP can calculate as

md5(md5($_REQUEST['HTTP_HOST']) . $_REQUEST['HTTP_HOST'] . "salt1I*@#31RTds34+543sf")

The value of $_REQUEST['HTTP_HOST' is "www.stratigery.com" for this particular HTTP request.

This is password for the extra password protection that Vigilante malware hunter writes into all WSO web shells it finds. Either the Vigilance Committee sells WSO access, or this is an example of their follow-on malware.

This is also a close relative of the V3-01 backdoor. It's only missing the built-in "TdsClient" code.

Origin

IP Address 46.182.5.3

46.182.5.3 has the DNS name gatewayemail.hosteur.net

gatewayemail.hosteur.net has the address 46.182.5.30 in DNS.

That's convenient, and very diligent.

whois says this about 46.182.5.3:

inetnum:        46.182.5.0 - 46.182.5.255
netname:        TDF-CL05
country:        FR
status:         ASSIGNED PA
created:        2013-04-09T13:12:22Z
last-modified:  2018-04-04T10:52:02Z
route:          46.182.4.0/22
origin:         AS204818
created:        2018-01-08T11:24:34Z
last-modified:  2018-01-08T11:24:34Z


Domain Name: HOSTEUR.NET
Registry Domain ID: 100896431_DOMAIN_NET-VRSN
Registrar WHOIS Server: whois.hosteur.com
Registrar URL: http://www.hosteur.fr
Updated Date: 2018-07-18T23:00:24Z
Creation Date: 2003-07-22T09:35:13Z
Registry Expiry Date: 2022-07-22T09:35:13Z
Registrar: HOSTEUR SARL
Registrar IANA ID: 1378
Name Server: DNS1.HOSTEUR.COM
Name Server: DNS2.HOSTEUR.COM

whois says this about hosteur.net:

Domain Name: hosteur.net
Registry Domain ID: 100896431_DOMAIN_NET-VRSN
Registrar WHOIS Server: whois.hosteur.com
Registrar URL: https://www.hosteur.com
Updated Date: 2018-07-19T01:00:24Z
Creation Date: 2009-11-22T09:01:50Z
Registrant Organization: 
Registrant Street: route du lac lussy 201, 
Registrant City: Ch??tel Saint Denis
Registrant State/Province:
Registrant Postal Code: 1616
Registrant Country: CH

Looks like an ISP in Chatel St Denis, a picturesque Swiss town on the western side of Switzerland, near Lausanne. How delightful!

Download

This code arrived 2019-03-08T17:05-0600.

The attacker(s) believed they were requesting the "RC" action of a WSO web shell, with the path part of of the URL as /wordpress/wp-content/plugins/wp-mobile-detector/cache/db.php.

They sent two HTTP parameters, "a" and "p1". WSO instances will immediately eval any PHP they find as the value of the "p1" parameter, if the "a" parameter has the value "RC", and it does have that value. This is one of the many ways people use WSO instances, this time as an immediate-code-evaluation back door.

Deobfuscation

The dropper code required no deobfuscation: the attacker(s) sent it un-encoded.

The PHP of the extensible back door that it was supposed to put in place just required a call to PHP's builtin rawurldecode().

Analysis

This is the main flow-of-control. It's clear enough.

$framer = new DomainFramer2("if%...);
$framer->find_paths();
$framer->preprocess_paths();
$framer->process($force_inject=TRUE);
$cscripts = $framer->get_cscripts();

class Obfuscator

public function __construct($script)
static public function rand_str($min, $max)
public function generate($key)
private function _gen_stub()
private function _encode_payload($key)

The constructor loads up a PHP payload (the $scrit). The other functions serve to obfuscate the PHP payload, and surround the obfuscateed PHP payload with a PHP script that would deobfuscated the PHP payload.

All of that fits in a string that can be "injected" into some other PHP source code file.

Reasonably good SOLID design: this class has a single responsibility, turning PHP source code in a string into another string, that's obfuscated PHP code. It's not really open for extension, but it's definitely closed for modification. No public variables, and it does not give back any instance variables in the form of references. Class Obfuscator doesn't seem too easy to subclass, so I'll give conformance to Liskov Substition Principle a C. Decent interface segregation. The user only has to contruct, and call generate(). I'll give it a B for Dependency Inversion. It really only deals in PHP strings.

class DomainFramer2

Class DomainFramer is where the attacker(s) went overboard on object orientation (OOOO).

public function __construct($backdoor_payload)
public function find_paths()
public function preprocess_paths()
public function process($force_inject=FALSE)
public function get_cscripts()
private function _process_one($path, $force_inject=FALSE)
private function _try_create_index($index_php)
private function _preprocess_one($path)
private function _fix_index_php($path)
private function _dump_backdoor($root_dir)
private function _patch_file($path, $root, $force_inject=FALSE)
private function _patch_index($path, $force_inject=FALSE)
private function _patch_cms($path, $force_inject=FALSE)
static public function walk_dir($dir, $depth=0, $skip_files=FALSE, $skip_dirs=TRUE)
static public function fix_rights($path)
static public function fix_time($path)
static public function get_docroot()
static public function morph_str($string)
static public function gen_space_string($len)
static public function morph_php_str($string)
static public function insert_in_head($path, $php_code, $force_inject=FALSE)
public function last_error()

The class has lots of "utility" functions that do not depend on instance variables included in this class. Perhaps there should be a third class here, or maybe just functions.

Because when doing OOOO everything has to be a method, the attacker(s) ended up writing 4 lines where 1 would do. They alse end up having to call these methods as class methods (DomainFramer2::fix_rights(...))

static public function fix_rights($path)
{
	@chmod($path, 0755);
}

static public function fix_time($path)
{
	@touch($path, time() - mt_rand(60*60*24*30, 60*60*24*365));
}

I'm going to guess that whoever re-wrote this was a High Ceremony Java programmer, maybe formally trained and maybe certified.

Proof of a re-write

I'm going to try to make the case that class DomainFramer2 constitutes a rewrite of the code-in-cookie backdoor's dropper, which is also common to the extensible back door.

Class DomainFramer2's static public function get_docroot() is virtually identical to code-in-cookie backdoor's function GetDocRoot()

get_docroot(), member function of class DomainFramer2:

static public function get_docroot()
{
    $request_uri = "";
    $docroot = "";
    if (strpos($_SERVER['REQUEST_URI'], "?") !== FALSE) {
        $request_uri = explode("?", $_SERVER['REQUEST_URI']);
        $request_uri = $request_uri[0];
    } else {
        $request_uri = $_SERVER['REQUEST_URI'];
    }
    $docroot_end = strrpos($_SERVER['SCRIPT_FILENAME'], $request_uri);
    if ($docroot_end === FALSE) {
        $docroot = $_SERVER['DOCUMENT_ROOT'];
    } elseif ($docroot_end === 0) {
        return "/";
    } else {
        $docroot = substr($_SERVER['SCRIPT_FILENAME'], 0, $docroot_end);
    }
    return str_replace("\\", "/", $docroot);
}

Function GetDocRoot() from code-in-cookie backdoor

function GetDocRoot()
{
    $request_uri = "";
    if (strpos($_SERVER['REQUEST_URI'], "?") !== FALSE) {
        $request_uri = explode("?", $_SERVER['REQUEST_URI']);
        $request_uri = $request_uri[0];
    } else {
        $request_uri = $_SERVER['REQUEST_URI'];
    }
    $docroot_end = strrpos($_SERVER['SCRIPT_FILENAME'], $request_uri);
    if ($docroot_end === FALSE) {
        return $_SERVER['DOCUMENT_ROOT'];
    } elseif ($docroot_end === 0) {
        return "/";
    } else {
        return substr($_SERVER['SCRIPT_FILENAME'], 0, $docroot_end);
    }
}

The same is true of class DomainFramer2's static public function walk_dir() and code-in-cookie backdoor's function GetDirectoryList(). The code is almost an exact match between the two.o

I will grant you that the code-in-cookie's PHP dropper is not a miracle of software engineering. But I also think that class DomainFramer2's author did not make anything clearer by doing doctrinaire object oriented overdesign.