Chapter 2. Answers

Table of Contents

Identify and explain the purpose of the binary
Identify and explain the different features of the binary. What are its capabilities?
The binary uses a network data encoding process. Identify the encoding process and develop a decoder for it
Command Packets
Reply Packets
The Decoder
Identify one method of detecting this network traffic using a method that is not just specific to this situation, but other ones as well
Identify and explain any techniques in the binary that protect it from being analyzed or reverse engineered
Identify two tools in the past that have demonstrated similar functionality
What kind of information can be derived about the person who developed this tool? For example, what is their skill level?
What advancements in tools with similar purposes can we expect in the future?

The caputured binary is a backdoor program with the capability of launching denial of service attacks. It is designed to run on Linux systems. The attacker needs root access to install the backdoor on a comprimised machine. Once the binary is installed, the attacker uses a special backdoor client program to establish a connection to the system and execute commands.

An interesting feature of the backdoor program is its use as a distributed denial of service (DDoS) tool. When the backdoor receives a command from the attacker (containing the victim's ip address or hostname), it starts a DoS attack against it. The DoS packet engine is very flexible and allows for many different kinds of attacks: udp flood, tcp flood, ping flood, smurf attack, dns smurf attack. With enought machines under the attacker's control, she can successfully impact major Internet sites, as evidenced by the events in Februrary 2000.

When the binary is started, it detaches itself from the controlling tty and becomes a background process. It overwrites its argv[0] with the string "[mingetty]", which is the default name of the login process on RedHat systems. Then it opens a raw socket and waits for command packets from the backdoor client.

The communication channel between the backdoor and the client is rather ingenious. It is perhaps the most interesting part of this tool. The backdoor uses a unique approach to conceal the identity of the attacker who controls it. The client communicates with the backdoor via IP packets with the protocol field set to 0x0B (0x11), which is an unassigned protocol number. These IP packets are very similar to UDP datagrams, in that they don't offer reliability and retransmission but can be easily spoofed. All the packets sent from the client to the backdoor are spoofed, making it almost impossible to trace them back to their real source. The only way to track down the attacker is to trace the replies from the backdoor to the client.

How does the backdoor know where to send the replies to? When the attacker wishes to communicate with the backdoor she sends an init command containing 10 IP addresses, encoded with a proprietary XOR-strength encryption algorithm. The source of the packet with the init command can be spoofed because the backdoor only uses the IP addresses inside the packet payload. Upon receiving the init command, the backdoor stores the client IP addresses. All replies are sent to all 10 client IP addresses. Only one of them needs to be the real IP address of the attacker. Looking at traffic generated by the backdoor it's impossible to the tell which address is the real one. If a system administrator or the authorities decide to go through the logs and track down the attacker, they will get 10 possible addresses, 9 of which are completely unrelated to the incident. Many of the backdoor DDoS commands don't even send back replies and can be triggered with only one spoofed packet.

There are 11 different commands that the backdoor can execute. Each of them has a number of parameters. Here is a list of all commands and their descriptions:

Backdoor Commands

init

Parameters: type, ip[]

The init command initializes the backdoor address list. If type is 0, only one IP address has to be specified in the ip parameter. All replies from the backdoor are sent to this IP address. If type is 1, the replies will be sent to this address and 9 other random addresses. If type is 2, the attacker specifies 10 IP addresses and the replies are sent to all of them.

status

Parameters: none

The status command causes the backdoor to send a reply packet with the type of the currently running DoS or shell process. Only one such process can be started at a time and it should be kill with the kill command when it is no longer needed. If no process is running, status return 0 (idle).

kill

Parameters: none

The kill command kills the currently running shell or DoS process. It is used to close the shell started by the bind_shell command or to stop the DoS attack in progress.

exec

Parameters: cmd

The shell command in the cmd is executed by the backdoor. Its stdout and stderr are discarded. No reply is sent. The command is executed via /bin/csh and will fail if /bin/csh doesn't exist.

exec_output

Parameters: cmd

The shell command in the cmd is executed by the backdoor. Its stdin and stderr are captured and the output is sent to the client as reply packets. The command is executed via /bin/csh and will fail if /bin/csh doesn't exist or /tmp is not writable.

bind_shell

Parameters: none

When the backdoor receives this command, it bind a root shell to port 23281/tcp and waits for a connection. The attacker can use telnet or netcat to connect to this port. The first line sent to must match the backdoor password, otherwise the connection is terminated. The password in the binary captured by the honeynet project is "SeNiF". To kill the shell process, use the kill command.

udp_flood

Parameters: src, dst, hostname, d_port

Launches a UDP flood attack. The backdoor forks a new process which sends the packets. To stop the attack, use the kill command to kill this process (the same applies to all DoS attacks available in the backdoor). The victim can be specified with the dst or hostname parameters. If a hostname is used it is resolved again after every 40000 packets have been sent, in case the dns record of the victim has changed. The source of the packets can be spoofed with the src parameter. The destination port is specified in d_port. The IP packets sent by this attack are UDP fragments with a fragment offset set to 65520, which maximizes the resource utilization of the victim's TCP/IP stack.

icmp_flood

Parameters: src, dst, hostname

Similar to udp_flood, but sends ICMP echo request packets.

A variation of this attack is the ICMP smurf attack. If the attacker sends spoofed ICMP echo requests to the broadcast address of a vulnerable network, all hosts on the network will send their responses to the victim. The entire network will act as a traffic amplifier for the attack. This kind of attack was first reported by Edward Henigin in 1997. It is possible to use the backdoor a tool for a ICMP smurf attack, but we'll have to use the IP address of the victim, because the author of the backdoor did not include support for resolving the source IP address of the packet.

syn_flood

Parameters: src, dst, hostname, d_port, sleep_after

Launches a SYN flood attack. A good description of the SYN flood atack is the Phrack 48 article by route. The victim is specified with the dst or the hostname parameters. The source ip address can be specified with src or left empty, in which case a random address is generated for each packet. The destination port for the SYN packets is given in d_port. It should be an open TCP port on the victim's system. The DoS process sleeps for 300 microseconds after it has sent sleep_after packets. If the parameter is not specified, the process sleeps after each packet.

dns_flood

Parameters: src, dst, hostname, s_port, sleep_after

Launches a DNS queries flood atack. Sends DNS queries for top-level domains (.com, .net, etc) to the victim. Useful for bringing DNS servers down. The victim is specified with the dst or hostname parameters. The source ip address of the queries can be given in src or a random address will be generated for each packet. The source port can be given in s_port or it will also be generated randomly. The DoS process sleeps for 300 microseconds after it has sent sleep_after packets. If the parameter is not specified, the process sleeps after each packet.

dns_smurf

Parameters: victim_ip, victim_hostname, s_port, sleep_after

Launches a DNS smurf attack using publicly accessible nameservers as traffic amplifiers. The backdoor binary contains a hardcoded list of more than 10000 DNS servers. The backdoor forks a process which continuously sends DNS requests for top-level domains (.com, .net, etc) with a spoofed source address. The source address is taken from the victim_ip parameter or resolved from victim_hostname. The address is resolved again after 40000 packets are sent, in case the dns record of the victim has been changed. All 10000 DNS servers will send their replies to the victim's ip address, causing a denial of service. The DNS Smurf attack was first described in s0ftpr0ject Security Advisory SPJ-002-000, July 19, 1999. If the s_port is specified, it is used as a source port for the queries, otherwise the source port is random. The DoS process sleeps for 300 microseconds after it has sent sleep_after packets. If it is not specified, the process sleeps after each packet.

All the packets between the client and the backdoor are sent as IP packets with protocol number 0x0B. They have the following format:

|--------|------|-------------|
| offset | size | description |
|--------|------|-------------|
|      0 |   20 | ip header   |
|     20 |    1 | packet type |
|     21 |    1 | unused      |
|     22 | >200 | packet data |
|--------|------|-------------|
The packet data at offset 22 is encoded with a simple obfuscation alogirthm. Disassembling the packet_encode and packet_decode functions is straightforward and gives us the following source:
/* Simple obfuscation of the packet data */
void packet_encode(int input_size, char* input, char* output)
{   
    int c;

    output[0] = input[0] + 0x17;
    for (c=1; c <= input_size; c++) {
        output[c] = output[c-1] + input[c] + 0x17;
    }
}   

/* The reverse of packet_encode */
void packet_decode(int input_size, char* input, char* output)
{
    int c;
    
    for (c=input_size-1; c > 0; c--) {
        output[c] = input[c] - input[c-1] - 0x17;
    }
    output[0] = input[0] - 0x17;
}

A decoder for the backdoor communication protocol is available: decoder.c. It uses libpcap and can sniff traffic in realtime or read tcpdump files. Running it on snort.log provided by project honeynet:

$ ./decoder -h
./decoder: invalid option -- h
the-binary Traffic Decoder
Syntax: the-binary [options]
  -i <iface>     Listens on a interface
  -r <dumpfile>  Reads in a tcpdump file

$ ./decoder -r snort.log
init: type=1 control_ip=203.173.144.35
init: type=1 control_ip=203.173.144.35
init: type=1 control_ip=203.173.144.35
exec_output: "rpcinfo -p 127.0.0.1"
reply:
   program vers proto   port
    100000    2   tcp    111  portmapper
    100000    2   udp    111  portmapper
    100021    1   udp   1024  nlockmgr
    100021    3   udp   1024  nlockmgr
    100021    1   tcp   1024  nlockmgr
    100021    3   tcp   1024  nlockmgr
    100024    1   udp    924  status
    100024    1   tcp    926  status

reply:
   program vers proto   port
    100000    2   tcp    111  portmapper
    100000    2   udp    111  portmapper
    100021    1   udp   1024  nlockmgr
    100021    3   udp   1024  nlockmgr
    100021    1   tcp   1024  nlockmgr
    100021    3   tcp   1024  nlockmgr
    100024    1   udp    924  status
    100024    1   tcp    926  status

reply:
   program vers proto   port
    100000    2   tcp    111  portmapper
    100000    2   udp    111  portmapper
    100021    1   udp   1024  nlockmgr
    100021    3   udp   1024  nlockmgr
    100021    1   tcp   1024  nlockmgr
    100021    3   tcp   1024  nlockmgr
    100024    1   udp    924  status
    100024    1   tcp    926  status

reply:
   program vers proto   port
    100000    2   tcp    111  portmapper
    100000    2   udp    111  portmapper
    100021    1   udp   1024  nlockmgr
    100021    3   udp   1024  nlockmgr
    100021    1   tcp   1024  nlockmgr
    100021    3   tcp   1024  nlockmgr
    100024    1   udp    924  status
    100024    1   tcp    926  status

reply:
   program vers proto   port
    100000    2   tcp    111  portmapper
    100000    2   udp    111  portmapper
    100021    1   udp   1024  nlockmgr
    100021    3   udp   1024  nlockmgr
    100021    1   tcp   1024  nlockmgr
    100021    3   tcp   1024  nlockmgr
    100024    1   udp    924  status
    100024    1   tcp    926  status

reply:
   program vers proto   port
    100000    2   tcp    111  portmapper
    100000    2   udp    111  portmapper
    100021    1   udp   1024  nlockmgr
    100021    3   udp   1024  nlockmgr
    100021    1   tcp   1024  nlockmgr
    100021    3   tcp   1024  nlockmgr
    100024    1   udp    924  status
    100024    1   tcp    926  status

reply:
   program vers proto   port
    100000    2   tcp    111  portmapper
    100000    2   udp    111  portmapper
    100021    1   udp   1024  nlockmgr
    100021    3   udp   1024  nlockmgr
    100021    1   tcp   1024  nlockmgr
    100021    3   tcp   1024  nlockmgr
    100024    1   udp    924  status
    100024    1   tcp    926  status

reply:
   program vers proto   port
    100000    2   tcp    111  portmapper
    100000    2   udp    111  portmapper
    100021    1   udp   1024  nlockmgr
    100021    3   udp   1024  nlockmgr
    100021    1   tcp   1024  nlockmgr
    100021    3   tcp   1024  nlockmgr
    100024    1   udp    924  status
    100024    1   tcp    926  status

reply:
   program vers proto   port
    100000    2   tcp    111  portmapper
    100000    2   udp    111  portmapper
    100021    1   udp   1024  nlockmgr
    100021    3   udp   1024  nlockmgr
    100021    1   tcp   1024  nlockmgr
    100021    3   tcp   1024  nlockmgr
    100024    1   udp    924  status
    100024    1   tcp    926  status

reply end
reply end
reply end
reply end
reply end
reply end
reply end
reply end
reply end

There are two approaches an attacker can take to hide her traffic. She can try to mimic existing traffic as closely as possible, or she can try to make her packets stand out so much that nobody notices. Both approaches have advantages and disadvantages. The author of the this backdoor used an unused IP protocol number, relying on the fact that most firewalls and IDSes have an "accept by default" policy. The only solution is to deny all protocols by default and only accept TCP and UDP.

Snort rule to detect traffic with an unknown IP protocol:

alert ip !$HOME_NET any -> $HOME_NET any (msg: "Weird IP protocol"; ip_proto: !tcp; ip_proto !udp;)
Netfilter rule to deny all IP protocols but TCP and UDP:
iptables -A INPUT -p !TCP -p !UDP -j DROP

Of course this doesn't help much, since there are lots of other ways to sneak traffic past a firewall or an IDS. For further information:

The author of the binary has tried to make it harder to analyze it by compiling it statically. This makes it impossible to tell which library functions are used with simple tools like objdump -t, but it doesn't stop more advanced tools like IDA and Fenris. For more information on using IDA see the analysis section.

Once the problem with the static binary was solved, the binary presented no further challenges. It used no advanced tricks to throw reversers off. No encrypted or self-modifying code, no ptrace() calls, no intentional buffer overflows.

This tool is very similar to other DDoS tools such as trinoo, Tribe Flood Network and stacheldraht. The program captured by the Honeynet Project is not based on the source of these widespread programs, but implements many of the same ideas and introduces some new ones. The communication channel is novel, and the multitude of available DoS attacks is also an improvement. The backdoor functionality of the honeynet binary is a simple, but useful addition.

Trinoo, TFN and stacheldraht use a three tier network of control: attacker(s) -> handler(s) -> agent(s). The advantage of this kind of network is that the identity of the attacker is protected by one additional layer and the whole system can be triggered by sending only one packet to each handler. The disadvantage is that if a running handler is captured, it will reveal the IP addresses of all agents under its control. The existance of a backdoor functionality in the Honeynet binary hints that it is used directly by the attacker, but it is also possible that there is a handler between them. The communication protocol in the captured binary uses packets of types 2,3 and 4. Maybe packets of types 0 and 1 are used for comunication between the attacker and the handler. Further information is required to confirm or deny this.

The author of this tool has a good understanding of UNIX programming and socket programming. The code is generally well written and effective. There are no immediate flaws in the tool. It could be improved, but as it stands now it is perfectly adequate for its purposes.

I was really impressed by the innovative pseudo-anonymous communication channel. I would estimate the skill level of the author as medium to high.

I was disappointed that the binary was not protected agains reverse engineering. Even a simple runtime unpacker would have made it much harder to disassemble. I expect that as this challange increases the awarenes of the whitehats about the reverse engineering process, it will prompt the blackhats to start using more sophisticated protection techniques. We'll see an arms race similar to the one in the virus scene in the early 90's.