IOT 环境搭建

binwalk

binwalk 是 IOT 固件分析中用来解压设备固件的常用工具,在 CTF 杂项中也常会用到 binwalk 进行文件提取,但是现在将要对 binwalk 进行更加深入的了解

binwalk 可以通过 apt 安装,也可以自己编译安装

建议尽量通过源码安装 binwalk,因为 apt 安装的 binwalk 可能不完整,后续遇到各种报错问题需要单独去解决,将缺少的东西安装回来


安装 binwalk

  • apt 安装 binwalk
sudo apt install binwalk

在 Kali Linux 2024.1 中使用 apt 安装的是 binwalk v2.3.3,目前最新版为 binwalk v2.3.4

  • 编译安装 binwalk

如果系统自带 apt 安装的 binwalk,且版本比较老旧,可以先卸载:

# 查看是否安装 binwalk
binwalk
# 如果已经安装 binwalk,首先卸载 binwalk
sudo apt remove binwalk
# 更新软件列表
sudo apt update

编译安装:

sudo git clone https://github.com/devttys0/binwalk.git /opt/binwalk
cd /opt/binwalk
sudo python3 setup.py install

# 测试安装
binwalk

安装 binwalk 运行过程中需要调用的命令行工具:

# binwalk 运行时,它依赖许多命令行工具来提取固件
sudo apt install mtd-utils gzip bzip2 tar arj lhasa p7zip p7zip-full cabextract cramfsswap squashfs-tools sleuthkit default-jdk lzop srecord

# 安装 C/C++ 编译器、liblzma、liblzo 和 zlib 依赖项
sudo apt install build-essential liblzma-dev liblzo2-dev zlib1g-dev

安装 sasquatch

用于分离 squashfs 固件系统,解开非标准的 squashfs 文件系统

如果没有安装 sasquatch,使用 binwalk -Me 提取固件的过程中会报如下警告:

WARNING: Extractor.execute failed to run external extractor 'sasquatch -p 1 -le -d 'squashfs-root' '%e'': [Errno 2] No such file or directory: 'sasquatch', 'sasquatch -p 1 -le -d 'squashfs-root' '%e'' might not be installed correctly

安装 sasquatch

sudo apt install mtd-utils gzip bzip2 tar arj lhasa p7zip p7zip-full cabextract cramfsprogs cramfsswap squashfs-tools 
sudo git clone https://github.com/devttys0/sasquatch.git /opt/sasquatch
cd /opt/sasquatch
sudo chmod +x build.sh
sudo ./build.sh

通过 sudo ./build.sh 编译时可能会出现报错:

unsquashfs.c: In function ‘read_super’:
unsquashfs.c:1835:5: error: this ‘if’ clause does not guard... [-Werror=misleading-indentation]
 1835 |     if(swap)
      |     ^~
unsquashfs.c:1841:9: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
 1841 |         read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
      |         ^~~~~~~~~~~~~
cc1: all warnings being treated as errors
make: *** [<builtin>: unsquashfs.o] Error 1

错误原因是代码中的 if 出现了问题,报错提示在第 1835 行出现了错误

该错误是因为 if 条件语句缺少必要的左右花括号 {},导致后面的 'ERROR' 语句无法被包含在条件语句块中执行

解决方法参考:关于Kali编译sasquatch时出现 ‘if’ clause does not guard… -Werror=misleading-indentation 的解决方案-CSDN博客

使用 Fixed gcc build errors by threadexio · Pull Request #47 · devttys0/sasquatch 该 pull 中的一个 patch 文件来进行补丁:

cd /opt/sasquatch  
sudo wget https://github.com/devttys0/sasquatch/pull/47.patch  
sudo patch -p1 < 47.patch  
sudo ./build.sh

再次编译后不会再报错,可以正常分离 squashfs 固件系统


安装 ubi_reader

用于分离 ubifs 固件系统,即:binwalk 分离后的后缀为 ubixxx.ubi 文件

