您还未登录! 登录 | 注册 | 帮助  

您的位置: 首页 > 软件测试技术 > 其他相关 > 正文

现有USB模糊测试技术的总结(上)

发表于:2019-09-05 作者:xiaohui 来源:嘶吼
Syzkaller(Google 团队开发的一款针对 Linux 内核进行模糊测试的开源工具),最近开始支持 USB 模糊测试,并且已经在 Linux 内核中发现了 80 多个漏洞。目前,鉴于 USB 本身的复杂性导致的安全性的影响和潜在的大量漏洞,几乎所有模糊测试专家都开始将他们的模糊测试技术应用于 USB 的模糊测试中。

什么是 USB 协议栈?

按着协议,USB 分为 USB host(USB 主机) 和 USB device/gadget(USB 从机),USB 主机能够主动发起会话而 USB 从机则不能发起会话。HOST 是主机,好比电脑端那个 USB,简而言之,主机好比电脑端那个 USB 接口,从机好比就是连接到 USB 接口的 U 盘。当我们谈论 USB 时,通常说的是 USB 主机,例如带有标准 USB 端口的笔记本电脑。下图是 Linux USB 主机栈。从下到上,分为硬件、内核空间和用户空间。

 


USB 主机控制器设备(又名 HCD)是连接到系统 PCI 总线的 PCI 设备,通过 USB 端口提供 USB 连接支持。根据 USB 技术的发展,它也被称为 USB 1.x 的 UHCI / OHCI,USB 2.x 的 EHCI 和 USB 3.x 控制器的 XHCI。要使内核使用此控制器,我们需要一个 USB 主机控制器驱动程序,它可以设置 PCI 配置和 DMA。上面是 USB 内核,实现底层 USB 协议栈,并使用通用内核 API(submit /recv URB)抽象发送 / 接收 USB 数据包的方式。上面是不同的 USB 从机驱动程序,例如 USB HID 驱动程序和 USB 大容量存储驱动程序。这些驱动程序会实现不同的 USB 类协议(例如,HID,大容量存储),为内核中的其他子系统(例如输入和数据块)提供粘合层,方便用户空间(例如创建 /dev 节点)。

 

由于 Linux 也广泛用于嵌入式系统,例如一些 USB 软件保护器(USB Dongle),USB 从机指的是 Linux 内的 USB 软件保护器硬件和 USB 模式。 USB 从机与 USB 主机模式完全不同。下图显示了 Linux 内核中的 USB 从机协议栈。

 


底部是 USB 从机控制器(又名 UDC),与 HCD 一样,UDC 也在 PHY 层内实现特定版本的 USB 标准。但是,与英特尔最常用的 HCD 不同,UDC IP 来自不同的硬件供应商,例如 DWC2/3,OMAP,TUSB 和 FUSB。这些控制器通常具有其自己的设计规范,并且当它们支持 USB On-The-Go(又名 OTG)模式时也可遵循 HCD 规范(例如 XHCI 规范)。 OTG 允许 UDC 在 USB 主机和 USB 从机模式之间切换。例如,当 Android 设备以 MTP 的形式与笔记本连接时,Android USB 从机控制器处于 USB 从机模式。如果 USB 闪存驱动程序插入 Android 设备,UDC 将在 USB 主机模式下工作。支持 OTG 的 UDC 也被 USB 3.x 标准中的双角色设备(Dual-Role Device,DRD)控制器取代。因此,不需要 OTG 数据线来切换 UDC 的角色,因为角色切换是在 DRD 控制器的软件中完成的。

 

要使用 UDC,你需要在内核中使用 UDC 驱动程序,通过行业标准总线( ( 包括 AMBA AHB 和 AXI 接口 ) )提供连接和配置,并为更高层设置 DMA。与 USB 主机协议栈中的 USB 内核一样,USB 从机协议栈中的 USB 从机内核也提供 API,通过回调和配置来注册和实现 USB 从机函数。例如,我们可以通过请求现有的大容量存储函数(f_mass_storage)将 USB 描述符传递到 USB 从机内核并实现典型的 USB 大容量存储设备。对于诸如 MTP 的更复杂的协议,用户空间守护进程或库提供协议逻辑并通过例如 configfs 或 usbfs 与从机函数通信。

USB 主机控制器 ( Host Controller )

USB 的拓扑结构决定了主机控制器就是最高统帅,没有主机控制器的要求,从机永远不能主动发数据。所以主机控制器在 USB 的世界里扮演着重要的角色,它是幕后操纵者。

比如说 USB 主机发送 Setup 数据包获取设备描述符是怎么发出去的 ? 这个过程包含很多信息,比如:如何在 D+ 和 D- 这两根线上传过去的、又传过来的。 这一切的工作都是主机控制器给我们做的,USB 主机控制器的规范有很多种,比如 UHCI/OHCI。

什么是 USB controller?

USB 设备和主机的接口就是 host controller,一个主机可以支持多个 host controller,比如分别属于不同厂商的。那么 USB host controller 本身是做什么的 ? 很简单用于控制,控制所有的 USB 从机的通信。 CPU 把要做的事情分配给主机控制器,然后自己想干什么就干什么去,主机控制器替他去完成剩下的事情,事情办完了再通知 CPU。否则让 CPU 去盯着每一个从机做每一件事情,那是不现实的。

控制器的主要工作是什么 ? 把数扔出去,把数拿回来。绝对不应该偷偷加工数据。

主机控制器控制总线上包的传输, 使用 1ms 或 125us 的帧。在每帧的开始时,主机控制器产生一个帧开始包 ( SOF: Start of Frame ) 。

