欢迎加入我们这场 Unblob(灵活的固件提取工具)的动手演示。 在本次研讨会环节中,我们将从一台电动汽车充电器中提取固件,深入 研究该固件,并最终对其进行仿真,以便实时与其中的 服务进行交互。Unblob 既适用于硬件版本,也适用于可下载版本 的固件,因此我们有丰富的目标环境。无需任何经验, 本环节适合各种技能水平,我们期待与大家现场 相见。
我们的目标是一台来自 Phoenix Contact 的电动汽车充电站控制器。你可以在此处找到更多详细信息。
CHARX control modular,交流充电控制器,搭载嵌入式 Linux 系统,IEC 61851-1,工作模式:Stand-Alone、Client、Server,
接口:
- 以太网(2x)
- 蜂窝通信(4G/2G)
- CHARX control modular 系统总线
- MICRO-USB type C
通信协议:
- OCPP 1.6J
- Modbus/TCP
- MQTT
可连接外围设备:
- 电能表
- RFID
- 直流剩余电流检测
- DIN 导轨安装
本次研讨会需要用到一些工具。你可以通过
运行 install-prerequisites 脚本来安装它们,方法如下:```sh
./install-prerequisites
## 获取固件
固件可以从供应商网站获取。此仓库中有一个名为
`download-firmware` 的脚本,你可以使用它来拉取固件,
无需打开浏览器。
我们今天的重点是供应商提供的固件,因为它包含我们所需的一切。
但类似的工作流程也可应用于从实机设备提取的内存转储。
有趣的是,我们甚至无需真实设备即可进行提取、探索和仿真。
## 使用 Unblob 进行提取
首先,确保所有依赖项都可用:```
unblob --show-external-dependencies
The following executables found installed, which are needed by unblob:
7z ✓
debugfs ✓
jefferson ✓
lz4 ✓
lziprecover ✓
lzop ✓
sasquatch ✓
sasquatch-v4be ✓
simg2img ✓
ubireader_extract_files ✓
ubireader_extract_images ✓
unar ✓
zstd ✓
现在我们可以使用 unblob 提取固件:``` unblob CHARXSEC3XXXSoftwareBundleV190.raucb
在一台配置不错的笔记本电脑上,提取大约需要 3 分钟。你应该会看到进度条向上移动:

提取完成后,应该会出现一个名为
`CHARXSEC3XXXSoftwareBundleV190.raucb_extract` 的目录。你可以进入
其中并列出内容。
### 数据块(Chunks)与未知数据块(Unknown Chunks)
Unblob 通过识别文件中的数据块来工作。如果某个块是
压缩流,它会被解压。如果是文件系统或归档文件,它
会被提取。如果提取或解压成功,这个块
被分割到磁盘后将被删除以释放空间。
这里,一个 SquashFS 版本 4 小端序(little-endian)块被分割到磁盘、提取,
然后删除。文件(以及因此产生的提取目录)使用
`{start_offset}-{end_offset}.{type}` 命名规则进行命名。
我们可以看到,在 squashfs 文件系统之后出现了 11KB 的 "unknown" 块。```
./0-132173824.squashfs_v4_le_extract
./132173824-132184833.unknown
你可以对它运行 binwalk 来查看其中包含的内容:```
binwalk 132173824-132184833.unknown
0 0x0 Object signature in DER format (PKCS header length: 4, sequence length: 10997 58 0x3A Certificate in DER format (x509 v3), header length: 4, sequence length: 4372 4434 0x1152 Certificate in DER format (x509 v3), header length: 4, sequence length: 4387
您可以使用 openssl 检查证书:```
dd if=132173824-132184833.unknown bs=1 skip=58 | openssl x509 -in /dev/stdin -inform der -noout -text
dd if=132173824-132184833.unknown bs=1 skip=4434 | openssl x509 -in /dev/stdin -inform der -noout -text
这意味着固件很可能使用厂商私钥签名,以便设备能够确保固件的真实性。
这是 unblob 的优势之一,它将未知的未知转化为可以被调查的已知的未知。
让我们来看看我们的 squashfs 文件系统的内容:``` ls -al 0-132173824.squashfs_v4_le_extract total 460532 drwxrwxr-x 4 kali kali 4096 dec 5 09:51 . drwxrwxr-x 3 kali kali 4096 dec 5 09:51 .. -rw-rw-r-- 1 kali kali 20971520 sep 8 09:59 bootimg.vfat drwxrwxr-x 3 kali kali 4096 dec 5 09:51 bootimg.vfat_extract -rwxrwxr-x 1 kali kali 2654 sep 19 2022 hook -rw-rw-r-- 1 kali kali 442 sep 8 09:59 manifest.raucm -rw-rw-r-- 1 kali kali 450584576 sep 8 09:59 root.ext4 drwxrwxr-x 22 kali kali 4096 sep 8 09:57 root.ext4_extract
我们可以看到一份纯文本清单、一个 shell 脚本、一个 MBR 和一个 EXT4 文件系统:```
find -maxdepth 1 -type f -exec file {} \;
./manifest.raucm: ASCII text
./hook: a /usr/bin/env sh script, ASCII text executable
./bootimg.vfat: DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "mkfs.fat", sectors/cluster 4, reserved sectors 4, root entries 512, sectors 40960 (volumes <=32 MB), Media descriptor 0xf8, sectors/FAT 40, sectors/track 63, heads 255, hidden sectors 163158016, reserved 0x1, serial number 0xd09aad9c, label: "KERNEL ", FAT (16 bit)
./root.ext4: Linux rev 1.0 ext4 filesystem data, UUID=8ed19606-02c4-42e7-9cfb-1a2839f93ec4 (extents) (large files) (huge files)
Both bootimg.vfat and root.ext4 were handled and extracted by unblob. The
VFAT partition contains everything related to boot and OS (Linux kernel, DTB,
TEE):```
oftree: Device Tree Blob version 17, size=27469, boot CPU=0, string block size=1657, DT structure block size=25756
tee.bin: data
zImage: Linux kernel ARM boot executable zImage (little-endian)
zImage-imx6ul-ksp0632.dtb: Device Tree Blob version 17, size=27469, boot CPU=0, string block size=1657, DT structure block size=25756
你会看到 unblob 有点贪心,会从 Linux 内核(`zImage`)中提取出一个 ELF 文件和一个 CPIO 归档,这些对应于最小的内核和 ramdisk。
EXT4 文件系统包含由 Linux 内核在启动时挂载的根文件系统:```
ls -alh root.ext4_extract
total 88K
drwxrwxr-x 22 kali kali 4,0K sep 8 09:57 .
drwxrwxr-x 4 kali kali 4,0K dec 5 09:51 ..
drwxrwxr-x 2 kali kali 4,0K dec 5 09:51 bin
drwxrwxr-x 3 kali kali 4,0K dec 5 09:51 boot
drwxrwxr-x 16 kali kali 4,0K sep 8 09:56 data
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 dev
drwxrwxr-x 53 kali kali 4,0K dec 5 09:51 etc
drwxrwxr-x 18 kali kali 4,0K sep 8 09:56 home
drwxrwxr-x 2 kali kali 4,0K jul 18 03:13 identity
drwxrwxr-x 9 kali kali 4,0K dec 5 09:51 lib
drwxrwxr-x 2 kali kali 4,0K jul 18 03:14 log
drwxrwxr-x 2 kali kali 4,0K sep 8 09:57 lost+found
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 media
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 mnt
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 proc
drwxrwxr-x 2 kali kali 4,0K sep 8 09:57 run
drwxrwxr-x 2 kali kali 4,0K dec 5 09:51 sbin
drwxrwxr-x 2 kali kali 4,0K jul 18 03:14 sdcard
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 sys
drwxrwxrwx 2 kali kali 4,0K jul 18 00:09 tmp
drwxrwxr-x 11 kali kali 4,0K sep 8 09:56 usr
drwxrwxr-x 11 kali kali 4,0K dec 5 09:51 var
让我们使用一组不同的 unblob 选项来进行一些探索:```
unblob -e /tmp/out -f -k -d 3 --report /tmp/report.json
--log /tmp/unblob.log CHARXSEC3XXXSoftwareBundleV190.raucb
这里我们持续使用 (`-e`) 提取到 `/tmp/out`,同时使用 (`-f`) 强制覆盖,并通过 (`-k`) 保留雕刻出的块,但将递归深度 (`-d`) 限制为 3。我们将详细报告 (`--report`) 写入 `/tmp/report.json`,并将日志文件 (`--log`) 写入 `/tmp/unblob.log`。
查看一下日志文件,你会看到 unblob 的内部工作原理。
报告文件包含有关已分析文件(大小、文件类型、路径、魔数、MIME 类型、MD5/SHA1/SHA256 哈希)、块(大小、偏移量、熵分布)以及任务(提取、解压缩、雕刻)的详细信息。结合一点 Python,你可以从这些报告文件生成漂亮的可视化结果。
你可以使用本仓库中提供的 `diagram.py` Python 脚本自行创建它们:```
python3 diagram.py /tmp/report.json sunburst
python3 diagram.py /tmp/report.json treemap
这些命令将在浏览器中打开一个页面,其中包含基于 plotly 的可视化 图表,如下所示:


既然我们已经更清楚地了解了内部结构,是时候列出我们 需要对设备进行正确仿真所需的信息了。
理想情况下,我们需要收集以下几项信息:
要获取有关平台、CPU 和架构的一些详细信息,我们可以查看 固件中嵌入的设备树二进制文件。