如果 binwalk 解压后只有 xxx.ubi 文件而没有文件系统,或者 binwalk 执行 ubireader_extract_files 程序失败:

MARNING: Extractor.execute failed to run external extractor 'ubireader_extract_files -o 'ubifs-root' "%e": [Errno 2] No such file or directory

这是因为 binwalk 缺少必要的组件:ubi_reader

注意:

ubi_reader 这个工具很重要,如果路由器固件是 ubi 格式,需要用 ubireader_extract_files 来提取,否则会无法解压出文件系统

参考文档:https://blog.csdn.net/gybwq/article/details/113850747

安装 ubi_reader

sudo apt install liblzo2-dev  
sudo pip install python-lzo  
sudo pip install ubi_reader

ubi_reader 工具提供了四个脚本:

  • 获取 UBI 信息、布局块等:ubireader_display_info
  • 提取镜像:ubireader_extract_images
  • 提取文件内容:ubireader_extract_files
  • 分析 UBI 镜像并创建 shell 脚本和 UBI 配置文件:bireader_utils_info

ubi_reader 工具的使用也很简单,可以不需要参数:

# 提取镜像里面的文件,输出保存到 ./ubifs-root/ 目录  
ubireader_extract_files rootfs.ubi

QEMU

VMware 和 Virtualbox 之类通常只能在 x86 计算机上虚拟出一个 x86 虚拟机,而 QEMU 支持在 x86 上虚拟出一个 ARM 虚拟机

QEMU 源码下载地址:Index of / qemu
虚拟机磁盘镜像下载地址:Index of /~aurel32/qemu

安装 QEMU

  • 通过 apt 安装 QEMU:
sudo apt install qemu qemu-kvm virt-manager bridge-utils binfmt-support
sudo apt install  qemu-system qemu-user-static   # 安装系统态、用户态

# 安装依赖库
sudo apt install -y gcc-arm-linux-gnueabi
sudo apt install qemu libncurses5-dev gcc-arm-linux-gnueabi build-essential gdb-arm-none-eabi synaptic gcc-aarch64-linux-gnu eclipse-cdt git

注意:

Ubuntu 24.04 这种新版本系统中貌似去除了 sudo apt install qemu,但仍可以通过 sudo apt install qemu-system qemu-user-static 安装,只不过版本是 qemu-8.2.2,不是最新版

QEMU 有 user mode 和 system mode 两种配置方式

其中 QEMU 在 system mode 配置下模拟出整个计算机,可以在 QEMU 之上运行一个操作系统;而 user mode 仅可用来运行对应架构的二进制文件,例如:交叉编译

  • 通过源码编译安装 QEMU

如果通过 apt 安装过 QEMU,首先卸载:

# 删除包和相关依赖
sudo apt remove --auto-remove qemu*
# 删除配置文件和相关的数据文件
sudo apt purge --auto-remove qemu*

采用源码编译安装 qemu-9.0.0

wget https://download.qemu.org/qemu-9.0.0.tar.xz
tar xvJf qemu-9.0.0.tar.xz
cd qemu-9.0.0

安装依赖:

sudo apt install ninja-build zlib1g zlib1g-dev libglib2.0-dev libpixman-1-dev libfdt-dev python3-venv libgtk-3-dev build-essential pkg-config binutils-dev 
sudo apt install flex bison

编译安装:

sudo mkdir build && cd build
# 以编译 x86_64 架构的 QEMU 为例,-softmmu 表示 system mode
sudo ../configure --enable-kvm --target-list=x86_64-softmmu --enable-debug
# 启动多核心编译加快速度
sudo make -j$(nproc)
# 将其安装到 /bin 目录下,即可通过终端启动
sudo make install

编译命令中一些参数的说明:

参数含义
--enable-kvm表示开启 kvm 支持
--target-list指定要编译的 CPU 架构(如果不指定,就是全部架构都编译),其中 -softmmu 表示 system mode,-linux-user 表示 user mode
--enable-debug能够对 QEMU 进行调试

