The network setup for this project is fairly simple:

The bridge is completely transparent to the attacker – they have no knowledge that they are passing through this machine. Therefore, it makes for an excellent machine to carry out the network logging between the honeypot and the internet. I will use the OpenBSD 3.1 native packet filtering tool, pf, to allow all inbound
connections to the honeypot and only allow outbound icmp echo requests, tcp 21 (FTP, active), tcp/udp 53 (DNS), tcp 80 (HTTP), and tcp 6667 (IRC). I take the previous measures to bring down my liability yet try not to raise suspicion from the attacker. The second logging facility on the bridge, pf being the first, will be Snort, a powerful sniffer and IDS. The third and final logging facility will be the trusty tcpdump. It will capture full packet dumps going to and from the ip of the honeypot. Data control from the honeypot is also controlled on the bridge. Refer the paper about data control for honeypots at The Honeynet Project. Thanks to the Brazil team of the Honeynet Research Alliance I can use a tool specifically developed for OpenBSD’s pf for data control calledsessionlimit. After compromise of the honeypot it will interact with pf in order to contain activity of the intruders. There is no way I can guarantee that the intruders will not indulge in malicious activity but I hope to limit that possibility with this tool. The interface on the bridge with the public ip will be used strictly for remote management purposes. This interface will be packet filtered to only allow SSH connections from specific ips and only allow outbound HTTP traffic to update Snort rules and email notification of said updated rules.
The Configuration
First I configured the OpenBSD bridge. When I refer to interfaces they are set up as follows – rl0 is the interface without an ip connected to the internet, rl1 is the interface without an ip connected to the honeypot, and rl2 is the interface with a public ip for remote management purposes connected to the internet.
Changes to /etc/rc.conf:

Enable packet forwarding in /etc/sysctl.conf so upon reboot it is enabled:

net.inet.ip.forwarding=1 # 1=Permit forwarding (routing) of packets

Create /etc/hostname.rl0:

# echo up > /etc/hostname.rl0

Create /etc/hostname.rl1:

# echo up > /etc/hostname.rl1

rl2 will get its public address assigned via DHCP from the ISP:

# echo dhcp NONE NONE NONE > /etc/hostname.rl2

Create /etc/bridgename.bridge0:

# echo add rl0 add rl1 up > /etc/bridgename.bridge0

The pf configuration file, /etc/pf.conf, needs to be created, here’s my end result:

# pf.conf ruleset
# to view the logfiles:
# tcpdump -n -e -ttt -r /var/log/pflog
# to tail -f the logfile:
# tcpdump -n -e -ttt -i pflog0


# my mgmt interface. pf can interpret interface as an ip
# very practical for dynamic ips

# these interfaces do not have an ip stack

# remote management ip addresses
mgmtips ="{ x.x.x.x/32, x.x.x.x/32 }"

# honeypot public ip
honeypot ="x.x.x.x/32"

# honeypot allowed TCP outbound services
allowed_svcs_tcp="{ ftp, domain, www, ircd }"

# honeypot allowed UDP outbound services
allowed_svcs_udp="{ domain, bootps }"

reserved ="{,,,,,,,,,,


# don't allow spoofed reserved addresses
block in quick on $outif from $reserved to any
block out quick on $outif from $honeypot to $reserved

# block and log outgoing packets that don't have honeypot address as source
block out log quick on $outif from ! $honeypot to any

# filtering on the bridge will be done on the outside (rl0) interface

# predetermined svc's from the honeypot will be allowed out individually
block             out log on $outif           all

# everything is allowed in to the honeypot
pass              in      on $outif           all keep state

# only ssh will be allowed to the mgmt interface
block             in  log on $mgmtif          all

# only smtp, domain, and http will be allowed out from the mgmt interface
block             out log on $mgmtif          all


# noise from my cable modem segment that is silently dropped
block in quick on $mgmtif inet from any to {, }


pass out log quick on $outif inet proto tcp from $honeypot to any
        port $allowed_svcs_tcp flags S/SA keep state
pass out log quick on $outif inet proto udp from $honeypot to any
        port $allowed_svcs_udp keep state
pass out log quick on $outif inet proto icmp from $honeypot to any
        icmp-type 8 code 0 keep state


pass in log quick on $mgmtif inet proto tcp from $mgmtips to $mgmtif
        port ssh keep state
pass out quick on $mgmtif inet proto tcp from $mgmtif to any
port { smtp, domain, http } flags S keep state
pass out quick on $mgmtif inet proto udp from $mgmtif to any
port domain keep state


Snort was next. First, I created a user snort with a login of /sbin/nologin. Then I downloaded Snort 1.9.0, compiled it, and tweaked the snort.conf file to fit my needs. I also installed oinkmaster. Oinkmaster is a perl script to update Snort rules from the latest ruleset available on I unpacked the tar.gz in /home/snort and then added an entry to snort’s crontab to update the rules every day at 3:00 PM. The output from oinkmaster, which is any rule that is deleted, modified, or added, is then emailed to me if there are any changes. Here is the crontab entry:

0 15 * * * cd $HOME/oinkmaster-0.6 ; TMP=`mktemp /tmp/oinkmaster.XXXXX` &&
(./ -o $HOME/rules/ -q -c > $TMP 2>&1; if [ -s $TMP ]; then mail
-s "Snort Oinkmaster Update `date +%m-%d-%Y`" < $TMP; fi; rm $TMP)

Next is data control with sessionlimit. It will monitor the state table (Note: outgoing traffic needs to have keep state) and block honeypot connections outbound when 1) the number of states associated with the honeypot increases too fast, 2) when the honeypot makes more than 20 connections, and 3) when the number of bytes associated with an ICMP state has reached a predefined limit – the default is 65k (a la lame ping -f DoS). Keep in mind the attacker’s interactive session with the honeypot won’t be affected, only new outbound connections. After 30 minutes, the sessionlimit rule added to pf will expire. All of this is logged to syslog. Since we are about to go live, we will start up sessionlimit manually:

# /usr/local/bin/sessionlimit -H x.x.x.x -i rl1 &

Enable packet forwarding now:

# sysctl -w net.inet.ip.forwarding=1

Manually initialize interfaces, bring up the bridge, and grab an ip for rl2:

# ifconfig rl0 delete
# ifconfig rl1 delete
# brconfig bridge0 add rl0 add rl1 up
# dhclient rl2

Make sure all of the interfaces and the bridge are up and configured correctly:

# ifconfig rl0
# ifconfig rl1
# ifconfig rl2
# brconfig bridge0

Enable pf and load rules:

# pfctl -e
# /sbin/pfctl -R /etc/pf.conf

Manually start Snort:

# /home/snort/snort-1.9.0/src/snort -i rl1 -deq -h x.x.x.x/32 -l /home/snort/log -c /home/snort/rules/snort.conf -D

Lastly, I run tcpdump by hand on rl1 to capture all traffic from my honeypot’s ip. A useful switch that was added in tcpdump 3.7.1 is -C which rotates the saved file every optarg * 1,000,000 bytes. This way I won’t have to load up an enormous file in ethereal, just makes analysis a little more manageable:

# tcpdump -i rl1 -n -s 1500 -C 2 -w /var/log/tcpdump/tcpdump.log host x.x.x.x &

For easy startup of Snort, tcpdump, and sessionlimit, I created a wrapper script called honeypot-wrapper. This way I only have to call the wrapper script and pass the honeypot ip as an argument to start these three services:


# snort, tcpdump, sessionlimit startup for honeypot


if [ -n "$1" ]; then
  echo -n "Usage: `basename $0` (honeypot ip)n"

if [ -x $SNORT ]; then
  echo -n " Snort starting...n"
  $SNORT -i rl1 -g snort -u snort -deq -h $ip/32
  -l $SNORTLOG -c $CONFIG -D >/dev/null 2>&1

if [ -x $TCPDUMP ]; then
  echo -n " Tcpdump starting...n"
  $TCPDUMP -i rl1 -n -s 1500 -C 2 -w $TCPDUMPLOG host $ip &
  >/dev/null 2>&1

if [ -x $SESSIONLIMIT ]; then
  echo -n " Sessionlimit starting...n"
  /usr/local/bin/sessionlimit -H $ip -i rl1 &
  >/dev/null 2>&1


The Deployment
The OS I chose for my first honeypot is OpenBSD 3.1 vanilla. There isn’t much to explain here – just install the OS and connect the honeypot to the bridge. With everything up and humming along now, all I have to do is sit back and wait for someone to take the bait. I have ssh access to the bridge’s management interface so I can log in from my management ip’s and look at the alert file in /home/snort/log/alert. I actually created a quick and dirty script in the ~snort directory to see a summary of attacks:
grep -v 'spp' ~snort/log/alert | grep '[**]' | sort | uniq -c

Here is the output:

# ./summary
9 [**] [1:1227:4] X11 outbound client connection detected [**]
3 [**] [1:1394:3] SHELLCODE x86 NOOP [**]
5 [**] [1:1418:2] SNMP request tcp [**]
4 [**] [1:1420:2] SNMP trap tcp [**]
4 [**] [1:1421:2] SNMP AgentX/tcp request [**]
1 [**] [1:1810:1] MISC Successful Gobbles SSH exploit [**]
1 [**] [1:1812:1] MISC Gobbles SSH exploit attempt [**]
1 [**] [1:249:1] DDOS mstream client to handler [**]
5 [**] [1:469:1] ICMP PING NMAP [**]
7 [**] [1:474:1] ICMP superscan echo [**]
1 [**] [1:498:3] ATTACK RESPONSES id check returned root [**]
1 [**] [1:587:2] RPC portmap request status [**]
1 [**] [1:598:5] RPC portmap listing [**]
9 [**] [1:618:2] SCAN Squid Proxy attempt [**]
3 [**] [1:628:1] SCAN nmap TCP [**]

Sure enough, someone took the bait after just 2 days, compromising the honeypot using the Gobbles SSH exploit.

This complete setup, which included getting the right hardware together, took me a few hours here and a few hours there over the course of a weekend. I am using old hardware – a Pentium 133MHz for the OpenBSD bridge and a Pentium 166MHz as the honeypot. After my setup was up and running smoothly I was overall pretty pleased with the honeynet design I had chosen, both in its simplicity and elegance.
To Do
Run Snort under DJB’s daemontools. chroot() Snort. chroot() and run as non-root tcpdump.

What Do You Think on This ? Say Here