Monday, January 11, 2016

MMD-0050-2016 - Incident report: ELF Linux/Torte infection (in Wordpress)

The indicator

Several hours ago, it was detected a suspicious inbound access on a Wordpress site with the below log:
(Thank's for the hard work from Y)
It's an unusual traffic coming from the unusual source of ip address:||56534 | | PIRIX-INET | RU | | Comfortel Ltd. | |57010 |  | CLODO      | RU |      | IT House Ltd
..the requests were aiming the "uploaded" index.php file in this Wordpress site, that contains malicious code:

The PHP has two functions, depends on the sent parameter, either it will print the eval() value of the remotely sent (likely obfuscated) data via HTTP (see the first condition), or the second option, will write the file with the data grabbed from the posted parameters.

From the sysadmin point of view, up to this step we know it's malicious and but we usually don't know what this is all about without web-searching here and there on these insufficient information, if we lucky maybe we can find the clue.. But in this case, the site's administrator is smart to manage a record of the inbound suspicious traffic for the session accessing the index.php.

From its data's part we extracted and beautified the posted text as per follows, and the new adventure is started from here..

It's a sequence of base64 encoded blob of data as arrays posted as a form's parameter value to the index.php file. Which is having an eval() value in it to be decoded in the index.php as per explained above. Yes, there's no way an admin can see this malicious activity evidence unless the stream data is captured or recorded (or it's a bit out of context but maybe we can do a proactive research to find the tool set used in a CNC site that was being used post this attack).

What is this?

What is the data, and what is it for. Let's decode it one step further.

The decoded results are as below; the first part:

The first data stored in $env variable is obviously another encoded base64 data, the rest is a PHP code. The comments in the picture explained it downloads remote file & targeting Linux system that can execute the shell command via PHP environment.

The next part is:

In this part we can see the rest of the malicious process as per described in the picture's comment.
The download hostname is resolved to below IP in RU network.||57010 | | CLODO | RU | | IT House Ltd

The point is, no trace for the downloaded file too since it will be deleted afterward. And, the shell execution is performed under environment of $env. So what the $env is? Let's decode it further:

Okay we can see some obfuscation in tags, some strings that doesn't make any sense and we can see some short codes. This must mean something, and we need the decrypter logic for it.

Using ELF payload decrypter logic

At this point it's time to see the payload downloaded for this threat, the crond32 and crond64.

It's up and alive, good. What are they?

These are ELF malware files. And obviously, the encoder logic must be in it.

Apparently this ELF grabs XDVSN_SESSION_COOKIE value via syscall from the shell environment, so we are in the right track and.. trailing a bit further to find the decoder scheme:

So the decoded base64 is parsed to a xor function, with the key value:

Knowing this part is good for the next low level monitoring purpose, and this is the important part since the rest of the process of the ELF will rely on the result. Now we will know exactly what to do.

A note: I have one habit in analyzing ELF cases we handle, if I think we know and have full control to a malware, I tend to make a PoC as infection evidence by the method of: "let's feed them with anything they want to detonate its malicious process, this method is actually not a good way to do for the beginners, and in my case I reversed it well first to make it sure it is safe beforehand.

Okay, moving on, in this case the similar method above was applied, and the parsed $XDVSN_SESSION_COOKIE is showing the below result:

You can see the three more malicious URL under domain inside the blob of data above under the tag of <lu>, <bu> and <su> and there are other tags too. Those hostnames are pointing to one IP located in LeaseWeb network in North Holland:

  "ip": "",
  "hostname": "",
  "city": "Amsterdam",
  "region": "North Holland",
  "country": "NL",
  "loc": "52.3740,4.8897",
  "org": "AS60781 LeaseWeb Netherlands B.V.",
  "postal": "1000"

Just to make sure these tags means something and the decryption is correct, in this ELF binary must be spotted the exact handler for each tag keyword, I checked again the ELF's assembly for these keyword's variable allocation code:

Now we all can be sure the data is correct. In every tag there is a handler for each and this ELF is composing them to further bad action(s).

Recognition of the Torte botnet threat

At this point our team remembered analysis of Torte Botnet published by Akamai researchers, you can view it here [link], and showing all of the infection indicators collected are matched. The report is having a lot of explanation of the overall threat scheme and the further ELF malware's work to interact with the CNC url to get more data to, in the end, send spams via SMTP connection which I also confirmed the same functions are found in this malware.

Okay, so what had happened here??

As for our incident case, it is an attempt to infect a Linux node to be part of the Torte Spam Botnet with using ELF malware (called as "Torte botnet spooler binary" by Akamai ; to make it simple, alongside to other ELF malware binaries let's call it as Linux/Torte).

The infection is cleverly done through a remote access interfaced by compromised Wordpress' uploaded PHP file, by a posted HTTP encoded data. And upon succeeded the threaded malware processes will run in the Linux server's memory without leaving much trace, except (1)a single index.php file used in initial hack as the backdoor of infection, (2)the malicious process and (3)several malicious environment variables used.

Behavior analysis

In a test bed the malware will initially load dynamic linker to load its shared libs/objects.

It then seeked and loaded the below list of its dependency libraries:


To perform its malicious activities, this malware is utilizing shell environment as its place to store its variables. In an infected machine, the Linux environment variables will be modified (mostly added) to support this malicious scheme, this can be used as reference by sysadmins as indicator for this infection too.

Below is the snapshot of the variables, please see the marked part. (There are also shell variables from web server's environment's too as "noise", please kindly bear with it).

In the marked entries you can see malware HTTP request variables.

The ELF malware saved and run in infected system as threaded "ps" processes. The original file was deleted right after the ELF malware is executed. If you use list of files (lsof), this process will be shown as "ps (deleted)". Again, the malicious shell variables and the "ps (deleted") process is what mostly to be spotted in an infected system instead of the injected index.php (or any name .php).

