前言
年初部门应急了一个 Zyxel VPN 未授权 RCE ,本来想跟着复现一下漏洞,结果发现在 .bin 中无法提取文件系统,了解得知 .bin 文件是 ZIP 格式的固件映像受密码保护。 通过如下文章学习到了Zyxel固件解密方法[1],以此篇文章记录并说明踩过的坑。
Zyxel VPN Firewall 是?种?络安全设备,由 Zyxel 通信公司提供。它结合了防?墙和 VPN(Virtual Private Network,虚拟专??络)功能,旨在保护企业?络免受未经授权的访问和恶意活动的威胁,并提供安全的远程访问解决?案。
固件提取
问题分析
1 | 固件版本 VPN100_V5.30(ABFV) |
解压 VPN100_V5.30(ABFV.0)C0.zip

尝试在 .bin 文件中提取文件系统,并没有提取出文件系统。
1 2 3 4 5 6 | $ binwalk -e 530ABFV0C0.bin$ cd _530ABFV0C0.bin.extracted/$ ls0.zip etc_writable fwversion wtp_imagecompress.img filechecksum kernelchecksum wtpinfodb filelist kernelvpn100.bin |
因为文件 530ABFV0C0.bin 是 ZIP 格式的固件映像受密码保护,也没有找到有关 Zyxel 使用密码的信息,但是固件一起的PDF文章中有一段对 530ABFV0C0.ri 的描述如下:

大致翻译为 .ri文件是一个二进制固件恢复映像文件,仅在系统固件损坏紧急情况下使用。如果正常的固件升级文件(.bin)不能使用,且系统无法启动,这个文件可以用于尝试恢复固件至可用状态。 由于 .ri 文件通常用于恢复损坏的固件,它可能包含完整的系统映像,所以尝试分析 .ri 文件。
尝试使用binwalk提取 bin 同目录下 .ri 文件。
1 | $ binwalk -e 530ABFV0C0.ri |

.ri 文件中提取出 240 和 240.7z。

240.7z 为 240 文件的压缩包,所以继续提取 240 文件。
1 2 | $ cd _530ABFV0C0.ri.extracted/$ binwalk -e 240 |

可以在提取到的 _240.extracted 文件夹下看到 zyinit 二进制文件,linux 常规的初始化启动进程就是init,所以将焦点放在了zyinit。

参考文章中提到分析 zyinit 发现它启动了其他外部程序,特别是 zld_fsextract 程序( zld_fsextract 应该是固件的解密程序)。
分析一下 zyinit 如何启动 zld_fsextract 。搜索关键字 zld_fsextract 再进行交叉引用。


一个一个看看,sub_1000722C+64 地址内容如下

这段函数实现了调用 ./zld_fsextract 程序,并对解压和处理固件进行操作。这样的话是不是可以直接运行 zld_fsextract 程序进行固件解密,再分析一下 zld_fsextract 程序。
1 | /zyinit/zld_fsextract /zyinit/zld_fsextract /tmp/Firmware /zyinit/unzip -s extract -e code |
zld_fsextract 程序用法如下

再通过搜索关键字 extract 并交叉引用看看 -s 接收的参数都实现什么功能。


