设备漏洞战记之固件提取篇

固件安全
2022-03-01 08:42
138896

固件提取篇

​@hvidwp

俗话说,巧妇难为无米之炊。在进行IOT漏洞挖掘的过程中,获取目标的文件系统,对二进制文件进一步分析,才能更好地理清目标设备的运行逻辑,从而发现其中的脆弱点。而无法获取固件中的文件,挖掘漏洞就会变成黑盒测试,这无疑是很困难的。

下面,我总结了一些常见的固件获取和固件解密的方法。

一、直接获取法

这类固件直接从官网能够下载到,使用binwalk、firmware-mod-kit这类工具能直接进行解包,比如华硕ASUS、NetGear等。通常我们能使用工具直接扫描出使用了何种压缩算法,以常见的嵌入式文件系统squash-fs为例,常见的有LZMA、LZO、LAMA2这些。

要注意的是,有些设备的固件官网并不提供,但在一些第三方网站的固件库中会收录,也可以在上面下载到相应的固件。还有些网站对于不同地区的发行产品不同,提供的下载固件也不同,有时要选择正确的地区,才能找到对应的固件,比较典型的就是tp-link。

还有就是可以人工向售后或者代理商索要。

二、固件加密类

还有就是厂商对固件进行了加密,在设备升级时,使用自己的方法先解密,再加载。一般通过binwalk等工具直接查看,无法查看到文件的压缩信息。下面以加密固件飞鱼星VM1200与未加密固件华硕AC66U为例。

root@ubuntu:/home/vincent/Desktop# binwalk B-MB3W202-201215-r11176.bin 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
root@ubuntu:/home/vincent/Desktop# binwalk RT-AC66U_B1_3.0.0.4_384_32738-gc9a116a.trx 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             TRX firmware header, little endian, image size: 44601344 bytes, CRC32: 0x807BC41B, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x19B364, rootfs offset: 0x0
28            0x1C            LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 4034848 bytes
1684324       0x19B364        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 42912124 bytes, 2623 inodes, blocksize: 131072 bytes, created: 2018-08-06 10:06:36

或者使用binwalk -E查看固件的熵值。熵是用来衡量不确定性的,如果熵值越大,说明固件越有可能是被加密或者压缩的,要注意的是,压缩也会使固件的熵值变大。


可以看到VM1200与AC66U,后者没有全部接近1。

解密固件的最简单方法是在固件中寻找解密例程,如果路由器可以解密新固件以进行更新,则解密例程必须位于旧固件映像中的某个位置。如果遇到加密的固件,请访问供应商网站并查找固件的存档版本,下载所有旧版本并开始四处浏览。

以下是常见的固件发行方案:

固件发布方案1

设备固件出厂时未加密,也不包含任何解密例程。解密例程与固件的未加密版本一起以更高版本(v1.1)一起提供,以用于将来的加密固件更新,随后的固件版本将被加密。

在这个方案中,我们可以从固件v1.1获取解密例程,并使用它来解密最新的固件1.2版本。

固件发布方案2

设备固件在原始发行版中已加密,供应商决定更改加密方案,并发布包含新解密例程的未加密过渡版本v1.2。

与方案1相似,我们可以从v1.2映像获取解密例程,并将其应用于最新的加密固件。阅读固件版本的发行说明可能有助于识别未加密的过渡版本。发行说明通常会指导用户在升级到最新版本之前先升级到中间版本,中间版本很可能是未加密的过渡固件。

固件发布方案3

设备固件在原始版本中是加密的。但是,供应商决定更改加密方案,并发布包含新解密例程的加密过渡版本。

在这种情况下,来获得解密例程就很困难了。一种方法是购买设备并直接从硬件中提取未加密的固件。另一种可能的方法是对固件进行更多的分析,以期“破解加密”。

下面以D-Link DIR-882的固件,针对第一种情况做实例分析。

binwalk提取

Binwalk是用于搜索给定二进制镜像文件以获取嵌入的文件和代码的工具。具体来说,它被设计用于识别嵌入固件镜像内的文件和代码。Binwalk使用libmagic库,因此它与Unix文件实用程序创建的魔数签名兼容。Binwalk还包括一个自定义魔数签名文件,其中包含常见的诸如压缩/存档文件,固件头,Linux内核,引导加载程序,文件系统等的固件映像中常见文件的改进魔数签名。

使用binwalk检查最新的固件,无法检测到标头等信息。

在供应商的FTP服务器上,我们可以找到该路由器的所有旧固件。如果我们使用binwalk检查最早的固件版本v1.00B07,它将正确检测到uImage标头和LZMA压缩数据:

这表明该设备的固件发布方案符合方案一,依次查看不同的固件版本,发现v1.04B02是一个过渡版本,包含在v1.10B02中。

然后,使用binwalk从v1.04B02固件中提取文件系统。

层层提取得到文件系统。

在文件系统中寻找解密例程,在/bin目录下找到一个**imgdecrypt**文件。

chroot解密技术

跨框架肯定是没办法运行migdecrypt的,这里使用QEMU执行跨架构的chroot。将待解密的固件复制到该文件系统中。

使用chroot启动/bin/sh运行shell。

成功启动busybox后,运行imgdecrypt来对待解密的固件进行解密。

发生了段错误,没解决好,我转到kali上去做了。

然后就可以使用binwalk进行解密了。

这就是遇到加密固件的解决办法,如果是第三种发布方案,因为家用路由器的计算能力有限,不会使用计算量大而难以破解的加密算法,而且一般供应商会对多个类型的路由器使用相同的加密方案,事实上,IDR-882的imgdecrypt文件还可以对DIR-878和DIR-867的固件进行解密。

三、获取权限类

如果碰到以上第三种加密方法,还有另外一些方法可以拿到文件系统。

例如将设备刷成老版本,通过历史漏洞获得设备的shell,想办法将设备上的文件直接导出,常用的漏洞有任意文件读、命令执行等。或者通过网页前端获取一些敏感信息等。

或者通过设备开放的服务,ssh、telnet、tftp等,也能够有效获取文件系统中的文件,可能会有厂家留下的后门密码。

以TP-link WR940N为例,查看开放了upnp、ssh,本身也支持telnet服务。

因为ssh只识别tplink软件的ssh,不支持用户的ssh,所以无法连接。

但有人通过修改固件中ssh的配置,使其支持用户ssh,这样就可以ssh直接练上去,但前提是需要解包固件,并对固件十分了解。

在网上下到一个poc,直接利用栈溢出获得shell,但不是交互式的,想办法通过tftp传上busybox,用busybox启telnetd,并指定它的shell,这样可以拿到完全交互的shell。

四、网络获取类

有些设备支持在线升级,可以通过wireshark配合热点抓设备升级的包,或者burpsuite抓APP请求设备升级的包 ,根据命名规则老固件下载地址,下面以华为路由为例 。

这款路由器在网上找不到现有固件,尝试一下是否可以通过抓包在线升级过程获取固件。
首先关闭防火墙,否则无法访问路由器的服务,无法做中间人攻击。
使用ettercap进行arp欺骗,sudo ettercap -Tq -i ens33 -M arp:remote /192.168.31.1// /192.168.31.134//
打开wireshark进行抓包。理论上说,点击升级固件之后,wireshark就能够记录升级固件的整个过程(HTTP),但是结果却并不理想。

还好华为路由器自带了抓包的功能(方便后期的调试和维护),所以直接使用这个功能抓取报文,比做中间人要直接了当得多。

在点击升级固件之后,可以看到大量发往58.49.156.104这个地址的报文,猜测极有可能是华为的服务器,过滤一下会看得更清楚

可以看到在通过三次TCP握手之后,华为路由器向服务器发送了get请求,uri就是获取固件的地址 http://update.hicloud.com/TDS/data/files/p14/s145/G4404/g1810/v272964/f1/WS5200_10.0.2.7_main.bin

五、逆向升级法

有些设备是通过软件进行升级,或者上位管理设备进行升级,那么通过逆向升级的程序,软件内置解包和通讯的方法。

六、调试接口获取类

如果电路板上有现场的JTAG接口,可以用JTAG建立连接,读出烧录的固件。

前提是电路板上有JTAG接口,但其实自带JTAG的电路板并不多,可以用Jlink烧录器等进行。

腾讯玄武实验室的 HyperChem,在GeekPwn2017上有详细分享。

七、拆flash、SD/TF卡、硬盘等,用编程器/读卡器获取固件

一般就是用热风枪吹下flash芯片,然后用编程器提取固件的内容,再把FLASH芯片焊回去。

这里的难点其实主要是如何在不损坏设备和自己的前提下,对芯片进行拆焊。