目前在 Ubuntu 24.04 中编译 AARCH64 架构的时候会报错

[2181/9361] Compiling C object libqemu-aarch64-linux-user.fa.p/target_arm_helper.c.o
ninja: build stopped: subcommand failed.  
make: *** [Makefile:167:run-ninja] 错误 1

解决方法:将报错文件 ../target/arm/cpu.c 的第 1020 行的 CS_ARCH_ARM64 改为 CS_ARCH_ARM,重新编译即可

编译完成后,会在 build 目录下生成 x86_64 架构下的 QEMU 本体:qemu-system_x86-64

在终端验证安装:

qemu-system_x86-64 --version

IOT环境搭建8.png

查看 QEMU 安装路径:

which qemu-system-x86_64

IOT环境搭建9.png


配置网络脚本

另外,QEMU 默认没有网络脚本文件,需要自己进行创建

/usr/local/etc 目录下(也有可能是 /etc 目录下,可以到时候根据报错路径来确定具体位置),新建 qemu-ifup 文件:

#!/bin/sh
set -x

switch=br0

if [ -n "$1" ];then
    ip tuntap add $1 mode tap user `whoami`
    ip link set $1 up
    sleep 0.5s
    ip link set $1 master $switch
    exit 0
else
    echo "Error: no interface specified"
    exit 1
fi

增加权限:

sudo chmod 755 /usr/local/etc/qemu-ifup

GNS3

GNS3 是一种可以仿真复杂网络的图形化网络模拟器,GNS3 允许在计算机中运行 Cisco 的 IOS

GNS3 其实是 Dynagen 的图形化前端环境工具软件,而 Dynamips 是仿真 IOS 的核心程序,Dynagen 运行在 Dynamips 之上,目的是提供更友好的、基于文本的用户界面

注意:GNS3 仅支持 Cisco 设备的仿真

Windows 安装 GNS3

首先下载安装 GNS3:Software | GNS3(这是官网的最新版,当然也可以去第三方下载特定版本)

安装过程参考:网络工具之GNS3安装及使用_gns3的安装步骤及导入路由器镜像的过程-CSDN博客

安装成功后界面如下:

IOT环境搭建45.png

另外 GNS3 也有 VM 版本,同样在 Software | GNS3 处下载(这是官网的最新版,当然也可以去第三方下载特定版本)

下载解压后名为 GNS3 VM.ova,直接导入 VMware Workstation 即可:(注意 GNS3 的版本需要与 GNS3 VM 的版本一致

IOT环境搭建47.png

在物理机上测试一下是否能正常访问 Web-UI:

IOT环境搭建62.png

同时在 GNS3 中配置 GNS3 VM:

IOT环境搭建61.png

配置成功后在 Servers Summary 处会显示 GNS3 VM 并且为绿色:

IOT环境搭建63.png

GNS3 自带的终端为 Putty,不过 GNS3 支持与 SecureCRT 之类的终端仿真软件进行绑定

下载安装 SecureCRT(一款 SSH 终端仿真软件),网上教程很多,请自行下载 SecureCRT 并破解(仅用于学习交流,请支持正版):

IOT环境搭建48.png

在 GNS3 中将终端改为 SecureCRT,如果你的 SecureCRT 安装没有问题,会自动识别到其所在路径:

IOT环境搭建46.png

自行检查 GNS3 识别到的 SecureCRT 安装路径是否正确:

IOT环境搭建49.png

选择 Run appliances on my local coputer:(如果安装了 GNS3 VM 也可以选 Run appliances in a virtual machine 将固件运行在 GNS3 VM 中)

IOT环境搭建60.png

初始化 GNS3 Server,保持默认即可(这里 Host binding 默认为 localhost,但建议设置为 127.0.0.1,这样当网络环境发生变化时,仍然能够连接到 GNS3 VM)

IOT环境搭建51.png


Linux 安装 GNS3

参考官方文档:GNS3 Linux Install | GNS3 Documentation

以 Kali Linux 为例:

sudo apt update
sudo apt install python3 python3-pip pipx python3-pyqt5 python3-pyqt5.qtwebsockets python3-pyqt5.qtsvg qemu-kvm qemu-utils libvirt-clients libvirt-daemon-system virtinst dynamips software-properties-common ca-certificates curl gnupg2 
pipx install gns3-server
pipx install gns3-gui
pipx inject gns3-gui gns3-server PyQt5

gns3   # 启动 GNS3

IOT环境搭建50.png


固件分析

路由器固件分为加密固件和未加密固件,对于未加密的固件使用 binwalk 可以直接提取,而对于加密的固件则需要先想办法解密

未加密固件的分析

以下分析都是以 Cisco 的 RV34X-v1.0.03.29-2022-10-17-13-45-34-PM.img 固件为例

下载地址:Software Download - Cisco Systems

如果以下所有流程全部正常走完,那就说明我们的环境是没有问题的


固件扫描

使用 binwalk 扫描固件,可以查看固件信息:

binwalk 路由器固件(一般以 .bin 或 .img 为后缀)

IOT环境搭建1.png


固件提取

使用 binwalk 提取路由器固件:

binwlak -Me 路由器固件(一般以 .bin 或 .img 为后缀)

binwalk 提取后,会在固件所在目录得到一个 _XXXXX.extracted 文件夹,其中通常有一个 _fw.gz.extracted 文件夹

在形如 _openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted 的文件夹中有一个 ubifs-root 文件夹

**如果通过 binwalk -Me 解压后没有 ubifs-root 文件夹,只有一个 0.ubi 文件,说明没有安装 ubi_reader**,请参照上面的环境搭建一节自行安装

其中存放着路由器文件系统的根目录 rootfs,其结构如下:

IOT环境搭建3.png

注意:如果上图中出现 var -> /dev/null,说明是有问题的

仔细看 binwalk 的提取信息,会发现很多如下警告:

WARNING: Symlink points outside of the extraction directory: /home/wyy/IOT/Cisco/RV34X-v1.0.03.29-2022-10-17-13-45-34-PM/_RV34X-v1.0.03.29-2022-10-17-13-45-34-PM.img.extracted/_40.extracted/_fw.gz.extracted/_0.extracted/_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/790534924/rootfs/www/index.html -> /tmp/www/index.html; changing link target to /dev/null for security purposes.

意思是:原本文件中存在的软链接指向了提取目录之外

就比如当前的 var 目录,它指向的是 Kali Linux 本机的 /tmp 目录(实际上应该指向路由器的 /tmp 目录,而不是本机的 /tmp 目录),为了安全考虑,binwalk 将这种软链接都置成了 /dev/null

这里如果放任不管,后面进行路由器的仿真会失败,比如路由器的某个服务需要去访问 var 目录下的文件,但它如果被置成 /dev/null 的话,目录自然是缺失的

解决方法是找到 binwalk 安装路径下的 /modules 文件夹,修改其中的 extractor.py 文件

如果是通过 apt 安装的 binwalk,不知道安装路径在哪里,使用如下命令搜索:

sudo find / -name binwalk

找到 extractor.py 文件后,搜索:"os.devnull",大概在文件的最末尾,1008 行,将 if not ... 改为 if 0 and not ...

IOT环境搭建4.png

然后使用 binwalk 重新解压固件,即可得到 var -> /tmp 的文件系统(如果是自行编译安装的 binwalk,可能需要首先在 binwalk 安装根目录下使用 sudo python3 setup.py install 重新安装一下再解压):

IOT环境搭建2.png

到这里就提取完毕了

补充另一种方法,安装 ubi_reader 后通过 ubireader_extract_files 工具单独对 0.ubi 进行提取也可以避免上述软链接的问题:

ubireader_extract_files 0.ubi

查看路由器属性

查看路由器属性(为后续配置搜集信息)

在路由器文件系统的 /bin 目录下,有一个 busybox 的二进制可执行文件:

cd /bin
file busybox

IOT环境搭建5.png

可见该路由器是 32 位 ARM 架构,小端序,动态链接

那么进行路由器仿真时就需要使用 32 位 ARM 架构的 QEMU


QEMU 运行异架构程序

在 x86 架构的 Kali Linux 下模拟运行 ARM 结构下的 busybox,测试一下 QEMU 是否正常

由于我们是在 x86 架构上运行 ARM 架构的 32 位二进制可执行程序,因此使用 qemu-arm-static 来运行

因为我们是运行二进制程序,因此使用 QEMU 用户态进行模拟,也就是带 static 的版本

还有一种带 system 的版本,是用于模拟系统级的 QEMU,其包括 CPU、内存、外设、操作系统等,能模拟出一个完整的操作系统环境

查看是否安装了所需的 QEMU 版本:(如果是自己编译安装的 QEMU,可能在 /usr/local/bin 路径下)

ls /usr/bin/qemu-arm*

IOT环境搭建6.png

注意:

必须根据文件的架构,使用相应架构的 QEMU 模块运行,不然会报 Invalid ELF image for this architecture 这个错误

首先将 qemu-arm-static 移动到固件目录,然后给予 busybox 执行权限,使用 QEMU 运行该 ARM 架构的二进制程序

sudo cp /usr/bin/qemu-arm-static ./
chmod +x ./bin/busybox
sudo chroot . ./qemu-arm-static ./bin/busybox

输出以下信息则说明运行成功:

IOT环境搭建7.png


加密固件的分析

厂商为了保护自己的产品,增加逆向分析的成本,通常会将路由器的固件进行加密,经过加密的固件使用一般的解包方法不能提取。要想分析这种固件,首先就要找到其对应的加密方法

实际上固件加密并不是随随便便拿来一种算法就可以的,由于家用路由器机能有限,所以 RSA 等效率较低的加密体系用的比较少,AES 或者 RC4 这些效率高的算法通常是首选的固件加密手段

加密场景

参考文章:路由器固件解密思路_固件加密解密-CSDN博客

一般常见的路由器加密场景有:

  1. 固件的初始版本未加密,后续某个版本加密了,在加密版本与初始版本中间的某个版本附带了解密程序

IOT环境搭建16.png

我们可以通过获取附带了解密程序的中间版本,分析其解密程序,然后用于固件解密

  1. 固件的老版本有加密,但是后续更换了加密方式,中间版本发布了未加密的过渡版本固件

IOT环境搭建17.png

我们可以通过获取带有解密程序的过渡版本固件分析,提取解密程序,然后用于固件解密

  1. 固件的老版本有加密,但是后续更换了加密方式,中间版本更换了新的未加密的解密程序

IOT环境搭建18.png

如果清楚早期加密方式,或者拥有早期解密程序,可以去分析更换解密程序的中间版本,来获取解密程序

如果没有早期相关解密信息,则更多是购买设备,从硬件直接提取未加密的固件

理论上也可以使用二进制对比分析工具,来分析尝试提取复原解密程序


判断方法

参考文章:

  1. 路由器固件解密思路_固件加密解密-CSDN博客
  2. 如何处理加密路由器固件-安全客 - 安全资讯平台

通过信息熵分析

熵泛指某些物质系统状态的一种量度,某些物质系统状态可能出现的程度

熵值越小,说明重复内容越多,系统越不稳定;熵值越大,说明信息中重复的内容越少,系统越稳定

  • 对于没有加密的二进制文件来说,一些指令出现的频率通常很高,并且数据结构几乎没有随机性,所以熵值一般比较低

  • 对于经过加密的二进制文件来说,都会想尽办法隐藏自己的信息,而导致很少有重复的内容,所以熵值一般都会比较高

提前安装 Matplotlib 库:

pip install Matplotlib

查看固件的信息熵:

binwalk -E 路由器固件(一般以 .bin 或 .img 为后缀)

以 D-Link 的 DIR_878_FW1.30B08.bin 固件为例,该固件是被加密过的:

IOT环境搭建10.png

可以看到其熵值几乎稳定在 1.0,符合加密的特点

经过我对多个固件的多次测试,发现通过熵值来判断固件是否加密不是特别可靠,仅仅只能作为一个参考

比如,以下是未加密的固件 RV34X-v1.0.03.29-2022-10-17-13-45-34-PM.img 熵值:

IOT环境搭建12.png

但我发现,未加密的固件熵值都是稳定的一条线,反而加密的固件最开始会有一段小波动,也许可以作为判断依据?


通过十六进制数据分析

使用 010 Editor 等十六进制查看工具打开固件,判断其中是否包含 0xFF0x00 字节、是否为随机的数据

以 D-Link 的 DIR_878_FW1.30B08.bin 固件为例,该固件是被加密过的:

IOT环境搭建11.png

其中间版本固件 DIR878A1_FW104B05_Middle_FW_Unencrypt.bin 是未加密的:

IOT环境搭建13.png

可以看到加密的固件中间出现了大面积的 0x00 断层,并且几乎不存在有意义的字符

未加密的固件开头是存在固件的设备型号和系统等信息的


通过 binwalk 分析

通过 binwalk 直接分析固件也是可以判断固件是否被加密的:

binwalk 路由器固件(一般以 .bin 或 .img 为后缀)

未加密的固件:

IOT环境搭建14.png

加密的固件:

IOT环境搭建15.png

可见被加密的固件无法被 binwalk 分析出任何信息


固件解密

以 D-Link 的 DIR_878_FW1.30B08.bin 固件为例

下载地址:DIR_878_FW1.30B08.bin

我们通过在 D-Link 官网找到该固件:D-Link Technical Support

发现该设备为 DIR-878,其存在很多历史版本:

IOT环境搭建19.png

将固件所有的历史版本下载进行查看:

IOT环境搭建20.png

在中间版本 DIR-878_REVA_FIRMWARE_v1.10B05 文件夹中,有一个名为 DIR878A1_FW104B05_Middle_FW_Unencrypt.bin 的固件,这就是我们前面提到的未加密的中间版本了

IOT环境搭建21.png

通过 binwalk 提取固件系统:

IOT环境搭建22.png

/bin 目录下存在一个名为 imgdecrypt 的二进制程序:

IOT环境搭建23.png

尝试通过 QEMU 运行它,由于该程序架构是 MIPS32 小端序,我们使用 qemu-mipsel-static 来模拟:

IOT环境搭建24.png

根据输出信息,是需要传入一个参数 <sourceFile>

尝试用这个程序为 DIR_878_FW1.30B08.bin 固件解密,将参数 <sourceFile> 设置为加密的固件:

IOT环境搭建25.png

执行后程序输出了 key:C05FBF1936C99429CE2A0781F08D6AD8

但是发现这样解密失败,仍然无法解压固件,貌似必须将加密固件放在文件系统内

我这里放在 /tmp 目录下,然后再次运行 imgdecrypt 程序,直接使用 binwalk 分析 /tmp 目录下的固件会报权限错误,需要使用 sudo binwalk

可以看到 binwalk 已经可以正常分析被加密的固件,说明我们解密成功:

IOT环境搭建26.png

然后我们来看看 imgdecrypt 这个二进制程序,使用 IDA 7.7 打开:(IDA 7.0 以上版本自带 MIPS 架构反编译插件,如果没有,也可以自己安装 RetDec 插件:avast/retdec-idaplugin: RetDec plugin for IDA

主函数如下:

IOT环境搭建27.png

主要解密逻辑主要涉及到 AESRSAsha512

IOT环境搭建28.png