以下为速记全文:
大家好,我是吴优。大家好,我是何丙阳。我们来自联想全球安全实验室,很高兴能够在这里为大家分享我们在USB FUZZ道路上一些研究成果、方法及思路,希望可以为大家在USB FUZZ上带来一些小小的帮助。参与本次工具开发的共有4个人,均来自于联想全球安全实验室,接下来我将分为三部分来分享本次议题。一是我们开发USB
FUZZ工具的动机;二是我们FUZZ工具的硬件模拟的设计思路;三是我们FUZZ引擎的开发。接下来我将会由一个漏洞来阐述我们进行USB安全测试的一个动机。大家也知道我们联想的主营产品是电脑,我们安全实验室也一直非常关注电脑的安全性,尤其windows hello人脸识别是我们关注的重心。在过去一段时间内,我们曾经用头模、面具、照片,对手机、平板、门锁、人脸识别售货机进行过破解,取得一些成果。但后来我们使用上述手段对windows hello人脸识别进行破解时,发现效果并不理想。后来在相关的搜索中,我们发现21年在black hat上有安全团队分享过相关的议题,在议题中他们提出了一个新的研究思路,用我们电脑最常见的USB接口去接入一个伪造的虚拟摄像头设备,然后传入红外人脸信息和一张RGB图片信息,从而达到破解 windows hello的目的。他们的研究方式给我们提供了一种新的研究思路,我们把我们的目光转向了通过USB接口去破解window hello。根据他们议题中的分享思路,他们是在USB接口中传入红外人脸信息和RGB信息。为了更进一步探究这个漏洞细节,我们对windows生物识别框架进行了逆向分析。在分析过程中,我们发现这个框架主要存在三个模块,分别是采集模块、计算模块以及存储模块,其中采集模块主要与生物硬件识别设备进行通讯交互,获取生物信息,然后再把生物信息送入计算模块中,与注册在数据库中的生物信息进行匹配对比。最后存储模块会存储每次匹配成功的结果,然后加密存储。然后我们对在三个模块之间流转的数据进行了一个抓包分析,我们发现这个数据仅包含了一个红外人脸的数据,它并不存在 RGB、图片信息。为了验证这个结论,我们用同事的红外人脸照片信息,在采集模块与计算模块交互的过程中下了一个hook,当windows调用人脸识别时,我们把hook位置的数据流替换成我们同事的红外人脸信息,这样导致的结果就是任何人都可以去解锁我们同事的这台电脑。因此我们得出一个结论就是,我们的USB只要传入红外人脸信息数据就可以去破解windows hello。根据上述的议题思路,我们接下来还需要伪造一个符合windows协议规范的摄像头,然后再在其中放入红外人脸照片信息。那么我们的硬件方案血型设计除了常规的主控、电源、转换芯片等,还需要注意一点,由于windows对于USB数据的要求比较高,我们还需要在硬件上支持一个高速USB接口。接下来大家请看一个windows hello破解的短视频。由于电脑使用windows hello进行登录时,会优先调用外接摄像头,而且对电脑对外接摄像头的合法性,它没有进行安全性校验,所以如果我们完全模拟一个真实的红外摄像头,通过USB传入我们的红外人脸信息,就可以去解锁这台电脑。那么微软现在有没有相对应的修复方案?根据我们的调研,微软提供了一套叫做增强型安全登陆的解决方案。为了测试这个方案,之后我们在国内购买了大部分主流品牌电脑,发现除了微软和联想ThinkPad系列进行了默认搭载之外,其他都可能无法拦截。我们在通过USB破解了wwindows hello之后,又把目标放到了整个 Bayi安全领域,发现近年来有很多USB攻击案例,比如去年发生在美国的起亚汽车事件,攻击者就可以通过接入汽车的USB接口把汽车开走。再比如我们上个月发生的ATM机盗刷事件,是由ATM机的USB接口开放了APP服务所导致。此外还有我们大家所熟悉的半停SB。还有我们在以往的操作系统中,USB驱动中也存在大量漏洞,容易导致系统崩溃。因此我们开始对USB的安全性产生质疑,各个厂商可能对USB接口并不是十分重视。缘于上述案例中USB的接口的脆弱的安全性,我们萌生了设计一套USB自动化安全测试的解决方案的想法,希望可以对主机的USB接口进行自动化测试。第一,我们希望能够多平台使用,它可以在windows、安卓、Linux等不同操作系统上使用,也可以在手机、平板、ATM机等不同设备上使用。这里就需要我们使用硬件进行设计,因为用软件模拟的话可能有比较大的局限性。第二,我们设想它应该具备很强的扩展性,可以尽可能多的模拟不同的USB设备,以测试主机USB接口在面对不同设备的鲁棒性。第三,我们希望它能够实现自动化测试,因此我们选用FUZZ技术,减少人工参与度。第四,我们希望它是低成本的,并且使用方便,在后续的操作与配置中不希望它太复杂。基于以上4点设想,我们在windows hello攻击硬件的基础上,设计了一套USB仿真设备,我们把它称为USB studio。为了实现这套设备,我们首先需要对USB协议有一个基础的了解,如今USB已经取代了几乎所有的其他外设连接标准,除了大家都基本了解的type A、type C接口类型,2.0、3.0的接口版本之外,我们还需要了解在USB通信过程中,主机与USB设备之间发生的轮询过程,USB设备在插入主机后进行供电复位等操作,然后向设备请求各类描述服务信息,打个比方,人的身份信息可以用身份证去表示,那么描述符就相当于 USB设备的身份证,主机系统获取了描述符,就可以知道整个USB设备的版本功能以及端点配置等所有一系列信息,然后就可以确定用什么样的方式去与USB设备进行通信、加载相对应的驱动去管理。在了解完USB协议之后,我们现在需要知道如何进行FUZZ开发,我们实现FUZZ的前提是什么?我们认为实现FUZZ的前提是,我们研发的USB studio这个设备它最基本的功能是在与主机交互的过程中,将自己模拟为一个遵循USB协议规范的合法设备,比如让主机认为它是一个合法的鼠标,合法的键盘,合法的U盘等等。在模拟完一个正常的设备之后,我们再对USB studio的通信交互数据进行变异,实现USB FUZZ,那么按照这个思路,我们提出三个问题:第一个问题——我们是不是在重复造轮子,市场上有没有成熟的FUZZ工具或者商业的解决方案等。为此我们进行了一些调研,也采购了一些USB FUZZ设备。比如大家应该会熟悉的基于UMAP2的Facedancer这款测试工具,我们拿来用了一段时间,发现它的成本并不低廉,而且在我们使用的过程中遇到了很多意想不到的问题与bug,同时它的扩展性和自动化程度并不是很理想,因此他并不满足我们设想的USB FUZZ需求。还比如在FUZZ领域内很成功的defensics,它有很多针对协议类的用例,比如针对蓝牙、针对WiFi的,但它并没有针对USB数据的一个测试用例。此外我们还去一些开源社区和论坛上,找到了一些USB FUZZ相关的项目,但是我们发现它通常都是基于软件模拟去实现的,当然他们非常优秀,但是它的操作与配置非常复杂,而且我们希望是用硬件去设计我们的整套USB FUZZ设备,这样它的适用性会比较广。因此我们确认了并不是在重复造轮子,在这之后,我们该如何进行FUZZ开发?现在我们需要将我们开发的这套USB FUZZ工具,也就是USB studio,模拟为一个正常的合法的有效的设备。接下来请看我们的实现过程,按照我们对USB协议规范的了解,主机USB通信就是一问一答的过程,USB主机在检测到USB设备插入后会对设备进行枚举,那么为什么要枚举?枚举就是从设备中获取各类描述符信息,这样主机就可以根据这些信息加载合适的驱动程序,从而知道设备是什么样的设备,如何进行通信等。模拟一个真实的USB设备,很重要一点就是USB的枚举过程,只要枚举成功了,那么接下来我们需要接下来的工作无非就是一些功能函数的实现了。接下来我们来看一下枚举的过程,它总共分为4步:第一步,建立通USB通信过程,主机会向USB设备询问一个数据包的设备描述符。第二步,主机为USB设备设置一个新地址。第三步,主机再次获取USB设备的设备表述符和配置表述符。第四步,主机再次获取USB设备的其他信息,比如字符串之类。那么在枚举实现之后,我们现在就可以完全的去模拟一个合法的正常的设备,比如让电脑或者说让一些设备认为我这个USB studio是一个我们需要的,我们假设它是一个鼠标,假设它是一个U盘等等。解决完将USB studio模拟成一个真实的USB设备之后,接下来我们来看看第三个问题,如何在一个硬件上,去模拟不同类型的USB设备?刚才我们已经提到过,在枚举过程中,是USB设备告诉主机我是一个U盘还是一个音箱或者其他类型的设备,然后主机再加载相应的驱动,那么这个过程本质上就是主机对设备描述符以及配置描述符信息进行判断处理。那么基于USB协议规范改变描述符的信息,就可以去模拟不同的USB设备。大家请看左边这张图,就是我们抓包获得的一个典型的USB枚举过程中的数据集合,在集合中的第一个数据包,它告诉主机插入的是什么设备?第四个数据包告诉了主机,我应该用什么样的方式去进行解析,进行判断,因此这些数据就是我们的模板对象。接下来我们将刚才模拟一个设备的设计代码,抽象成一个不包含任何数据的代码框架,然后将我们刚才这些数据的模板对象填充到这个框架中,就可以实现在一个硬件上去模拟不同的USB设备。但是当我们做完一个通用的模板框架之后,我们又遇到了一个新的问题,就是每个USB设备在响应完标准的USB请求之后,都会有自己独立的特性单元控制请求,就比如最上面这张图,它会有一些自己的逻辑去进行处理判断。比如摄像头会向主机发送一些景深光圈的信息,麦克风会向主机发送一些音量大小、音量、声音补偿等之类的信息。这些逻辑如果硬编码在我们的固件中,其实跟我们希望模拟多个设备的初衷是相悖的。我们想了很多办法,最后我们决定在固件中嵌入Lua脚本引擎,以解决这个问题。大家也都知道Lua是一种轻量级的解析型语言,可以与很多高级语言进行交互,那么我们通过导出固件中的USB接口函数,在关键位置添加Lua回调,比如下面右边这张图,我们就可以通过Lua在外置的脚本里面去实现这部分逻辑,实现一个正常的USB设备,一个完全模拟的USB设备。同时我们也发现这样设计固件代码之后,我们也可以用一些很低成本的去实现一些攻击逻辑。比如下面用一个Lua脚本去实现一个简单的 BadUSB,当我们把USB studio模拟成一个键盘,然后在Lua里面创建,比如保存功能键映射码的数组,保存字母键映射码的数组,然后在当需要执行恶意脚本的时候,传入我们的操作码08,就能通过Lua脚本去把我们的命令发送给受害者的电脑。左边这段脚本,就简单的模拟了一个Windows弹计算机,当然我们也可以实现很复杂的逻辑。在讲完我们所有的USB模拟之后,在一个硬件上模拟多个设备,通过Lua脚本去进行差异化处理之后,接下来我们来看一看我们的USB Studio整个固件架构。首先USB设备的模拟端其实是建立在一个标准的USB通信协议之上,然后在其上是我们特定的应用层协议,比如audio、uvc、大容量存储等等,将一些端点设置、收发函数、描述符设置之类的函数进行了封装。最后是我们的进行差异化处理的一个Lua脚本,根据不同的逻辑,我们就可以实现不同的模拟。介绍完我们的USB studio之后,下面是我们FUZZ引擎的开发,接下来将由我的同事来为大家进行分享。各位下午好,我是吴优,下面将由我来给大家继续介绍。我身后这张图是我们在实际的FUZZ过程当中的一张示意图,在我们图的左边是我们的Target的设备,它里面我们会设置一个agent,它的作用是可以采集我们Tony的端在FUZZ的过程中接收到的或者说收集到的一些异常的信息,把这些信息传给我们的FUZZ端。中间这个设备就是刚刚何丙阳讲的USB Studio,它可以去模拟一个正常的USB设备,然后去发送我们的USB数据,那么这些数据都不是由我们的USB Studio自己产生的,而是由我们的FUZZ端生成这些数据,然后变异这些数据,再反馈给我们的USB Studio。那么我会给大家介绍我们的FUZZ端是如何产生这些数据,如何将这些数据进行变异之后,进行封装发给我们的USB
Studio,并且我如何去将我们USB Studio和agent产生的异常信息的反馈的信息怎么去处理。另外我还会讲一下我们的 USB FUZZ,在提高效率方面,我们做了哪些工作,比分析有哪些更好的点。首先来到FUZZ设计这一块,我们首先考虑的是我们要对什么样的数据,什么样的USB描述符进行FUZZ。之前已经了解过,USB在传输媒体的过程中,它最重要的数据就是它的描述信息,那么我们要变异或者要生成的数据,也就是这些交付的数据,就是我身后的描述符的信息。这张图是我们用USB tree去解析的一个键盘的描述符的信息。我们可以看到其实对于描述符来说,它的每一个字节都有自己特定的含义,比如说它可以表示键盘设备的版本、型号、功能或者类别,然后这些信息会经过我们的FUZZ端生成,但是我们生成之后我们要发送给我们的USB studio,但USB studio他并不知道我们的数据包是什么样子,因此在FUZZ端和USB studio之间,我们协商了一套数据的封装格式,可以看到在我左边这张图就是我们出对数据包封装的格式,首先我们的USB studio会根据封装数据包的第一个字节去识别出它的操作码,这个操作码可以帮助我们的CPU去执行相应的功能。比如说重启我们的USB studio,发送我们的描述符数据,或者说去执行后面的Lua脚本。另外我们USB studio会解析数据包后面的第二和第三个字节,这两个字节代表的是我们整个传输数据包的总长度,然后在解析完所有的数据之后,它会继续解析后面的第四个字节。比如说第四个字节它是01,01表示的就是当前键盘设备的描述符,在这些描述符里面,它会解析出当前设备描述符的所有数据,然后紧接着他会去解析后面的,比如说0b它代表的是当前设备的配置描述符,依次的去解析完之后,它会将这所有的数据填充到它开发出来的USB的数据框架里面,从而起到了一个FUZZ的作用。在了解完我们是生成什么样的数据,怎么样封装数据之后,我们来到了我们的数据的流程设计阶段,我们设想过了,我们要做的是模拟一个真实的设备,并且对真实的设备进行FUZZ,那么我们就要用真实的描述符的信息去进行生成。那么生成这样的真实的描述符的信息之后,我们把它封装成一个模板,如果这些数据直接发送给我们的USB studio,那么它就可以真实的去模拟出比较符合我们USB规范的一个USB设备。如果这些数据直接经过我们的FUZZ引擎变异,或者根据变异的策略封装数据包之后,发送给我们的USB studio,再由我们的USB studio传送给我们的目标机,那么这样就起到了一个对 USB交互数据的FUZZ的作用。另外在整个流程中,我们会将这些变异的数据进行记录,这样的记录可以让我们很快的进行二次验证。我们的二次验证是基于我们的反馈,在我们的异常数据回放模块,我们会将我们的反馈机制加进来。那么我们是怎么去思考去设计我们的反馈机制的?我们从以下3点去考虑。首先是一个生成数据,我们前面讲过了,因为FUZZ的数据是随机的,我们没有办法去掌握哪些数据是有用的,所以我们需要把所有的数据都进行记录,这样就便于我们后面的对异常现象进行二次验证。第二块是我们同样会对我们的USB studio反馈的信息进行处理。那么USB studio会反馈什么样的信息呢?我们将所有FUZZ打包或者FUZZ后的数据传输给我们的USB studio,那么里面都包含USB交互过程中的所有的描述符,那么我们FUZZ端需要知道我们当前发送的描述服务信息执行到了哪一步。比如说我们在USB
studio,它会告诉我们当前你给我的数据包,我们交互到了哪一步,比如说我们现在执行到了设备描述服务,我就会告诉你我们现在到了设备描述这一块。这样的策略有助于我们调整后面的变异的策略,能够帮助我们知道当前的USB的驱动或者系统执行到了哪一块的描述符。然后第二点我们也会对操作码进行响应,比如说我们封装的数据包中的我们操作码,我们的USB studio对操作进行响应之后,比如说虫体,比如说去执行Lua脚本这种功能,那么他肯定要给我们的发展FUZZ进行反馈,我们是否真的识别这些数据,是否真的去执行了这些代码。第三块我们还加入了一个掉电检测的功能,这是由于我们在使用FUZZ数据,对windows系统去FUZZ的时候, windows系统很容易就会产生一些崩溃或者异常,这些异常会让我们的 windows去重启或者蓝屏。这种蓝屏我们通过 windows一般很难去检测到这样的异常,所以我们只能在我们的USB studio中加入了掉电的选择。因为我们的windows系统一旦重启或者说蓝屏之后,我们的USB接口就会掉电,那么这种掉电我们就可以监测它的状态,来判断当前的FUZZ的数据是否对windows造成了异常。除了这些东西,我们还在我们的被测端加了一个agent, agent的作用是可以监控整个系统的应用崩溃的情况,这是因为我们在一次对 Linux进行FUZZ的过程中,我们本来是想对它的USB相机的驱动进行FUZZ,但是我们很巧的发现了它的蓝牙进程居然崩溃了,我们并不知道为什么会这样子,所以我们为此对整个系统目前运行的应用也进行了一个异常崩溃的检测。那么讲完我们怎么去检测这些异常之后,我们在提高我们的USB FUZZ的效率过程中,我们遇到了哪些挑战?首先我们要解决的是一个热插拔的问题,比如说大家应该都用过USB的键盘或者设备,如果要让我们的系统重新检测、重新识别我们的USB设备,就需要我们重新去插拔。我们在FUZZ的过程中也是需要重新插拔的,因此这种人工插拔的方式特别的影响我们FUZZ的效率。为此我们去研究了一下USB插拔的原理,我们发现系统它仅仅只是对 USB的D+和D-的两个电平引脚的变化,来判断当前的USB接口是插入或者拔出。我们发现当系统检测到USB引脚D+ 和 D-,变频是处于下拉的状态,那么系统就会判定当前的USB接口是处于拔出的状态;当它检测出递加或者递减的两个接口,两个引脚它电平上拉的状态,那么它就会判定当前的USB接口是插入。为此我们找到了两种解决方案,首先第一种方案就是我们用直接去控制当前USB接口它引脚的输出电瓶的变化来模拟出它USB的插拔的效果。第二种办法我们直接对我们的MCU去进行复位,让我们的USB重新上电,这种方式也可以模拟出USB插拔。在解决完USB的物理上插拔的问题之后,我们开始把我们的想法,我们的思路聚焦于如何优化我们的编译策略,如何去减少我们的FUZZ的时间。为此我们去看了一下face dancer的FUZZ源码,我们发现它的FUZZ逻辑是将USB相互数据的所有描述符都进行一次随机变异,那么我们计算过了,如果根据face dancer这样的FUZZ效率,因为一个字节它是16进制表示的,那么它就有256种的变异的可能性。由于一个USB的设备它的描述符可能有几百或者上千甚至更多的字节,如果我们对它所有的字节数都进行变异的话,我们所花费的时间或者找到它异常的时间就会变得特别多。因此我们改进了一些FUZZ的方式,首先我们选择一些有代表性的bug位置,因为前面我们了解过了,在USB轮询的过程中,它是对所有的描述符依次轮询的,因此我们可以先变异我们的设备描述符,我们将变异后的设备描述符发送给我们的目标机之后,发现它并没有任何的问题。那么我们接着可以进行它在轮询过程中下一段的描述符,这样的话就可以避免我们对整体的描述符都进行变异,也就可以节省一些我们的时间。第二个就是我们的非法指令,比如说有的特定的USB协议,比如说我们的uvc协议,它里面会有一些状态码,比如说06代表它的一些状态码信息,但是我们可以把它的这些值改变成它从来没有出现过的值,比如说10,比如说09这种值也有可能会造成一些 uvc的协议无法识别的现象。第二块是我们也创新了一些编译的方式,我们已经知道,usb的描述符当是当前usb设备的一个身份证,有些信息并不会代表整个USB的信息,比如说要我们的主机会识别1114b描述服里面的,比如说它会识别设备的版本、设备的类型,比如说识别它是一个键盘或者鼠标,甚至一个是照相机,那么这种信息是不需要变异的。因为如果一旦变异的话,USB Studio它模拟的效果就没有了,那么我们也就起不到FUZZ效果,为此我们找到了很多这样通用的不需要模拟的字节或者这样的信息,这样的话也可以减少我们的FUZZ的时间,并且间接的提高我们FUZZ效率。剩下的就是我们同样对一些数据值,单个的数据或者整块的数据值也进行了一些策略的改变。比如说我们在一次对 windows进行编发的过程中,我们进行异常的数据包抓取,分析之后,我们发现能造成windows蓝屏或者说拒绝服务的一些数据包,其实仅仅是因为在它在解析某一块描述符的时候,它少了一个字节,所以我们把这种编译策略也加到了对整个的描述符编译的方式里面。同样的我们在FUZZ的过程中,我们在设计的过程中也遇到了一些问题,比如说我们平常用串口传输的都是一些比较短的数据包,但我们这一次的描述服务信息都是很长的,那么这种长数据包就会造成一个现象——因为串口在传输长数据包的时候,一些物理干扰的因素导致它会产生一些误差。在我们的数据比较 com分析的这张图里面,我们可以看到在上面一条数据是我们FUZZ生成的数据,下面一条数据是实际能够让我们主机产生异常的数据,可以看到它其实有4个字节或者3个字节的误差,那么这种误差能够让我们在二次验证的时候还提不稳定,因此为了解决这个问题,我们目前的临时方案是降低它的传输速率,或者改变它的传输方法。比如说我们会使用一些更高效更稳定的传输方法,例如用蓝牙或者 WiFi的传输形式。下面来看一下我们实际的一个FUZZ的演示,这是一个二次验证的数据回放的过程,我们将编译的数据包,重新产生异常的数据包,对我们的 windows系统重新回放。可以看到我们的主题,由于我们的FUZZ数据,剩下的FUZZ的数据已经蓝屏了。那么在演示完之后,我来给大家再次总结一下我们本次议题讲的内容。首先我们对windows hello的破解和模拟做了一个总结,然后复现了当前的漏洞,并且我们发现其实 windows hello的破解,不需要像之前Black hat的人说的,还要一张RGB的图片,我们仅仅只需要一张红外图像信息就可以破解。其次,我们讲了关于USB Studio的模拟和开发。最后,我们为了能够让我们的USB studio更好的使用,为此我们添加了我们的自动化的FUZZ。在做完这些工作之后,我们希望USB studio能干其他的事情,比如能够做USB协议分析的一些工作,因为目前关于USB协议分析的设备都很昂贵。第二个是如果我们能对协议进行分析,那么我们希望能够做一些中间人攻击的思路。第三个是我希望我们的USB studio能够改进得更轻便、更加的便携。*峰会议题PPT及回放视频已上传至【看雪课程】https://www.kanxue.com/book-leaflet-171.htm
PPT及回放视频对【未购票者收费】;
【已购票的参会人员免费】:我方已通过短信将“兑换码”发至手机,按提示兑换即可~
《看雪2023 SDC》
看雪安全开发者峰会(Security Development Conference,简称SDC)由拥有23年悠久历史的顶尖安全技术综合网站——看雪主办,面向开发者、安全人员及高端技术从业人员,是国内开发者与安全人才的年度盛事。自2017年七月份开始举办第一届峰会以来,SDC始终秉持“技术与干货”的原则,致力于建立一个多领域、多维度的高端安全交流平台,推动互联网安全行业的快速成长。
文章来源: https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458529810&idx=1&sn=6dbfc059c55004f2efc3a04c7baef02e&chksm=b18d009886fa898e52c72154fb9c454a06191956e31d0e0f0fe5d231c30e905405519c6feb80&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh