Vigor 3910 相关分析
Vigor 3910
Vigor 3910 是台湾 Draytek(居易科技)公司推出的一款四核心网关设备,提供 10G SFP+、2.5G 以太网等接口,并且支持 VPN 和防火墙功能,因此在企业场景有较多应用。
已经有前辈在 2022 年 hexacon 发布了针对 Vigor 3910 的相关研究,本文在此研究基础上整合相关工具并复现 CVE-2023-31447 漏洞。
固件处理
Draytek 提供固件下载地址,我们下载 3.9.7.2 和 4.3.2.5 两个版本用于后续分析。
使用 binwalk 分析两个文件的熵值
Vigor 3910 v3.9.7.2 |
Vigor 3910 v4.3.2.5 |
3.9 版本可以解析出很多特征,而 4.3 版本似乎采取了某种加密,无法直接解析。考虑固件升级策略,在 3.9 版本中可能预置了 4.3 版本的解密密钥,所以我们先分析 3.9 版本固件。
根据参考文章得知,固件通过 THUNDER 关键字分割为多个部分,包括两个 boot.bin,init.bin 和 ATF stage 1,先按照特征将固件拆开
1 | dd if=v3910_3972.all of=boot1.bin skip=8198 count=12288 bs=16 |
在 ATF stage 1 中可以找到 BL1: Booting BL2
等字符串,此为 ARM Trusted Firmware 相关内容,所以 3910 设备上可能使用了 ATF 技术。参考 ATF 启动流程,CPU 会先执行 BL1,BL1 通常被烧录在 ROM 中,BL1 完成初始化工作之后会通过 UUID 查找其他 BL 的位置,BL2、BL3、系统镜像等部分被单独打包在 fip.bin,存放到 flash 内。考虑到关键部分应该在 fip.bin,所以要想办法找到此文件并解包。
查看 ARM ATF 开源代码发现 fip.bin 是以 TOC_HEADER_NAME 和 TOC_HEADER_SERIAL_NUMBER 开头
1 | /* This is used as a signature to validate the blob header */ |
从 stage1.bin 中查找这两个定义
fip.bin |
于是找到了 fip.bin 的起始位置,从这里开始将文件分割,得到 fip.bin (将前 8 字节删除)
1 | dd if=stage1.bin of=fip.bin skip=16383 bs=16 |
接着下载并编译 fiptool
1 | git clone https://github.com/ARM-software/arm-trusted-firmware |
然后对 fip.bin 进行拆分
1 | fiptool unpack ./fip.bin |
得到 nt-fw.bin、soc-fw.bin、tb-fw.bin 等文件,nt-fw.bin 即 BL33。
逆向分析此文件,其中包含 Decrypt file
,expand 32-byte k
等字符串,而 expand 32-byte k
恰好是 salsa20 或者 chacha20 算法的标志(根据参考文章可知其实是 ChaCha20 算法),并且在程序中能够找到密钥
ChaCha20 密钥 |
进一步分析解密函数,它还会从加密的文件头部获取 nonce 值,由于固件不是整个都使用 ChaCha20 算法进行加密,所以还要分析其格式,找到加密的镜像以及 nonce 参数。
观察固件开头数据
v4.3.2.5 文件开头 |
其中包含 env_Image、nonce 等字符串,参考 BL33 中的解密逻辑推测,此处数据结构为
1 | int data_length; |
所以 nonce 可以提取出来: UODAjyXZOzH0
,加密的镜像长度也已知: 0x034A1A00
将 enc_Image 部分拆出,编写解密代码进行解密(去掉前 3 个字节)
1 | dd if=v3910_4325.all of=enc_Image skip=15 count=3449248 bs=16 |
1 | import sys |
解密之后得到 ARM64 Linux boot Image,检查其熵值
enc_Image_decrypted.bin 的熵值 |
熵值有变化,进一步查看分析结果发现,Linux 文件系统是以 cpio 形式嵌入到内核中的,binwalk 无法直接解包,所以接下来还要对内核进行分析,尝试解压 cpio 文件。
逆向分析内核,通过搜索字符串找到 sub_991C1C 函数
1 | __int64 __fastcall sub_991C1C(_BYTE *a1, __int64 a2) |
代码中包含 decompressor failed
等提示,似乎和解压数据相关,对 sub_991C1C 函数进行交叉引用定位到以下代码
1 | __int64 sub_991F9C() |
sub_991C1C 函数第一个参数是全局变量,数据以 0x184C2102 开头,这是 LZ4 压缩的标志。而 qword_33EB2F0 存放的值为 0x2A0B6D6,为压缩数据的长度。
因此我们可以根据以上参数从内核中提取出这部分 lz4 压缩的数据,然后手动解压。
1 | dd if=enc_Image_decrypted.bin of=lz4.bin bs=1 skip=10353688 count=44086998 |
最终得到一个 cpio 压缩文档,直接用 cpio 命令解压,解压后即可看到 Linux 文件系统。
1 | cpio -idmv < ./decompressed.bin |
将以上流程编写代码实现自动化
1 | import sys |
模拟执行
3910 设备上运行了一个 Linux 系统,但主要的业务逻辑都位于 qemu 启动的 sohod64.bin 中,即然是 QEMU 启动,理论上也可以在本地运行起来。
根据参考文章,检查 firmware 目录下的启动脚本,发现 qemu 启动时存在一个非标准参数 -dtb DrayTek
,猜测是开发者修改过 QEMU 源代码,自行添加的参数。
Draytek 提供设备的 GPL 代码,下载 3910 型号的 GPL 代码分析确定,开发者为 QEMU 添加了一些新功能,用来支持 drayos 运行,所以我们需要编译这份 GPL 代码。
1 | ./configure --enable-kvm --enable-debug --target-list=aarch64-softmmu |
编译好之后得到需要的 qemu-system-aarch64,接下来要修改原始的启动脚本,适配本地环境。
宿主机需要新添加两张网卡,修改 network.sh 脚本,将网卡名称替换到脚本中
1 |
|
然后构造启动脚本,首先按照参考文章的提示,修改自带的启动脚本,当尝试启动文中提到的版本(4.3.1)时一切正常,但启动新版时会出现错误
1 | [qemu_ivshmem_write_internal:2729] already wait for more than 100ms, check host. |
通过逆向分析发现和 portmap 内存有关系,而这块内存又和参数 memsize 有关,因此尝试将 memsize 值修改为 1
1 |
|
启动时先执行 network.sh,随后执行 myrun.sh,访问 192.168.1.1 即可看到登录页面
系统成功启动 |
漏洞分析
根据描述,漏洞出现在 user_login.cgi 中,在 soho64.bin 搜索该字符串,结果中有一个地址找不到任何引用,在程序中搜索该字符串的地址可以找到 IDA 未识别的位置,此处存在大量 URI -> handler 的映射关系,因此也能找到 user_login.cgi 的 handler,其中关键代码如下
1 | *(a4 + 0x10LL) = 200; |
首先获取用户传递的 fid 参数,转换成 int 类型之后进入 switch 处理
当 fid 等于 101 时,会调用 user_login_101 函数
1 | __int64 __fastcall user_login_101(int a1) |
明显看到漏洞,代码从用户请求中获取 src_ip 等参数,没有经过任何过滤就将其作为格式化字符串传入 snprintf 函数,存在格式化字符串漏洞。
构造出 PoC
1 | POST /cgi-bin/user_login.cgi HTTP/1.1 |
发送到设备后在终端观察系统已经崩溃
系统崩溃 |
参考文章
https://www.hexacon.fr/slides/hexacon_draytek_2022_final.pdf
https://www.cnblogs.com/arnoldlu/p/14175126.html
https://zhuanlan.zhihu.com/p/391101179
https://harmonyhu.com/2018/06/23/Arm-trusted-firmware/#bl1
https://android.googlesource.com/platform/external/lz4/+/HEAD/doc/lz4_Frame_format.md
- 本文作者: Catalpa
- 本文链接: https://wzt.ac.cn/2024/02/19/vigor_3910/
-
版权声明:
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。