So far there's no sign of any persistent effort for malware, i.e.: an autostart, to survive the reboot. It looks like the actor(s) wanted it to be that way for some reason. The deletion of the malicious "ps" processes, following by unset the malicious environment variables will cure the system, don't forget to delete the index.php (the uploaded backdoor file) and patch the Wordpress flaw.

Block list

It is very recommendable to block this listed hostnames and IP addresses:    (CNC backconnect source) (wordpress attacker bot/backdoor source)  (wordpress attacker bot/backdoor source) (malware download server)

Outbound traffic filtration note

This part is copy of the outbound traffic filtration plan I made in email for follow up. I think it is good for others to know too, so please bear the textual format.

This threat, without traffic record, it's hard to analyze. But in the ELF is stated all we need to figure its outbound connection. Like access to GET request:

[0x0804b280]> pd @0x0804DE24  !222
0x0804de24      8d45d8         lea eax, [ebp-local_10]
0x0804de27      c74424080500.  mov dword [esp + 8], 5
0x0804de2f      c7442404f903.  mov dword [esp + 4], 0x80503f9 ; "/img/" 
0x0804de37      890424         mov dword [esp], eax           ; noted the trailing "/"
0x0804de3a      e859b1ffff     call sym.std::string::append
0x0804de3f      8d55d8         lea edx, [ebp-local_10]
0x0804de42      c74424080400.  mov dword [esp + 8], 4
0x0804de4a      c7442404ff03.  mov dword [esp + 4], 0x80503ff ; "logo"
0x0804de52      891424         mov dword [esp], edx
0x0804de55      e83eb1ffff     call sym.std::string::append
0x0804de5a      8d45d8         lea eax, [ebp-local_10]
0x0804de5d      c74424080400.  mov dword [esp + 8], 4
0x0804de65      c74424040404.  mov dword [esp + 4], 0x8050404 ; ".gif"
0x0804de6d      890424         mov dword [esp], eax
0x0804de70      e823b1ffff     call sym.std::string::append
0x0804de75      8d55d8         lea edx, [ebp-local_10]
0x0804de78      c74424080700.  mov dword [esp + 8], 7
0x0804de80      c74424040904.  mov dword [esp + 4], 0x8050409 ; "?sessd="
0x0804de88      891424         mov dword [esp], edx
0x0804de8b      e808b1ffff     call sym.std::string::append
using these parameters:
[0x0804b280]> pd @0x080503ff!55
    ;-- str._sessd_:
    ; DATA XREF from 0x0804de80 (unk)
            0x08050409 .string "?sessd=" ; len=8
    ;-- str._sessc_:
    ; DATA XREF from 0x0804dead (unk)
        |   0x08050411 .string "&sessc=" ; len=8
    ;-- str._sessk_:
    ; DATA XREF from 0x0804df0d (unk)
       ||   0x08050419  string "&sessk=" ; len=8
also it uses these user-agents:
; DATA XREF from 0x0804cda3 (unk)
0x08050368     .string "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)" ; len=58
0x080503a2      0000           add byte [eax], al
; DATA XREF from 0x0804cfd4 (unk)
0x080503a4     .string "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.7.6)" ; len=58
Using decrypted tags from $XDVSN_SESSION_COOKIE (see picture above), the used tags to be sent in HTTP/1.1 with GET method by CThreadPool::httpGet.i.e.: "lt" --> "sessc" ; and "sk" --> 2ssk"; "bu"-->"Host:"
0x0804df5f      e89cedffff     call sym.CThreadPool::httpGet;
esp=0x177ffc NULL; eip=0x804cd00 sym.CThreadPool::httpGet
Composing its GET request should came up to a HTTP GET commands like this:
GET //img/logo.gif?sessd=xx&sessc=100&sessk=64537b63727a28b0 OR 226d9b250f8ad270 [..]
Host: sk2. touchpadz .com 
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
            {OR} Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.7.6)
Accept: */*
this should work..Noted, I didn't test it further yet. PS: I secured (read: tweaked it w/double bytes) some characters in text of sent request traffic template to avoid the false positive.

Follow up & Epilogue

The sample we gained from this infection I posted in the kernelmode [link].
The detection ratio is not bad, you can see it here -->[-1-] and [-2-].
Thank's for support from Y (for a good forensics & evidence collecting effort) & W (in investigation) from our team. And also to the Akamai team for the good report.

We hope this information will be useful for fellow sysadmins, and researchers who follow the threat. All of information was written in a way that hopefully can be reproduced for IR and investigation purpose.
The additional information and follow up will be added in this section, as usual.


1 comment: