记得以前在公司时,经常碰到未经授权的DHCP服务器接入网络,可能是做实验,没有把虚拟机的网络与真实网络屏蔽,这样就很难搞。而且还遇到一特邪门的事情,VOIP的DHCPServer蹿入了用户网络,导致用户拿到的是IP电话的IP,通过DHCP获取IP,就有这个麻烦,谁快就拿谁的。那么,如何通过Scapy找到DHCP李鬼呢?可以自己写,也可以使用内置的函数dhcp_request()
这个工具非常简单,就是创建一个DHCP请求包,在网络中发送广播,如果接受到DHCPACK,就会返回这个ACK包,这样就可以分析到底是哪个DHCP发送的IP地址
dhcp_request()需要两个参数,iface表示使用哪个网卡接口,如果没有赋值,那么使用conf.iface所指定的网卡,这种情况对多个网卡好用,还有一个参数是conf.checkIPaddr,如果为1,那么会有提示,可能会检查IP地址,还没仔细看这个参数是干嘛用的。设置好之后,就可以直接使用了
conf.iface=0
dhcp_request(iface='wlan0')
如果留空,那么就是conf.iface指定的网口,一般留空就好了
>>>dhcp_request()
Begin emission:
.Finished to send 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets
<Ether dst=00:0c:29:3e:0f:dasrc=5c:63:bf:76:90:20 type=0x800|<IP version=4L ihl=5L tos=0x0len=576 id=57084 flags= frag=0L ttl=64 proto=udp chksum=0x15f7src=192.168.1.1 dst=192.168.1.104 options=[]|<UDP sport=bootps dport=bootpclen=556 chksum=0x5266 |<BOOTP op=BOOTREPLY htype=1 hlen=6 hops=0 xid=0 secs=0 flags=ciaddr=0.0.0.0 yiaddr=192.168.1.104 siaddr=0.0.0.0 giaddr=0.0.0.0chaddr='\x00\x0c)>\x0f\xda\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'sname='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'file='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'options='c\x82Sc' |<DHCP options=[message-type=offer server_id=192.168.1.1 lease_time=7200subnet_mask=255.255.255.0 router=192.168.1.1name_server=192.168.1.1 end pad ... pad]|>>>>>
>>> a=_
>>>a.summary()
'Ether / IP / UDP 192.168.1.1:bootps >192.168.1.104:bootpc / BOOTP / DHCP'
>>>a.sprintf('%Ether.src%:%IP.src%')
'5c:63:bf:76:90:20:192.168.1.1'
这样就可以看出DHCP服务器的IP地址与MAC地址了,可以看看DHCP应答的包结构
>>>a[BOOTP].show()
###[ BOOTP ]###
op= BOOTREPLY
htype= 1
hlen= 6
hops= 0
xid= 0
secs= 0
flags=
ciaddr= 0.0.0.0
yiaddr= 192.168.1.104
siaddr= 0.0.0.0
giaddr= 0.0.0.0
chaddr='\x00\x0c)>\x0f\xda\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
sname='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
file='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
options= 'c\x82Sc'
###[ DHCP options ]###
options= [message-type=offer server_id=192.168.1.1 lease_time=7200subnet_mask=255.255.255.0 router=192.168.1.1name_server=192.168.1.1 end pad ...pad]
这个工具有一定的局限性,就是太模拟客户端了,如果有一个最快的DHCP返回了DHCPRequest,那么就显示这个最快的数据包
如何能找到所有的DHCP服务器呢?这个需要添加srp()的参数multi=True
等到接收到所有的DHCP应答,才返回接收到的结果
这个就不能用方便的dhcp_request()了
改写一下脚本
>>>conf.checkIPaddr = False
>>> fam,hw =get_if_raw_hwaddr(conf.iface)
>>> dhcp_discover =Ether(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=hw)/DHCP(options=[("message-type","discover"),"end"])
>>> ans, unans =srp(dhcp_discover,multi=True) # Press CTRL-C after several seconds
Begin emission:
Finished to send 1 packets.
.*...*..
Received 8 packets, got 2 answers, remaining 0 packets
>>>ans.summary()
Ether / IP / UDP 0.0.0.0:bootpc >255.255.255.255:bootps / BOOTP / DHCP ==> Ether / IP/ UDP 192.168.1.1:bootps > 255.255.255.255:bootpc /BOOTP / DHCP
Ether / IP / UDP 0.0.0.0:bootpc >255.255.255.255:bootps / BOOTP / DHCP ==> Ether / IP/ UDP 192.168.1.11:bootps > 255.255.255.255:bootpc /BOOTP / DHCP
>>> for p in ans:print p[1][Ether].src, p[1][IP].src
...
00:de:ad:be:ef:00 192.168.1.1
00:11:11:22:22:33 192.168.1.11
第二步参考
http://trac.secdev.org/scapy/wiki/IdentifyingRogueDHCPServers
其实,可以看dhcp_request()源代码的,源代码是这么写的
def dhcp_request(iface=None,**kargs):
ifconf.checkIPaddr != 0:
warning("conf.checkIPaddr is not 0, I may not be able to match theanswer")
if iface isNone:
iface = conf.iface
fam,hw =get_if_raw_hwaddr(iface)
returnsrp1(Ether(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=hw)/DHCP(options=[("message-type","discover"),"end"]),iface=iface,**kargs)