SOF 包用于同步帧的开始和跟踪帧的数目,包在帧中被传输,或由主机到从机 ( 输入事务 ) ,或由从机到主机 ( 输出事务 ) 。传输总是由 主机发起的 ( 轮询传输 ) 。回此每条 USB 总线只能有一个 主机。每个数据包的传输都有一个状态阶段同 ( 同步传输除外 ) ,数据接收者可以在其中返回 ACK ( 应答接收 ) ,NAK ( 重试 ) ,STALL ( 错误条件 ) 或什么也没有 ( 混乱数据阶段,设备不可用或已经断开 ) 。

USB 模糊测试的历史

FaceDancer

由于可编程 USB 硬件模糊测试工具——FaceDancer的出现,USB 模糊测试开始吸引更多的关注。它支持 USB 主机和从机模式模拟,并允许发送预先形成带有漏洞的 USB 请求和响应。 Umap/Umap2提供了一个用 Python 编写的模糊测试框架,它具有面向 FaceDancer 的不同 USB 从机和响应模板。TTWE 框架通过使用两个 FaceDancer 分别模拟 USB 主机和 USB 从机来实现 USB 主机和 USB 从机之间的 MitM,此 MitM 允许两个方向的 USB 数据包突变,从而实现双方的模糊测试。

目前所有这些解决方案都集中在 USB 主机协议栈上,其原因是人们假设恶意 USB 从机不是恶意的 USB 主机(例如笔记本电脑),并且大多数 USB 从机固件都是闭源的,因此很难被分析。这意味着,大多数漏洞 / 错误存在于 USB 内核(用于解析 USB 响应)和一些常见的 USB 驱动程序(例如键盘)中。这些解决方案的优点是能够完全模拟 USB 从机。但是,在我看来,却有两方面不足:

1. 过于依赖硬件;

2. 目标反馈有限。

由于 FaceDancer 速度很慢,这使得任何基于它构建的解决方案都无法扩展测试功能。由于在实践中,经常需要将 FaceDancer 和目标设备作为模糊测试的基本要素,所以,这也对 FaceDancer 的可扩展性带来了更多挑战。反馈是另一个重要问题,模糊输入的突变是基于模板和随机化的,除了系统日志记录之外,没有来自目标的实时反馈 ( 例如代码覆盖率 ) 。因此,模糊测试的准确率是非常不可信的。

为了摆脱硬件依赖性,使用虚拟化 ( 例如 QEMU ) 来进行保存。vUSBf使用 QEMU/KVM 运行内核映像,并利用 QEMU 中的 USB 重定向协议将对 USB 从机的访问重定向到由模糊测试工具控制的 USB 模拟工具,如下所示:

 


虽然 vUSBf 提供了一个很好的编排体系结构来并行运行多个 QEMU 实例,以此解决可扩展性问题,但模糊测试工具本质上是基于模板的,而反馈也还仍然依赖于系统日志记录。

 

POTUS

为此,有研究人员开发了POTUS 项目,POTUS 项目也可以发现位于 Linux USB 驱动程序的漏洞。

2017 年,伦敦大学的安全研究人员发布了 POTUS 工具,这是一种可以发现 Linux USB 设备驱动程序漏洞的工具。该工具通过设置虚拟机,通用 USB 设备以及故障注入,发送模糊符号等技术来测试 USB 驱动程序继而查找漏洞。

研究人员通过 POTUS 测试 USB 驱动程序发现了两个 Linux 内核漏洞。一个是 CVE-2016-5400,USB 设备驱动程序中用于与 Airspy 软件定义无线电(SDR)通信的内存泄漏漏洞,而另一个是自 2003 年以来已存在的 Linux 内核的乐高 USB 塔驱动器使用后释放漏洞(无 CVE 标识符)。

POTUS 的工作原理如下所示:

 


systemtap 是一个诊断 linux 系统性能和功能问题的开源软件,并且允许开发人员编写和重用简单的脚本深入探查 linux 系统的活动,可以快速安全的提取过滤总结数据,以便能够诊断复杂的性能或功能问题。

 

在 USB 模糊测试中,SystemTap 用于检测内核存在的漏洞,并将漏洞数量记录下来。基于不同状态下的故障数量的路径优先级排序算法可以控制 " 分叉(fork)" 的数量。fork ( ) 函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者输入的变量不同,两个进程也可以做不同的事。一个进程调用 fork ( ) 函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同,相当于克隆了一个自己。

给定路径的故障数量表示代码覆盖率,因此,故障数量越大则代码覆盖率越高。另外,POTUS 还在 QEMU 中实现了一个通用的 USB 虚拟从机,以使用可配置的设备描述符和数据传输来模拟不同的 USB 从机。 虚拟从机中的 USB 驱动程序(USB 驱动程序)使用系统调用来使用暴露在虚拟从机的不同设备节点。与 vUSBf 相比,POTUS 就具有模糊测试反馈机制(通过计算路径内的故障数量),从而支持更多 USB 从机模拟。但是,在 USB 驱动程序中模拟某些 USB 从机操作的手动进程、符号执行的基本限制——路径爆炸( path explosion),以及依赖于路径故障数量的未知有效性和局限性,使得 POTUS 很难被广泛使用。

本文我们先从什么是 USB 协议栈开始讲起,然后再讲到 USB 模糊测试的历史,其中讲到了一些过去的常用技术和工具,不过它们都存在着一些问题。下文,我们将介绍最新的 USB 模糊测试的解决方案。