
DHCP exhaustion script written in python using scapy network library
Whitehat DHCP hardening validation: exhaust a pool, hijack neighbours' leases, evict hosts off their addresses with forged ARP, and report whether the network stopped you. Needs root and Python 3.11+.
Debian / Kali: grab the latest .deb from
Releases and install it —
puts dhcpig and dhcpig-web on PATH, no venv needed:
curl -LO https://github.com/kamorin/DHCPig/releases/download/v2.7.2/dhcpig_2.7.2-1_all.deb
sudo apt install ./dhcpig_2.7.2-1_all.deb
sudo dhcpig-web --open
Global install (any Linux, Python 3.11+, no venv):
git clone https://github.com/kamorin/DHCPig && cd DHCPig
sudo pip install --break-system-packages .
sudo dhcpig-web --open
Installs straight into the system Python as root, so sudo dhcpig-web finds the command with
no .venv/bin/ path juggling. --break-system-packages overrides Debian/Kali's PEP 668 guard
against pip touching system packages — that guard exists to protect apt-managed packages, not
because this install is unusual; the .deb or a venv avoid needing it at all.
From source (any Linux, Python 3.11+):
git clone https://github.com/kamorin/DHCPig && cd DHCPig
python3 -m venv .venv && .venv/bin/pip install -e .
sudo .venv/bin/dhcpig-web --open
Open the printed http://127.0.0.1:8787/?token=... URL. Three gotchas:
.venv/bin/
path — sudo resets PATH.?token= is mandatory. Without it you get 401s and a blank page.ssh -L 8787:127.0.0.1:8787 user@<vm-ip>. Drop --open.On Debian/Kali, sudo apt install -y python3-venv first if the venv step fails.
sudo .venv/bin/dhcpig exhaust eth0 --report run.json
sudo .venv/bin/dhcpig release eth0 --scope 192.168.4.0/22 # DESTRUCTIVE
sudo .venv/bin/dhcpig active-scan eth0 --scope 192.168.4.0/22 # read-only
sudo .venv/bin/dhcpig release-previous eth0 # undo a previous run
dhcpig ifaces
-v0 prints results only; -v3 adds packet-level debug. Full flag reference: man dhcpig
(or packaging/dhcpig.1 before install).
DHCP Exhaustion (exhaust) — destructive
DHCP Release Active Clients (release) — destructive
Post Exhaustion / Reset (release-previous) — recovery
--max-age drops stale entriesFind Neighbors (active-scan) — read-only
Passive scan (scan) — read-only, CLI only
Everything lands in the event log, worst first: findings, then one line per host, then an
OUTCOME roll-up. Verbosity 0 (web) or -v0 (CLI) hides the packet traffic. The JSON export
is the complete record — the log is a summary.
Leases are kept after a run so the exhausted state can be verified. Release them:
sudo .venv/bin/dhcpig restore eth0 # same process still running
sudo .venv/bin/dhcpig release-previous eth0 # any time later, from the lease journal
The journal ($XDG_STATE_HOME/dhcpig/leases-<iface>.jsonl) records MAC, IP, server and
timestamp per lease taken — engagement data. Delete it when you're done.
Only run this against networks you own or are explicitly authorized to test. release and
exhaust disrupt live clients by design; --scope is optional and defaults to the whole
segment. The authors are not responsible for misuse.
Design notes and internals: docs/DESIGN.md. Contributing: CONTRIBUTING.md.
Licence: GPL v2 or later.
| Flag |
|---|
--dry-run | recon only: ARP sweep + control transactions run for real, nothing mutating is sent |
--scope CIDR | bound the targets (repeatable); defaults to the interface's own network |
--rate N | pps, default 7 — not on exhaust, which self-paces |
--no-evict | skip the ARP-conflict phase |
--report FILE | write a session report to FILE when the run ends; format follows FILE's extension (.json/.csv/.html, default JSON) |
--client-mac MAC | exhaust only; use this MAC instead of a random one (repeatable — rotates through the list) |
--request-option SPEC | exhaust/active-scan; DHCP option-55 (parameter-request-list) content to send, e.g. 12,14-19,23 (default: the built-in macOS-order profile) |
--no-spoof-eth-src | exhaust only; use the real NIC MAC as the Ethernet source for every frame (Wi-Fi; APs drop frames whose source MAC isn't the associated station) |