# 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. ----- ## 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 ----- ## 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 push 1000h ; size .text:0804B37D call _malloc .text:0804B382 mov edi, eax ; buffer for com mand .text:0804B384 call fillConfig .text:0804B389 call init_random .text:0804B38E call runKiller .text:0804B393 call fillCmdHandlers #### 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; } ``` Each configuration field is filled in the following way: ----- Some strings are stored in an encrypted ELF file and are decrypted before being recorded: ----- The following data is saved to the examined sample’s configuration: |Num- ber|Data type|Value|Purpose| |---|---|---|---| |0|uint32|—|Command and control server’s IP ad- dress| |1|uint 16|—|port| |2|string|'kami\x00'|displayed in main on stdin upon launch- ing 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; rv:41.0) Gecko/20100101 Firefox/41.0"|cmd14 User Agent for request| |12|string|"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"|cmd14 User Agent for request| |13|string|"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36"|cmd14 User Agent for request| |14|string|"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36"|cmd14 User Agent for request| |15|string|"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11) AppleWebKit/601.1.56 (KHTML, like Gecko) Version/9.0 Safari/601.1.56"|not used| |20|string|"GET "|cmd14 generating requests| |21|string|"HTTP/1.1"|cmd14 generating requests| |22|string|"Host: "|cmd14 generating requests| ----- |Num- ber|Data type|Value|Purpose| |---|---|---|---| |23|string|"Connection: keep-alive"|cmd14 generating requests| |24|string|"User-Agent: "|cmd14 generating requests| |25|string|"Accept: text/html,application/xhtml +xml,application/xml;q=0.9,image/webp,*/ *;q=0.8"|cmd14 generating requests| |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- ber)|returns the data pointer for conf_entry with the number value| |uint32 get_conf_uint32(int number)|returns unit32 stored under the data pointer for conf_entry with the number value| |uint16 get_conf_uint16(int number)|returns unit16 stored under the data pointer for conf_entry with the number value| |uint8 get_conf_uint8(int number)|returns unit8 stored under the data pointer for conf_entry with the number value| ----- #### 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 differ-** ent manner. The init_rand function from Linux.DDoS.87: ----- The init_random function from Linux.DDoS.87: ----- #### 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: ----- 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 cmp ds:couldOpenExe, 0 .text:0804B146 jz short loc_804B158 .text:0804B148 lea ebp, [esp+0A3Ch+var_226] .text:0804B14F cmp ds:couldOpenCWD, 0 .text:0804B156 jnz short loc_804B17E .text:0804B158 .text:0804B158 loc_804B158: ; CODE XREF: run Killer+1C6j .text:0804B158 sub esp, 0Ch .text:0804B15B push 0 ; status .text:0804B15D call ___GI_exit ``` 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: ----- 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: ----- 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; } struct cmd_handlers { cmd *handlers; char length; } ``` The structure is filled in the following way: ----- 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: |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| ----- Then the Trojan removes its name to hide itself: ``` .text:0804B3D8 mov ebp, [esi] ; esi = argv[0] .text:0804B3DA push ebp ; a1 .text:0804B3DB call strlen .text:0804B3E0 add esp, 10h .text:0804B3E3 mov ecx, eax .text:0804B3E5 test eax, eax .text:0804B3E7 jle short loc_804B3F6 .text:0804B3E9 xor edx, edx .text:0804B3EB .text:0804B3EB loc_804B3EB: ; CODE XREF: main +94j .text:0804B3EB mov eax, [esi] .text:0804B3ED mov byte ptr [eax+edx], 0 .text:0804B3F1 inc edx .text:0804B3F2 cmp ecx, edx .text:0804B3F4 jnz short loc_804B3EB ``` The child processes are subsequently launched (the code is simplified and contains no requests to the configuration): ----- 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: ----- If recv returns an error, a socket is opened, and its content is recorded to the fd global variable: ``` .text:0804B553 recv_failed: ; CODE XREF: main +159j .text:0804B553 mov eax, ds:fd .text:0804B558 test eax, eax .text:0804B55A js short fd_closed_or_uninitialized .text:0804B55C sub esp, 0Ch .text:0804B55F push eax ; fd .text:0804B560 call ___libc_close .text:0804B565 add esp, 10h .text:0804B568 .text:0804B568 fd_closed_or_uninitialized: ; CODE XREF: main +1FAj .text:0804B568 push eax .text:0804B569 push 0 .text:0804B56B push 1 .text:0804B56D push 2 .text:0804B56F call ___GI_socket .text:0804B574 add esp, 10h .text:0804B577 mov ds:fd, eax ``` During reading/writing, a minute-long time-out is set: ----- Then a connection to the C&C server is established: ``` .text:0804B5CE mov [esp+4ACh+cnc_sockaddr.sin_fam ily], 2 .text:0804B5D8 add esp, 14h .text:0804B5DB push 0 .text:0804B5DD call get_conf_uint32 .text:0804B5E2 mov dword ptr [esp+0], 1 .text:0804B5E9 mov [esp+49Ch+cnc_sock addr.sin_addr.s_addr], eax .text:0804B5F0 call get_conf_uint16 .text:0804B5F5 ror ax, 8 .text:0804B5F9 mov [esp+49Ch+cnc_sockaddr.sin_port], ax .text:0804B601 add esp, 0Ch .text:0804B604 mov eax, ds:fd .text:0804B609 push 10h .text:0804B60B lea edx, [esp+494h+cnc_sockaddr] .text:0804B612 push edx .text:0804B613 push eax .text:0804B614 call ___libc_connect ``` 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: ----- The MAC address of a network card is also sent to the C&C server: ----- 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: |Field|Purpose|Size| |---|---|---| |fullLength|full length of the received com- mand|2| |sleepTime|time for execution (every command runs a new process using fork and then kills it)|4| |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 the length is zero, the processor of the received command is launched: ----- #### 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: ----- Code to initiate an analysis of the packet header: ----- Parsing code for received targets: ``` .text:0804BAC7 parse_next_target: ; CODE XREF: pro cess+A3j .text:0804BAC7 mov edx, [ecx+pkct_cmd.target.ip_addr] .text:0804BACA mov [esi+target_parsed.target_ip], edx .text:0804BACC mov al, [ecx+pkct_cmd.target.masksize] .text:0804BACF add ecx, 5 .text:0804BAD2 mov [esi+target_parsed.masksize], al .text:0804BAD5 mov [esi+target_parsed.sockaddr.sin_ family], 2 .text:0804BADB mov [esi+target_parsed.sock addr.sin_addr.s_addr], edx .text:0804BADE add esi, 18h .text:0804BAE1 cmp ecx, ebp .text:0804BAE3 jnz short parse_next_target .text:0804BAE5 mov edx, [esp+4Ch+target_count] .text:0804BAE9 add ecx, 6 .text:0804BAEC mov [esp+4Ch+var_18], ecx .text:0804BAF0 lea eax, [edx+edx*4] .text:0804BAF3 sub ebx, eax .text:0804BAF5 sub ebx, 6 .text:0804BAF8 mov [esp+4Ch+unprocessed_bytes], 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: ``` ----- #### 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: ----- Then child processes are run: ----- #### Command handlers ----- 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 packet is being sent } } #### cmd0 – UDP Flood ``` First, the parameters received are parsed: ----- 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| ----- Then the Trojan creates a “raw” socket and enters the IP header: ``` .text:0804AB7F push IPPROTO_UDP .text:0804AB81 push SOCK_RAW .text:0804AB83 push AF_INET .text:0804AB85 call ___GI_socket .text:0804AB8A mov [esp+6Ch+fd], eax .text:0804AB8E add esp, 10h .text:0804AB91 inc eax .text:0804AB92 jz loc_804AE5E .text:0804AB98 mov [esp+5Ch+var_14], 1 .text:0804ABA0 sub esp, 0Ch .text:0804ABA3 push 4 .text:0804ABA5 lea eax, [esp+6Ch+var_14] .text:0804ABA9 push eax .text:0804ABAA push IP_HDRINCL .text:0804ABAC push SOL_IP .text:0804ABAE mov ebx, [esp+78h+fd] .text:0804ABB2 push ebx .text:0804ABB3 call ___GI_setsockopt ``` After that, it is generated using the header of a IP/UDP datagram for each objective received: ----- 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: ----- Then the Trojan counts checksums and shifts its attention to the next target. This procedure continues until the process is terminated: ----- #### cmd1 – Source Engine Amplification It operates like the previous command; however, the packet’s content is retrieved from the configuration: ----- #### cmd2 – DNS flood This command uses parameters similar to the previous ones; however, in this case, the value transac``` tion_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 = getNumberOrDefault(params_count, params, 4, 64); frag = getNumberOrDefault(params_count, params, 5, 0); sport = getNumberOrDefault(params_count, params, 6, 0xFFFF); dport = getNumberOrDefault(params_count, params, 7, 53); transaction_id_1 = getNumberOrDefault(params_count, params, 9, 0xFFFF); random_data_length = getNumberOrDefault(params_count, params, 0, 12); query = getString(params_count, params, 8, 0); ``` A packet containing 100 domain requests is generated and sent to the specified address. The Recursion **desired flag is set:** ----- 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. It also allows values to be specified for TCP flags using these parameters: ----- Setting flags in the packet: ----- In addition, TCP parameters with numbers 2 and 8 are installed into the packet—maximum segment ``` size and timestamp: .text:0804A05D mov byte ptr [ebx+28h], TCPOPT_MAXSEG .text:0804A061 mov byte ptr [ebx+29h], 4 .text:0804A065 call rand_cmwc .text:0804A06A mov byte ptr [ebx+2Ch], 4 .text:0804A06E and eax, 0Fh .text:0804A071 mov byte ptr [ebx+2Dh], 2 .text:0804A075 add eax, 578h .text:0804A07A mov byte ptr [ebx+2Eh], TCPOPT_TIMESTAMP .text:0804A07E ror ax, 8 .text:0804A082 mov byte ptr [ebx+2Fh], 0Ah .text:0804A086 mov [ebx+2Ah], ax .text:0804A08A call rand_cmwc .text:0804A08F mov dword ptr [ebx+34h], 0 .text:0804A096 mov [ebx+30h], eax .text:0804A099 mov byte ptr [ebx+38h], 1 .text:0804A09D mov byte ptr [ebx+39h], 3 .text:0804A0A1 mov byte ptr [ebx+3Ah], 3 .text:0804A0A5 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: ----- #### 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 GRE protocol and uses the following parameters: ``` TOS = getNumberOrDefault(params_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, param, 1, 1); useSameAddr = getNumberOrDefault(params_count, param, 19, 0); //inner ip.dstAddr == outer ip.dstAddr ``` The GRE packet is generated as follows: ----- ----- #### 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:08048A3A mov [ebx+ipgre_9.outer_iphdr._ip.pro tocol], IPPROTO_GRE .text:08048A3E mov [ecx+gre_packet.protocolType], 5865h ; GRE_NET_TEB .text:08048A44 mov eax, ds:selfaddr .text:08048A49 mov edx, [esp+6Ch+arg_4] .text:08048A4D mov [ebx+ipgre_9.outer_iphdr._ip.sr c_addr], eax .text:08048A50 mov ecx, [esp+6Ch+saved_frame] .text:08048A54 mov eax, [esp+6Ch+counter] .text:08048A58 mov [ecx+ether_packet.type], 8 ; IP #### cmd14 HTTP Flood ``` During one iteration, the command sends 10 HTTP requests that look as follows: ----- ## Linux.DDoS.89 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: ----- ----- Running the command handler in Linux.DDoS.89: ----- ### 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: ----- 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: ----- ----- If the Trojan fails to use the **bind system call, it connects to the corresponding port because it is as-** sumed 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: ----- 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: |Num- ber|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 dis- played 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| ----- |Num- ber|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 informa- tion 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: ----- 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: ----- 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. |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| ----- ## Linux.Mirai SHA1: 7e0e07d19b9c57149e72a7ed266e0c8aa5019a6f A modified version of Linux.DDoS.87 and 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 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| ----- |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,applic- ation/xml;q=0.9,image/webp,*/*;q=0.8"|| |34|"Accept-Language: en-US,en;q=0.8"|| |35|"Content-Type: application/x-www-form-urlen- coded"|| |36|"setCookie('"|| |37|"refresh:"|| |38|"location:"|| |39|"set-cookie:"|| |40|"content-length:"|| ----- |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- pleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"|User Agent| |48|"Mozilla/5.0 (Windows NT 10.0; WOW64) Ap- pleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"|User Agent| |49|"Mozilla/5.0 (Windows NT 6.1; WOW64) Ap- pleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"|User Agent| |50|"Mozilla/5.0 (Windows NT 6.1; WOW64) Ap- pleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"|User Agent| |51|"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7"|User Agent| All samples of the Trojan use a function that hides the following strings: ``` def decode(str_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. ----- Next, the Trojan calculates a function taken from the argv[0] value: ``` 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 #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 dd offset sub_80517E0 .rodata:08055DC8 dd offset sub_8051730 .rodata:08055DCC dd offset create_config .rodata:08055DD0 dd offset sub_8051760 .rodata:08055DD4 dd offset sub_80523F0 .rodata:08055DD8 dd offset strcopy .rodata:08055DDC dd offset runkiller .rodata:08055DE0 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 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. ----- **Code fragment for Linux.DDoS.87** **Code fragment for Linux.Mirai** -----