ARP 协议也叫作地址解析协议,就是IP地址转换成MAC地址的协议python
原理:在局域网内广播,向全部的主机发送包含目标IP地址的请求报文,若是该IP地址的主机接到了报文,那么就会将本身的MAC地址返回给发送端。一样根据这个原理就能够实现扫描局域网的全部主机。bash
一个完整的ARP数据报包括:14字节的以太网首部 + 28字节的ARP数据报网络
前者包括:6字节的目的MAC地址 + 6字节的发送端MAC地址 + 2字节的类型(0x0806:ARP协议)socket
后者包括:2B 硬件类型+2B 协议类型+1B 硬件地址长度+1B协议地址长度+2B 操做类型+6B 发送端 MAC 地址+4B 发送端 IP 地址+6B 目的端 MAC 地址+4B 目的端 IP 地址测试
# 将16进制的MAC地址转换成,须要的字符格式 def mac2a(m): return binascii.a2b_hex(m) # 将ip地址列表转换成,须要的字符格式 def ip2a(i): ipi = i[0]*256*256*256+i[1]*256*256+i[2]*256+i[3] iph = hex(ipi) return binascii.a2b_hex(iph[2:]) # 向指定IP发送ARP报 def send(ip): # 设置协议族类型和上层协议 rawS = socket.socket(socket.PF_PACKET,socket.SOCK_RAW, socket.htons(0x0806)) # 绑定网卡和端口号 rawS.bind(("wlo1",socket.htons(0x0800))) # 以太网头封包,6s:6B的目的端MAC,6s:6B 发送端MAC,2s:2B的协议类型 tha = mac2a('ffffffffffff') #target hardware address 目的端硬件地址 sha = mac2a('34238769543e') #sender hardware address 发送端硬件地址 ethHdr = tha+sha+'\x08\x06' # ARP数据封包 hrd = '\x00\x01' #硬件地址类型,默认1:以太网 pro = '\x08\x00' #网络地址类型,0800:IP地址 hln = '\x06' #硬件地址长度,单位B pln = '\x04' #网络地址长度,单位B op = '\x00\x01' #操做类型,1:arp请求,2:arp响应 #sha = sha #发送端硬件地址 spa = ip2a([192,168,199,112]) #发送端网络地址 #tha = tha #目的端硬件地址 tpa = ip2a(ip) #目的端网络地址 arpPkt = hrd+pro+hln+pln+op+sha+spa+tha+tpa # 发送 rawS.send(ethHdr+arpPkt)
def a2ip(a): return '%d.%d.%d.%d'%tuple(map(ord,list(a))) def a2mac(a): h = binascii.b2a_hex(a) return ':'.join([h[i:i+2] for i in xrange(0,len(h),2)]) #监听ARP响应 def listen(): pc=pcap.pcap("wlo1") #注,参数可为网卡名,如eth0 for pt,pd in pc: #pt为收到时间,pd为收到数据 eth = dpkt.ethernet.Ethernet(pd) if eth.type==2054: arp = eth.data if arp.op==2: #ARP响应 print "在线",a2ip(arp.spa)," ",a2mac(arp.sha)
~/python/pcap/arp$ sudo python lanScan.py 扫描开始 在线 192.168.199.1 d4:ee:07:1b:71:9c 在线 192.168.199.135 fc:64:ba:04:e0:2f 在线 192.168.199.148 90:00:4e:1e:19:ba 在线 192.168.199.153 a0:88:69:9d:ef:3b 在线 192.168.199.154 84:9f:b5:41:aa:f1 在线 192.168.199.154 84:9f:b5:41:aa:f1 在线 192.168.199.164 24:fd:52:92:14:86 扫描结束 ~/python/pcap/arp$
这样就可已知道全部的局域网的主机了,也能够使用 ping 命令,查看对方的操做系统,例如:spa
~/python/pcap/arp$ ping 192.168.199.1 PING 192.168.199.1 (192.168.199.1) 56(84) bytes of data. 64 bytes from 192.168.199.1: icmp_seq=1 ttl=64 time=1.69 ms 64 bytes from 192.168.199.1: icmp_seq=2 ttl=64 time=1.20 ms # 主要看ttl字段,通常状况下 # Linux系统的TTL值为64或255 # Windows NT/2000/XP系统的TTL值为128 # Windows 98系统的TTL值为32 # UNIX主机的TTL值为255
#!/usr/bin/python # -*- coding: UTF-8 -*- # sendARP.py # 探测局域网 IP import socket import struct import binascii import dpkt import pcap import thread # 将16进制的MAC地址转换成,须要的字符格式 def mac2a(m): return binascii.a2b_hex(m) # 将ip地址列表转换成,须要的字符格式 def ip2a(i): ipi = i[0]*256*256*256+i[1]*256*256+i[2]*256+i[3] iph = hex(ipi) return binascii.a2b_hex(iph[2:]) # 向指定IP发送ARP报 def send(ip): # 设置协议族类型和上层协议 rawS = socket.socket(socket.PF_PACKET,socket.SOCK_RAW, socket.htons(0x0806)) # 绑定网卡和端口号 rawS.bind(("wlo1",socket.htons(0x0800))) # 以太网头封包,6s:6B的目的端MAC,6s:6B 发送端MAC,2s:2B的协议类型 tha = mac2a('ffffffffffff') #target hardware address 目的端硬件地址 sha = mac2a('34238769543e') #sender hardware address 发送端硬件地址 ethHdr = tha+sha+'\x08\x06' # ARP数据封包 hrd = '\x00\x01' #硬件地址类型,默认1:以太网 pro = '\x08\x00' #网络地址类型,0800:IP地址 hln = '\x06' #硬件地址长度,单位B pln = '\x04' #网络地址长度,单位B op = '\x00\x01' #操做类型,1:arp请求,2:arp响应 #sha = sha #发送端硬件地址 spa = ip2a([192,168,199,112]) #发送端网络地址 #tha = tha #目的端硬件地址 tpa = ip2a(ip) #目的端网络地址 arpPkt = hrd+pro+hln+pln+op+sha+spa+tha+tpa # 发送 rawS.send(ethHdr+arpPkt) def a2ip(a): return '%d.%d.%d.%d'%tuple(map(ord,list(a))) def a2mac(a): h = binascii.b2a_hex(a) return ':'.join([h[i:i+2] for i in xrange(0,len(h),2)]) #监听ARP响应 def listen(): pc=pcap.pcap("wlo1") #注,参数可为网卡名,如eth0 for pt,pd in pc: #pt为收到时间,pd为收到数据 eth = dpkt.ethernet.Ethernet(pd) if eth.type==2054: arp = eth.data if arp.op==2: #ARP响应 print "在线",a2ip(arp.spa)," ",a2mac(arp.sha) #listen() thread.start_new_thread(listen,()) print "扫描开始" for i in xrange(1,255): send([192,168,199,i]) print "扫描结束"