GENIA

固件基础

2023-12-08

固件是什么东西?

是一种嵌入在硬件设备中的软件。通常它是位于 特殊应用集成电路(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
2
3
4
查看固件详细信息(包括使用的文件系统种类):
binwalk xxx.bin
自动提取文件系统:
binwalk -Me xxx.bin

分析文件系统

看上去物联网设备的文件系统和 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
2
3
4
5
WARNING: The FIRMWARE variable is not set. Defaulting to a blank string.
WARNING: The LOG variable is not set. Defaulting to a blank string.
WARNING: The EMBA variable is not set. Defaulting to a blank string.
ERROR: The Compose file './docker-compose.yml' is invalid because:
networks.emba_runs value Additional properties are not allowed ('name' was unexpected)

需要手动修改 docker-compose.yml 文件的一部分,把 name 属性给去掉:

1
2
3
4
5
6
7
8
9
networks:
emba_runs:
driver: bridge
internal: true
driver_opts:
com.docker.network.bridge.name: emba_runs
ipam:
config:
- subnet: "172.36.0.0/16"

第二个问题是 pip 源找不到需要版本的库,直接修改下载脚本,将需求版本改成清华源可以找得到的最高版本。

第三个问题是 :

1
2
3
4
5
6
7
8
9
10
11
12
The following packages have unmet dependencies:
mongodb-org : Depends: mongodb-org-shell but it is not going to be installed
Depends: mongodb-org-server but it is not going to be installed
Depends: mongodb-org-mongos but it is not going to be installed
E: Unable to correct problems, you have held broken packages.
------------------------------------------------------------------------------------------------
Error detected - status code 100
Command: apt-get install mongodb-org -y
Location: ./installer/IF20_cve_search.sh, line 148
Stack Trace:
[1] IF20_cve_search(): ./installer/IF20_cve_search.sh, line 148 -> IF20_cve_search
[2] main(): ./installer.sh, line 349 -> main -d

解决步骤:

1
2
3
4
5
6
7
8
1.添加 MongoDB 软件源
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list
2.导入 MongoDB GPG 公钥
wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -
3.更新软件包列表:
sudo apt update
4.安装
sudo apt install mongodb-org -y

第四个问题就是下载 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:

  1. setattr("/runtime/tmpdevdata/image_sign", "get", "cat /etc/config/image_sign");:这是一条命令,用于设置文件或资源的属性。它在 /runtime/tmpdevdata/image_sign 上执行了一个 get 操作,即读取 /etc/config/image_sign 文件的内容,并将结果存储在 /runtime/tmpdevdata/image_sign 中。
  2. $image_sign = query("/runtime/tmpdevdata/image_sign");:这行代码用于查询 /runtime/tmpdevdata/image_sign 文件的内容,并将结果存储在 $image_sign 变量中。
  3. 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] 是变量值。这个命令似乎是用来执行某种加密操作。
  4. 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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' 
ELF Header:
Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, big endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: MIPS R3000
Version: 0x1
Entry point address: 0x4009b0
Start of program headers: 52 (bytes into file)
Start of section headers: 7524 (bytes into file)
Flags: 0x1007, noreorder, pic, cpic, o32, mips1
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 8
Size of section headers: 40 (bytes)
Number of section headers: 30
Section header string table index: 27

可见该文件是大端格式的 MIPS 架构。

使用 QEMU 对其进行模拟(用户模式)。

会输出一些提示让你添加对应参数:

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

重新执行命令:

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

解密成功。

这种方法使用的前提是固件更新前曾发布过中间版本没有被加密,且中间版本可供下载。目前我知道的只有 D-Link 提供的 FTP 服务器可以下载到其产品的中间版本固件。可以关注一下官网的固件更新通告。

固件漏洞复现

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
2
3
4
5
6
7
8
9
10
11
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
tap0
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 ifconfig tap0 10.10.10.1/24
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$ ifconfig tap0
tap0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 10.10.10.1 netmask 255.255.255.0 broadcast 10.10.10.255
ether ee:df:a6:72:52:7d txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

该型号的固件在 D-Link ftp和官网都已经找不到了。这里用的是 winmt 师傅提供的附件。

这个型号的路由器既存在后门漏洞,也存在栈溢出漏洞。因为都找得到资料,可以一一复现一下。

后门漏洞

攻击者通过该漏洞获取 Telnet 服务的账号和密码,并借此任意登录该型号路由器的 Telent 服务,执行任意系统指令。

依旧先使用 binwalk 进行解压,得到文件系统后用 firmwalker 扫一遍,输出了很多 sh 脚本目录,中间有一个:

对它进行进一步分析:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh
echo [$0]: $1 ... > /dev/console
if [ "$1" = "start" ]; then
if [ -f "/usr/sbin/login" ]; then
image_sign=`cat /etc/config/image_sign`
telnetd -l /usr/sbin/login -u Alphanetworks:$image_sign -i br0 &
else
telnetd &
fi
else
killall telnetd
fi

大致猜测一下,与 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 的时候总是报错,网上也找不到解决办法。服了。