当前位置:网站首页>【FirmAE论文节译】FirmAE: Towards Large-Scale Emulation of IoT Firmware for Dynamic Analysis

【FirmAE论文节译】FirmAE: Towards Large-Scale Emulation of IoT Firmware for Dynamic Analysis

2022-08-06 08:10:06xyzmpv

简介:

本篇为FirmAE对应的论文FirmAE: Towards Large-Scale Emulation of IoT Firmware for Dynamic Analysis的节译,原文发表于ACSAC2020上,作者为Mingeun Kim等人。原文可以在FirmAE的github repo处获取。
第一次翻译非专业论文,文笔有限,敬请见谅(使用了大量机翻以减轻工作量,但大部分内容均经过调整)。
翻到一半发现有佬翻过了 暴毙 传送门 但还是翻完了

正文:

2.4 Firmadyne 框架 ( Firmadyne framework)

Firmadyne [17] 是迄今为止最先进的固件仿真框架,它最初被设计用于大规模分析。许多研究 [24, 60, 64] 都采用该框架来进行动态分析。我们也利用Firmadyne研究(模拟过程的)失败原因。

在对固件进行解包后,Firmadyne 使用一个预制的、定制化的 Linux 内核和动态链接库,以此来支持不同的硬件设备,比如说NVRAM(非易失性随机访问存储器)。为了(更好的)实现仿真,Firmadyne会对目标镜像进行两次模拟:第一次模拟(预模拟)记录下有用的信息,以便第二次模拟进一步利用该信息。 为此,定制化的内核包括有一个特殊的驱动程序,该驱动程序通过hook掉主要的系统调用来记录下有用的信息。 例如,该驱动程序通过hook掉inet_ioctl()inet_bind()两个系统调用以获取被模拟的固件中所使用的网络接口名称以及IP地址。Firmadyne的定制化动态链接库还解决了硬件问题。例如,动态链接库libnvram 基于硬编码的默认值存储和返回 NVRAM 值(实际实现是通过动态链接库hook掉了nvram_get等nvram操作函数)

虽然Firmadyne有着良好的前景,但其网络可达性和 Web 服务可用性的(成功)仿真比率相当低,分别仅为 29.4% 和 16.3%。 为此,我们仔细调查了失败案例并提出了一项技术用来解决(仿真过程中的)失败。
注:Firmadyne模拟失败率高的前提是它的固件样本来源和样本数广泛,其固件样本来自42个厂商而样本数达到了2W+,而FirmAE的固件样本数(1K+)与来源明显少得多,因此FirmAE的性能提升实际上是有疑问的。

3.1 目标和范围 (Goal and scope)

目标

我们的目标成功模拟嵌入式设备,特别是运行它们的网络服务,因为此类设备的 Web 接口是远程攻击者的主要目标。[5、12、17、32、60、64]。我们的目标不是决心消除仿真环境(与真实环境相比)的所有差异。相反,我们致力于实现服务于动态测试的简洁仿真我们的仿真目标可以用以下几个属性加以说明

  • 1)启动时没有任何kernal panic
  • 2)宿主机的网络可达性,以及
  • 3)可用于动态分析的网络服务。

我们的目标是保持这些属性,因为这些属性是运行Web服务同时避免在固件仿真(过程)中出现问题的最低要求。因此,我们通过检查目标固件的网络可达性和 Web 服务可用性来检查仿真成功率。

范围

在各种嵌入式设备中,我们选择无线路由器和IP摄像机作为我们的分析目标,因为它们的广泛存在在我们的日常生活中,同时也经常成为攻击目标。实际上,许多僵尸网络 [5, 32] 也依靠它们来发动大规模 DDoS 攻击。值得注意的是,其他具有相似特征的嵌入式设备也可以用我们的方法来解决(模拟问题)。

3.2 仲裁式仿真(Arbitrated emulation)

