Before anything can happen, Honeyd needs to be configured correctly. Honeyd uses a simple text-based configuration file to specify on which IP addresses to run virtual honeypots and also to specify which services are available for each host. The configuration language is a context-free-grammar that can be described in BNF (Backus-Naur form); see Figure 4.6. For each configuration command, the complete syntax is described in compact form. If in doubt about the particular options of a command, you can use Figure 4.6 as a quick reference sheet. Before we explain all of the commands in detail, let us start with a brief overview of the main configuration commands.
Code View: config = creation | addition | delete | binding | set | annotate | route [config] | option creation= "create" template-name | "create" "default" | "dynamic" template-name addition= "add" template-name proto "port" port-number action | "add" template-name "subsystem" cmd-string ["shared"] ["restart"] | "add" template-name "use" template-name "if" condition delete= "delete" template-name | "delete" template-name proto "port" port-number binding = "bind" ip-address template-name | "bind" condition ip-address template-name | "bind" ip-address "to" interface-name | "dhcp" template-name "on" interface-name ["ethernet" cmd-string] | "clone" template-name template-name set = "set" template-name "default" proto "action" action | "set" template-name "personality" personality-name | "set" template-name "personality" "random" | "set" template-name "ethernet" cmd-string | "set" template-name "uptime" seconds | "set" template-name "droprate" "in" percent | "set" <template-name> "maxfds" <number> | "set" template-name "uid" number ["gid" number] | "set" ip-address "uptime" seconds annotate= "annotate" personality-name [no] finscan | "annotate" personality-name "fragment" ("drop" | "old" | "new") route = "route" "entry" ipaddr | "route" "entry" ipaddr "network" ipnetwork | "route" ipaddr "link" ipnetwork | "route" ipaddr "unreach" ipnetwork | "route" ipaddr "add" "net" ipnetwork \\ "tunnel" ipaddr(src) ipaddr(dst) | "route" ipaddr "add" "net" ipnetwork ipaddr \\ ["latency" number"ms"] ["loss" percent] \\ ["bandwidth" number["Mbps"|"Kbps"] \\ ["drop" "between" number "ms" "-" number "ms" ] proto = "tcp" | "udp" | "icmp" action = ["tarpit"] ("block" | "open" | "reset" | cmd-string | \\ "internal" cmd-string \\ "proxy" ipaddr":"port ) condition = "source os =" cmd-string | "source ip =" ipaddr | "source ip =" ipnetwork | "time " timecondition |
A template refers to a completely configured computer system. The first step in creating virtual honeypots is to configure a template for each different computer system. Afterward, a template can be assigned to an IP address to bring up a virtual honeypot at that address. The virtual honeypot has all the characteristics of the assigned template, including operating system behavior and which services should run on each port.
New templates are created with the create command. The possible parameters for create are described by its BNF:
creation := "create" <template-name> | "create default" | "dynamic" <template-name>
The syntax supports three different cases. We will describe only the purpose of the first two and refer you to Chapter 5 for a discussion of the third option. In the first case, we specify an arbitrary template name. Each template needs to be named differently because we must be able to uniquely identify them by their name. If you try to create the same template name twice, Honeyd will be unable to load the configuration and print an error message instead. A template name is used to reference a specific template for further configuration like adding additional services and eventually to bind it to an IP address to create a honeypot.
The second case is more interesting because it refers to the default template. Whenever Honeyd receives a packet for an IP address, it tries to find a template with a name that corresponds to the destination IP address. For example, when Honeyd receives a packet for 10.1.0.135, it will look for a template with the same name (10.1.0.135). If such a template cannot be found, Honeyd uses the default template instead.
Using the default template, it is very easy to instrument address space quickly. For example, if we want to instrument all available addresses in a C-class network with the same configuration, we could just create and configure the default template. There would be no need to assign any template to individual IP addresses.
The set and add commands change the configuration of a template. The set command assigns a personality from the Nmap fingerprint file to a template. The personality determines the behavior of the network stack and can be chosen from a number of popular operating systems. We discuss a list of popular choices following. The set command also defines the default behavior for the supported network protocols. The possible parameters for set are as follows:
set ::= "set" <template-name> "default" <proto> "action" <action> | "set" <template-name> "personality" <personality-name> | "set" <template-name> "personality" "random" | "set" <template-name> "ethernet" <cmd-string> | "set" <template-name> "uptime" <seconds> | "set" <template-name> "droprate in" <percent> | "set" <template-name> "uid" <number> ["gid" <number>] |
The default behavior of a template determines how the host reacts to packets for unassigned ports or protocols. The protocol can be TCP, UDP, or ICMP. The action determines how this host reacts by default for each of the protocols. The action may be block, reset, or open.
Open specifies that all ports are open by default. This setting affects only UDP or TCP packets and can be used, for example, to capture the first payload of a worm attack.
Block means that all packets for the specified protocol are dropped by default. When block has been specified, the honeypot does not respond to packets for that protocol or port. This feature can be used to simulate the behavior of a firewall.
Reset indicates that all ports are closed by default. If a TCP port is closed, the virtual honeypot responds with a TCP RST to a SYN packet for that port. If a UDP port is closed, the virtual honeypot replies with an ICMP port-unreachable message.
Given this information, we can now easily create an invisible honeypot using the configuration in Figure 4.7.
create invisible set invisible default tcp action block set invisible default udp action block set invisible default icmp action block |
An invisible honeypot may seem like a pointless exercise, since its whole purpose is to be unreachable via the network. On the other hand, if you recall the discussion of the default template and that Honeyd uses it only if no other template can be found, an invisible host can selectively disable the default template. For example, let's say that you want to instrument a C-class network, but you know that there are two production systems on that network. We could disable Honeyd for two IP addresses by assigning the invisible template to them.
Probably, the most important use of the set command is to assign a network personality to a template. The personality determines how response packets are formed by Honeyd. Among other things, the personality influences how TCP sequence numbers are generated, how the IP identification number is changed, and how quickly TCP timestamps are incremented.
The available personalities depend on the version of Nmap's fingerprint database. If you installed Honeyd in /usr/local/, you should be able to find the database at /usr/local/share/honeyd/nmap/prints. Otherwise, you might have to change the path according to your install directory. It is also possible to use the fingerprint database provided by the Nmap package. Use the following shell script to generate a list of all available personality names:
grep "^Fingerprint" /usr/local/share/honeyd/nmap.prints | cut -f2- -d" | sort -u
At the time of this writing, Nmap knows of about a thousand different fingerprints. Figure 4.8 shows a list of some popular personality names. Use any one of the names in the database to assign an operating system network stack to a template — for example:
create linux set linux personality "Linux 2.6.6"
If you cannot decide on a name, you can ask Honeyd to randomly choose a template for you by specifying the template name as random. This is not usually a good idea; however, because the Nmap database contains many fingerprints that are not functional due to pathetic network behavior. For example, if you were to use "Apple Newton MessagePad 2100, Newton OS 2.1" as the personality, it would be impossible to establish TCP connections because this personality always returns a TCP RST even when trying to establish a connection.
Although there are several more options to the set command, only the uptime and Ethernet options are discussed here. For the other options, please consult Section 5.1, which discusses advanced configuration options. The uptime of a host refers to the elapsed time since it has been booted. Depending on the operating system, it can be determined by the value of the TCP timestamp option [55]. Usually, it is initialized to zero when the system boots. If you know the frequency with which the timestamp is updated, you can guess how long the system has been running. Netcraft uses this information to determine how long a web server has been running. See, for example, http://uptime.netcraft.com/. Honeyd can simulate this behavior by initializing the timestamp value via the set command:
set linux uptime 259200 # three days
For operating systems that do not support the timestamp option or that initialize the timestamp value randomly, the uptime option has no effect.
The Ethernet option assigns an ethernet MAC address to a template explicitly. Recall that knowing a MAC address is necessary to send a packet to a host. Previously, we mentioned that we can use Proxy ARP to send the MAC address of the Honeyd host to either the router or another machine on the local network. One reason for not using the Proxy ARP approach is that anyone on the local network can easily determine that the IP addresses of virtual honeypots all refer to the same MAC address. This might be a dead giveaway if we wanted to fool intruders who have access to the local network. Using the Ethernet option of the set command, we can give each virtual honeypot its own unique MAC address. Honeyd takes care of all the required ARP interactions, and as a result, we no longer need to configure Proxy ARP. You can specify the MAC address explicitly — for example:
set 10.1.0.134 ethernet "3f:12:4e:14:d0:32"
On the other hand, Honeyd also supports a shorthand by specifying the name of the device vendor. If we want to simulate a Cisco router, we might want to set the Ethernet address to "cisco". Honeyd then creates a random MAC address in the address space reserved by Cisco.
When a template that has an associated IP address gets cloned or bound to an IP address, Honeyd automatically creates a new Ethernet address for the resulting IP address or template. The new Ethernet address is created by randomizing the last three bytes.
Warning
For a network to operate correctly, it is very important that all MAC addresses be unique. If there are MAC address collisions, bad things can happen. Using this option requires that you make sure that no such collisions happen.
The add command is the centerpiece of any template. It allows us to specify which services are remotely accessible and what application should run on each port. The syntax of the command is as follows:
addition ::= "add" template-name proto "port" port-number action | "add" template-name "subsystem" cmd-string ["shared"] | "add" template-name "use" template-name "if" condition |
The add command always refers to the template that we want to configure. If the template does not exist yet, it needs to be initialized via the create command. Although the BNF of the add command shows three different versions, the use of the latter two — specifying subsystems and configuring dynamic templates — is not explained here but in Chapter 5 instead.
The first version of the add command is the most common and requires that we specify a protocol, a port number, and a command to execute for each service. For example, we could start an SSH simulator for TCP connections on port 22 by specifying
add linux proto tcp port 22 "./scripts/ssh-emul.py"
When a remote host establishes a TCP connection on port 22 with the Linux template, Honeyd starts a new process that executes the service script ./scripts/ssh-emul.py. The script receives network input via its stdin, and, conversely, the script's stdout is sent over the network to the remote host. Instead of configuring TCP services, the add command can also be used for services that run over UDP — for example, a script to emulate the Domain Name Service (DNS). For each new connection, Honeyd needs to fork a new process. This can lead to a performance bottleneck if Honeyd simulates virtual honeypots that receive a lot of network traffic.
You might have noticed that the syntax for the add command specifies a token with the name action. In the preceding example, we have replaced this with the path of a Unix shell script that Honeyd is supposed to execute for new connections on the specified port. A closer look at Figure 4.6 reveals that the full syntax for the action token is more complex:
action ::= ["tarpit"] ("block" | "open" | "reset" | cmd-string | "internal" cmd-string | "proxy" ipaddr":"port ) |
By studying the preceding BNF, we see that instead of specifying a Unix shell script, Honeyd also recognizes the actions that we have previously used for the default behavior of a template. Now we see that we can use block, reset, and open also on a per-port basis. For example, the default behavior of a template might be to accept TCP connections on all ports, but for Nmap's operating system detection to work some ports need to be closed. We could use the following command to simulate a closed port that rejects TCP connections with a TCP RST segment:
add linux proto tcp port 23 reset
The keyword internal tells Honeyd to load a Python module that can be executed internally without the need to create a new process for each connection. When a virtual honeypot needs to handle lots of traffic, creating new processes can become a performance bottleneck. For more information on internal Python services, see Section 5.4.
Another interesting feature is the proxy keyword. It allows us to forward network connections to a different host. For example, we might want to have a nameserver as virtual honeypot but do not want to actually simulate a nameserver. Instead, we just configure the template to forward UDP packets or TCP connections to a host that does run a nameserver. Let's assume that the nameserver is running on IP address 10.0.0.2. The template could look like this:
add linux proto tcp port 53 proxy 10.0.0.2:53 add linux proto udp port 53 proxy 10.0.0.2:53
To provide more dynamic behavior, Honeyd can do variable expansion on the service parameters. It expands the following four variables for both the service and the proxy statement: $ipsrc, $ipdst, $sport, and $dport. Variable expansion allows a service to adapt its behavior depending on the particular network connection it is handling. It is also possible to redirect network probes back to the host that is doing the probing. For example, we might have noticed someone attacking random hosts on our network via SSH. (Evil laugh). Just for the fun of it, we decide to send the attack back to the adversary:
add linux proto tcp port 22 proxy $ip_src:22
In this case, an adversary establishes a connection to port 22 of the virtual Honeypot, and Honeyd connects back to the SSH server running on the machine from which the adversary is attacking. Any commands sent to the honeypot are directly send back to her.
Redirecting attacks back to the source is, of course, merely a party trick and not that useful in practice. However, this flexibilty is helpful for regular service scripts as we can pass the IP source address and source port number as parameters to a command. Within a script, this information is also available via the following environment variables: HONEYD_IP_SRC, HONEYD_IP_DST, HONEYD_DST_PORT, HONEYD_SRC_PORT, and HONEYD_PERSONALITY. In Chapter 5, we discuss in detail how to create scripts that emulate Internet services.
The final command necessary to complete the configuration of a virtual honeypot is the bind command. It is used to assign a template to an IP address. If a packet arrives for an IP address that has no template assigned to it, Honeyd uses the default template instead. The complete syntax of the bind command is as follows:
binding ::= "bind" ip-address template-name | "bind" ip-address "to" interface-name | "bind" condition ip-address template-name | "dhcp" template-name "on" interface-name ["ethernet" cmd-string] | "clone" template-name template-name |
The semantics of the first command are very intuitive. It tells Honeyd to use a specific template for a given IP address. Whenever Honeyd receives a packet for that IP address, the daemon consults the template configuration to determine if a port is open and which service to start when a connection has been established. The other configurations are more esoteric: Binding an IP address to an interface name allows Honeyd to integrate real machines into a virtual routing topology, and conditional binding can be used as a shorthand to configure dynamic templates. These additional options are all described in detail in Chapter 5.
When Honeyd binds a template to an IP address, it essentially creates a new template with the name of the IP address and copies the complete configuration of the original template to the template corresponding to the IP address. This has multiple advantages: We can use all configuration commands on the IP address without changing the configuration of the template, or we can change the template configuration without changing the configuration of previously configured IP addresses.
The clone command is a more general form of the bind command. Instead of duplicating a template configuration to an IP address, we can use clone to copy a template configuration to a new template name. For example, we might create a base template that specifies the default behavior of all protocols and then clone new templates from it. The resulting configuration file is smaller because we do not have to repeat the protocol defaults over and over again.
The dhcp command creates a virtual honeypot that is assigned an IP address automatically via DHCP. This is very useful for integrating virtual honeypots into an existing production network. The dhcp command takes two parameters: the name of the template and the interface on which the DHCP requests should be sent. On startup, Honeyd automatically acquires IP addresses for each dhcp statement as long as there is a DHCP server listening on your local network. The dhcp command works only for templates that have an ethernet address assigned to them. While a virtual honeypot is waiting for an answer from the DHCP server, it is assigned a private IP address within the range 169.254.1.1 to 169.254.255.255. This limits a single Honeyd instance to about 65,000 virtual honeypots that acquire addresses via DHCP. In practice, it is unlikely that there is any DHCP server that could hand out that many leases. The optional Ethernet argument can be used to prevent a random MAC address from being assigned to the virtual honeypot.
The delete command can be used to reconfigure virtual honeypots on the fly. It has the following syntax:
delete ::= "delete" <template-name>|\\ "delete" <template-name> <proto> "port" <port-number>
The command can be used to either delete a template completely or to remove specific services from a template. When a template has been deleted, Honeyd stops knowing about it — for example, if you delete a template called 10.1.0.1, subsequent connection attempts to that IP address can be handled by the default template. Existing connections to a template are not affected and stay connected to a service even if it has been deleted.
This command is most useful when trying to create a more dynamic virtual honeypot environment. Using the honeydctl application, it is possible to reconfigure Honeyd on the fly; see Section 5.8. An example scenario is a Bait and Switch network [72], where we have a shadow honeynet that replicates an existing production network. When the IDS detects an adversary, the bad traffic gets redirected to the shadow honeynet. We can implement the shadow network by creating a tool that frequently scans the production network and replicates the topology and hosts dynamically on the Honeyd host via honeydctl. When a host on the production network goes down, we can delete the corresponding template, and when it comes back up, we can recreate it as a virtual honeypot.
The include directive does not affect the configuration of a honeypot, but it can be used to organize a complicated Honeyd configuration into several files. The include command takes a single filename as the parameter and essentially substitutes the include command with the contents of the file. Includes are allowed to be nested for up to ten levels.