Monday, September 29, 2014

MMD-0028-2014 - Linux/XOR.DDoS : Fuzzy reversing a new China ELF

Sticky note: The latest incident (MMD-0033-2015) we disclosed on ELF Linux/XOR.DDoS malware is here -->[LINK]

This research is detected & solved by a hard work of MMD members. Credits are in the bottom of the post.
The case is on and malware infrastructure is mostly up & alive, we don't want to be too details in writing because of that reason, we don't want to teach this crook of what they're lacking of by this post, yet this post necessary to raise awareness of this new emerged threat. Feel free to follow the process at will.

The infection

During the rush of #shellshock we saw another new threat emerged. We saw an attack log of one-liner shell script being injected via ssh connection. By the attack source+CNC IP and the payload, this looks like a China crook's new hack scheme to spread new ELF DDoS'er threat. This is spotted silently spread during the ‪#‎shellshock waves, noted: it was NOT using #shellshock exploit itself.

The details of the attacker's trace in one-liner shell command is as per shown below:

If we beautified it as per below we will see the obfuscation this shell script:

↑the marked mark is the point of all these code, to download the file 3502.rar from some defined host addresses.

The mentioned RAR file itself is actually a shell script too:

You can read the codes here, no free ride copy/paste this time, since we have hard times with those false positives from antiviruses

The main() function is explaining how this script works, read the comments we made (in purple colored words):

Shortly. The blue color explaining the obfuscation strings saved in some variables. The yellow marked color words are functions to be executed, and the red color area is the main function of this script, to download and install a payload.

The obfuscation used is in the enc() and dec() function (see that big pic codes) for encryption and decryption, by using the below code (I picked this one, the one used for decrypting)

tr "[.0-9a-zA-Z\/\/\:]" "[a-zA-Z0-9\;-=+*\/]";
They called it encryption, but is just a mere obfuscator using the character map translation in "tr". Below is the easy shell script I made to decode them:

Below is the result:

We'll see another 3502 file. And a bunch of the CNC used. Noted the username and password they use ;)

If you permutated the URL with the payload name you will some ALIVE malware URLs like these:

What is this thing? In short: It's a sophisticated & well-thought ELF malware infection scheme, aiming Linux in multiple platform. It downloads, detect all parameter need to download the payload or source code of payload. It detected infected host's architecture, compiler. libraries together with sending sensitive information of the host, sent request to CNC to download the certain bins or to download resources to hack and then install the ELF binary.

The POC of this hack is the payload below:

The payload

The header looks very "fine":

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x8048110
First block:

Various analysis can resulted to the payload was coded in C, hmm..a quality up, we have a challenger here :) A new DDoS'er made in China. Here's the codes (for future reference):

'crtstuff.c'
'autorun.c'
'crc32.c'
'encrypt.c'
'execpacket.c'
'buildnet.c'
'hide.c'
'http.c'
'kill.c'
'main.c'
'proc.c'
'socket.c'
'tcp.c'
'thread.c'
'findip.c'
'dns.c'  
Some pointers for characteristic:

Self copy:

// create file for self-copy
open("/boot/[a-z]{10}", O_WRONLY|O_CREAT, 0400)
open("/boot/[a-z]{10}", O_WRONLY)

//chmod 755
chmod("/boot/[a-z]{10}", 0750)

// start to write..
open("/boot/[a-z]{10}", O_RDONLY)
Auto start:
// install SYS

.text:0x8048B2E   mov     dword ptr [esp], offset aSbinInsmod <== "/sbin/insmod"
.text:0x8048B35   call    LinuxExec_Argv
.text:0x8048B3A   mov     dword ptr [esp], 2
.text:0x8048B41   call    sleep

// xinetd setup..

.text:0x8048852   call    abstract_file_name
.text:0x8048857   mov     [ebp+var_8], eax
.text:0x804885A   mov     eax, [ebp+arg_0]
.text:0x804885D   mov     [esp+0Ch], eax
.text:0x8048861   mov     dword ptr [esp+8], offset aBinShS <== "#!/bin/sh\n%s\n"
.text:0x8048869   mov     dword ptr [esp+4], 400h
.text:0x8048871   lea     eax, [ebp+newpath]
.text:0x8048877   mov     [esp], eax
.text:0x804887A   call    snprintf
   :