仲裁式仿真的一个关键特征是它采用了干预(intervention)干预表示有意添加的,可能与真实设备的行为不同的行为。这一
行为可以在不显著影响仿真固件内目标程序行为的假定下,绕过未解决的问题。判断是继续维持现状还是应用干预的过程被称为仲裁(arbitration)干预可以根据需要以不同方式实施,也可以被注入(inject) 到被称为仲裁点(arbitration point)的,合适的仿真步骤中去。正确的仲裁点可以通过分析给定的高级行为模型(high-level behavioral model)的失败(模拟)案例来进行标定(note)。然后,就可以在这些仲裁点处注入干预措施。由于干预侧重于高级行为,因此从一小部分固件中获得的(仲裁点与干预行为)可以广泛应用于遭受类似(模拟失败)问题的其他固件,即使它们(模拟失败)的根本原因并不相同。

我们的干预措施利用了基于linux的固件的抽象设计。我们对我们的数据集进行了初步研究,发现适当的干预措施可以帮助模拟器绕过许多未解决的问题。例如,当网络设置过程由于未知的外设访问(unknown peripheral access)NVRAM支持不足(insufficient NVRAM support)而停止时,不管根本原因如何,强制配置一个固定的网络设置(forces the configuration of a fixed network setting)的干预措施总可以解决该问题。 虽然仲裁仿真可能违背了全系统仿真的主要理念,但我们假设干预措施引入的微小差异对目标程序的行为只有轻微的影响。事实上,我们通过在1124份固件中的892份中成功了运行模拟的web服务来支持这一假设,通过进行动态安全分析,我们还发现了12个0day漏洞。

4.1 启动时仲裁 (Boot arbitrations)

启动顺序错误(Improper booting sequence)

引发启动顺序错误的主要原因是用于系统初始化的程序没有被正确执行。通常,大多数系统都需要在引导过程中进行初始化。在Linux内核中,初始化通常由一个名为init的程序执行,内核试图通过检查预定义的路径来找到这个程序,例如/sbin/init/etc/init/bin/init。然而,一些固件为初始化程序定制了路径,这就使得内核无法初始化进而崩溃。

这种错误经常发生在NETGEAR固件中。在分析它们之后,我们发现它们使用了preinit(作为初始化程序),这一点也广泛存在于开源嵌入式设备项目OpenWrt[22]中,经过我们的验证,(NETGEAR固件)确实是基于OpenWrt实现的。我们还发现一些TP-Link固件也使用了preinit为了解决这个问题,Firmadyne构建了一个脚本,它可以基于一个硬编码的文件列表,搜索并执行这些初始化过程中常用程序。然而,这些预置的文件路径并不足以处理在野的初始化程序的不同路径。
注:实际就是写了一个脚本,通过字典扫描可能的初始化程序路径并执行,防止初始化失败。

我们提出了另一种利用来自目标固件内核的信息的方法。具体来说,我们在引导过程的开始时进行了一次干预,以此从固件的内核中提取有用的信息。具体来说,我们使用了内核的命令行字符串,而它常常被用于在启动过程中设置内核的默认配置。注意到这样的字符串是在开发阶段预定义的,因此它会很自然地嵌入到内核镜像中。此信息可能包括初始化程序路径、控制台类型、根目录、根文件系统类型或内存大小。 例如,从NETGEAR固件中的一个内核镜像,我们可以获得一个console=ttyS0,115200 root=31:08 rootfstype=squashfs init=/etc/preinit字符串。(通过该字符串)我们可以识别其初始化程序路径为/etc/preinit,具有的控制台类型为ttyS0且波特率为115200,根文件系统类型为squashfs。通过使用从原始内核获得的信息来配置模拟环境,即使其初始化程序的路径并不正常,客系统也可以正确地初始化。如果我们不能提取任何信息,我们将会从提取的文件系统中寻找诸如preinitpreinitMT等初始化程序。

缺少文件系统结构(Missing filesystem structure)

其他失败情况是由于缺少文件或目录而造成的。当内部程序访问这些路径时,它们就会崩溃,进而导致仿真停止。Firmadyne试图通过在自定义启动脚本的开头创建和挂载硬编码路径,如procdevsysroot来解决此类问题。一些硬编码的路径确实发挥了作用;例如,创建/etc/TZ/etc/hosts解决了一些此类失败。然而,这种方法不能适用于更为多样的情况。此外,由于它在固件初始化之前强制创建文件和目录,会导致其与内部程序发生冲突。因为内部程序也会在相同路径中创建和挂载其他文件或目录。
我们通过插入一个与之前情况类似的干预措施来进行仲裁,但从文件系统而非内核中检索信息在模拟给定的固件之前,我们从其文件系统中的二进制可执行文件中提取所有字符串。然后对它们进行过滤,以获得很可能指示出路径的字符串,并根据这些路径来调整文件结构。特别是,我们选择了以通用Unix路径开头的字符串,例如/var/etc等。

4.2 网络仲裁 (Network arbitrations)

启动过程完成后,应进行网络配置,使宿主机系统能够与客系统(guest system)进行通信,并最终能够进行动态分析。对于网络通信,QEMU要求主机创建一个额外的网络接口,TAP。此TAP接口已连接到客系统中的一个网络接口。然后,主和客系统通过它进行交流。
但是,正确配置TAP接口并不是一件简单的事情,因为它应该根据目标网络接口类型设置对应的特定选项。 这种网络接口类型可以是以太网、无线局域网(WLAN)、网桥或虚拟局域网(VLAN)。由于在客系统中静态区分接口类型并不容易,因此需要对目标固件先进行一次仿真。
Firmadyne对固件进行两次模拟。在第一次模拟即预模拟中,Firmadyne通过hook系统调用来收集内核日志。由于收集的日志包括仿真期间访问的网络接口的名称和IP地址,因此它们可以在最终仿真中用于网络配置。然而,许多固件仍然模拟失败。

IP别名处理无效(Invalid IP alias handling)

将多个IP地址分配给一个网络接口(的行为)称为IP别名[58]。它在路由器中普遍存在,因为它允许通过IP地址单独管理服务。在IP别名中,网络接口生成多个自身的实例,给每个实例分配一个唯一的IP地址。例如,一个IP地址为192.168.1.1的桥接网口br0可以有169.254.39.31.1.1.1的IP别名,它们分别被分配给它的实例br0:0br0:1。然后,br0被链接到一个以太网接口,eth0。这样,br0就可以通过任何这些IP地址来访问。
与这种IP别名相关的故障案例经常在D-Link固件中发现。经过调查,我们发现它们是由于Firmadyne不能正确处理IP别名造成的。该问题发生在宿主机系统中的Firmdyne网络配置期间。在预模拟步骤中,内核会记录IP别名。然后,Firmadyne解析日志,并尝试将所有记录的IP地址分配给客系统中的相应接口。然后,它为这些IP地址添加静态路由规则,以将它们链接到宿主机中的TAP接口。这就导致了多个路由规则被添加到单一的TAP接口,使网络发生冲突。
根据IP别名的相关知识,FirmAE通过允许宿主机使用其默认路由规则来进行仲裁。特别是,即使使用了IP别名,一旦客系统的网络接口连接到主机的TAP接口,所有数据包也都会自动在主客系统之间路由。因此,在这些情况下不需要干预,这表明了在正确情况下进行干预的重要性。(无为而治了属于是)

没有网络信息(No network information)

一些固件在其内核日志中不包含任何关于可连接的网络接口的信息,如eth。这些固件只配置了环回接口(lo),而没有设置其他网络接口。由于缺乏可连接的网络接口,这些固件无法从宿主机系统中访问。此外,一些固件试图将它们的web服务器绑定到一个并不存在的网络接口上,最终导致了崩溃。

通过分析这些案例,我们发现一些固件使用动态主机配置协议(DHCP)从DHCP服务器检索IP地址,作为其WAN接口。DHCP是一种在终端设备中设置网络接口的流行协议,因为它不需要任何用户交互。一般来说,无线路由器充当DHCP服务器,为客户端连接到的局域网接口分配IP地址。但是,除非用户手动配置(路由器),(路由器)也可以从外部DHCP服务器获取一个IP地址,以将其WAN接口连接到互联网。实际上,我们分析的固件试图通过其WAN接口和主机系统的TAP接口之间的连接来利用DHCP协议获取IP地址。但是,由于模拟环境中不存在DHCP服务器,仿真固件无法获取IP地址并配置网络接口。进一步,由于没有配置网络接口,因此无法设置一个对多个网络接口进行分组的桥接接口。最终导致了绑定到这些网络接口的内部程序无法正常运行。

