很多人可能觉得路由器或IoT安全研究很容易,只要用QEMU模拟跑起来就行,对于嵌入式硬件安全研究领域的新手来说,知道如何使用QEMU模拟固件可能是最难的部分,虽然我无法提供很多建议帮助,但可以提供固件仿真上的一些经验。
在开始之前,我将假定你的固件是基于UNIX的,并且不能在其他实时操作系统(RTOS)(例如VxWorks或Windows CE)上运行。我还将假定你已解密/取消加密了固件,并提取了root文件系统。如果你在使用加密固件时遇到麻烦,请查看我之前有关处理加密固件的文章。
https://www.thezdi.com/blog/2020/2/6/mindshare-dealing-with-encrypted-router-firmware
0x01 qemu仿真方法初探
设备仿真的关键部分是确定最终目标。你只想运行一个二进制文件?文件中的一个服务?还是想要完整的设备仿真?由于使固件仿真正常工作是一项耗时的任务,因此你的目标将极大地影响你的仿真策略。有时,由于调整仿真而浪费了无数的时间,因此需要购买了一些低成本设备。
对于运行单个二进制文件(例如解密例程),请考虑使用更轻量级的用户空间QEMU仿真方法。如果你的目标是编写漏洞利用程序,那么使用物理设备可能是最好的选择,因为漏洞利用程序最终会针对实际设备使用。仿真可能无法说明诸如指令缓存之类的细微硬件行为,这些行为可能会影响内存破坏漏洞。但是,对于开发和测试更高级漏洞的利用程序(例如CGI脚本命令注入或PHP页面中的登录逻辑缺陷),硬件仿真非常合适。
https://www.qemu.org/docs/master/user/main.html
0x02 确定CPU架构
模拟任何设备的第一步就是确定目标的CPU体系结构。通常,我们无需实体设备即可确定这一点,确定CPU类型的一种方法是通过分析固件二进制文件,在二进制文件上运行file命令可以快速告诉我们正在处理的CPU体系结构:
图1–file和readelf命令的输出
但是,该file命令没有提供详细的结果。readelf带有-AARM二进制文件选项的命令提供了更详细的CPU信息,这对于完整的系统仿真和交叉编译至关重要。
确定使用无线路由器时的CPU体系结构的另一种方法(以TP-Link TL-WR841-ND为例)是通过在Internet上搜索设备型号。通常,这将使我们进入提供有关设备硬件信息的OpenWRT设备页面。快速搜索还可以告诉我们主要的片上系统(SoC)部件号以及设备FCC ID。然后,我们可以查找相应SoC芯片的数据表,并确定确切的CPU架构。
这也是搜索特定于家族的处理器核心数据表以熟悉CPU的绝佳时机。该数据手册将提供特定于器件的信息,例如加载地址和低级存储器布局,这些信息可能有助于仿真和分析。你也可以查找FCC归档报告以了解 设备的内部视图。
https://fccid.io/TE7WR841NXV9/Internal-Photos/TL-WR841N-Int-Photo-2192209
0x03 用户模式仿真
当只需要模拟一个二进制文件时,按进程模拟就很有用。有两种方法可以在用户模式QEMU中模拟单个二进制文件,第一种选择是用户模式过程仿真。可以使用以下命令之一完成此操作:
qemu-mipsel -L ` `qemu-arm -L ` `qemu- -L
当二进制链接到外部依赖性(例如uCLibc或加密库)时,-L选项很重要。它告诉动态链接器查找具有所提供前缀的依赖项,以下是imgdecrypt为D-Link DIR-882路由器运行二进制文件的示例。
图2-imgdecrypt
模拟该过程的另一种方法是使用QEMU执行跨架构的chroot。为此,我们将qemu-< arch >-static二进制到/usr/bin/固件根文件系统的目录。然后我们chroot进入固件根并获得一个工作外壳:
图3-使用QEMU执行跨架构的chroot
这是由于QEMU在安装过程中已向内核注册,以通过binfmt_misc机制处理具有某些magic字节的二进制文件而导致的。因此,该技术与使用相同机制的Scratchbox交叉编译工具包不兼容。你可以在此 StackOverflow帖子中找到有关跨体系结构chroot的更详细说明。
https://www.zerodayinitiative.com/blog/2020/5/27/incompatible%20with%20the%20Scratchbox https://unix.stackexchange.com/questions/151010/how-does-chroots-use-of-qemu-for-cross-compile-environments-work
此方法是我首选的模拟设备的首选方法。它设置迅速,可以让我在固件root文件系统中尝试不同的二进制文件,而不必过多担心依赖项。请注意,在这种仿真模式下,chroot shell中没有初始化任何userland服务,因此没有系统或网络服务可用。但是,这仅足以运行一个二进制文件或测试一个小组件就足够了。
0x04 完整的系统仿真
有时,我们需要更全面地分析固件,并且将从完整的系统仿真中受益,有很多方法可以完全模拟设备。以下是一些最常见的仿真技术,研究人员已使用这些技术来查找实际的漏洞,然后将其提交给ZDI。
在仿真过程的第一部分,我们将使用QEMU创建在目标体系结构上运行的完整Linux虚拟机。然后,我们将固件root文件系统传输到VM中,并将chroot传输到固件的root文件系统中。要创建在QEMU中运行的完整VM,我们通常需要满足以下条件:
-QEMU磁盘映像文件(qcow2) -为目标体系结构编译的Linux内核映像 -初始RAM磁盘映像(initrd)
要获得以上各项,你可以设置交叉编译器,编译内核并下载安装程序以获取初始RAM磁盘。然后,你可以将Linux安装到QEMU磁盘映像文件上。但是,交叉编译内核是Linux初学者的一项任务,如果你有兴趣自己准备这些文件,请查看进一步阅读部分中的链接。在此博客中,我们将采用一种更简单的方法,我们将下载和使用由Debian开发人员Aurelien Jarn准备的预编译Debian映像。另外,你可以使用“ gef”插件的作者Chris(@hugsy)提供的镜像。
https://blahcat.github.io/2017/06/25/qemu-images-to-play-with/ https://people.debian.org/~aurel32/qemu/
在所有文件都放置到位后,我们可以使用以下命令之一启动CPU架构的QEMU VM:
sudo qemu-system-mipsel -M malta -kernel vmlinux-2.6.32-5-4kc-malta -hda debian_squeeze_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" sudo qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" sudo qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.img-3.2.0-4-vexpress -drive if=sd,file=debian_wheezy_armhf_standard.qcow2 -append "root=/dev/mmcblk0p2" sudo qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.img-3.2.0-4-vexpress -drive if=sd,file=debian_wheezy_armhf_desktop.qcow2 -append "root=/dev/mmcblk0p2"
-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和仿真固件的HTTP和HTTPS页面通过SSH与VM通信。
图4-启动预编译的Debian映像
启动了VM并为我们提供了可用的Debian VM 后,仿真的第二部分便开始了。使用SCP或HTTP将固件的root文件系统传输到虚拟机,我发现将整个root文件系统打包在TAR中是处理传输的最有效方法。然后,我们需要安装/proc,/dev以及/sys虚拟机的目录中的固件文件系统中的相应文件。最后,我们chroot使用以下命令进入固件文件系统:
chroot ~/firmware_rootfs /bin/sh
执行第二个选项chroot后,/bin/sh在更改root目录后运行,你可能需要将此命令更改为/bin/bash或/bin/busybox获取有效的shell。
图5-Busybox
使用shell程序,我们可以导航到/etc/rc.d或/etc/init.d运行适当的RC脚本以启动用户态服务。仔细分析rc.d文件夹并检查脚本,你需要调整启动脚本,以解决缺少网络接口,NVRAM库调用失败以及各种有趣的问题。仿真过程的这一部分非常类似于处理加密的固件。通常,你只需要对rcS脚本进行适当的调整即可使目标服务正常运行,该过程的这一部分可能需要花费数周的分析和其他工作。
0x05 Firmadyne和ARM-X
固件仿真需要做很多工作,有时候,站在巨人的肩膀上是更好的选择,有两个主要项目可帮助加快固件仿真过程,分别是Firmadyne和ARM-X。
Firmadyne
Firmadyne在工作时非常棒。它是一个固件仿真平台,自动仿真基于Linux的设备固件。Firmadyne支持MIPS和ARM处理器。它将提取root文件系统,推断网络接口,并创建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固件研究的新手,那么此ppt也是一个很好的学习资料。
https://www.youtube.com/watch?v=NVl6uJiEaoI https://armx.exploitlab.net/ https://github.com/firmadyne/firmadyne
希望在此博客的帮助下,你可以使用QEMU进行固件模拟仿真。上面演示的所有技术(包括ARM-X和Firmadyne)已用于我们程序的各种提交中。探索不同的技术,看看哪种对你有用。
0x06 参考信息
MIPSEL QEMU Image Preparation https://blahcat.github.io/2017/07/14/building-a-debian-stretch-qemu-image-for-mipsel/
Debian on an emulated ARM machine https://www.aurel32.net/info/debian_arm_qemu.php
Debian on an emulated MIPS(EL) machine https://www.aurel32.net/info/debian_mips_qemu.php
Arm1176 (ARMv6) QEMU Emulation https://azeria-labs.com/emulate-raspberry-pi-with-qemu/
AArch64 (ARMv8) QEMU Image Preparation https://blahcat.github.io/2018/01/07/building-a-debian-stretch-qemu-image-for-aarch64/
ARM emulation https://balau82.wordpress.com/arm-emulation/
本文翻译自:https://www.zerodayinitiative.com/blog/2020/5/27/mindshare-how-to-just-emulate-it-with-qemu如若转载,请注明原文地址: