我在日常跟踪漏洞情报的过程中,看到
Vigor3900
最新版本固件
1.5.1.6
存在多处后台命令注入漏洞(CVE-2024-44844/CVE-2024-44845)
[1]
。正好最近看到几个固件仿真小工具,我打算一并试试效果。
Vigor3900
是
DrayTek
推出的一款高性能、多功能的企业级路由器,专为满足中大型企业、跨国公司及组织机构的网络需求而设计。支持多
WAN
冗余和负载均衡,具备强大的
VPN
功能和高级防火墙,适合复杂网络环境中的远程办公和分支机构互联,提供稳定、安全的网络解决方案。
3.1 固件提取
DrayTek
官网提供固件下载
[2]
固件版本:Vigor3900 v1.5.1.6
https://fw.draytek.com.tw/Vigor3900/Firmware/v1.5.1.6/Vigor3900_v1.5.1.6.zip
首先尝试
binwalk
提取压缩包中
.all
文件,只获取到一个
.ubi
文件。
$ binwalk -e V3900_1516.all
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
131120 0x20030 UBI erase count header, version: 1, EC: 0x0, VID header offset: 0x200, data offset: 0x800
$ ls _V3900_1516.all.extracted/
20030.ubi
一般情况下使用
ubireader
提取
.ubi
文件,可惜失败了。
$ ubireader_extract_files _V3900_1516.all.extracted/20030.ubi
UBI Fatal: Less than 2 layout blocks found.
通过了解得知
[3]
,
ubi_reader
工具对于
ubi
文件要求较为严格,它并不能处理所有厂商定制的
UBI
镜像。
ubidump
具备更强的兼容性,在处理特定固件格式时做了更多定制化处理。
使用
ubidump.py
[4]
进行提取。
$ cd _V3900_1516.all.extracted/
$ python3 ubidump.py -s . 20030.ubi
==> 20030.ubi <==
1 named volumes found, 2 physical volumes, blocksize=0x20000
== volume b'rootfs' ==
saved 3402 files
$ ls rootfs/
bin config_backup dev lib proc sbin tmp var
boot data etc mnt rom sys usr www
判断架构为 32位arm 小端。
$ file rootfs/bin/busybox
rootfs/bin/busybox: ELF 32-bit LSB executable, ARM, EABI4 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, stripped
firmwalker
简单扫一下找找
web
服务,发现
lighttpd
服务。
$ ./firmwalker.sh /home/iot/Desktop/vigor/_V3900_1516.all.extracted/rootfs
***Search for web servers***
##################################### search for web servers
##################################### apache
##################################### lighttpd
s/usr/sbin/lighttpd
s/usr/lib/lighttpd
s/etc/lighttpd
s/etc/init.d/lighttpd
3.2 固件仿真
固件仿真可以尝试一下
Sevnup
[5]
(根据文件系统信息自动下载相关的内核文件、配置ip地址、打包上传文件系统等)。
图1 Senvup 模拟固件
图2 Senvup 模拟固件
只需要在
qemu
里运行框中四条命令就行(
qemu
里不能复制粘贴,所以我运行完
ifconfig
后使用
ssh
连上去)。
ifconfig eth0 10.10.10.2/24
ping 10.10.10.1
wget http://10.10.10.1:8000/load_in_mips.sh
sh load_in_mips.sh
图3 Senvup 模拟固件
执行完四条命令后直接进入
shell
并修改权限。
图4 Shell
前文已经提到过
web
服务是
lighttpd
,尝试运行
/etc/init.d/httpd
,出现报错。
图5 运行 lighttpd 报错
看看
/etc/init.d/lighttpd
和
/etc/lighttpd/serverport.conf
,
lighttpd
如何解析
serverport.conf
。
图6 /etc/init.d/lighttpd 源码
图7 /etc/lighttpd/serverport.conf 源码
可以看到
lighttpd
会根据当前
web_Port
变量的值(
http
服务器端口) 向
serverport.conf
写入内容,配置
lighttpd
服务器的监听端口,看来并没有获取到
web_port
的值。
grep -r "web_port"
匹配关键字发现端口应该是
80
。
图8 grep -r "web_port"
将
/etc/init.d/lighttpd
中
web_Port
改成
80
成功启动。
图9 修改 /etc/init.d/lighttpd web_port
图10 启动 lighttpd
访问却出现
404
。
图11 访问报错
继续看看
/www
目录下都有什么文件,发现
/www/mobile
目录下存在
idnex.html
。并且访问
ip/mobile
即可访问到
/www/mobile/index.html
。
图12 ls /www
图13 访问 /www/mobile
用户手册上说默认后台地址就是
192.168.1.1
(我仿真的环境是
10.10.10.2
) 而不是
/www/mobile
目录下,所以
/www
目录下应该同样存在
idnex.html
文件。并且从用户手册得知默认账户密码
admin/admin
。
图14 用户手册
发现
/www/ajax.zip
包含
index.html
,
unzip
解压得到
index.html
并成功访问。
图15 grep -r "index.html"
图16 解压 ajax.zip
图17 访问成功
接下来我们发现,登录又失败了,因为是后台漏洞所以必须拿到
cookie
,我们来抓包看看怎么回事。
图18 登录失败
图19 抓包
登录认证请求的
/www/cgi-bin/mainfunction.cgi
文件,拖进
ida
搜索关键字
fail
。
图20 ida 搜索关键字 fail
Web UI Log-in Failure
应该就是这,交叉引用看看。
图21 交叉引用
分析代码可知
sub_2BDE4
接收了用户名、密码、远程 IP 并返回登录状态
v30
。
图22 sub_2C15C 伪代码
继续跟进
sub_2C15C
,程序会将用户输入密码与系统中存储的密码进行匹配。
图23 sub_2BDE4 伪代码
所以继续回到
shell
,搜索
passwd
相关文件,
find . -name "*passwd*"
。
图24 find . -name "
passwd
"
系统中存了密码但是认证还是失败,证明可能有脚本操作
/etc/data-default/passwd
,继续搜索关键字
grep -r /etc/data-default/passwd
。
图25 grep -r /etc/data-default/passwd
运行
/etc/data-default/passwd
后成功登录。
图26 登录成功
图27 登录成功
成功了,可以复现漏洞了。
4.1 CVE-2024-44844
图28 CVE-2024-44844 漏洞描述
情报描述
name
参数通过
run_command
函数导致命令注入,我的
ida
并没有成功将
sub_21F28
识别为
run_command
,我这里手动改了一下。
先来看看
run_command
,
run_command
接收输入为
a1
,代表一个字符串。并没有对
a1
进行任何的输入验证即调用
popen
执行。
图29 run_command 伪代码
漏洞触发在
sub_24764
图30 sub_24764 伪代码
函数
cgiGetValue(dword_44D3c,"name")
cgiGetValue(dword_44D3C, "type")
从请求中获取参数
name
type
,
name
被传递给了
sub_ACD4
函数,返回值
v3
被作为证书文件的名字使用。因为
name
值用户可控且没有任何过滤,导致可能插入恶意系统命令。对
type
进行验证,只有符合预期合法值才可通过。
name = "a & touch test &"
cat /etc/ipsec.d/certs/a & touch test & | grep "BEGIN CERTIFICATE" -A 50
漏洞复现:
图31 CVE-2024-44844 漏洞复现
图32 CVE-2024-44844 漏洞复现
4.2 CVE-2024-44845
图33 CVE-2024-44845 漏洞描述
情报描述
option
参数通过
filter_string
函数进行过滤,因为
filter_string
过滤不当并传入
system
导致命令注入,我的
ida
又没有成功将
sub_ACD4
识别为
filter_string
,我这里手动改了一下。
先看看
filter_string
,
filter_string
作用是将特定字符(
;
%
|
>
'