上文我们介绍了USB协议栈和USB模糊测试的历史,其中讲到了一些过去的常用技术和工具,不过它们都存在着一些问题。今天,我们将介绍最新的5种USB模糊测试的解决方案。
Syzkaller
不过幸运的是,最近安德烈•科诺瓦洛夫(Andrey Konovalov)在Google上添加了Syzkaller USB模糊测试支持,并证明了它能够发现更多漏洞。 Andrey解决了使用Syzkaller 对USB进行模糊测试时的两个主要问题:
1.内核任务的代码覆盖率;
2.同一内核映像中的设备模拟。
由于USB事件和操作发生在IRQ或内核上下文,而不是进程上下文中(例如,旧内核中的khub内核任务中的USB插入检测),因此基于系统调用的跟踪和代码覆盖不起作用。为了能够在内核中的任何位置报告代码覆盖率,我们需要使用扩展的KCOV内核API来注释与USB相关的内核源代码(例如hub.c),以报告代码覆盖率。不过,Syzkaller不使用QEMU,而是使用gadgetfs将模糊测试工具的内核驱动程序暴露给用户空间,然后用户空间可以管理输入内容以进行模糊测试。通过在内核配置中启用USB主机协议栈和USB从机协议栈,并使用虚拟HCD和UDC驱动程序将它们连接在一起。如下所示,Syakaller能够模糊USB主机设备驱动程序,如USB HID,海量存储等通过用户空间对USB模糊测试工具的内核驱动程序进行模拟。
Syzkaller USB模糊测试工具可能是第一个真正的基于覆盖的USB主机设备驱动模糊测试工具,不过这还要归功于现有的Syzkaller基础设施以及对USB主机和从机发起的黑客技术。目前Syzkaller已经被发现了大量的漏洞和错误,它的局限性开始显现,目前发现的大多数问题都在驱动程序的初始化阶段(例如探测)。在用户空间中,模糊测试工具能够通过探索USB从机描述符中的不同VID / PID组合,来配置模糊测试工具内核驱动程序,进而表示任何USB从机。一方面,Syzkaller能够触发几乎所有USB主机设备驱动程序进行加载,因此代码覆盖功能特别强大。另一方面,由于在用户空间模糊测试工具或模糊测试工具内核驱动程序内没有提供用于特定设备的真实模拟代码,因此大多数模糊测试在驱动程序初始化之后停止,因此仅覆盖驱动程序的一小部分。
最新的USB模糊测试技术
如上所述,大家可能已经注意到,所有这些模糊测试解决方案都集中在USB主机协议栈上,尤其是USB主机设备驱动程序上。另外,由于人们经常将USB引用到USB主机协议栈,并且这些设备驱动程序因包含比内核中的其他组件(例如Windows上的设备驱动程序)更多的漏洞而闻名。但是,以上讲的所有USB模糊测试工具所涵盖的部分都非常少。所以未来的USB模糊测试技术必须解决这个问题。
以下是现有的5种解决方案:HCD驱动程序模糊测试、协议引导或状态模糊测试(Protocol-guided/Stateful fuzzing)、Android USB模糊测试、协议引导或状态模糊测试、Type-C/USBIP/WUSB模糊测试,下面我们就来详细了解一下。
HCD驱动程序模糊测试
如果我们总是将自己限制在USB主机协议栈中,那么HCD驱动程序就会被忽略。与设备驱动程序不同,HCD驱动程序无法通过系统调用在用户空间访问(不过可以使用sysfs调整某些参数)。相反,它们从上层(内部)的USB内核(例如,usb_submit_urb)和HCD层(外部)的DMA接收输入内容。从安全角度来看,外部输入会比内部输入带来更多的威胁。
要直接对HCD驱动程序的内部输入进行模糊测试,我们需要能够修改暴露给USB内核的内核API的参数,并从HCD驱动程序获取代码覆盖率。为了直接模糊HCD驱动程序的外部输入,我们需要对DMA缓冲区和事件队列以及来自HCD驱动程序的代码覆盖率进行修改。请注意,由于TX和RX的代码路径不同,因此在这两种情况下代码覆盖率通常不同。因此,我们需要一个细粒度代码覆盖率报告来反映这一情况。对DMA缓冲区和事件队列进行修改实际上是在构建具有模糊功能的HCD仿真器,对于诸如Intel XHCI之类的常见HCD驱动程序,QEMU已经提供了相应的HCD模拟(例如qemu / hw / usb / hcd-xhci.c),并且可以尝试在其中添加模糊测试功能。对于QEMU不提供HCD模拟的其他HCD驱动程序,需要从头开始构建HCD模拟。
USB从机协议栈模糊测试
截止目前,我们还没有对USB从机协议栈进行系统的模糊测试。这种做法在过去是没问题的,因为我们经常假设USB从机不会发生恶意攻击。然而,在嵌入式系统(例如Android设备)中广泛使用的USB OTG和DRD控制器,已经将包括USB从机在内的设备也当作了攻击目标。例如,我们现在经常会用USB接口对手机进行充电,而没有人希望他们的手机在充电期间被黑客攻击。在架构上,Syzkaller USB 模糊测试工具设想了一种模糊USB从机协议栈的方法,如下所示:
用户空间模糊测试工具不会让用户空间模糊测试工具与USB模糊内核驱动程序进行通信,而是与USB主机设备驱动程序进行通信。这样,模糊测试工具活动将通过USB主机协议栈传播到USB从机协议栈。因此,我们需要配置内核,以便在同一个内核映像中启用所有不同的gadget函数,以及代码覆盖率报告。然后,我们可以模拟USB从机内核和USB从机功能驱动程序(UDC驱动程序除外)。
Linux-USB Gadget 驱动框架(简称 Gadget )实现了 USB 协议定义的设备端的软件功能。相对于 Linux USB 主机驱动而言。Gadget 框架提出了一套标准API, 在底层, USB 设备控制器 (USB Device Controller, UDC) 驱动则实现这一套 API, 不同的 UDC (通常是 SOC 的一部分) 需要不同的驱动, 甚至基于同样的 UDC 的不同板子也需要进行代码修改,这一层我们可以称之为平台相关层。
请注意,Syzkaller设想了一种对USB从机协议栈进行模糊测试的方法,这是由于Syzkaller的架构和限制而产生的自然结果。由于Syzkaller是一个系统调用模糊测试工具,这意味着输入突变发生在系统调用参数中。但这并不意味着我们必须在系统调用层(例如用户空间)进行模糊测试。如果再次查看上图,我们可以找到一条从模糊测试工具到模糊测试目标的路径(例如,USB主机设备驱动程序或USB从机驱动程序)。那么,我们怎么才能知道所有模糊输入是否都被成功传播到目标而不是被中间层过滤?这就要看基于系统调用的模糊测试是否适合内核中的USB模糊测试。同样,Syzkaller USB模糊测试工具可以适应Syzkaller本身的限制,而不是考虑从头开始构建USB模糊测试工具(例如,USB主机或从机协议栈)。
所以,缩短模糊测试路径将解决以上存在的问题。例如,我们可以通过在QEMU中构建USB UDC模拟工具/模糊测试工具来摆脱整个USB主机协议栈,直接启用UDC驱动程序模糊测试。但是,这并不意味着任何DMA写入都可以转换为对上层USB从机驱动程序的有效USB请求。因此,缩短模糊测试路径只是暂时的解决办法。所以最终的解决方案还是通过修改算法和代码覆盖粒度。最后,我们可能需要在协议栈中的不同层上使用不同的模糊测试工具,以确保所有模糊输入都被传播到目标中而不进行过滤。例如,我们可能需要构建一个USB主机模拟工具/模糊测试工具,直接向不同的USB从机驱动程序发送USB请求。
Android USB模糊测试
通过维护自己的内核分支并实现额外的USB从机功能驱动程序(例如MTP),Android可能是USB从机协议栈的主要使用用户。与典型的USB主机相比,Android设备中的OTG/DRD支持也使攻击面增加了一倍。不过最大的挑战是运行一个Android内核映像,其中包含使用QEMU的真实Android设备使用的相应UDC/DRD驱动程序。由于SoC可以自定义,在QEMU中运行非AOSP内核会带来额外的困难。这就是为什么许多Android模糊测试仍需要借助物理设备来进行。
协议引导或状态模糊测试
在USB从机协议栈模糊测试中,我们讨论了为什么我们可能想缩短模糊测试路径,因为我们想要避免模糊输入内容在到达目标之前被过滤。事实证明,要想实现路径的缩短,过程要比想象的复杂得多。如果我们再次查看上图(Syzkaller中USB从机模糊测试),则模糊测试工具输入的进程是从系统调用开始,并在最终传送到USB从机协议栈之前传递不同的USB主机设备驱动程序。虽然模糊路径很长,并且可以在此过程中过滤模糊输入。但同时,中间的这些额外层保证发出的任何模糊输入都是合法的USB请求,其携带由正确的驱动程序状态触发的相应协议的有效载荷。例如,模糊测试工具经由USB大容量存储驱动程序生成的最终USB请求可能包含一个合法的SCSI命令(例如read),该命令由USB主机设备驱动程序的内核逻辑而不是初始化部分触发。
这就是我称之为“协议引导或状态”的模糊测试。可以看出,在一个层中垂直“深入”是很重要的,例如,在初始化或探测阶段之后探索内核驱动程序的其他部分。简单地说,要对USB主机或从机驱动程序进行模糊测试,我们需要与目标建立虚拟连接(例如,确保内核驱动程序已初始化并准备好处理输入内容),并引导模糊测试工具学习输入内容(例如USB大容量存储中的SCSI协议)。最后,在包含其他层以重用现有协议和状态控件之间进行权衡,从而增加模糊路径和复杂性,并在模糊测试工具中直接实现轻量级协议引导或状态模糊测试,以减少模糊测试路径。
Type-C/USBIP/WUSB模糊测试
除了USB主机和USB从机之外,USB中还有更多东西,包括USB Type-C,USBIP,WUSB等。虽然我们可以重用USB模糊测试中学到的一些经验教训,但这些技术引入了不同的软件协议栈。 需要不同的注意力来解决他们的怪癖。