.text:0x804887F   mov     eax, [ebp+var_8]
.text:0x8048882   mov     [esp+0Ch], eax
.text:0x8048886   mov     dword ptr [esp+8], offset aEtcInit_dS <== "/etc/init.d/%s"
.text:0x804888E   mov     dword ptr [esp+4], 400h
.text:0x8048896   lea     eax, [ebp+filename]
.text:0x804889C   mov     [esp], eax
.text:0x804889F   call    snprintf
.text:0x80488A4   mov     dword ptr [esp+4], offset aW <== "w"
.text:0x80488AC   lea     eax, [ebp+filename]
.text:0x80488B2   mov     [esp], eax
.text:0x80488B5   call    fopen
   :
.text:0x8048980   mov     dword ptr [esp+8], offset aEtcRcD_dS90S <== "/etc/rc%d.d/S90%s"
.text:0x8048988   mov     dword ptr [esp+4], 400h
.text:0x8048990   lea     eax, [ebp+newpath]
.text:0x8048996   mov     [esp], eax
.text:0x8048999   call    "snprintf"
.text:0x804899E   lea     eax, [ebp+newpath]  // assemble flag component for file attribs
.text:0x80489A4   mov     [esp], eax      <== "filename"
.text:0x80489A7   call    "unlink"
.text:0x80489AC   lea     eax, [ebp+newpath]
.text:0x80489B2   mov     [esp+4], eax    <== "newpath"
.text:0x80489B6   lea     eax, [ebp+filename]
.text:0x80489BC   mov     [esp], eax      <== "oldpath"
.text:0x80489BF   call    "symlink"
.text:0x80489C4   cmp     [ebp+var_C], 0
.text:0x80489C8   jnz     short loc_80489E8
.text:0x80489CA   mov     dword ptr [esp+8], 0AD1473B8h <== "group"
.text:0x80489D2   mov     dword ptr [esp+4], 0AD1473B8h <== "owner"
.text:0x80489DA   lea     eax, [ebp+filename]
.text:0x80489E0   mov     [esp], eax      <== "filename"
.text:0x80489E3   call    "lchown"
Malicious environment setup (i.e. export cmd):
0x06988C   HOME=/
0x069893   HISTFILE=/dev/null
0x0698A6   MYSQL_HISTFILE=/dev/null
0x0698C0   PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

Encryption:

There are some encryption to be decrypted in this malware, that I tested as per below, that looks having xor pattern:

// checking decryptor...

.text:0x804CB63   mov   dword ptr [esp+4], offset aM_Nfr7nlqqgf_0
.text:0x804CB6B   lea   eax, [ebp+filename]
.text:0x804CB71   mov   [esp], eax
.text:0x804CB74   call  dec_conf           // decrypting function..
.text:0x804CB79   mov   dword ptr [esp+8], 0Ch // <== break it here..

Breakpoint 1, 0x0804cb79 in main ()
query offset aM_Nfr7nlqqgf_0: "m.[$nFR$7nLQQGF"
query register: $esp
0xffffa1b0:  "[\305\377\377\343\033\v\b\020"
;-----------------------
.text:0x804CB81   mov    dword ptr [esp+4], offset aM_Nfr7n9_0
.text:0x804CB89   lea    eax, [ebp+var_114D]
.text:0x804CB8F   mov    [esp], eax
.text:0x804CB92   call   dec_conf

Breakpoint 2, 0x0804cb9 in main ()
query offset aM_Nfr7n9_0: "m.[$nFR$7n9"
query register: $esp
0xffffa1b0:  "[\304\377\377\363\033\v\b\f"
;-----------------------
.text:0x804CBBD   mov    dword ptr [esp+4], offset aM4s4nacNa ; "m4S4nAC/nA"
.text:0x804CBC5   lea    eax, [ebp+var_E4D]
.text:0x804CBCB   mov    [esp], eax
.text:0x804CBCE   call   dec_conf
.text:0x804CBD3   mov    [ebp+var_34], 0

Breakpoint 3, 0x0804cbd3 in main ()
query offset aM4s4nacNa ; "m4S4nAC/nA"
query register: $esp
0xffffa1b0:  "[\307\377\377#\034\v\b\v"
Here is the xor used as the component logic for the decryption function:

With the key that lead to this address:

It "looks like" the author is having "interesting" way to remind him the XOR key itself, I don't investigate this further since I had the goal..

A hard-coded callback IP address

And look what I got next to the xor key :))

So now we know the CNC is too ;)

IP: 103.25.9.228||59270 | 103.25.9.0/24 | CLOUD 
Country: "HK | CLOUDRELY.COM" |CLOUD RELY LIMITED

The bummer part of this malware is, it crashed itself when run under limited permission...

"msec   calls "
-----------------------------------------------------------------------
(120): execve("./SAMPLE-MALWARE", ["./SAMPLE-MALWARE"], ["SHELL=etc..])
(125): set_thread_area(0xffc8373c)
(126): set_tid_address(0x92e6888)
(127): set_robust_list(0x92e6890, 0xc)
(128): futex(0xffc83a04, FUTEX_WAKE_PRIVATE, 1)
(129): rt_sigaction(SIGRTMIN, {0x8053860, [], SA_SIGINFO}, NULL, 8)
(130): rt_sigaction(SIGRT_1, {0x8053780, [], SA_RESTART|SA_SIGINFO}, NULL, 8)
(131): rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8)
(132): getrlimit(RLIMIT_STACK,etc)
(133): uname({sysname="Linux", nodename="mmd", release="mmd-amd64", 
             version="#1 SMP mmd-7u1", machine="saever-momma"})
(142): readlink("/proc/self/exe", "/home/mmd/test/SAMPLE-MALWARE", 1023)
(143): clone(Process)
(145): exit_group(0)
(146): [pid new] setsid()
(147): open("/dev/null", O_RDWR)
(148): fstat64(3, {st_dev=makedev] etc) 
(149): dup2(3, 0)
(150): dup2(3, 1)
(151): dup2(3, 2)
(152): close(3)
(153): readlink("/proc/self/exe", "/home/mmd/test/SAMPLE-MALWARE", 1023) = 20
(154): stat64("/boot" etc)
(155): stat64("/lib", etc)
(156): stat64("/lib/udev" etc)
(157): stat64("/var", etc)
(158): stat64("/var/run", etc)
(159): gettimeofday({1411989055, 135168}, NULL) 
(160): readlink("/proc/self/exe", "/home/mmd/test/SAMPLE-MALWARE", 1023) 
(161): unlink("/lib/udev/udev") 
(162): open("/home/mmd/test/SAMPLE-MALWARE", O_RDONLY)
(163): open("/lib/udev/udev", O_WRONLY|O_CREAT, 0400)
(165): open("/home/mmd/test/SAMPLE-MALWARE", O_RDONLY)
(166): open("/boot/[a-z]{10}", O_WRONLY|O_CREAT, 0400)
(168): open("/boot/[a-z]{10}", O_WRONLY)
(169): clone(Process attached
(171): waitpid(Process suspended
(173): clone(Process attached
(175): exit_group(0)
(179): rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8)
(180): rt_sigaction(SIGCHLD, NULL, {SIG_IGN, [CHLD], SA_RESTART}, 8)
(181): nanosleep({1, 0},..
(192): chmod("/boot/[a-z]{10}", 0750)
(193): open("/boot/[a-z]{10}", O_RDONLY)
(194): "--- SIGSEGV (Segmentation fault) @ 0 (0)" --- ref: [a-z]{10}
(197): "rt_sigprocmask(SIG_SETMASK, [], NULL, 8)"
It saves the file in /boot with this regex: [a-z]{10}

What is the purpose of this malware?

The first is backdoor, and then, obviously DoS (SYN, UDP, TCP flood), using encrypted (temporary) config. Below is the PoC of the DDoS function names:

0x09305E   build_syn // SYN Flood
0x0950D0   build_tcphdr // TCP Flood
0x097101   build_udphdr // UDP FLood
And below is part of backdoor operation using HTTP/1.1 GET (to download / update) and callback in HTTP/1.1 POST:
.text:0x804A917   mov   dword ptr [esp+8], offset aPostSHttp1_1Sh
                        value: "POST %s HTTP/1.1\r\n%sHost: %s\r\nContent-T"
.text:0x804AB1D   mov   dword ptr [esp+8], offset aGetSHttp1_1Sho
                        value: "GET %s HTTP/1.1\r\n%sHost: %s\r\n%s"
Based on the code it looks like using AES.DDoS'er and IptabLes strategy to install, but the source are different. So, this is another new China DDoS'er, I call this as Linux/XOR.DDoS.

Virus Total and sample

Virus total detection is below (click the image to access..) One of 55 is a bad detection..

Sample is shared in kernel mode-->[here]

Conclusion & Credits

This threat is the first time we see using complicated installer/builder. I and other team mates start to feel like playing CTF with this crook. They (China actors) are improving in steps, we must be aware. Please stay safe folks..

Credit: @shibumi (threat sensoring), @wirehack7 (formulation), and others who doesn't want to be mentioned.

Additional

(A reserved section for additional and updates)

#MalwareMustDie!!