FirmAE使用强制将网络配置为默认设置的干预来仲裁这些案例。具体来说,我们设置了一个以太网接口eth0,其IP地址为192.168.0.1。设置以太网接口后,对于内核日志中包含桥接口信息的固件,将使用默认的桥接口br0进行链接。这种简单的干预措施大大有助于模拟web服务。(不愧是你,偷懒都能偷得光明正大)

ARM中的多个网络接口(Multiple network interfaces in ARM)

为了支持多个网络接口,必须选择加载目标固件的适当机器。我们选择了virt,QEMU支持的机器之一,遵循之前[17]研究中使用的方法。它在对几个固件的模拟中表现良好;然而,它无法模拟具有多个网络接口的ARM固件。Firmadyne试图通过准备固定数量(4)的虚拟接口来解决这一多接口问题。它的基本假设是,接口的数量应该大于或等于从内核日志中提取的接口名的后缀。例如,如果记录中有eth1,则eth0很可能也存在。然而,几乎所有的ARM固件仍然没有被成功模拟。

我们仔细研究了这些例子,但我们无法确定确切的原因。然而,我们可以通过强制设置以太网接口的数目为1这一“高级干预”来解决故障。更具体地说,我们的干预强制设置了唯一的以太网接口eth0,并避免设置其他接口。因此,我们设置了一个桥接网络接口,并在必要时将其连接到主机。通过这种干预,可以模拟大部分ARM固件。

VLAN设置不足(Insufficient VLAN setup)

VLAN是路由器的一个典型特性,因为它提供了一个隔离的网络环境,按逻辑对子网进行分组。与以太网或WLAN等其他网络接口相比,VLAN接口具有不同的特性,因此必须进行额外选项的设置。为了支持VLAN,应将TAP接口的类型设置为VLAN,并为其分配适当的VLAN id

iptables中的过滤规则(Filtering rules in iptables)

许多路由器设置了一个防火墙,以从设计上防止未经授权的远程访问。否则,攻击者可以访问管理接口。我们数据集中的一些固件也通过使用iptables来实现此策略。因此,客系统内核会丢弃所有来自宿主机的数据包。我们主要在TP-Link(设备)上发现了这些情况,(在这种情况下)即使主客系统间网络配置正确,客系统也是无法正常访问的。

这并不代表模拟失败,因为设置iptables模拟了真实设备的原始行为。 然而,这种过滤阻止了对固件潜在漏洞和威胁的分析。显然,在分析过程中识别出的漏洞可能无法被远程利用。然而,许多设备所有者或管理员错误地更改了这些规则,使设备可以被公开访问[14,15,51]。

FirmAE通过检查客系统中的过滤规则,并在它们存在时删除它们来进行仲裁。 这可以通过刷新iptables中的所有策略。并设置默认策略来接收所有传入数据包实现。然后,从宿主机上就可以访问客系统网络,并进行动态分析。

4.3 NVRAM仲裁

模拟类似于真实环境的外设是固件仿真(2.3)中最具挑战性的部分之一。NVRAM本质上是一个闪存(flash memory),是被广泛应用于嵌入式设备中,用于存储配置数据的外设之一。嵌入式设备中的内部程序经常从(NVRAM)中存储/获取必要的信息。除非支持NVRAM,这些程序常常会崩溃。

Firmdyne实现了一个自定义的NVRAM库来模拟与NVRAM相关的函数。通过设置名为LD_PRELOAD的环境变量,可以提前加载此自定义库以包含其他库。这将拦截与NVRAM相关的函数,如nvram_get()nvram_set(),并模拟一个不存在物理访问的NVRAM。具体来说,当调用nvram_set()时,一个键值对将存储在一个文件中,然后在调用nvram_get()时获取它。某些情况下,nvram_get()会在调用nvram_set()之前被调用,(为了预防这种情况)Firmdyne会使用特定固件中的默认文件初始化键值对,这(包含初始NVRAM值的文件)通常存在于设备中,以实现设备的出厂重置功能。Firmadyne有一个包含少数默认文件的硬编码路径的列表来提取键值对。然而,我们的数据集中的许多固件仍然没有被成功模拟。

支持自定义的NVRAM默认文件(Supporting custom NVRAM default files)

