Full Packet Friday: Parsing DHCP Traffic

Matt B
4 min readJan 7, 2017

--

As tough as it is to avoid writing about this MongoDB fiasco currently going on, I wanted to take a moment and look at parsing DHCP traffic using Python. If you’ll recall, last week’s FPF post focused on understanding what DHCP packets tell us, and the various options within the data. Today’s post is going to be relatively short, and could easily blend into tomorrow’s script-focused content. Seeing as it’s parsing network traffic, I felt it appropriate to post on a Friday.

dpkt

My go-to module for parsing PCAPs with Python is dpkt. There are certainly other options available, however this is what I’ve used for a while and just stick with it. I won’t go through all the intricacies of dpkt, but rest assured it can handle DHCP traffic.

Parsing the Packet

First, we need to get the packet to a state where we can examine the DHCP data. With dpkt, our first few lines look something like:

f = open(sys.argv[0])
pcap = dpkt.pcap.Reader(f)
for ts, buf in pcap:
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
udp = ip.data

Let’s examine the above, step by step. First, we open the PCAP file and pass it to dpkt’s Reader. The for loop actually takes into account the timestamp of the frame, and then the buffer itself. Here’s an example of what the buffer looks like from our DHCP PCAP:

Screenshot of buffer data from four DHCP frames

Within this data, we can see physical source and destination (remember we’re at the MAC layer right now), however I’m more interested in that data field. Let’s break those out:

Screenshot of IP data from four DHCP frames

Now we’re starting to get to more familiar. We’ve got data we can expand into IP addresses, as well as the UDP datagram. For example:

Screenshot of UDP datagram from four DHCP frames

Now, this is where we rely on dpkt to help us with some DHCP data. Let’s feed the UDP data to dpkt:

dh = dpkt.dhcp.DHCP(udp.data)

Output:

Screenshot of DHCP data from four DHCP frames

There we go! Remember our DHCP data that was found in Wireshark:

Screenshot of a DHCP Request packet from Wireshark

The decoded information includes the transaction ID (xid) and the opts nested lists (opts) that contain information about our DHCP content. Let’s bring the parsing together:

f = open(sys.argv[1])
pcap = dpkt.pcap.Reader(f)
for ts, buf in pcap:
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
udp = ip.data
dhcp = dpkt.dhcp.DHCP(udp.data)
print "Source -> Destination"
print "{} -> {}".format(socket.inet_ntoa(ip.src), socket.inet_ntoa(ip.dst))

Output:

Screenshot of DHCP parsing script output

Note that in this really simple example, we just break out the IP data. Let’s dig into some of the DHCP opts.

Defining DHCP Traffic

The first thing I wanted to do was define some of my DHCP traffic and correlation. Refer to the screenshot above for some of the DHCP options. For this example, I’m going to focus on the 53 option, which determines the DHCP Message Type.

dhcp_dict = {
1 : 'Subnet Mask',
50 : 'Requested IP Address',
53 : 'DHCP Message Type',
54 : 'DHCP Server Identifier',
55 : 'Parameter Request List',
58 : 'Renewal Time Value',
59 : 'Rebinding Time Value',
61 : 'Client Identifier',
255 : 'End'
}
dict_53 = {
1 : 'Discover',
2 : 'Offer',
3 : 'Request',
5 : 'ACK'
}

I’m interesting in defining those options so I can add some context to my parsed packet. I can now let the opts values tell me a bit about what’s going on with my packets.

Screenshot of DHCP parsing script output

I threw in the hyphens and new line just to help read output, but there we go! This was just a simple example of how to extract DHCP information from a PCAP. You could build in try/except statements to test for DHCP, and if so, move on. That would allow for passing an entire PCAP to the script and then extracting relevant DHCP information.

Until tomorrow, Happy Forensicating!

--

--