用热风枪的时候主要有两个要素,一个是温度,一个是风速,温度太高会损坏设备,太低没办法融化焊锡。

对于含铅焊锡使用温度在330-350摄氏度之间,如果采用无铅焊锡,温度则在350-370摄氏度之间。比较好的做法是使用高温胶带将芯片四周包裹起来,起到隔热保护的作用,对于不同的芯片,最好先下载查看芯片手册,有些对温度有特别的要求。

需要注意的是芯片是有方向的,第一脚的地方有一个圆点,焊接或用编程器读取时,弄清芯片的方向。

我这里因为有芯片夹,刚好是八脚的,所以可以不用吹下来,要注意的是,编程器可以选择由编程器供电读芯片,也可以选择由设备供电。

这个编程器一般会带一个锁紧座,方便烧录完一个芯片后,可以方便的换下下一个芯片继续烧录。

在读取数据时,还需要对数据进行处理,修复错误数据以及去除ECC校验位。Flash芯片分为Nor Flash和Nand Flash。如果目标芯片是NorFlash,就不需要考虑去除ECC校验位,直接进行固件解析,如果是Nand芯片,则必须去除ECC校验位。

根据编程器,下载对应的软件,选择正确的芯片进行读取就可以了。

ICSP串行接口,一般是用在单片机编程上。

修复数据错误

取数据的过程中可能由于硬件问题或数据传输的原因(比特翻转),导致部分数据读取出错。因此需要多次读取,并校验读取结果。如果多次读取的内容一致,说明读取过程没有出现问题,如果多次读取的结果不一致,则需要对读取结果进行数据修复。

由于这种数据出错是随机的,因此一般采用基于统计的方法修复错误数据。首先进行多次读取,并统计出所有变化的字节。这些字节在多次读取中出现频率最高的值,即为原始数据的值。

去除ECC校验位

Nand Flash包含若干个块,一个块包含若干个页。由于电气特性的限制,Nand Flash是以页为单位读取,以块为单位擦写。Nand Flash在擦写过程中,氧化层结构会逐步被破坏,因此Nand Flash有擦写次数限制,擦写次数超出限额会形成坏块。

IoT设备会在软件层面实现坏块管理,充分利用Nand Flash的存储空间,延长使用寿命。坏块管理一般使用ECC校验算法,ECC校验算法一般每256字节原始数据生成3字节校验数据,在Nand Flash上存储原始数据的同时会存储校验数据。

由于ECC校验算法的使用,导致我们从Nand Flash中读出的数据混合了原始数据和校验数据。要想对固件进行正确的解析,必须去除这些校验数据。一般Nand Flash每页存储512字节原始数据,并分配16字节用于存储校验数据、坏块标记和文件系统信息,这16字节被称为spare area。但是原始数据和spare area的排布并不是固定的,常见的排布方式有两种。

原始数据和spare area的排布是由操作系统层面对Nand Flash读写的实现方式决定的,因此没有固定的标准。一般可以根据芯片手册,结合NandFlash页大小、spare area大小以及常见的排布形式进行尝试。

八、串口(UART)调试口获取固件

串口识别:串口有两种标准,串口识别的时候,一般是把设备拆开以后,串口一般有四个脚,第一步要找到地(GND),地是很好找的,和电源相连的那个地,或者芯片跟地相连的。地确定了以后,我们把它接到USB接口上,我先把接收的脚接上,两个脚都有可能是高电,这时把接收的脚和地接上,然后随便接上一个脚,设备一启动,如果这个时候只要有输出了,就是接对了;然后把另外一个脚一接,三个脚就接好了。

还有网上看来的思路,没有试过。

1.通过修改Uboot启动参数,通过TFTP来让嵌入式系统运行我们修改过的文件系统,然后再系统运行后提取固件。

2.用第三方linux挂载硬盘,替换/etc目录下的passwd和shadow,shadow-的root项。

3.X86系统,用u盘版的linux挂在上去,然后mount,类似WinPE方式入侵。

4.类似linux系统忘记密码的解决方案,再启动选项上加一个single和init=/bin/sh

5.让系统在启动时执行删除密码命令。在启动选项上加上一个init='passwd root -d'。

前提是能够进入uboot的命令行。

还有一个比较骚的方法。

