3. 固件文件系统分析:文件系统类型、挂载与关键文件识别
拿到一个固件,解压只是第一步。真正的好戏,在文件系统里。
我个人习惯,先看文件系统类型。这决定了你用什么工具、怎么挂载。搞错了,轻则解不开,重则把固件搞坏。嗯,咱们一步步来。
3.1 文件系统类型:Squashfs、JFFS2、YAFFS2
嵌入式设备里,文件系统就那么几种。说白了,它们都是为了在有限的Flash空间里,高效、可靠地存数据。
| 类型 | 特点 | 常见场景 |
|---|---|---|
| Squashfs | 只读、压缩率高、体积小 | 固件根文件系统(最常见) |
| JFFS2 | 可读写、磨损均衡、掉电安全 | 配置分区、日志分区 |
| YAFFS2 | 专为NAND Flash设计、速度快 | 大容量存储、多媒体设备 |
Squashfs 是我遇到最多的。为什么?因为它只读,固件厂商不希望你在运行时改系统文件。压缩率很高,一个几十兆的固件,解出来可能上百兆。
避坑指南: 我曾经遇到一个路由器固件,binwalk解出来全是Squashfs碎片。后来发现厂商用了非标准的压缩参数。这时候,你得手动指定块大小和压缩算法。
JFFS2 和 YAFFS2 都是可写的。JFFS2有磨损均衡,适合频繁擦写的分区。YAFFS2更快,但只支持NAND Flash。
你想想看,如果固件里有个config分区,大概率是JFFS2。如果是摄像头存视频的,可能是YAFFS2。
3.2 文件系统挂载与浏览
知道了类型,接下来就是挂载。我一般用两种方式:
- binwalk -Me:自动解压并挂载。适合快速浏览。
- 手动挂载:更可控,适合调试。
手动挂载Squashfs的典型命令:
# 先找到偏移量(如果有)
binwalk firmware.bin | grep "Squashfs"
# 假设偏移是 0x100000
dd if=firmware.bin of=rootfs.squashfs bs=1 skip=$((0x100000))
# 挂载
sudo mount -t squashfs -o loop rootfs.squashfs /mnt/firmware
为什么用 dd 切出来?因为很多固件前面有uboot头、内核,直接挂载会报错。我习惯先切出纯文件系统镜像。
小技巧: 挂载JFFS2时,记得加 -o ro 只读挂载。我曾经手滑写入了东西,结果固件校验失败,设备变砖。嗯,血的教训。
浏览文件系统,我推荐用 tree 命令看整体结构:
tree -L 3 /mnt/firmware
这样一眼就能看出目录布局。常见的目录有 /bin、/sbin、/usr、/etc、/lib、/www 等。
3.3 关键文件识别
挂载后,别急着到处翻。我有个固定的检查清单:
- /etc/passwd, /etc/shadow:用户和密码。很多设备用硬编码密码。
- /etc/inittab:启动进程。看哪些服务开机自启。
- /etc/init.d/ 或 /etc/rc.d/:启动脚本。这里经常藏着后门。
- /bin/busybox:嵌入式瑞士军刀。版本号能暴露漏洞。
- /www/ 或 /htdocs/:Web管理界面。找硬编码API、未授权接口。
- /lib/modules/:内核模块。驱动漏洞常在这里。
- *.conf, *.cfg, *.xml:配置文件。找明文密码、密钥。
实战案例: 我分析过一个摄像头固件,在 /etc/init.d/S99local 里发现一行 telnetd -l /bin/sh。厂商居然留了个telnet后门,密码是空。这就是典型的「调试接口未关闭」。
还有一个容易被忽略的:/tmp 目录。虽然挂载时是空的,但运行时会有日志、临时文件。如果固件里有 /tmp 下的脚本,说明它会在运行时写东西。
为什么会这样?很多厂商图省事,把调试脚本直接打包进固件。你想想看,这些脚本在运行时暴露的信息,往往比静态分析更多。
3.4 知识体系结构图
下面这张图,是我自己总结的固件文件系统分析流程。你可以照着这个顺序来,不容易漏东西。
重要提醒: 分析固件时,一定要在隔离环境里操作。有些固件里的脚本会尝试连接网络、执行危险命令。我一般用Docker或者虚拟机,快照随时回滚。
好了,文件系统这块就这些。记住:类型决定工具,挂载要小心,关键文件别放过。下次你拿到一个固件,按这个流程走一遍,基本不会漏掉重要信息。