-
-
[翻译]基于QEMU的IoT设备仿真
-
发表于: 2020-6-14 10:38 10693
-
经验分享:如何“仅用QEMU仿真固件”
5.27.2020|Vincent Lee
原文地址:https://www.thezdi.com/blog/2020/5/27/mindshare-how-to-just-emulate-it-with-qemu
翻译:看雪翻译小组 八企鹅
校对:看雪翻译小组 Nxe
我们定期的去MindShaRE查看各种逆向工程的技巧和窍门。我们的目标是让工作变得尽可能简单和讨论逆向工程中一些日常遇到的问题。你可以在这里查看之前发布这一系列的文章。
通常,人们谈及到路由器或者IoT安全研究的时候总是说:“用QEMU仿真就行了!”他们还可能告诉你“低买高卖”在股票市场中能赚到钱。然而,困难的是你并不知道什么时候是股票的最低点和最高点。同样的,知道如何使用QEMU仿真固件可能是嵌入式安全研究领域对于新手来说是最难的部分。
在文章开始之前,假设你的固件类UNIX系统上运行,而不是在其他实时操作系统(RTOS)(例如VxWorks或Windows CE)上运行,并且你的固件已解密/反混淆,提取了根文件系统。如果你遇到加密固件的问题,请查阅我之前关于处理加密固件的博客
明确仿真的最终目标
设备仿真的关键一步是确定最终目标。 你只想运行一个二进制文件吗? 一项服务怎么样? 还是想要完整的设备仿真? 由于使固件仿真正常工作是一项耗时的任务,因此您的目标将极大地影响您的仿真策略。有时,由于调整仿真而浪费了无数的时间,只是证明购买了一些低成本设备。
对于运行当个二进制文件(例如解密例程),请考虑使用更轻量级的用户空间QEMU仿真方法如果你的目标是编写一个漏洞利用程序,最好是使用一台物理设备,因为漏洞利用程序最终是针对现实世界设备所使用的。仿真可能无法解决细微的硬件表现,比如指令缓存,这可能会影响内存损坏漏洞的利用。然而,完全可以利用仿真来开发和测试针对运行在更高层次的漏洞的利用程序,比如CGI脚本命令执行或者PHP页面中的登录逻辑缺陷。
确定CPU架构和信息收集
模拟任何事情的第一步是确定目标的CPU体系结构。通常,我们无需上手实际设备就可证明目标的CPU架构。确定CPU类型的一种方法是通过分析固件的二进制文件。在任何二进制文件上运行file命令可以快速告诉我们正在处理的CPU体系架构。
图1——file和readelf命令的输出
但是,file命令没有提供最详细的结果。 用于ARM二进制文件的带有-A选项的readelf命令提供了更详细的CPU信息,这对于完整的系统仿真和交叉编译至关重要。
确定无线路由器时的CPU体系结构的另一种方法(以TP-Link TL-WR841-ND为例[1])是通过在Internet上搜索设备型号。 通常,这将使我们进入提供有关设备硬件信息的OpenWRT设备页面。 快速搜索还可以告诉我们主要的片上系统(SoC)部件号以及设备FCC ID。 然后,我们可以查找相应SoC芯片的数据表,并确定CPU架构。
这也是搜索特定于系列的处理器核心数据表以熟悉CPU的绝佳时机。 该数据手册将提供特定于器件的信息,例如加载地址和低级存储器布局,这些信息可能有助于仿真和分析。 你也可以查找FCC归档报告以了解设备的内部视图。
用户模式仿真
当只需要模拟一个二进制文件时,按进程模拟就很有用。 有两种方法可以在用户模式QEMU中模拟单个二进制文件。 第一种选择是用户模式过程仿真。 可以使用以下命令之一完成此操作:
qemu-mipsel -L <prefix> <binary> qemu-arm -L <prefix> <binary> qemu-<arch> -L <prefix> <binary>
当二进制链接到外部依赖库(例如uCLibc或加密库)时,-L选项非常重要。 它告诉动态链接器查找具有所提供前缀的依赖项。 以下是为D-Link DIR-882路由器运行imgdecrypt二进制文件的示例。
图2——imgdecrypt
模拟该过程的另一种方法是使用QEMU执行跨架构的chroot。 为此,我们将qemu- <arch> -static二进制文件复制到固件根文件系统的/ usr / bin /目录中。 然后,我们将root目录修改为固件根目录并获得一个有效的shell:
图3——使用QEMU执行跨架构的chroot
由于安装过程中QEMU向内核注册以通过binfmt_misc机制处理具有某些魔术字节的二进制文件,因此上述的方法是可能实现的。该技术与使用相同机制的Scratchbox交叉编译工具包不兼容。 您可以在此StackOverflow帖子中找到有关跨体系结构chroot的更详细说明。
此方法是我首选的模拟设备的首选方法。 它设置迅速,可以让我在固件根文件系统中尝试不同的二进制文件,而不必过多担心依赖项。 请注意,在这种仿真模式下,chroot shell中没有初始化任何userland服务,因此没有系统或网络服务可用。 但是,这仅足以运行一个二进制文件或测试一个小组件就足够了。
发挥优势:完整的文件系统
有时,我们需要对固件进行更全面的分析,并从完整的系统仿真中受益。 有很多方法可以完全模拟设备。 以下是一些最常见的仿真技术。 研究人员已使用这些技术来查找实际的错误,然后将其提交给ZDI程序。
在仿真过程的第一部分,我们将使用QEMU创建完整Linux虚拟机去运行目标架构。 然后,我们将固件根文件系统传输到VM中,并将chroot传输到固件的根文件系统中。在QEMU上创建并运行完整的VM,我们通常需要满足以下条件:
--QEMU磁盘映像文件(qcow2)
--为目标架构编译的Linux内核映像
--(有时需要)初始RAM磁盘映像(initrd)
要获得以上各项,你可以设置交叉编译器,构建内核并下载安装程序以获取初始RAM磁盘。然后,你可以将Linux安装到QEMU磁盘映像文件上。然而,交叉编译内核对Linux初学者来说是一项复杂而繁重的任务。如果您有兴趣自己准备这些文件,请查看进一步阅读部分中的链接。 在此博客中,我们将采用一种更简单的方法。 我们将下载和使用由Debian开发人员Aurelien Jarn准备的预构建Debian映像。 或者,您可以使用“ gef”插件的作者Chris(@hugsy)提供的映像。
-M或-machine选项指定QEMU支持的主板型号,该选项允许用户选择目标硬件平台。-append选项可让你调整传递给Linux内核的内核选项。我喜欢将QEMU命令放入bash脚本中,以加快进行调整和启动VM的过程,此外,我们应该在QEMU调用中附加以下选项以连接网络接口并添加端口转发设置:
-net user,hostfwd=tcp::80-:80,hostfwd=tcp::443-:443,hostfwd=tcp::2222-:22 \ -net nic
添加这些选项,能使我们通过宿主机的2222端口与VM进行SSH通信,模拟固件中的HTTP和HTTPS页面也是如此才能进行访问
图4——启动预构建的Debian映像
一旦启动了VM并为我们提供了可用的Debian VM,仿真的第二部分便开始了。使用SCP或HTTP将固件的根文件系统传输到VM。我发现将整个根文件系统打包成TARball中是处理传输的最有效方法. 然后,我们需要将VM的/ proc,/ dev和/ sys目录挂载到固件文件系统中的相应文件。最后,我们使用以下命令将root目录更改到固件的文件系统中:
chroot ~/firmware_rootfs /bin/sh
第二个选项是告诉chroot在更改根目录后运行/ bin / sh。 您可能需要将此命令更改为/ bin / bash或/ bin / busybox才能获得有效的shell。
图5——Busybox
使用有效的Shell,我们可以定位到/etc/rc.d或/etc/init.d并运行适当的RC脚本以启动用户态服务。仔细分析rc.d文件夹并检查脚本,您需要调整启动脚本,以解决缺少网络接口,NVRAM库调用失败以及各种的问题。这一部分的仿真过程非常类似于处理加密的固件;分析每个固件都将是一场冒险,这是研究的定义。通常,您需要调整rcS脚本,使其恰好足以使目标服务正常运行。 该过程的这一部分可能需要花费数周的调查和其他工作。
固件仿真需要巨大的工作量。 有时候,站在巨人的肩膀上是更好的选择。 有两个项目可帮助加快固件仿真过程,分别是Firmadyne和ARM-X。
只需60%的时间,它每次都起作用:Firmadyne
Firmadyne是一个固件仿真平台,能尽可能的自动仿真基于Linux的设备固件。Firmadyne支持MIPS和ARM处理器。 它将提取根文件系统,推断网络接口,并创建QEMU磁盘映像以进行仿真。 它还尝试模拟NVRAM。 如果你需要针对新目标的完整系统仿真,建议你先尝试Firmadyne。 然后,你可以尝试修复它遇到的一些错误,然后再尝试其他仿真技术。 我在使用较新的QEMU版本运行Firmadyne时遇到了麻烦。 但是,使用Docker安装它通常可以避免此问题。
ARM-X
ARM-X固件仿真框架针对基于ARM的固件。 它是内核,脚本和文件系统的集合,以使用QEMU模拟固件。 它带有一些仿真配置示例,可帮助您进行项目。 我建议在试用ARM-X VM之前,在YouTube上观看Saumil Shah(@therealsaumil)进行的长达一小时的Hack in The Box 2019演示记录。 如果您是IoT固件研究的新手,那么此演示文稿也是一个很好的起点。
总结
希望在此博客的帮助下,你可以“仅用QEMU进行模拟”。 上面演示的所有技术(包括ARM-X和Firmadyne)已用于我们程序中。 条条大路通罗马,但用QEMU模拟固件却没有一个固定的方法。 探索不同的技术,看看哪种对你有用。 熟悉使用名为QEMU的知识,你会惊讶于它如何以意想不到的方式帮助你。 最后,我很想了解你的仿真技术,并希望你下次提交相关文章。
你可以在Twitter @TrendyTofu上找到我,并关注该团队以获取最新的利用技术和安全补丁。
更多阅读:
MIPSEL QEMU映像的准备
https://blahcat.github.io/2017/07/14/building-a-debian-stretch-qemu-image-for-mipsel/
在仿真的ARM机器上的Debian
https://www.aurel32.net/info/debian_arm_qemu.php
在仿真的MIPS(EL)机器上的Debian
https://www.aurel32.net/info/debian_mips_qemu.php
Arm1176(ARMv6)QEMU仿真
https://azeria-labs.com/emulate-raspberry-pi-with-qemu/
AArch64 (ARMv8) QEMU映像的准备
https://blahcat.github.io/2018/01/07/building-a-debian-stretch-qemu-image-for-aarch64/
ARM仿真
https://balau82.wordpress.com/arm-emulation/
脚注
[1] 这款价格低廉的路由器是启动漏洞研究之旅的理想目标。 查看我写的这两部分系列文章,并开始使用该设备。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
- [翻译]基于QEMU的IoT设备仿真 10694
- [翻译]DLINK路由器加密固件逆向分析 11032
- [翻译]如何通过将JavaScript代码隐藏在png图像里绕过CSP的检测 10170