Monday, 23 February 2015

Finding rogue DHCP servers with a Raspberry Pi

You can download the dhcp-server-sniffer perl script here.

The main purpose of this script is to find rogue DHCP servers in a subnet and get their IP and MAC address. If you are looking to capture a complete dhcp converation, this is not the tool for you, dhcpdump is a nice tool for that job.

I decided to put the DHCP server sniffer script onto a Raspberry Pi so that we could monitor all traffic on a particular subnet that is used for teaching server administration. Sometimes a rogue DHCP server accidently gets run on this subnet.

Getting the script to run on the Pi was a matter of copying the script onto the Pi and then installing some CPAN libraries

apt-get install libnetpacket-perl libnet-pcap-perl libnet-dhcp-perl

One i was happy that is was running correctly, I left the Pi in a comms cabinet and patched it into the subnet that I wanted to monitor. It is currently sniffing DHCP traffic for the a subnet in that cabinet. I didn't bother attaching a keyboard, mouse or monitor to it so access is over the network via ssh only.

I did encounter a small problem, when I put the Pi into the comms cabinet and plugged it into the network, it grabbed a DHCP address. There's no monitor on the Pi now, so how do I find out the IP address of the pi so that I can ssh to it?!

One way is to use nmap and go through the entire network to see which devices are listening to the ssh port.

So from some other Linux desktop machine you could run the following nmap command:

waltersa@awdeb:~$ nmap -p22 -oG - | grep open
Host: () Ports: 22/open/tcp//ssh///
Host: () Ports: 22/open/tcp//ssh///
Host: () Ports: 22/open/tcp//ssh///

Here we can see that three devices answered, and I happen to know that the first two are the routers for the local subnet, so our pi has to be the third one.

A second, more foolproof way is to use a combination of fping and arp. Before putting the Pi into comms cabinet, make a note of it's MAC address, the one on my Pi was b8:27:eb:53:90:e5.

Then from any Linux machine on the local subnet, ping all machines in the subnet with fping. 'apt-get install fping' if you need to.

fping -g

Pinging every machine in the subnet causes your PC to do arp lookups for each device on the subnet, these are MAC address and IP address pairings. To see this information do an arp -an and look for the MAC address of our Pi.

labadmin@specialistlab:~$ arp -an
? ( at 00:23:ae:6a:f9:67 [ether] on eth0
? ( at 00:04:96:41:45:c0 [ether] on eth0
? ( at 00:18:8b:19:38:61 [ether] on eth0
? ( at 00:04:96:43:9f:40 [ether] on eth0
? ( at b8:27:eb:53:90:e5 [ether] on eth0
? ( at 00:18:8b:19:45:46 [ether] on eth0
? ( at 00:24:7e:0e:2e:8e [ether] on eth0
? ( at 00:00:5e:00:01:01 [ether] on eth0
? ( at 00:23:ae:6a:b2:de [ether] on eth0
? ( at 00:18:8b:1a:3b:4d [ether] on eth0

Here we can see that our Pi, b8:27:eb:53:90:e5, has an IP address of

Now that we have all the information we need to ssh the Pi, I'll talk about the DHCP sniffer script.

This script captures packets in a switched networking environment so it will not capture a complete DHCP conversation. It will only capture those parts that are broadcasts. This is good enough for our purposes as a rogue DHCP server IP address, which is what we want to find, is included in the DHCP payload in these ethernet broadcasts.

Lets talk about the output of the script. Run it with sudo.

pi@raspberrypi ~ $ sudo ./ 
Timestamp         | Message Type  | DHCP Server IP  | Ether MAC   
20150220 10:43:21 | DHCP Ack      |    | 0004964145c0
20150220 10:43:21 | DHCP Ack      |    | 000496439f40
20150220 10:53:49 | DHCP Nak      |    | 0004964145c0
20150220 10:53:49 | DHCP Nak      |    | 000496439f40
20150220 10:53:50 | DHCP Offer    |    | 0004964145c0
20150220 10:53:50 | DHCP Request  |   
20150220 10:53:50 | DHCP Ack      |    | 0004964145c0
20150220 10:53:50 | DHCP Ack      |    | 000496439f40

This is the current local time of the computer that is doing the sniffing, namely our Pi's time, not the time from the DHCP server or the client.

Message Type
This field is taken from the DHCP packet payload, this is the type of DHCP packet being captured. You will probably see DHCP Ack, DHCP Offer, DHCP Request and DHCP Nak type packets. This wikipedia page isn't bad for looking up more information about this.

DHCP Server IP
The IP address displayed read from the DHCP Payload data itself and is the IP address of the DHCP server that is talking to the client PC. Is not taken from the IP layer of the packet.

Ether MAC
Ok this is where it gets a little tricky, the ether MAC is taken from the ethernet part of the packet. So it may or may not be the MAC address of a DHCP server. In the above output, the MAC address that is displayed are the MAC address of the two routers, which act as DHCP relay agent. So these are not the MAC addresses of our DHCP servers. The question would be why display them here at all? Well the answer is, for a rogue DHCP server, the MAC address displayed WILL be the MAC address of the rogue DHCP server. The reason for this is that this conversation is not being relayed by the subnet routers. This MAC address is very usefull for giving to the network administrator to do lookups against the switches mac address table, or CAM table in order to pinpoint the rogue to a particular switchport.

Well I think thats it. I'm going to leave that Raspberry Pi hidden in that comms cabinet waiting for when a rogue DHCP server appears again and starts to cause havoc.

You can download the dhcp-server-sniffer perl script here.

Friday, 6 February 2015

DHCP Server Sniffer Perl Script

I needed something to detect rogue DHCP servers on our network so I created a small perl script that listens to DHCP broadcasts and prints the IP address of the DHCP server along with the originating MAC address. This is useful in an information gathering situation where you need to confirm that there is in fact a rogue DHCP server present on your LAN.

You can download the dhcp-server-sniffer perl script here.

This perl script uses libpcap to sniff the local subnet for DHCP broadcast packets that contain a DHCP server IP address. In particular we want to capture REQUEST packets sent by the client.

A typical DHCP session looks like the following:

Client does a DISCOVER (broadcast)
Server sends and OFFER (can be broadcast or unicast)
Client sends a REQUEST (this is a broadcast)
Server sends an ACK

When a client sends one of these REQUEST packets, they also include the IP address of a DHCP server they are sending to. These are ethernet broadcast packets and so are ideal for our packet sniffer. Once captured, these packets are then processed and the IP address of the DHCP server is printed to the screen. If the packet being processed happens to be a reply from the server, the originating MAC address is also printed. This way we can easily see the IP addresses of any hosts that are acting as DHCP servers, be them legitimate or rogue.

You will need to run the script as root, and can optionally pass the interface name to listen on to the script at the command line.

This script was developed and tested on Debian GNU/Linux using Perl 5 and should run on any Linux based system without much problem.

Some output from a sample run.
root@p1155-awdeb:~# ./
DHCP Offer detected | DHCP Server IP: | src MAC: 0004964145c0
DHCP Request detected | DHCP Server IP:
DHCP Ack detected | DHCP Server IP: | src MAC: 0004964145c0
DHCP Release detected | DHCP Server IP:
DHCP Offer detected | DHCP Server IP: | src MAC: 000496439f40
DHCP Request detected | DHCP Server IP:
DHCP Ack detected | DHCP Server IP: | src MAC: 0004964145c0
DHCP Ack detected | DHCP Server IP: | src MAC: 000496439f40

The CPAN Libaries needed to run this script:

To install these CPAN libraries on debian based systems:

  apt-get install libnetpacket-perl libnet-pcap-perl libnet-dhcp-perl

Reference material: