在前三节中,我们可以得到部分的存储数据,嗅探感兴趣的数据块以及观察每个进程使用的资源信息等,但是我们却无法获取所有的存储数据,如果 PCB 板上没有了串口的话,或者 wifi 密码使用的不是默认的口令呢? 上述的研究意义就不大了。
本节中,我们将尝试从 Flash 芯片中提取出数据,解压后就能得到可用的数据,这种提取不依靠昂贵的设备,在之前的研究基础上,结合 Flash 芯片的 datasheet 实现提取。
一、 提取存储内容
在第三节中,我们已经可以根据 datasheet 知道 flash 芯片的引脚信息。 如图一所示。
图一 Flash 芯片部分引脚意义
我们也有 Flash 芯片的操作指令集,这样我们就可以自己开发程序实现与 Flash 之间的 SPI 通信。
在上节中,我们已经测试了在启动的过程中, CPU 芯片 Ralink 会与 Flash 芯片进行通信,这个会干扰我们尝试读取芯片的内容,所以我们需要断开他们之间的通信,最好是基于路由器的电路实现。
二、 难道我们要拆掉 Flash 芯片上的焊锡
最简单的办法是直接断开 Flash 芯片的引脚上的焊锡,这样就会与电路完全断开,我们就可以消除掉所有的干扰进而完全的控制芯片,但是,这样需要额外的设备,还需要有经验和时间,甚至可能造成芯片的损坏。
第二种方法就是能不能让 CPU 芯片及其周边所有的设备都处于无效或待机状态。微处理器通常会有一个 reset 引脚,当接上低电位时就处于关闭状态,这个引脚一般用于强制重启设备。但是从电路板上引出 CPU 这个引脚的麻烦比较大。
如果仅对一个芯片供电而不对其他的芯片供电呢?我们能不能只对 Flash 芯片供电而不是整个电路板供电?如果只是单独用 3v 的电源直接给 Flash 芯片供电,而不用 PCB 上的电源电路。这样有可能会破坏 Flash 芯片,反正这个路由器便宜而且广泛使用,当然这样也有可能会间接的给 CPU 供电了。如图二所示。
图二 直接给 Flash 芯片供电
在我们供电之后,我们就观察 UART 串口打印的数据,虽然可以看到 PCB 板上有 led 灯亮了,但是 UART 却没有数据打印,也就是说 Ralink 没有运行。尽管 Ralink 是关闭的,但是由于电路的影响,还是有可能会对我们读取 Flash 中的内容造成影响。如果有影响的话,那只能把 Flash 焊出来单独研究。
Led 灯和一些静态模块不会和 Flash 芯片有数据交互的,所以对我们的分析没有影响。
接下来,我们就用一个 bench 电源,能够支持足够多的电量消耗,当然,也可以用 Usb 供电等解决。
三、 连接 Flash 芯片
现在我们可以不用将 Flash 或者 Ralink 焊断,我们可以直接连接到 Flash,从而实现按块读取存储单元的数据。 所有的微处理器都可以实现数据的读取,一个专用的 SPI 转 USB 将会极大的提高效率。我们采用了一个基于 FT232T 的电路板,支持 SPI 以及其他低层次协议。如图三所示。
图三 Flash 芯片数据读取连接示意图
四、 提取数据
我们需要一个软件能够读取 USB-SPI 连接器上的数据,并将存储器中的内容保存为二进制文件,开源的 Flashroom 能够帮助我们解决这个问题。
在测试的过程中发现,无论是 OSX 和 Ubuntu 虚拟机上都存在问题,但是在树莓派上能够工作。如图四所示。
图四 Flash 芯片内容读取数据已经读取了,接下来就是分析存储器中的数据。
五、 分解二进制数据
上图中的 file 能够帮助我们大概的看一下二进制文件的格式,我们可以利用 binwalk 来彻底的解压二进制数据。如图五所示。
图五 binwalk 解压二进制数据
之前我们已经得到了这些数据相关的信息,如整个的内存映射表,结合这些,整个二进制的结构就会更加清晰。如图六所示。
图六 Flash 存储映射表
根据上述的地址, 整个二进制文件被分成 4 个段,使用 dd 命令完成,如下所示:
$ dd if=spidump.bin of=bootloader.bin bs=1 count=$((0x020000))
131072+0 records in
131072+0 records out
131072 bytes transferred in 0.215768 secs (607467 bytes/sec)
$ dd if=spidump.bin of=mainkernel.bin bs=1 count=$((0x13D000-0x020
000)) skip=$((0x020000))
1167360+0 records in
1167360+0 records out
1167360 bytes transferred in 1.900925 secs (614101 bytes/sec)
$ dd if=spidump.bin of=mainrootfs.bin bs=1 count=$((0x660000-0x13D
000)) skip=$((0x13D000))
5386240+0 records in
5386240+0 records out
5386240 bytes transferred in 9.163635 secs (587784 bytes/sec)
$ dd if=spidump.bin of=protect.bin bs=1 count=$((0x800000-0x66000
0)) skip=$((0x660000))
1703936+0 records in
1703936+0 records out
1703936 bytes transferred in 2.743594 secs (621060 bytes/sec)
这样我们创造了 4 个不同的二进制文件:
1、 bootloader.bin:uboot,这个文件没有被压缩,因为它是最先运行的, CPU 并不知道压缩算法。
2、 mainkernel.bin:Linux 内核,使用的是 LZMA 压缩,这是最基本的固件。
3、 mainrootfs.bin:文件系统,使用的是 LZMA 压缩算法的 squashfs 格式,里面包含了所有的二进制文件和配置文件等。
4、 protect.bin:保护区域,第三节中已经遇到的。
六、 提取数据
接下来详细的分析 4 个段的数据。
Bootloader, binwalk 分析如图七所示。
图七 binwalk 分析 bootloader.bin
其中有 UImage 头,uboot 根据这个头信息来识别存储区域。有点像 Linux 下的 file 命令,解释第一个头的意思。
由于 bootloader 前面已经有分析,此处就跳过。
Kernel, binwalk 分析如图八所示。
图八 binwalk 分析 mainkernel.bin
在分析之前,我们首先需要知道采用了什么样的压缩算法。此处使用了嵌入式设备中普遍使用的 lzma 压缩, 这样就不会有明文的 string 保存其中了,用 strings 命令后发现没有有意义的字符串。
有很多工具能够解压缩 lzma 算法,如 7z 或者 xz 等。但是对 mainkernel.bin 都无效。
$ xz --decompress mainkernel.bin
xz: mainkernel.bin: File format not recognized
这可能是 UImage 头部信息占有了最开始的 64 个字节,在分析中,我们跳过前面 64 个字节, 然后看到以 0x40 开头的就是 lzma 压缩的开始, 如图九所示。
图九 跳过 mainkernel.bin 的前 64 个字节
再次使用 xz 命令解压:
$ xz --decompress mainkernel_noheader.lzma
xz: mainkernel_noheader.lzma: Compressed data is corrupt
由此可见, xz 已经能识别是 lzma 压缩, 但是并不是完全的正确格式。 由于我们是尝试解压所有的 mainkernel 区域, 但是并不是整个的数据区域都是有效的, 查看二进制发现最后的 0xff 就是无效的, 如图十所示, 去掉最后部分, 实现了 xz 的解压。
图十 分析 mainkernel 的格式实现 xz 解压
Xz 解压成功之后, 我们可以用 strings 命令查看其中包含的有用的字符串了, 如图十一所示。
图十一 strings 查看解压后的 mainkernel.bin 中的字符串
上述的字符串都我们分析 wifi 密码生成算法没有什么帮助, 如 Wi-Fi Easy and Secure Key Derivation 仅仅是 wifi 设备中的一个硬编码字符串。
Filesystem, binwalk 分析如图十二所示。
图十二 binwalk 分析 mainrootfs.bin
Mainrootfs 段没有一个 UImage 头, 由上图可见, 采用的是 squashfs 文件系统, 这个在嵌入式设备中经常使用,有很多的版本,让我们看看 mainrootfs.bin 使用的是什么版本标志。如图十三所示。
图十三 mainrootfs 中的 squashfs 标志
已有脚本文件能够实现自动化的分析 squashfs。 此处使用的是 Firmware Modification kit中的 unsquashfs_all.sh 实现解压。 如图十四所示。
图十四 unsquashfs_all.sh 解压 mainrootfs.bin
这样我们得到了文件系统中的所有二进制文件、 配置文件以及快捷方式等。 如图十五。
图十五 文件系统目录结构
根据第一节中的字符串, 我们就可以查找感兴趣的文件了, 如图十六所示。
图十六 感兴趣的文件
这样文件在挖掘路由器漏洞中将会发挥重要作用。
Protected, binwalk 分析如图十七所示。
图十七 binwalk 分析 protect.bin
第三节中已经分析, 这块存储区域没有压缩, 包含了启动过程中所必需含有的字符串,用 strings 命令查看得到如图十八所示。
图十八 strings 查看 protect.bin 文件
这些内容与 curcfg.xml 很像, 第三节已经分析。
七、 后记
至此硬件逆向已经完成, 我们得到了存储器中所有的数据, 接下来就是进一步的深挖已有的数据。 当然, 如果你无法从硬件中得到这些数据, 你可以去官方网站上下载固件, 官方提供的可能不是所有的数据, 但是应该能够满足研究的要求。
本文由 看雪智能硬件安全小组成员 光棍节 编译,来源 Juan Carlos Jiménez@The World
戳👇 图片加入看雪智能硬件安全小组哦!
❤ 往期热门内容推荐
更多优秀文章,长按下方二维码,“关注看雪学院公众号”查看!
看雪论坛:http://bbs.pediy.com/
微信公众号 ID:ikanxue
微博:看雪安全
投稿、合作:www.kanxue.com