我们发现在许多情况下,固件中默认文件的路径随设备的不同而变化,甚至它们的键值对也有不同的模式。 例如,在一些D-Link固件中,默认文件位于/etc/nvram.default/mnt/nvram_rt.default处。此外,一些netgear固件中的默认文件可以在/usr/etc/default目录下中找到。这些文件中的键-值对用不同的分隔符分隔,例如回车位或NULL字节。一些默认文件甚至具有品牌(自定义的)独特格式,如OBJ或ELM。注:这一点在iot设备的网络协议中也很常见

为了开发一种大规模仿真的方法,FirmAE在预仿真期间进行了仲裁。具体来说,FirmAE记录了在预仿真过程中使用nvram_get()nvram_set()函数访问的所有键值对。然后,它会扫描目标固件的文件系统,并搜索包含有多个已记录的、值仍然未知的键名(key)实例的文件(实际就是未知的NVRAM配置文件)。(如果这样的文件存在的话)FirmAE会从文件中提取键值对,并在最终仿真中使用它们

没有NVRAM默认文件(No NVRAM default file)

不幸的是,并不是所有的固件映像都有默认的NVRAM文件。即使存在默认文件,它也可能不包含所请求的键-值对。解决这个问题的一个简单方法是对未初始化的key返回NULL值,正如Firmadyne所做的那样。然而,我们观察到许多情况下,nvram_get()返回NULL后出现了segmentation fault。通过对崩溃的程序进行逆向工程,我们发现,令人惊讶的是,许多程序并没有验证nvram_get()的返回值。它们只需将返回值传递给与字符串相关的函数,如strcpy()strtok(),并由于空指针解引用(NULL pointer dereference)而崩溃。
FirmAE通过仲裁nvram_get()函数的行为来处理这个问题。在访问未初始化的键(key)时,FirmAE不会返回NULL值,而是返回一个指向空字符串的指针。 这个简单的改变显著地减少了崩溃,特别是在NETGEAR固件中。因为在没有物理设备的情况下,我们无法获得真正的键值对,这一方法将可能是 避免 在许多内部程序中 由于错误处理不足而导致的崩溃 的最佳方法之一。

4.4 内核仲裁

嵌入式设备中的许多程序通过内核中的设备驱动程序与外设协作。通常来说,它们通过ioctl命令与外设沟通。不幸的是,模拟这一过程并非一个简单的任务,因为每一个设备驱动程序都有取决于其开发人员和相应的设备的特征。 尽管Firmadyne实现了一些支持/dev/nv/nvram/acos_nat_cli的虚拟内核模块,但它不能涵盖实际场景中固件的不同特性。我们的数据集中的许多固件也会由于这个问题而崩溃。

对内核模块的支持不足(Insufficient support of kernel module)

由于Firmadyne使用硬编码的设备名称和ioctl命令实现了虚拟模块,因此一些程序在访问具有不同配置的内核模块时会失败。例如,许多网络设备映像使用了一个名为acos_nat的模块,该模块用于与安装在/dev/acos_nat_cli上的外设进行通信。在这些固件中,一个Firmadyne模块返回不正确的值,并导致httpd的web服务出现无限循环。此外,我们发现ioctl命令因固件架构的不同而不同,因此也应该考虑这一点。

FirmAE的高级解决方案致力于模拟特定的内核模块。这里的关键直觉(key intuition)是,许多内核模块是通过共享库访问的,这些库具有发送相应ioctl命令的函数。因此,FirmAE拦截库函数调用,类似于处理NVRAM问题(4.3)。当程序调用库函数时,FirmAE将返回一个预定义的值。从而使得不需要根据设备架构来模拟每个ioctl命令。在本例中,我们只关注acos_nat,而通过共享库进行的其他外设访问也可以以相同的方式进行处理。

内核版本不正确(Improper kernel version)

我们发现一些固件面临着内核版本的问题。Firmdyne在固件模拟中使用的定制Linux内核版本为v2.6.32。但是,最新的嵌入式设备使用了内核的更新版本。升级内核版本似乎是解决这个问题的一个简单的解决方案。实际上,我们通过实验测试了Linux内核v4.1.17,并成功地模拟了更多的固件。然而,一些固件,特别是较旧的固件,无法被新版本的内核所模拟。这些固件在libc库中出现崩溃。

我们研究了这些情况,并确定Linux内核v4.1.17的地址空间布局随机化(ASLR)与旧版本的libc不兼容。 为了解决这个问题,我们在编译新内核时使用了兼容性选项。具体来说,我们设置了CONFIG_COMPAT_BRK选项,它排除了堆内存中的随机brk区域。有了这个新的内核,FirmAE就能够处理上述情况。也可能 存在有其他的,在我们的实验中没有检测到的兼容性问题。为了解决这些问题,需要进一步测试具有各种编译选项的多个内核版本,这是我们未来研究的目标之一。

4.5 其他仲裁 (Other arbitrations)

一些失败的案例可以通过其他次要的干预措施来解决。

未执行的Web服务器(Unexecuted web servers)

为了对web服务进行动态分析,我们需要同时实现网络的可达性和web服务的可用性。在某些固件中,即使网络配置成功,web服务器也无法运行。我们找不到明确导致这种现象的根本原因。但是,通过施加强制执行web服务器的干预可以解决这个问题。具体来说,就是在目标固件的文件系统中搜索被广泛使用的web服务器,如httpdlightitpdboagoahead,以及它们相应的配置文件,并(直接)执行它。

超时问题(Timeout issues)

确实应该强制停止经过较长时间仍然没有响应的固件模拟过程。因此,需要设置一个合适的超时时间。Firmadyne使用60秒作为超时时间;然而,固件,特别是来自NETGEAR的固件,需要很长时间来完成它们的启动过程,因此导致了它们的仿真(在启动完成前)最终被阻止。我们调查了这些案例,并经验性地发现了一个合适超时时间——240秒。虽然这个更改很简单,但它已经成功地实现了60多个固件的模拟。(离谱)

缺乏可进行仿真的工具(Lack of tools for emulation)

嵌入式设备的开发人员通常会抛弃不必要的功能来节省存储空间。因此,固件可能没有适当的工具来模拟自身。由于模拟的环境没有任何存储空间限制,我们可以添加几个需要的工具。为了进行成功的仿真,应该在文件系统中准备一些Linux命令,如mountln。我们通过将最新版本的busybox添加到目标固件的文件系统中来解决这个问题。这一简单的添加支持了基本的命令,使仿真得以成功。(注:在模拟成功的shell目录下有firmdyne文件夹。里面存放了新版的busybox

感想(碎碎念):

自闭死了体会到了翻译一半然后发现别人翻译完了的痛苦感。

总的来说,这篇文章很好的总结了模拟过程中可能存在的问题,对于改进FirmAE或排查模拟失败的原因来说都是很好的参考。

参考安恒海特的iot-all-in-one里面的仿真部分,大部分论文似乎都着眼于对特定类型设备的fuzz二进制分析而非emulationRehosting,导致模拟的适用范围往往很小(我印象里主打large scale和通用性的应该只有FirmAEFirmdyne当然我论文读的少 )。而特化的模拟方式能不能随着iot设备发展继续发展下去,我觉得是一个问题。

个人觉得模拟本质上来说是为了(给 我这样的穷鬼 广大安全研究人员)提供一个可用的虚拟分析环境,它应该去往通用性上走,去做更好的工具(或者对已有的特化工具做集合,提供统一的固件模拟接口,就像不同平台下的编译器套件)。它应该想办法增加对新设备新固件的适应性与可扩展性(当然也受制于底层架构比如qemu),而非仅仅是对少部分设备的深入模拟。

希望有一天能出现比FirmAE更好用的工具吧…毕竟一键搭qemu-system实在是爽,也能节省大量的时间。(目前git上的项目给我的还是一种手工活的感觉?至于商用模拟套件是不是已经实现了large scale,希望有了解的能介绍一下?毕竟论文已经有一些年头了 )

后面看看能不能出Firmdyne的论文翻译和FirmAE的源代码阅读 逃)

希望不要又有人翻译过了2333

如果有大佬觉得FirmAE有根本性问题或者我的想法有问题也请指出,防止我浪费时间2333(非学术界非专业人士,姑妄言之)

原网站

版权声明
本文为[xyzmpv]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_45209963/article/details/126156795

随机推荐