固件是什么东西?
是一种嵌入在硬件设备中的软件。通常它是位于 特殊应用集成电路(ASIC)或可编程逻辑器件(PLD)之中的 闪存 或 EEPROM 或 PROM (都属于只读存储器)里,有的可以让用户更新。
固件位于软件和硬件的模糊地带,和软件一样,它可以被电脑执行。但是它又和一般软件不同,不存储在硬盘上,常常栖身于芯片。
构成固件的代码会非常直接地与硬件沟通,而常规的软件要做到这一点则一般需要经过API操作系统还有设备驱动。其原因在于固件的作用就是连结着软硬件的底层且基础的纽带,也是控制系统硬件的方式。
一个耳熟能详的例子就是PC内部的 UEFI 和 BIOS。
固件对于这些底层的联动非常重要,所以它有时候也需要升级才能提供特定的功能或者修复bug。以 BIOS 为例,升级主板的 BIOS 可以提高主板的兼容性。我电脑的蓝牙驱动总是莫名奇妙掉掉,升级了 BIOS 之后就不再出现这样的问题了。
固件通常没有加密什么的,开发者大都专注于提高操作系统和应用程序的安全性,而不是固件,这也使得固件成了黑客和间谍的目标。
这主要是因为被黑的固件在格式化硬盘之后,即使会留存下来,也很难检测,而且由于固件直接控制硬件,固件被黑甚至会导致硬件损坏。
固件获取办法
从官网获取
见各厂商官网
通过流量拦截获取
如果设备厂商的官网不提供最新版的固件下载,就可以用此方法。在设备升级时,对设备或者控制设备的 APP 端进行流量代理转发,来实施中间人(MITM)攻击。
需要用到的一些工具都集成在 Kali Linux上,看来得搞个 Kali 才行。
没学过抓包,这块可能得先放一放。
使用编程器从闪存中读取
通过串口调试提取固件
固件分析
固件分析的第一步就是把固件从芯片中提取出来。具体提取过程好像不是当前学习的重点。
工具
binwalk
用于搜索给定二进制镜像文件以获取嵌入的文件和代码的工具。是一个固件分析工具,旨在对固件进行分析、提取及逆向工程。
文件系统
通俗来说,文件系统是管理硬盘的软件系统。
严格地说,文件系统是一套实现了数据的存储、分级组织、访问和获取等操作的抽象数据类型。
SquashFS
是一套供 linux 内核使用的只读压缩文件系统,它遵循 GPL 开源协议。适用于长时间开机且对稳定性要求更高的系统,为了降低成本,很多物联网设备都采用 SquashFS。
使用 binwalk 对固件进行扫描可以获取相关信息,比如下面这个:

JFFS2
一种基于闪存存储介质的日志文件系统。同样是开源的。
YAFFS2
是目前唯一一个专门为 NAND 闪存而设计的文件系统。它采用了类日志结构,并结合 NAND 闪存的特点,提供了掉电保护机制,可以有效地避免意外掉电对文件系统一致性和完整性的影响。
YAFFS 使用独立的日志文件来跟踪文件系统内容的变化。
UBIFS
无序区块镜像文件系统 是 JFFS2 系统的一种替代。它是一个闪存文件系统,主要用在闪存设备中。
CramFS
专门针对闪存设计的只读、压缩的文件系统。
提取固件中的文件系统
固件分析的内容包括固件的文件系统、架构以及固件中存在的安全隐患。
一般官网下载或者提取到的都是 .bin 文件,其中包含 Boot Loader、内核、文件系统以及其他内容。
其中文件系统保存了需要重点研究的 Web 应用、协议、核心控制程序等,是我们的重点研究对象。
使用系统自带命令提取
在提取之前首先得确认固件用的是哪种文件系统。
可以将签名作为识别文件系统的特征。

SquashFS 比较特殊,共有 6 个签名,设备厂商通常会对其进行自定义。
上面表格中的内容不知道是否准确,我在网上查到的资料说其实 SquashFS 头部特征有 7 种,分别是:sqsh、hsqs、qshs、shsq、hsqt、tqsh、sqlz
具体含义应该不用特别清楚。
以 firmware.bin 为例,直接搜索是否含有头部信息即可:

