The Reverse Challenge Answers
  1. Identify and explain the purpose of the binary.

    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.

  2. Identify and explain the different features of the binary. What are its capabilities?

    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.

    1. Query the current status of a running daemon.

      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

    2. Initialize a remote client's IP address.

      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.

    3. Fork a child process which executes a remote command blindly.

      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.

    4. Fork a child process which executes a remote command, then returns its output.

      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".

    5. Fork a child process which later becomes a concurrent rshd daemon.

      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.

    6. Fork a child process which executes an IP Fragmentation attack.

      The command code is 5. See "files\Logs\cmd_frag" for more information.

    7. Fork a child process which starts a TCP SYN flood attack.

      The command code is 10. See "files\Logs\cmd_tcp_syn" for more information.

    8. Fork a child process which starts a TCP SYN flood attack with speed control.

      The command code is 11. See "files\Logs\cmd_tcp_syn_speed_control\" for more information.

    9. Fork a child process which starts a UDP DNS flood attack with random source IP address.

      The command code is 4. See "files\Logs\cmd_udp" for more information.

    10. Fork a child process which starts a UDP DNS flood attack with random source IP address and speed control.

      The command code is 9. See "files\Logs\cmd_udpx" for more information.

    11. Fork a child process which starts a UDP DNS flood attack with source IP address.

      The command code is 12. See "files\Logs\cmd_udpf" for more information.

    12. Kill the child process if it is present.

      The command code is 8. See "files\Logs\cmd_kill" for more information.

  3. The binary uses a network data encoding process. Identify the encoding process and develop a decoder for it

    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
    	> #include 
    	265c266,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.

  4. Identify one method of detecting this network traffic using a method that is not just specific to this situation, but other ones as well.

    Apply anti-spoofing rules at the network boundary. See Network Ingress Filtering described in RFC 2827.

  5. Identify and explain any techniques in the binary that protect it from being analyzed or reverse engineered.

    The binary is statically linked and stripped. It's evident that gcc's optimizatioin option '-finline-functions' was also used while compiling the binary.

  6. Identify two tools in the past that have demonstrated similar functionality.

    Similar tools include Trinoo, Tribe Flood Network (TFN), TFN2K, Stacheldraht and Mstream.