The binary is a Distributed Denial of Service attack agent (daemon). Once started, it runs as a daemon, and open a raw socket with the protocol parameter 11 (NVP), then it waits for imcoming pakcets. A hacker can uses a handler (client) program to communicate with agents. A handler needs to use raw sockets to build a packet with IP header's protocol field set to 11 as well. A simple handler program was developed to demonstrate the binary's capabilities, the souce code of our handler is available here.
Let's first take a look at its application protocol. In a packet sent from a client to a daemon, the first byte of the IP data is always 2. In a packet sent from a daemon to a client, the first byte of the IP data sent from a daemon to a client is always 3. For every packet sent between a client and a daemon, the third byte offset is the starting position of the encoded command request/reply data.
In the encoded data sent from a client, the first byte is a command code. The daemon supports 12 commands. The range of a valid command code is [1, 12]. The second byte offset is the starting position of command parameter(s). The following commands are not listed in the original order.
A client sends a packet with the command code 1 to ask the daemon whether there is a child process running. The daemon returns a boolean code at byte offset 4 in the encoded data, followed by a byte of the child type ID if there is one. The daemon never starts more than one child process. Here is the text dump of two decoded packets for this command:
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 05/31-08:37:38.781965 0:50:56:F8:2A:35 -> 0:50:56:F8:2A:25 type:0x800 len:0xEE 192.168.218.158 -> 192.168.218.160 NVP TTL:64 TOS:0x0 ID:45414 IpLen:20 DgmLen:224 02 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ... =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 05/31-08:37:38.791965 0:50:56:F8:2A:25 -> 0:50:56:F8:2A:35 type:0x800 len:0x1F9 192.168.218.160 -> 192.168.218.158 NVP TTL:250 TOS:0x0 ID:42850 IpLen:20 DgmLen:491 03 00 00 01 07 00 B1 66 00 00 40 0B 92 1C C0 A8 .......f..@..... ...
In the sencond packet, "01 07" is used as identification code. "00" tells taht there is no child process running
The first byte in the encoded data is the command code 2, The second byte in the encoded data is an option parameter. A client's IP addresss is stored from the third byte to the sixth byte. If The option code is zero, the daemon will just send one reply for a request. If the option code is two, the daemon will generate 10 random IP addresses, then overwrites the first one with the client IP address, and send its reponse to those ten IP address for a future command that requires output. If the option code is one, the daemon will generate ten IP addresses and overwrite one of them at a random position with the client IP address. This command must be first before the first command (stat) or the fourth command (rcmd) can is invoked. Because the daemon needs to know where to send a reply. Here is the text dump of a decoded packet in the snort log released by the Honeynet project
02/28-04:32:34.417321 0:50:56:1:0:0 -> 0:50:56:DC:13:A2 type:0x800 len:0x1B4 172.16.196.132 -> 172.16.183.2 NVP TTL:237 TOS:0x0 ID:27401 IpLen:20 DgmLen:422 02 00 00 02 01 CB AD 90 23 00 00 00 00 00 00 00 ........#....... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
As can be seen here, the intruder is using "01" for the option byte. And his handler's IP address is 203.173.144.35/p35-tnt7.syd.ihug.com.au (CB AD 90 23). In our decoded text dump of the snort log, "files/snortlog/decoded.log", you can find two packets #10 and #19 went to the box that a handler might be running. It's worth noting that there should be two more packets in the snort log. Our guess is that a loopback IP address was randomly generated, and they went to the loopback interface.
Its command code is 7. See "files\logs\cmd_rcmd_blind\decoded.log" for the text dump of a packet that was created for this command.
The code of this command is 3. This is what's happening is the fourth packet in the snort log released by the Honeynet project. Here is our decoded text dump of the packet:
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 02/28-04:41:37.934005 0:50:56:1:0:0 -> 0:50:56:DC:13:A2 type:0x800 len:0x1B4 172.16.196.132 -> 172.16.183.2 NVP TTL:237 TOS:0x0 ID:38665 IpLen:20 DgmLen:422 02 00 00 03 72 70 63 69 6E 66 6F 20 2D 70 20 31 ....rpcinfo -p 1 32 37 2E 30 2E 30 2E 31 00 00 00 00 00 00 00 00 27.0.0.1........ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ...
The intruder was executing "rpcinfo -p 127.0.0.1".
Its command code is 6. Once this command is received, the daemon will fork a child that later becomes a rsh daemon listening on the TCP port 23281. The child daemon would be running as an concurrent server which allows multiple connections. An authentication string "SeNiF" is required to get a shell started. One can use nc to connect to it. See "files\logs\cmd_rshd\decoded.log" for the decoded text dump of a packet for this command. If the TCP port 23281 is already taken, the binary's code couldn't handle it properly because the return value of a bind call is not checked.
Due to the limitation of time, we won't explain the remaining command in details. Instead, for each command, we'll provide a pointer to a directory that contains a command file ("cmd") that has a line of a "command string" we used in our client program, a raw packet dump file ("raw.log"), and decoded packet text dump file ("decoded.log"). And you're encourage to try out the client program we wrote.
The command code is 5. See "files\Logs\cmd_frag" for more information.
The command code is 10. See "files\Logs\cmd_tcp_syn" for more information.
The command code is 11. See "files\Logs\cmd_tcp_syn_speed_control\" for more information.
The command code is 4. See "files\Logs\cmd_udp" for more information.
The command code is 9. See "files\Logs\cmd_udpx" for more information.
The command code is 12. See "files\Logs\cmd_udpf" for more information.
The command code is 8. See "files\Logs\cmd_kill" for more information.
The following block of code is taken from the disassembly generated by IDA Pro, it is responsible for encoding a byte buffer,
.text:0804A194 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ .text:0804A194 .text:0804A194 ; Attributes: bp-based frame .text:0804A194 .text:0804A194 encode proc near ; CODE XREF: main+286p .text:0804A194 ; main+582p .text:0804A194 .text:0804A194 var_C = byte ptr -0Ch .text:0804A194 arg_len = dword ptr 8 .text:0804A194 arg_in_buf = dword ptr 0Ch .text:0804A194 arg_out_buf = dword ptr 10h .text:0804A194 .text:0804A194 edi_len = edi .text:0804A194 esi_in_buf = esi .text:0804A194 ebx_out_buf = ebx .text:0804A194 ecx_index = ecx .text:0804A194 .text:0804A194 push ebp .text:0804A195 mov ebp, esp .text:0804A197 push edi .text:0804A198 push esi .text:0804A199 push ebx .text:0804A19A mov edi_len, [ebp+arg_len] .text:0804A19D mov esi_in_buf, [ebp+arg_in_buf] .text:0804A1A0 mov ebx_out_buf, [ebp+arg_out_buf] .text:0804A1A3 mov al, ds:NULL .text:0804A1A9 mov [ebx_out_buf], al .text:0804A1AB mov al, [esi_in_buf] .text:0804A1AD add al, 17h .text:0804A1AF movsx eax, al .text:0804A1B2 push eax .text:0804A1B3 push offset aC ; "%c" .text:0804A1B8 push ebx_out_buf .text:0804A1B9 call sprintf .text:0804A1BE mov ecx_index, 1 .text:0804A1C3 cmp ecx_index, edi_len .text:0804A1C5 jz short loc_804A1DD .text:0804A1C7 nop .text:0804A1C8 .text:0804A1C8 loc_804A1C8: ; CODE XREF: encode+47j .text:0804A1C8 movzx edx, byte ptr [ebx_out_buf+ecx_index-1] .text:0804A1CD movzx eax, byte ptr [ecx_index+esi_in_buf] .text:0804A1D1 lea eax, [edx+eax+17h] .text:0804A1D5 mov [ecx_index+ebx_out_buf], al .text:0804A1D8 inc ecx_index .text:0804A1D9 cmp ecx_index, edi_len .text:0804A1DB jnz short loc_804A1C8 .text:0804A1DD .text:0804A1DD loc_804A1DD: ; CODE XREF: encode+31j .text:0804A1DD lea esp, [ebp+var_C] .text:0804A1E0 pop ebx .text:0804A1E1 pop esi .text:0804A1E2 pop edi .text:0804A1E3 mov esp, ebp .text:0804A1E5 pop ebp .text:0804A1E6 retn .text:0804A1E6 encode endp .text:0804A1E6 .text:0804A1E6 ; ---------------------------------------------------------------------------The following reverse-engineered C code is used in our client program to communicate with a running daemon,
void my_encode(unsigned int len, unsigned char *in, unsigned char *out){ unsigned int i; out[0] = 0; sprintf((char *)out, "%c", in[0] + 0x17); for(i = 1; i != len; i++){ out[i] = in[i] + out[i-1] + 0x17; } }As can be seen here, the encoding routine takes three parameters. The first one is the length of an input buffer. The second one is a pointer to an input buffer to be encoded. The third one is a pointer to a buffer to store the encoded result. Its encoding algorithm is simple. First, add 23 (0x17) to the first byte and store the result as the first byte in the output buffer. Then, for each of the rest bytes in the input buffer, the sum of its value, 23 (0x17), and the value of the byte at the previous position in the output buffer is calculated and stored at the corresponding position in the output buffer.
We patch the file "log.c" in the source code of Snort 1.8.6 so that we could use the patched version to generat decoded text dump files from raw log files. The patch file is in "files\Snort 1.8.6 Patch". Here is the code listing:
20a21 > #include265c266,304 < --- > > /*Inlined decoding routine. > Referenced values: start, len, and dump_ready. > Modified values: start, dump_ready. > */ > { > #define EFFECTIVE_SIZE 400 > > int tmp_char; > u_int index; > u_char *decoded; > > if (start[0] == 2 || start[0] == 3){ > decoded = (u_char *) alloca(len); > memcpy(decoded, start, len); > > //The encoded bytes start from the third byte. > tmp_char = start[2] - 0x17; > > while (tmp_char < 0){ > tmp_char += (char) 0x100; > } > > decoded[2] = tmp_char; > > for (index = 3; index < len && index < EFFECTIVE_SIZE; index++) { > tmp_char = start[index] - start[index -1] - 0x17; > > while (tmp_char < 0){ > tmp_char += 0x100; > } > > decoded[index] = (char) tmp_char; > } > dump_ready = 0; > start = decoded; > } > } >
Run "patch log.c log.c.patch" and "make" to build a patched version of Snort. A command line like "snort -dev -r raw.log > decoded.log" will work.
Apply anti-spoofing rules at the network boundary. See Network Ingress Filtering described in RFC 2827.
The binary is statically linked and stripped. It's evident that gcc's optimizatioin option '-finline-functions' was also used while compiling the binary.
Similar tools include Trinoo, Tribe Flood Network (TFN), TFN2K, Stacheldraht and Mstream.