对 IoT 设备的网络攻击是一个严重威胁。这些攻击利用 IoT 固件中的软件漏洞。 fuzz是一种有效的软件测试技术,用于漏洞挖掘。在 IOT漏洞挖掘工作中,我们介绍 Firm-AFL,用于 IoT 固件的第一个高通量灰盒模糊器。 Firm-AFL解决了物联网模糊中的两个基本问题:
1、 它通过启用模糊处理来解决兼容性问题。可在系统中模拟的 POSIX 兼容固件仿真。
2、 它解决了性能瓶颈系统模式仿真技术采用新型技术引起称为增强过程仿真。通过组合系统模式仿真和用户模式仿真以新颖的方式,增强过程仿真提供高兼容性,如系统模式仿真和高吞吐量作为用户模式仿真。
我们的评估结果显示,( 1) Firm-AFL功能齐全,能够挖掘到现实世界中的 IOT设备漏洞 ;( 2) FIRM-AFL 的平均吞吐量比基于系统模式仿真的 fuzz高 8.2倍 ;( 3) Firm-AFL 能够找到 1day漏洞比基于系统模式仿真的 fuzz速度快得多,并且能够找到 0day漏洞。
物联网设备对我们的隐私安全的影响非常大。据不完全统计直至 2017年为止,全球物联网设备超过了 82亿,人们的生活都离不开 IOT设备, IOT设备的不安全问题已迫在眉睫。目前黑客对 IOT设备的主要恶意行为是创建大型的僵尸网络(例如: Mirai、 VPNFilter和 Prowli)。恶意程序会通过 IOT设备的 1day或 0day直接拿到 root权限。因此,防御者必须要在攻击发生之前找到漏洞并修补。
Fuzz是一种软件测试技术,通过给目标程序发送变异的样本可以高效的进行漏洞挖掘;其中 AFL( American Fuzzy Lop,一种以代码覆盖率作为变异策略的 fuzz)的知名度最高,在 DARPA Cyber Grand Challenge 的决赛中,大部分选手都会使用 AFL 做漏洞挖掘。
IOT设备 fuzz所存在的问题:
尽管 fuzz在通用平台上能对程序进行有效的测试,但是因为 fuzz对硬件配置有较高的要求,所以一般情况下不能直接在 IOT设备上进行 fuzz,比如:提取一个固件并找到一个应用程序,然后使用 AFL对此程序进行 fuzz,正常情况下 fuzz会失败。
为此,最近的研究者提出了一系列的解决方案,从直接对 IOT设备进行 fuzz(例如: IOTFuzzer_Full);一种结合结合了硬件和软件的混合 fuzz(例如: AVATAR);到完全使用软件进行系统模拟(例如: Firmadyne)。最近由 Muench et al 的研究报告指出:使用软件进行系统模拟的效率要比使用 IOT 设备的效率高得多,因为大多数 IOT 设备的硬件配置本身并不高。
吞吐量是影响 fuzz效率的关键因素;然而即使是使用软件进行系统仿真,其性能也并不理想,根据我们的测试结果来看, system-mode大约比 user-mode慢十倍(在使用 AFL的情况下);慢十倍也就意味着同样是发现一个漏洞, system-mode要多花十倍的系统资源。根据我们的分析来看, system-mode主要开销有两个,一个是将虚拟内存转换为物理机内存,即内存管理单元(例如: SoftMMU);另一个主要开销是模拟系统调用的开销。
我们的解决方案:通过增强过程仿真进行灰盒模糊处理
在研究中我们发现,这是据我们所知第一个能同时完成以下两项设计目标的 IOT固件 fuzzer: 1、透明性:在进行 fuzz之前不需要对固件的代码进行修改; 2、效率:整个 system-mode的吞吐量接近于 user-mode的吞吐量。我们找到了能实现这两个目标的关键技术,也就是同时兼容了 system-mode的通用性和 user-mode的效率。
更准确的说,我们提出了一种名为“增强过程模拟”的新技术。顾名思义,这项技术的主要思想就是通过完整的系统模拟来增强进程模拟(或 user-mode)。被 fuzz的程序大部分时间会在 user-mode中运行以提升效率,只有某些特殊时刻程序才会在 system-mode中运行,以保证程序能正确执行。
为了评估这项技术的可行性,我们结合了 AFL和 Firmadyne,实现了一个名为 FirmAFL的 fuzz原型。从用户的角度来看,当用户使用 Firm-AFL时,一方面可以像普通 AFL做 fuzz那样对固件进行基于代码覆盖率的 fuzz,另一方面 Firm-AFL偶尔也会切换到 Firmadyne进入 system-mode,以确保程序能够正常执行。
我们已经用一组真实的 IOT固件来对 Firm-AFL进行基本评估,结果表明:
(1)、就想使用 system-mode运行固件一样, Firm-AFL可以正确的运行固件;
(2)、 Firm-AFL的平均吞吐量相比于 TriforceAFL(此 fuzzer启用了轻量级的快照)这样的基于完整 system-mode的 fuzzer快了 8.2倍;
(3)、在单个机器上 Firm-AFL找到 1day漏洞的速度比使用 system-mode做 fuzz的 fuzzer快了 3到 13倍,并且在 8小时内找到了两个 0day漏洞。
综上所述,我们在本论文中作出了如下贡献:
1、 我们认为,全系统仿真的运行开销很大,当批量进行固件 fuzz时,效率并不理想;我们将进一步研究开销大的根本原因;
2、 摘要针对全系统仿真 (高通用性、低效率 )和用户模式仿真 (低通用性、高效率 )的矛盾特点,我们提出了一种“增强过程仿真”的新技术;
3、 我们为 IOT固件设计并实现了第一个基于代码覆盖率的灰盒 fuzzer, Firm-AFL;
4、 我们对我们的系统进行了全面的评估,并打印出系统的各个部分的运行开销;我们的改进使得 fuzz的平均速度提高了 8.2倍,并且能够在 8小时内挖掘到两个 0day;
5、 目前最新版本的 Firm-AFL支持三种 CPU架构: mipsel、 mipseb和 armel,这涵盖了 Firmadyne数据库中 90.2%的固件。 Firm-AFL源码已经上传至 GitHub: https://github.com/zyw-200/FirmAFL
Fuzzing是一种软件测试技术,旨在通过执行带有随机输入的目标程序并寻找有趣的程序行为(例如: crash)来发现 bug。根据执行时收集和使用的信息的多少, fuzzer可以被分为黑盒、白盒和灰盒。黑盒 fuzzer将程序视为黑盒,不利用任何执行反馈来做随机输入的变异,这种方法最初被用于 Linux的程序测试;相反的,白盒 fuzzer是根据对目标程序有着深入的了解下,对随机输入进行变异,这类程序分析技术通常代价较大,例如动态污点分析和符号执行;最后则是灰盒 fuzzer,此类测试会根据有限的信息(例如代码覆盖率)来对随机输入进行变异。
目前最流行的灰盒 fuzzer变异策略是根据代码覆盖率进行变异。这些 fuzzer检测目标程序以收集代码覆盖率信息,之后收集到的信息会被用来指导样本的变异——能触发新代码的样本会被遗传算法选中,而不能触发新代码的样本会被丢弃。这种简单的策略在实际应用中效率很高。事实上,在实际应用中,因为灰盒 fuzzer的速度很快甚至可以胜过白盒 fuzzer,灰盒 fuzzer的轻量级使得灰盒 fuzzer的执行速度比白盒 fuzzer快百倍甚至千倍,换言之,吞吐量对灰盒 fuzzer至关重要。
AFL是著名的灰盒 fuzzer。它可以静态或动态的分析程序。当有源代码时, AFL就会静态插桩;当没有源代码时,例如: fuzz商业程序( COTS)时, AFL会使用二进制转换器(例如: qemu的 user-mode)来执行检测。因为大多数物联网设备的源代码和设计文档是专有的,所以只能进行动态检测。事实上就算是固件提取也要费一番功夫。
QEMU是一个基于动态二进制转换快速处理器的模拟器。与传统的逐条执行目标程序的模拟器不同, qemu一次性翻译多个基本块,并使用块链将它们连接在一起。这种块链设计使得 qemu大部分时间都会在代码缓存( cache)内执行,从而使得转换开销最小化。动态检测可以在转换过程中执行以引入新功能,例如:分支监视和污点传播。
除了指令翻译外,还有一个重要的任务是地址空间翻译。在不同的执行模式下翻译的方式会有很大的不同。在系统模式下, qemu实现了一个软件内存管理单元( MMU)来处理内存访问。软件 MMU将虚拟机的虚拟基址( GVAs)映射到物理机的虚拟地址( HVA)。这个映射过程对客户操作系统( OS)是透明的,这意味着 qemu允许客户操作系统通过页表的接口设置 GVA到客户物理地址( GPA)通过页面表的界面映射处理页面错误。在底层, qemu为每个内存访问插入一个从 GVA到 GPA的转换逻辑。为了加快翻译速度, qemu使用转译后备缓冲区( TLB)来缓存转译的结果。此外,为了避免在地址转换发生时使代码缓存和块链失效,所有已转换的块都是用 GPA进行索引,并且只有在两个基本块位于同一物理页面内时才执行块链。 GPA到 HVA的映射使用线性映射(即 HVA=GPA + offset)。
与 system-mode不同,在 user-mode中主机虚拟地址( HVA)的计算方式为:客户虚拟地址( GVA) + 常量偏移量。因此,这种转换比 system-mode中的转换快得多。
随着 IOT设备成为热门的攻击目标, IOT固件的漏洞挖掘也变得越来越重要。在测试程序时有两个挑战,第一个挑战是兼容性:许多 IOT程序依赖于设备的特殊硬件组件,因此如果没有硬件支持将无法继续测试;第二个挑战是代码覆盖率:众所周知,黑盒 fuzzer的代码覆盖率很低,而白盒 fuzzer在代码量很大的情况下容易跑崩。表 1对各种 fuzzer的性能进行了对比。
AVATAR旨在通过提供更好的硬件组件支持,进行嵌入式固件的动态分析。它通过构架一个有处理器模拟器( qemu)和真实硬件组成的混合执行环境来进行固件分析,其中 AVATAR充当的是 qemu和真实硬件之间的软件代理。这使得 AVATAR可以利用模拟器来执行和分析指令并将 I/O操作传输到物理硬件上。作者使用 S2E(白盒 fuzzer)来挖掘 Redwire Econotag Zigbee传感器的漏洞。因为是白盒 fuzzer并且物理硬件的配置也不高,预计 AVATAR的吞吐量会极低。
IOTFuzzer直接在真实设备上执行黑盒 fuzz。与传统的基于黑盒的 fuzz相比,他的主要优势就是通过目标设备的配套固件来执行 fuzz。通过自动分析配套固件程序中的数据流,可以更好的理解通讯协议,从而生成更好的测试样本,提高触发 bug的几率。也就是说,根据我们的评估, IOTFuzzer从来没有超过‘ 1样本 /秒’的吞吐量,这是很慢的。
Firmadyne并不执行 fuzz,它只是增加了 qemu-system-mode对固件支持的数量。它提供了对 ARM和 MIPS架构的支持,这些架构在商业中很流行。在硬件模拟方面, Firmadyne通过修改内核和驱动程序来完全模拟系统,以处理由于硬件的缺乏而导致的大量异常。与前两种解决方案相比,该方案能很快的适应新的 IOT固件。全系统模拟的吞吐量通常比 IOT设备要好。
Muench等人比较了不同配置下的黑盒 fuzzer的吞吐量,包括: IOT设备执行(直接将输入发送到物理设备)、部分模拟(只发送硬件请求)和完全模拟。他们的仿真基于 PANDA提供的图像重播功能。他们得出的结论是完全模拟( FE)具有最高的吞吐量,主要是因为 IOT处理器要比桌面级处理器慢很多。然而即使是桌面级处理器,吞吐量也不会超过‘ 15样本 /秒’。
AFL是一个非常著名的灰盒 fuzzer,它可以通过 qemu-user-mode进行二进制 fuzz。只可惜,因为缺乏必要的硬件支持, qemu-user-mode并不能模拟 IOT固件程序。例如:使用支持 qemu-user-mode的 AFL对固件进行模拟时全都失败了(表三)。此外,因为吞吐量第的问题,直接采用 Firmadyne进行完整的系统模拟并不可行。
总而言之,现有的固件 fuzzer并不能做到代码覆盖率的最大化,而最先进的 fuzzer(例如: AFL)却因为硬件的原因,无法直接用于固件 fuzz。目前为止还没有高效的 IOT灰盒 fuzzer。
AVATAR
IOTFuzzer
Firmadyne
Muench et al.
AFL
种类
白盒 fuzzing
黑盒 fuzzing
PoC
黑盒 fuzzing
灰盒 fuzzing
兼容性
高
高
高
高
低
硬件支持
混合
全硬件
全模拟
混合
不支持
代码覆盖率
中
低
N/A
低
高
吞吐量
极低
低
中
中偏低
高
0day检测
是
是
否
是
是
表 1:固件测试工具的比较
鉴于目前 IOT固件 fuzzer的不尽人意的现状,我们的目标是为 IOT固件设计一个高吞吐量的灰盒 fuzzer。为此,我们决定在模拟的基础上设计一个 fuzzer。这么做是出于两点考虑:首先,灰盒 fuzzer需要收集代码覆盖信息来作为样本变异的依据,正如 $2.1中所说,代码覆盖率检测并不是很难,由于大多数 IOT固件只有二进制程序,因此工具最好是基于模拟器的;其次是性能,根据 Muench等人的研究表明,虽然可以直接在 IOT设备上执行 fuzz,但是因为硬件配置的原因,使用完全模拟会更快,因为桌面级 CPU的处理速度更快。
Firmadyne最大的问题是吞吐量不够,因此即是在 system-mode下进行 fuzz,速度也不会超过‘ 15样本 /秒’。为了找到限制吞吐量的原因,我们使用了两种工具( basename和 uptime)分别测试在 system-mode和 user-mode下的执行时间,结果如表 2所示。根据测试结果可得出:如果在 fuzz时使用 user-mode将明显的提高吞吐量。导致时间差异的原因如下:
B1、 内存地址转换。在 system-mode中, qemu使用软件模拟 MMU对所有内存访问进行地址转换;相比之下, user-mode的地址转换要简单的多。因此,即使只考虑 user-mode本身执行所花费的时间,也要比 system-mode少得多。
B2、 动态代码翻译。 User-mode下做代码翻译比 system-mode要快;在 system-mode下,块链接仅限于同一物理页中的基本块,这意味着在 user-mode中调用转换程序的频率更高。
B3、 系统调用模拟。在 user-mode中系统调用是由主机操作系统和硬件直接处理的,因此它比 system-mode要快得多,因为在 system-mode中操作系统和硬件设备都得被模拟;因为需要让程序正确的执行,就需要硬件模拟,但并不是所有的系统调用都需要依赖硬件模拟,换言之,并不是所有的系统调用都需要模拟。
在本次工作中,我们解决了上述的三个问题,并大幅提高了 fuzz 的吞吐量。
System-mode(ms)
User-mode(ms)
程序
总用时
系统执行
系统代码翻译
用户执行
用户代码翻译
总用时
系统执行
用户执行
用户代码翻译
Basename
4.08
1.79
0.53
1.41
0.35
0.34
0.02
0.11
0.22
Uptime
7.48
2.39
0.76
2.79
1.55
0.89
0.04
0.31
0.54
表 2: system-mode和 user-mode的运行时性能
这项工作的目标是设计一个 IOT固件的高吞吐专有灰盒 fuzzer,在 $2中提到,想要实现这个目标就需要解决两个问题:兼容性和性能; system-mode可以解决兼容性的问题,但是性能较差; user-mode可以解决性能问题,但是兼容性较差。我们提出了一种名为“增强进程模拟”的新技术,它同时拥有了 system-mode和 user-mode的优点。
一般来说增强进程模拟的目标是在 user-mode中正确执行大量固件程序,并满足以下要求:
(1) 可以在系统模拟器(例如 qemu-system-mode)中正确的执行 IOT固件,所幸,大部分 IOT固件都能在 Firmadyne下运行;
(2) 固件为 POSIX兼容的操作系统。所幸许多固件镜像都是用 Linux作为操作系统。
通过增强进程模拟,我们将实现如下目标:
1、 透明度。 在增强进程模拟中运行的用户级程序的行为应该与在 system-mode用运行的程序一样。
2、 效率。 由于吞吐量是样本变异的主要因素,增强进程模拟需要尽可能高效。理想情况下,它应该接近于纯 user-mode的性能。
为了实现上述设计目标,我们采用了一种新颖的方式对 system-mode 和 user-mode 进行混合。图 1 简单解释了我们的方法。
图 1 :增强进程模拟的概述
首先, IoT 固件在系统模式下启动,模拟器和用户级程序(包括 fuzzer)在模拟器内正确启动。当被 fuzz的程序达到预定的点(如 main函数的入口点,或接收到第一个网络数据包)后,进程的执行被迁移到 user-mode,以获得较高的执行速度。只有在极少数情况下,程序会回到 system-mode执行,以保证程序能正确执行。
为了降低迁移成本,将会在这两种模式之前共享内存。更具体地说, system-mode的物理内存被分配为一个内存映射文件(称为 RAM文件)。这个 RAM文件也映射到 user-mode的地址空间。但不同的是 system-mode和 user-mode会以不同的方式访问这个 RAM文件; system-mode将 RAM文件视为物理内存,因此通过物理地址访问它;而 user-mode通过虚拟地址访问共享内存。因此, RAM文件中的物理页面需要按照页面粒度通过它的虚拟地址映射到 user-mode的地址空间。因此,当 user-mode未建立页面映射时,需要将进程迁移到 system-mode以建立此映射。我们将在 $3.2中详细介绍内存映射的细节。
在到达系统调用之前,只要有适当的内存映射,进程就能在 user-mode中正确执行。而在到达系统调用时,如果直接在物理机系统中执行固件的系统调用一般不会成功,因为物理机和固件不仅是软件不同,硬件也不同。为了确保透明性,我们需要将执行迁移到 system-mode中来处理系统调用,当系统调用结束时,我们将执行迁移回 user-mode;我们会在 $3.3中详细讲解技术细节。
用 AFL对程序做 fuzz时,当程序执行到预定点, AFL的 fork服务器会在这个点上重复 fork一个新的程序实例(这个点称为 fork point),并提供随机样本输入。同样的,在固件 fuzz中,我们将在 system-mode中启动固件,并启动指定程序。使用 DECAF(基于 system-mode的动态分析平台)提供的虚拟机自省( VMI),我们能够监控指定程序的执行,并在执行到预定点时得到通知。
此时,我们将遍历指定进程的页表,收集虚拟到物理页映射信息,并将其发送到 user-mode。然后对每次虚拟地址到物理地址的映射都通过 user-mode建立映射,建立映射所需要用到的 mmap函数如下:
上述代码顾名思义。本质上,我们将 RAM 文件的一个物理地址作为偏移量映射到指定的虚拟地址。参数 prot 由对应的页表项的保护位决定。
从此开始, system-mode暂停运行, CPU状态被发送到 user-mode,然后在 user-mode继续运行。
在 user-mode的进程执行期间,如果访问内存地址已经映射在此地址空间,那么程序执行不会出错。否则,物理机 CPU将引发页面错误。我们在 user-mode中为页面错误注册了一个信号处理程序,如果出现页面错误时物理机系统会把页面错误事件传递给 user-mode,当收到这个信号时, user-mode会记录故障处指令的 CPU状态,然后暂停执行,并将 CPU状态传递给 system-mode,期望 system-mode能处理页面故障并建立故障虚拟地址的新映射。
当 system-mode接收到 CPU状态并恢复执行时,模拟的 CPU会因为页面不存在而引发一个页面错误。页面错误处理程序将在物联网固件的操作系统中响应此页面故障,并尝试建立映射。大多数情况下,操作系统会建立一个类似映射(取决于内核线程和中断处理程序的调度),而导致页面错误的指令也将被重新执行;极少数情况下,如果操作系统因为某些原因无法建立映射,那么进程将被杀死。
这里的一个关键问题是确定何时建立了页面映射或何时发生错误,这样我们就可以在不同模式之间快速切换,以最大限度的提高执行速度。事实上这个问题的答案是很重要的,因为操作系统会同时处理多个任务,可能会同时发生大量的页面切换。
我们会用工具测量每个基本块的结束时间,以确认映射建立的时间。如果当前执行在指定的进程(或线程)内,就说明程序已从内核返回到用户空间以恢复错误指令。该映射必须在 TLB中存在,以便我们可以直接找到这个映射。此时,我们将映射信息和 CPU状态传递回 user-mode,而 user-mode将通过调用 mmap函数创建新的映射并继续执行。
如果因为某些原因出现了错误,进程被杀死了,我们可以通过 DECAF提供的虚拟机自省( VMI)功能收到消息,然后终止两边的执行。
当前的操作系统会在进程启动时以一种惰性的方式加载内存,所有的代码页都被分配到它的地址空间,直到第一次内存访问导致页面错误之前,都不会建立虚拟页到物理页的映射。
这种惰性设计对 fuzzer的性能有不利的影响。正如我们在 $4.1中讨论的,每个 fuzz迭代的子进程都重复的从父进程派生出来。因此,总有一堆由未映射代码页引起的页面错误。这对我们的系统伤害极大,因为处理页面错误的开销远比在物理机系统上做本地处理大得多。
为了解决此问题,我们决定在物理内存中预加载给定的进程代码页,并在两种模式之间执行映射。这有助于我们避免在每次 fuzz迭代时重复加载代码页,从而提高 fuzz吞吐量。为此,我们在引导过程中模拟 system-mode对每个程序代码页的访问,以强制操作系统将每个页映射到进程的地址空间,从而减少有这些预加载页面引起的页面错误的数量。
程序中的系统调用会因为底层硬件、固件和需求的不同而不同。因此,如果没有正确的处理由系统调用引起的异常, user-mode下的 IOT固件可能会崩溃;例如:大多数 IOT设备都有网络接口,而本地模拟器上没有此接口;当 user-mode中的 IOT程序执行需要与 IOT系统中特定的网络接口交互时,就会引发故障;另一种情况时访问桌面计算机未定义的 NVRAM的系统调用。
因此,为了确保固件能正确执行,我们必须将系统调用从 user-mode重定向到 system-mode。更具体的说,当 user-mode遇到系统调用时,他会暂停执行,保存当前的 CPU状态,并将其发送给 system-mode; system-mode接受到 CPU状态并继续执行,这将导致客户系统直接切换到内核模式以处理相应的系统调用。同样,由于客户系统的内核是多任务的,在系统调用返回之前可能会发生环境变化;因此,我们会用处理页面错误的方式来处理此问题,在每个基本块的末尾安装工具。如果当前的基本块在内核空间( r0),但下一个程序计数器在用户空间( r3),并且当前执行环境是针对执行系统调用的线程的,那么我们就会检测系统调用何时返回;此时 system-mode暂停执行,保存 CPU状态,并将其传递回 user-mode,然后继续执行。
在检查 IOT程序发出的系统调用时,我们发现许多系统调用都与文件系统有关。 IOT固件程序要么访问已有的文件或目录,要么就临时创建文件或目录。我们决定对这组系统调用做一些优化。我们从固件中映射文件系统,并将其作为物理机操作系统中的一个目录挂载,这样 user-mode就可以直接访问它了;同样地, user-mode就可以直接将文件系统相关的系统调用传递到物理机操作系统,而不是重定向到 system-mode。
正如 $5.3所示,与文件系统相关的系统调用会大幅消耗系统资源,因此这种优化对整体性能影响很大。
利用 $3中介绍的技术,我们设计了基于 AFL的 IOT固件 fuzzer—— Firm-AFL。在 $4.1中,我们将会介绍 AFL的工作流程,然后在 $4.2中,我们会介绍如何将增强进程仿真集成到 AFL中。
AFL是一个根据代码覆盖率进行变异的灰盒 fuzzer。它维护了一个样本集,该集合储存了所有的样本,包括用户选择的初始样本,以及从现有样本中变异而来的新样本,这些样本会使程序的代码覆盖率最大化。
启动 AFL的主程序在 afl-fuzz中。它从样本集中挑选一个原始样本执行一次随机变异,生成一个新的随机样本,并将这个样本喂给目标程序(假设目标程序是一个二进制可执行程序)。
AFL会使用 qemu-user-mode启动程序,并从 fuzz过程中收集目标程序的代码覆盖率信息,以检测分支转换。目标程序的代码覆盖率信息被编码并储存在位图中。
由于在 fuzz过程中需要反复执行目标程序, AFL利用“ fork”这种机制来提高效率。它首先运行目标程序到特定位置(例如: main函数入口),使程序的代码和数据正确初始化,然后重复的从它派生出子进程;通过这种方式可以快速跳过新进程的初始化设置。因此,父进程被成为 fork-server;然后将样本喂给派生出的子进程中,覆盖率信息被收集并储存在位图中;而位图在三个进程( afl-fuzz, fork-server,子进程)之间共享。 Afl-fuzz将比较子级中的位图实例和过去所有执行结果积累的位图,已确定是否应该将这个变异的样本保留并存储在样本集中。
我们希望在不改变原有 AFL的情况下,加入对 IOT固件 fuzz的功能。为此,我们将 qemu-user-mode替换为增强进程模拟,其余组件保持不变。新的工作流程如图 2所示。
图 2:Firm-AFL 概述
为了 fuzz IOT固件中的程序,我们需要启动固件镜像,并在系统启动后启动程序。这是在 fork-server中的 system-mode中完成的。
我们利用 Firmadyne来模拟固件。我们还在 Firmadyne中加入了 DECAF中的虚拟机自省( VMI)功能。这样我们就能够知道目标程序何时启动或终止,还可以知道目标程序何时执行到指定位置。
AFL选择的默认分支点是 main函数的入口点。在我们的案例中,我们希望通过网络接口触发 IOT程序中的漏洞;因此我们会 hook网络相关的系统调用,当这些系统函数被第一次调用时就会创建分支点。
在 AFL的工作流程中,我们可以简单地利用系统调用的分支点来派生一个子进程并启动一个新的 fuzz实例。而在我们的例子中,我们不仅需要为 user-mode派生一个子进程,而且还需要为 system-mode派生一个虚拟机实例,因为两个模式必须同步。
事实上,创建一个虚拟机需要的系统资源太多,所以我们会创建一个虚拟机的快照;当 fuzz完成时我们可以恢复快照。 qemu-system-mode提供了保存快照的功能,将所有 CPU寄存器和内存空间保存到特定的文件;然后读写这些文件的速度依然缓慢。
在我们的系统中,我们基于写时复制原理实现了一个轻量级的快照机制。更具体地说,我们首先将映射到 qemu-system-mode的 RAM文件标记为只读;那么,内存写操作将导致页面错误,我们复制这个页面,然后把这个页面标记为可写。因此我们记录在一次 fuzz期间修改的所有内存页;当恢复快照时,我们只需要将这些记录下来的页写回即可。
输入是通过检测系统调用提供的。对于从网络接口接收输入的 IOT程序,我们直接在 user-mode中检测与网络相关的系统调用;因此我们不需要将这些系统调用重定向到 system-mode。
收集代码覆盖率信息。由于大部分执行都发生在 user-mode中,而 system-mode仅用于处理页面错误和部分系统调用,所以我们可以像原始的 AFL那样在 qemu-user-mode中插入分支转换来计算覆盖位图。
在本节中,我们会评估我们的 Firm-AFL fuzzer。本节的目的是测试我们的方法是否已经解决了性能瓶颈并实现了两个目标;简而言之,我们会回答以下几个问题:
透明度。 Firm-AFL在对固件进行 fuzz时是否可以像 system-mode那样正确的执行 IOT程序?
效率。 Firm-AFL的吞吐量(样本 /秒)相比于完全基于 user-mode的 fuzzer的吞吐量如何?
优化的有效性。 我们的优化技术成功的解决了已知的性能瓶颈吗?
漏洞挖掘的效率。 在 IOT固件漏洞挖掘方面, Firm-AFL到底是否有用?
我们在测试时使用了三套程序。第一组程序时两个标准: nbench和 lmbench。它们用于测试模拟的正确性和系统资源开销。第二组程序由来自四个不同的供应商的七个 IOT程序组成(表 3)。我们选择这些程序是因为它们是处理网络请求的关键程序,因此是远程攻击的理想目标。它们用于测试灰盒 fuzzer的性能。第三个数据集时 Firmadyne数据集,其中包括了其 HTTP和 uPnP服务与 15个 1day攻击的相关固件(表 6) .我们收集这些数据是为了评估 Firm-AFL漏洞挖掘的透明度和效率。
实验(除了 $5.4外)是在一台 8核 Intel( R) Core( TM) i7-3940XM 3.00GHz CPU和 23.5GB RAM 1TB硬盘上进行的。操作系统为 Ubuntu 16.04.5 LTS。 qemu和 AFL的版本分别为 2.10.1和 2.06b。我们在每十次迭代后获得所有测量值。我们最终报告的数字是 20次测量的平均值。默认情况下,我们将分支点设置在接收到网络数据后的位置,并由 AFL引擎提供随机输入。
为了评估增强进程模拟的透明度,我们首先使用 nbench测试软件进行测试。在生成输出之后,基准测试将把实际输出和预期输出进行比较。如果生成的输出是错误的,则意味着模拟出错了。结果表明,该系统能够在无误差的情况下完成所有的基准测试。
我们还利用 Frimadyne的数据库对 Firm-AFL的透明度进行了评估。我们收集了 120个带有 HTTP服务和独特设备模型的固件镜像。我们从固件镜像中提取并使用 chroot挂载文件系统;但是因为系统环境的原因,这些程序刚启动就崩溃了;然后我们在尝试 system-mode和增强进程模拟下使用正常样本输入(初始样本)并运行;结果是在这两种模式下所有的程序都能正常运行。对于固件程序,我们需要进一步比较 system-mode和增强进程模拟下生成的系统调用序列,确认系统调用的序列是相同的。
最后我们对每个表 6中的漏洞我们都使用全 system-mode和增强进程模拟进行复现和利用并进行了执行跟踪。我们已经确定两种模式的执行轨迹是相同的。
综上所述,本次测评表明 Firm-AFL 可以像全 system-mode 那样提供完全透明的模拟。
程序
文件大小 (KB)
描述
厂商
硬件类型
硬件名称
版本
CPU架构
Cgibin
129.4
CGI binary program
DLINK
Router
DIR-815
1.01
MIPSEL
Httpd
90.2
Embedded HTTP server
Dnsmasq
162.3
Embedded DNS server
Dropbear
307.3
Embedded SSH server
TPLINK
TL-WR940N
V4_160617
MIPSEB
Httpd
169.2
Embedded HTTP server
Jjhttpd
103.3
Embedded HTTP server
Trendnet
TEW-813DRU
V1(1.00B23)
lighttpd
327.3
Embedded HTTP server
netgear
WNAP320
3.0.5.0
表 3:测评中使用的 IOT程序
我们从两个角度测试进行效率测试。首先我们使用 bench跑分对增强进程模拟的性能开销进行评估。
nbench 的结果如表 4 所示。 nbench 是一个测试 CPU 的测试组件。这个测试的增强模式并没有施加太多开销,主要是因为这些测试并没有很多内存同步操作和重定向系统调用,所以相对简单;为了测试重定向系统调用产生的开销,我们使用了 lmbench 。结果如表 5 所示,可以看到对于普通的系统调用(例如文件相关的系统调用),开销几乎可以忽略不计;但是对于需要重定向的系统调用(例如 TCP 相关的),开销就要大得多。
跑分项
增强模式
用户模式
速度下降比例
Numeric sort
679.12
686.56
1.08%
String sort
78.36
79.54
1.48%
Bitfield
3.47E+08
3.45E+08
0%
FP emulation
163.85
161.72
0%
Fourier
1383.6
1384
0%
Assignment
20.45
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2021-2-23 09:38
被pureGavin编辑
,原因:
上传的附件: