ARP协议
ARP 协议也叫做地址解析协议,就是IP地址转换成MAC地址的协议
原理:在局域网内广播,向所有的主机发送包含目标IP地址的请求报文,如果该IP地址的主机接到了报文,那么就会将自己的MAC地址返回给发送端。同样根据这个原理就可以实现扫描局域网的所有主机。
ARP请求报文
一个完整的ARP数据报包括:14字节的以太网首部 + 28字节的ARP数据报
前者包括:6字节的目的MAC地址 + 6字节的发送端MAC地址 + 2字节的类型(0x0806:ARP协议)
后者包括:2B 硬件类型+2B 协议类型+1B 硬件地址长度+1B协议地址长度+2B 操作类型+6B 发送端 MAC 地址+4B 发送端 IP 地址+6B 目的端 MAC 地址+4B 目的端 IP 地址
ARP发送
# 将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)
ARP监听
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 命令,查看对方的操作系统,例如:
~/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 "扫描结束"