extract、list、model 等选项对应着命令行工具的不同操作模式,应该用于处理某种文件(例如 ZIP 文件)或配置。(例如extract为提取模式,list为列表模式)。
现在可以尝试模拟MIPS环境执行二进制文件尝试提取文件了。
QEMU 模拟
先来判断一下需要模拟什么环境,这里 N32 有一个比较大的坑。
1 2 | $ file zld_fsextract zld_fsextract: ELF 32-bit MSB executable, MIPS, N32 MIPS64 rel2 version 1 (SYSV), statically linked, stripped |
通过判断 zld_fsextract 文件类型, 一开始使用 qemu-system-mips 内核镜像选择 vmlinux-3.2.0-4-5kc-malta 结果环境启动不了。第二次换内核镜像为 vmlinux-2.6.32-5-4kc-malta 环境成功启动,但是运行 zld_fsextract 报错不兼容。
1 2 | # ./zyinit-bash: ./zyinit: cannot execute binary file |
分析得知 N32 是用在32位和64位 MIPS处理器上的一种中间形式[2],它允许使用64位寄存器和内存寻址,但保持了32位数据模型,这样可以减少由于64位数据类型较大而带来的性能和内存使用上的开销。所以需要选择支持N32 ABI的MIPS64架构的模拟器来运行。
准备文件系统和内核镜像
1 2 | vmlinux-2.6.32-5-5kc-malta 内核镜像debian_squeeze_mips_standard.qcow2 文件系统 |
启动模拟环境
1 | $ qemu-system-mips64 -M malta -kernel vmlinux-2.6.32-5-5kc-malta -hda debian_squeeze_mips_standard.qcow2 -append "root=/dev/sda1 console=tty0" -net nic -net tap,ifname=tap0,script=no,downscript=no -nographic |
启动后用户名和密码都是root即可登录模拟系统
接下来在宿主机创建一个网卡,是 qemu 内能和宿主机通信。
宿主机安装依赖
1 | $ sudo apt-get install bridge-utils uml-utilities |
将如下代码保存为 net.sh 并运行即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | sudo sysctl -w net.ipv4.ip_forward=1sudo iptables -Fsudo iptables -Xsudo iptables -t nat -Fsudo iptables -t nat -Xsudo iptables -t mangle -Fsudo iptables -t mangle -Xsudo iptables -P INPUT ACCEPTsudo iptables -P FORWARD ACCEPTsudo iptables -P OUTPUT ACCEPTsudo iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADEsudo iptables -I FORWARD 1 -i tap0 -j ACCEPTsudo iptables -I FORWARD 1 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPTsudo ifconfig tap0 192.168.100.254 netmask 255.255.255.0 |
然后配置 qemu 虚拟系统的路由,在 qemu 虚拟系统运行如下 net.sh 并运行。
1 2 3 | #!/bin/shifconfig eth0 192.168.100.2 netmask 255.255.255.0route add default gw 192.168.100.254 |
//虚拟系统可能没有 vim 或 nano,使用 echo 一行一行写。
这样宿主机和模拟环境就可以网络互通了。
QEMU 固件提取
将刚才问题分析时宿主机上整个文件夹上传到 qemu 系统
1 | $ scp -r VPN100/ root@192.168.100.2:VPN100 |
这样就可以在虚拟机使用 zld_fsextract 二进制文件获取固件映像信息了,记得将 530ABFV0C0.bin 移动到 zld_fsextract 同目录下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # cp 530ABFV0C0.bin _530ABFV0C0.ri.extracted/_240.extracted/# cd _530ABFV0C0.ri.extracted/_240.extracted/# ./zld_fsextract 530ABFV0C0.bin -s listname :kernelscope :-f kernelvpn100.bin -f kernelchecksum -D /nc_scope :-f kernelvpn100.binversion :3.10.87build_date :2023-06-30 03:00:45checksum :8c27e89fc31dc52276d5a0917dea5caecore_checksum :1f226cc478dcd00f57e90b620c761137name :codescope :-f bmvpn100.bin -f bmchecksum -f kernelvpn100.bin -f kernelchecksum -d wtp_image -d db -i -D /rwscope :-d db/etc/zyxel/ftp/conf -D /nc_scope :-f fwversion -f filechecksum -f wtpinfo -f compress.img.sig -f fwversion.sigversion :5.30(ABFV.0)build_date :2023-06-30 03:32:50checksum :273360e448e46f81b59f002c69eee18ccore_checksum :17768559763bbf5ab2d7aebe1fd4a51dname :WTP_wtp_image/nwa5120scope :-f wtp_image/nwa5120 -D /dbnc_scope :version :5.10(###.10)build_date :2021-01-21 10:04:56checksum :core_checksum : |
通过 ./zld_fsextract 530ABFV0C0.bin -s list 输出信息结合前文 zyinit 程序中获取到信息,使用 zld_fsextract 程序提取固件。
1 2 | /zyinit/zld_fsextract /zyinit/zld_fsextract /tmp/Firmware /zyinit/unzip -s extract -e code# ./zld_fsextract 530ABFV0C0.bin ./unzip -s extract -e code |
这时会在 /rw/ 路径下生成 compress.img ,将这个文件传输到宿主机使用 binwalk 提取即可得到 squashfs-root 文件系统。
1 2 3 4 5 6 7 8 9 10 | # ls -al /rw/total 94480drwxr-xr-x 3 root root 4096 Mar 19 07:58 .drwxr-xr-x 23 root root 4096 Mar 19 07:59 ..-r--r--r-- 1 root root 96575488 Apr 19 2022 compress.imgdrwxr-xr-x 6 root root 4096 Apr 19 2022 etc_writable-rw-r--r-- 1 root root 139 Apr 19 2022 filechecksum-rw-r--r-- 1 root root 35655 Apr 19 2022 filelist-rw-r--r-- 1 root root 327 Apr 19 2022 fwversion-rw-r--r-- 1 root root 8375 Apr 19 2022 wtpinfo |
这里是宿主机提取 compress.img 得到 squashfs-root 截图。

拿到固件就可以开开心心进行漏洞复现和分析啦。
总结
参考文章中不仅讲到了固件提取,还进行了密码分析。读者如果感兴趣可以跟着继续深度学习,这里只是将实操过程中的步骤进行更详细的展示,也是一次学习过程的笔记记录。
相关链接
[1] Zyxel固件提取和密码分析
Zyxel固件提取和密码分析 - hn security (humanativaspa.it)
[2] MIPS ABI n32意味着什么?