在地址 0x00120200 处发现了 SquashFS 头部特征。
使用 dd 命令将从 0x00120200 地址(注意必须是签名的起始地址)开始的内容提取出来,注意需要把地址转换为 10 进制。(1180160)
命令格式为:
1 | dd if=输入文件名 bs=读入/输出大小 skip=从文件头开始跳过块数 of=输出文件名 |

检查一下提取的文件系统:

没问题。sqsh 具体对应的就是小端。
最后一步执行 unsquashfs 命令,将文件系统完整地提取出来。

但是我这里失败了。先查看一下压缩方式:

确实用的是 lzma。那应该不是 unsquashfs 不支持的问题。
使用 sasquatch 这个工具(https://github.com/devttys0/sasquatch)可以解压:

使用工具提取
上面的果然还是太麻烦了。直接 binwalk 一把梭最好了。
1 | 查看固件详细信息(包括使用的文件系统种类): |
分析文件系统
看上去物联网设备的文件系统和 linux 的文件系统很类似。
firmwalker
https://github.com/craigz28/firmwalker
就是一个简单的 bash 脚本。它的 data 目录下包含了与 firmwalker 匹配的敏感字符串的特征。也支持自定义添加想要搜索的字符串。

进到firmwalker目录下,输入 ./firmwalker.sh + 文件系统目录
即可。它会顺带把分析结果输出到 一个 txt 文件里便于查看。
trommel
https://github.com/CERTCC/trommel
和 firmwalker 类似的辅助工具。
命令语法为:
trommel.py -p 文件系统目录 -o 输出结果的文件名 -d 输出结果目录
试验一下,发现输出的内容相比 firmwalker 更多一些。

除了包括 password、secret 等敏感词,还将 PHP 文件中 $_GET
、$_SERVER
、shell、system 等危险函数也列举出来。
emba
https://github.com/e-m-b-a/emba
[EMBA安装、使用与源代码分析][https://ylcao.top/2023/04/27/EMBA%E5%AE%89%E8%A3%85%E3%80%81%E4%BD%BF%E7%94%A8%E4%B8%8E%E6%BA%90%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90/]
一款功能更丰富的工具。是开源的固件扫描软件,可以对于已经提取出的基于 linux 的固件进行分析。还可以分析物联网设备的操作系统的内核。
对于虚拟机配置的要求挺高的,具体可以看上面的文档。
ubuntu18.04安装这个工具太痛苦了,装了很久很久都没装好,期间遇到了无数报错。或许用 kali 会好一点。
总之就是太折磨了,比装 firmAE 折磨一百倍。如果不是非用它不可就别装了。
第一个问题是:
1 | WARNING: The FIRMWARE variable is not set. Defaulting to a blank string. |
需要手动修改 docker-compose.yml 文件的一部分,把 name 属性给去掉:
1 | networks: |
第二个问题是 pip 源找不到需要版本的库,直接修改下载脚本,将需求版本改成清华源可以找得到的最高版本。
第三个问题是 :
1 | The following packages have unmet dependencies: |
解决步骤:
1 | 1.添加 MongoDB 软件源 |
第四个问题就是下载 CVE-Search 的时候 git 用不了的问题,那也没什么办法,只能手动下载。
每次重开的时候都要求删掉 external 文件夹,所以必须在脚本开始运行后再把下好的 cve-search 拖进去。试了下还是会显示 git 报错。看看脚本,大概在37行的位置:

如果已经存在 cve-search 目录,它依旧会通过 git pull 检查是否是最新版本。把 git pull 注释掉,跳过这个检查。
后面还会执行一次下载操作,因为没挂代理真的很慢很慢,只能挂着等。
寄了,挂在那等着下载结果吃个饭回来发现虚拟机死机了。
放弃了。先放着吧。
FACT
https://github.com/fkie-cad/FACT_core
一款拥有 Web 界面的自动化固件测试平台。可以以图形的形式展示分析结果。
下好了,但是用不了,很崩溃。
固件模拟
在没有实体设备的情况下模拟实体设备的方式。
QEMU
是一种通用的开源计算机仿真器和虚拟器。
- QEMU模拟器主要有两种比较常见的运作模式:User Mode(使用者模式)、System Mode(系统模式)。
- User Mode下,用户只需要将各种不同平台的处理编译得到的Linux程序放在QEMU虚拟中运行即可,其他的事情全部由QEMU虚拟机来完成,不需要用户自定义内核和虚拟磁盘等文件;
- System Mode下,最明显的特点是用户可以为QEMU虚拟机指定运行的内核或者虚拟硬盘等文件,简单来说系统模式下QEMU虚拟机是可根据用户的要求配置的。该模式下,QEMU 能模拟整个计算机系统,包括中央处理器和其它周边设备,还能再一部物理设备上虚拟多部不同的虚拟设备。
安装:
1 | sudo apt-get install qemu qemu-user-static |
qemu 除了能够模拟不同硬件架构下应用程序的运行环境外,也能以调试模式来启动待调试的程序,这样就可以借助 IDA 进行分析了。
Firmware Analysis Toolkit
FrimAE
固件加密方式
大多数厂商为了保证固件的安全会对固件进行加密,使得提取文件系统变得困难。
情况 1
设备出厂时未加密(v1.0),解密程序和未加密版本的固件(v1.1)一起提供,此后发布加密固件(v1.2)。我们可以获取 v1.1 ,从中获取到解密程序来解密 v1.2。然后进行更新。
搞不懂为啥要这么干,直接厂商掌握解密程序不就好了,还非要泄露出来
情况 2
设备固件的原始版本进行了加密,但是厂商决定更改加密方案,并发布一个未加密的新固件作为中间版本,其中包含了未来新版本的解密程序。通过这个中间版本的固件得到新版本的解密程序。
情况 3
不管是初始版本还是中间版本还是最新版本都进行了加密。这个基本上除了硬件提取就没别的办法了。
一个解密实例
D-Link DIR-822-US 系列的 3.15B02版本固件

就是它了!

解压后的文件夹包含 .bin 和 一个 release notes pdf。
先用 binwalk 扫一下:

啥也扫不出来。
执行 binwalk -E,查看固件熵值:

熵值计算是一种确认给定的字节序列是否压缩或加密的有效手段。熵值大,意味着字节序列有可能是加密的或是压缩过的。熵值小,则正好相反。
上图熵值恒定在 1,即意味着加密。
看看 release note:

在升级到当前版本之前会有个中间版本,v303WWb04_middle 。
D-Link搭建了一个ftp服务器供用户下载资源:support.dlink.com - /resource/products/
在这里可以下载官网搜索不到的中间版本。
说不定里面就包含解密程序。下下来之后用 binwalk 进行解压,得到 中间版本的文件系统,在里面寻找更新固件的程序。
通过 grep 寻找文件系统中的敏感字符串:
1 | genia@ubuntu:~/Desktop/firmware/D-Link DIR-822-US 3.15B02/_DIR822C1_FW303WWb04_i4sa_middle.bin.extracted$ grep -rE "update|firmware|upgrade|download" '/home/genia/Desktop/firmware/D-Link DIR-822-US 3.15B02/_DIR822C1_FW303WWb04_i4sa_middle.bin.extracted/squashfs-root' |

查找到一些固件更新下载的有效信息集中在 /etc/templates/hnap/ 目录下。其中有个 php 文件名字叫做 StartFirmwareDownload。
这是少见的在文件名中就含有 download 的。估计执行的就是下载固件的操作。审计一下代码,不会php,所幸有注释。

fw encing ——> firmware encrypt image ?
丢给万能的 gpt:
setattr("/runtime/tmpdevdata/image_sign", "get", "cat /etc/config/image_sign");
:这是一条命令,用于设置文件或资源的属性。它在/runtime/tmpdevdata/image_sign
上执行了一个get
操作,即读取/etc/config/image_sign
文件的内容,并将结果存储在/runtime/tmpdevdata/image_sign
中。$image_sign = query("/runtime/tmpdevdata/image_sign");
:这行代码用于查询/runtime/tmpdevdata/image_sign
文件的内容,并将结果存储在$image_sign
变量中。fwrite("a", $ShellPath, "encimg -d -i ".$fw_path." -s ".$image_sign." > /dev/console \n");
:这行代码使用fwrite
函数(或类似的函数)将一条命令写入某个文件,文件路径由$ShellPath
变量表示。这条命令是encimg -d -i [fw_path] -s [image_sign] > /dev/console
,其中[fw_path]
和[image_sign]
是变量值。这个命令似乎是用来执行某种加密操作。del("/runtime/tmpdevdata");
:这行代码用于删除目录/runtime/tmpdevdata
及其内容。这可能是清理或释放临时文件的一部分。
可以查看 image_sign 的内容:

wrgac43s_dlink.2015_dir822c1 即 encimg -d -i [fw_path] -s [image_sign] > /dev/console
的一个参数,如果我们能获取到 encimg 文件并运行它,即可完成固件的解密。
依旧使用 grep:

路径一目了然:squashfs-root/usr/sbin/encimg
用qemu 对 encimg 进行模拟运行需要知道它的架构:
1 | genia@ubuntu:~/Desktop/firmware/D-Link DIR-822-US 3.15B02/_DIR822C1_FW303WWb04_i4sa_middle.bin.extracted/squashfs-root$ readelf -h '/home/genia/Desktop/firmware/D-Link DIR-822-US 3.15B02/_DIR822C1_FW303WWb04_i4sa_middle.bin.extracted/squashfs-root/encimg' |
可见该文件是大端格式的 MIPS 架构。
使用 QEMU 对其进行模拟(用户模式)。
会输出一些提示让你添加对应参数:

结合前面的 php 代码,fw_path 即待解密的固件路径,image_sign 即我们从文件中得到的 wrgac43s_dlink.2015_dir822c1。
重新执行命令:

再次用 binwalk 扫一扫这个固件并查看熵值:

解密成功。
这种方法使用的前提是固件更新前曾发布过中间版本没有被加密,且中间版本可供下载。目前我知道的只有 D-Link 提供的 FTP 服务器可以下载到其产品的中间版本固件。可以关注一下官网的固件更新通告。
固件漏洞复现
TP-Link Smart Home Router 远程代码执行漏洞
TTDP 是 TP-Link 公司的一个专有协议。运行在 UDP 的1040 端口上。该协议的 v1 版本有一个远程代码执行漏洞。用户可以利用该漏洞在该路由器上以 root 权限执行任意命令。
用 binwalk 解压固件后,查找 TDDP 相关程序:

上 IDA,还是 ARM 架构的,通过检索 tddp 字符串找到 tddp 程序入口(函数 sub_936C):

安装 tunctl 工具,使得 QEMU虚拟机 和 物理机之间可以实现通信。
1 | sudo apt-get install uml-utilities |
安装完成后配置虚拟网卡:
1 | genia@ubuntu:~/Desktop/firmware/TP-Link SR20/_tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin.extracted/squashfs-root$ sudo tunctl -b -t tap0 |
D-Link DIR-815
该型号的固件在 D-Link ftp和官网都已经找不到了。这里用的是 winmt 师傅提供的附件。
这个型号的路由器既存在后门漏洞,也存在栈溢出漏洞。因为都找得到资料,可以一一复现一下。
后门漏洞
攻击者通过该漏洞获取 Telnet 服务的账号和密码,并借此任意登录该型号路由器的 Telent 服务,执行任意系统指令。
依旧先使用 binwalk 进行解压,得到文件系统后用 firmwalker 扫一遍,输出了很多 sh 脚本目录,中间有一个:

对它进行进一步分析:
1 | !/bin/sh |
大致猜测一下,与 telnet 登录(login)有关,其中一个重要信息存储在了 /etc/config/image_sign 中,很可能就是 Alphanetworks 账户的密码。
找到 /etc/config/image_sign:wrgnd08_dlob_dir815ss
下面直接用 FirmAE 进行模拟:

模拟成功后先扫一扫目标地址的端口:

telnet 默认处于开启状态。
接着利用获得的账号和密码尝试进行 telnet 登录并成功 get shell:

栈溢出漏洞
参考自 winmt 师傅的文章:https://bbs.kanxue.com/thread-272318.htm
这次使用 ubuntu 20.04 进行复现。不知道为什么,编译 binwalk 配套工具 sasquatch 的时候总是报错,网上也找不到解决办法。服了。