How to Make a DHCP Listener using Scapy in Python

Learn how you can make a DHCP listener by sniffing DHCP packets in the network using the Scapy library in Python.
  · 3 min read · Updated apr 2022 · Ethical Hacking · Packet Manipulation Using Scapy

Dynamic Host Configuration Protocol (DHCP) is a network protocol that provides clients connected to a network to obtain TCP/IP configuration information (such as the private IP address) from a DHCP server.

A DHCP server (can be an access point, router, or configured in a server) dynamically assigns an IP address and other configuration parameters to each device connected to the network.

The DHCP protocol uses User Datagram Protocol (UDP) to perform the communication between the server and clients. It is implemented with two port numbers: UDP port number 67 for the server and UDP port number 68 for the client.

In this tutorial, we will make a simple DHCP listener using the Scapy library in Python. In other words, we'll be able to listen for DHCP packets in the network and extract valuable information whenever a device connects to the network we're in.

To get started, let's install Scapy:

$ pip install scapy

If you have trouble installing Scapy, I suggest you follow this tutorial if you're in Ubuntu or other similar distribution or Windows 10 here.

As you may already know, the sniff() function in Scapy is responsible for sniffing any type of packet that can be monitored. Luckily, to remove other packets that we're not interested in, we simply use the filter parameter in the sniff() function:

from scapy.all import *
import time


def listen_dhcp():
    # Make sure it is DHCP with the filter options
    sniff(prn=print_packet, filter='udp and (port 67 or port 68)')

In the listen_dhcp() function, we pass the print_packet() function that we'll define as the callback that is executed whenever a packet is sniffed and matched by the filter.

To filter DHCP, we match UDP packets with port 67 or 68 in their attributes.

Let's define the print_packet() function:

def print_packet(packet):
    # initialize these variables to None at first
    target_mac, requested_ip, hostname, vendor_id = [None] * 4
    # get the MAC address of the requester
    if packet.haslayer(Ether):
        target_mac = packet.getlayer(Ether).src
    # get the DHCP options
    dhcp_options = packet[DHCP].options
    for item in dhcp_options:
        try:
            label, value = item
        except ValueError:
            continue
        if label == 'requested_addr':
            # get the requested IP
            requested_ip = value
        elif label == 'hostname':
            # get the hostname of the device
            hostname = value.decode()
        elif label == 'vendor_class_id':
            # get the vendor ID
            vendor_id = value.decode()
    if target_mac and vendor_id and hostname and requested_ip:
        # if all variables are not None, print the device details
        time_now = time.strftime("[%Y-%m-%d - %H:%M:%S]")
        print(f"{time_now} : {target_mac}  -  {hostname} / {vendor_id} requested {requested_ip}")

First, we extract the MAC address from the src attribute of the Ether packet layer.

Second, if there are DHCP options included in the packet, we iterate over them and extract the requested_addr (which is the requested IP address), hostname (the hostname of the requester), and the vendor_class_id (DHCP vendor client ID). After that, we get the current time and print the details. Let's start sniffing:

if __name__ == "__main__":
    listen_dhcp()

Before running the script, make sure you're connected to your own network for testing purposes, and then connect with another device to the network and see the output. Here's my result when I tried connecting with three different devices:

[2022-04-05 - 09:42:07] : d8:12:65:be:88:af  -  DESKTOP-PSU2DCJ / MSFT 5.0 requested 192.168.43.124
[2022-04-05 - 09:42:24] : 1c:b7:96:ab:ec:f0  -  HUAWEI_P30-9e8b07efe8a355 / HUAWEI:android:ELE requested 192.168.43.4        
[2022-04-05 - 09:58:29] : 48:13:7e:fe:a5:e3  -  android-a5c29949fa129cde / dhcpcd-5.5.6 requested 192.168.43.66

Conclusion

Awesome! Now you have a quick DHCP listener in Python that you can extend, I suggest you print the dhcp_options variable in the print_packet() function to see what that object looks like.

Get the complete code here.

Learn also: How to Make a SYN Flooding Attack in Python.

Happy hacking ♥

View Full Code
Sharing is caring!



Read Also



Comment panel