uboot,每次启动时都有3秒时间,这个时间是可设的,一般有3秒时间在等待输入(或者其它快捷键,一般有提示),进入uboot模式后,uboot有帮助命令,这些命令里有一条引起我的注意,就是md。md有什么作用?显示内存,能够把内存显示出来。这就有点意思了。发现只要是Nor flash,md可以把Nor flash的内容显示出来(因为nor flash可以通过CPU直接寻址),这就相当于md命令可以提取固件。但md命令是需要知道起始地址和长度的,知道起始地址和长度就可以把固件提取出来。怎么知道起始地址和命令?我查看了更多的命令的信息,结果发现bdinfo和flinfo可以查看到flash起始地址和容量。如果还是找不到的话就重启一下,重启时不要打断,看它会不会打印更多flash地址分布信息,通过这些信息基本就能找到起始地址把固件提取出来了。

总结一下:第一步,获取flash的存储信息,它这个flash有多大、什么型号的、CPU访问它的地址区间是什么?第二步,用md命令提取固件信息。第三步,记录下来。第四步,分析输出信息,获取固件。

要注意一下这个Nor flash和Nand flash的区别。

NOR Flash 的读取和我们常见的 SDRAM 的读取是一样,用户可以直接运行装载在 NOR FLASH 里面的代码,这样可以减少 SRAM 的容量从而节约了成本。 NAND Flash 没有采取内存的随机读取技术,它的读取是以一次读取一块的形式来进行的, 通常是一次读取 512 个字节,采用这种技术的 Flash 比较廉价。用户 不能直接运行 NAND Flash 上的代码,因此好多使用 NAND Flash 的开发板除了使用 NAND Flah 以外,还作上了 一块小的 NOR Flash 来运行启动代码。
所以对于使用了nandflash固件,需要先将nand flash读到内存,然后用md把内存读出来。

uboot命令:获取flash中固件存放地址信息的命令集合:

printenv、flinfo、ubifsls、iminfo、bdinfo、sf probe、base等

uboot命令:读取flash中固件内容到内存的命令集合:

mtdparts default、loada、loadk、cp、sf read、ext4lload、fatload

uboot命令:读取内存的命令集合如下:

md、md64、md b、md w、md l、mm

九、用逻辑分析仪监听flash,ram获取信息

它的优点是不用拆东西,只要把这个东西接上去就可以了,而且这个东西也挺好接的。但缺点是逻辑分析仪目前价格便宜的频率低,但flash一般频率比较高,都是100兆、200兆。我做了一个实验,结果发现确实是可以的。需要把这几个脚引出来,在它启动的时候抓取数据,用夹子夹在芯片上,那个标红色的脚是第一脚。抓在上面以后,通过SPI接口把传输的这个数据保存。

前面是SPI的命令,命令里面这个是输出的数据。前面第一个是读的意思,这三个应该是地址,后面的是数据。这边是发出的命令,那边是接收的命令,结果是这个逻辑分析仪提取出的东西跟flash里的固件的二进制是一致的,说明这个思路是可行的,找了一个速度稍微慢点的设备,也是可以把固件提取出来的。

参考

https://www.anquanke.com/post/id/214730
https://paper.seebug.org/1608/
https://paper.seebug.org/1651/
https://bbs.pediy.com/thread-230095.htm

分享到

参与评论

0 / 200

全部评论 8

zebra的头像
学习大佬思路
2023-03-19 12:14
Hacking_Hui的头像
学习了
2023-02-01 14:20
tracert的头像
前排学习
2022-09-17 01:32
szukodf的头像
binwalk必须重装吗,kali自带的不行吗
2022-08-23 10:16
buggart的头像
kali集成还是不错的,但是我感觉自己装可以选择更多的插件和工具,binwalk支持很多拓展的
2022-08-29 23:43
iotstudy的头像
写的真不错,很良心,细节满满。 热风机拆flash这种细节,有没有相关视频介绍,少走一些坑。 如果获取了telent后门,路由器支持U盘植入。想把固件直接提前到U盘中,cp直接拷贝到u盘中,sys等一些目录无法直接拷贝,这样对提取的固件是不是还是有影响的;如果采用tar压缩固件,提示read-only filesystem。是否有其他对应的解决办法呢?
2022-03-31 10:03
iotstudy的头像
dd命令还是不错,已经解决了。
2022-05-07 08:52
splash的头像
很棒 常见方式齐活了
2022-03-29 14:01
mambainveins的头像
2022-03-11 13:26
buggart的头像
沙发
2022-03-03 12:35
投稿
签到
联系我们
关于我们