内核 FUZZ 思路

内核 API  函数:是提供给 Ring3 调用,在 Ring0 完成最终功能的函数。这些函数接收 Ring3 传入的参数,如果处理参数的过程存在问题的话,很有可能成为一个内核漏洞。这样的内核 API 函数有很多,例如 SSDT、Shadow SSDT 等。
Hook API的代码:很多安全软件为了防御病毒木马,对很多内核 API 进行了 Hook/Inline Hook。然而这些 Hook 内核 API 的代码也存在安全问题。如果对参数的处理不当或内部逻辑的错误,也很有可能出现内核漏洞。
网络协议处理的内核代码:有一些协议的处理是在 SYSTEM 进程中的,也就是在内核模块中处理的,可以通过网络协议 Fuzz,构造畸形协议数据包,来挖掘这方面的漏洞。
IoControl:从已公布的漏洞来看,IoControl 类型的漏洞是最多的,可以作为内核漏洞挖掘的重点方向。IoControl 作为 Ring0/Ring3 缓冲区交互的重要方式,很有可能会出现参数处理不当的问题,或者内部逻辑甚至设计缺陷引发的问题。

既然 IoControl 类型的内核漏洞如此多,那么如何挖掘这种类型的漏洞呢?首先再来回顾下 Ring3和Ring0 通讯的重要函数 DeviceIoControl():

 BOOL DeviceIoControl(
HANDLE hDevice, //设备句柄
DWORD dwIoControlCode, //Io 控制号
LPVOID lpInBuffer, //输入缓冲区指针
DWORD nInBufferSize, //输入缓冲区字节数
LPVOID lpOutBuffer, //输出缓冲区指针
DWORD nOutBufferSize, //输出缓冲区字节数
LPDWORD lpBytesReturned, //返回输出字节数
LPOVERLAPPED lpOverlapped //异步调用时指向的 OVERLAPPED 指针
);

正常情况下,DeviceIoControl() 的参数都是自己程序指定的,不会是畸形的参数,驱动中也主要考虑功能的实现,对于畸形参数和处理逻辑缺陷方面的安全问题不够重视。因此可以通过构造畸形参数来 Fuzz 驱动程序的处理是否存在漏洞。

这种 Fuzz 称为“IoControl Fuzz”。关于 IoControl Fuzz,有2种方法:

IoControl MITM(Man-In-The-Middle)Fuzz

这种方法类似于“中间人攻击”,是在内核 Hook NtDeviceIoControlFile(),当识别到 IoControl 的对象为要 Fuzz 的对象对,获取该函数的参数,并按照预先的 Fuzz 策略对参数或参数指向的缓冲区数据进行篡改,然后将篡改后的参数传递给原始的 NtDeviceIoControlFile():

IoControl Driver Fuzz

MITM 方式虽然巧妙,但多数情况下,难以覆盖某驱动程序所有的 IoControlCode,就算覆盖所有的 IoControlCode,这种 Fuzz 也只是“一次性”的,不够全面。

为了能够对驱动程序中的某个 IoCodeCode 做全面的 Fuzz,需要对 DeviceIoControl() 的每个参数都进行畸形化,每个参数值可以畸形出很多不同的值,然后将各个参数值进行组合。这种方法称为 IoControl Driver Fuzz。

内核 FUZZ 工具介绍

[一] 莫斯科一家公司的安全研究实验室 eSage Lab(http://www.esagelab.com)有一个开源工具 IOCTL Fuzzer,是 CLI 工具,功能如下

* 根据进程名称、驱动名称、设备名称、IoControlCode 进行 IRP 过滤
* IRP Fuzz
* 监视模式
* 通过控制台或文件输出日志

IOCTL Fuzzer 是在处理 IRP 的时候提取出满足配置文件中指定条件的 IRP,然后将该 IRP 的输入参数进行随机修改来进行 Fuzz,也即是 MITM Fuzz 方法。该工具使用 XML 文件来配置 Fuzz 对象和 Fuzz 策略。

其短板是,通过 XML 配置固然简单,但不够灵活,每次改变 Fuzz 对象和 Fuzz 策略都要重启 Fuzz 程序,使用不便。且 Fuzz 策略不够细致,可能会遗漏。

[二] 书中(工具及源码见随书光盘)给出一个 GUI 的 IoControl Fuzz 工具,能进行 MITM Fuzz 和 IoControl Driver Fuzz。其关键概念和概要设计如下:

Fuzz 对象:被 Fuzz 的对象或触发 Fuzz 的条件
Fuzz 策略:Fuzz 过程中对参数和数据畸形化的方案
Fuzz 项:Fuzz 对象和 Fuzz 策略合起来,称为一个 Fuzz 项。对于 Fuzz 程序来说,所有的 Fuzz 项就是其输入。Fuzz 程序支持多个 Fuzz 项同时工作,且能灵活地增删改,不发重启 Fuzz 引擎。

漏洞挖掘实战

书中展示了几个已经被修补了的漏洞的挖掘,利用的是上面提到的 IoControl Fuzzer 和 WinDbg 内核调试跟踪。

[一] 超级巡警 ASTDriver.sys 本地提权,影响 v4 Build0316 及以前的版本

超级巡警中有个恢复 Hook 的内核函数功能,在实现时没有对输入缓冲区进行检查,可导致向任意地址写 0。Fuzz 蓝屏后,可以在 WinDbg 中发现以下信息,进一步使用 !analyze -v 和反汇编追踪,可以发现漏洞代码位置,具体过程见书中内容。

[二] 东方微点 mp110013.sys 本地提权,影响东方微点防御软件 1.2.10581.0278 及以前的版本

mp110013.sys 对 0x8000012C 这个 IoControlCode 的处理存在问题,它会调用输入缓冲区的第一个 DWORD,如果用户在第一个 DWORD 填入错误的值,那么派遣例程会将这个值修改为 0。所以只要在 0 这个地址放入 shellcode,并且在输入缓冲区的第一个 DWORD 填入错误值,就能执行 Ring0 Shellcode。

[三] 瑞星 HookCont.sys 驱动本地拒绝服务漏洞,影响 23.0.0.5 及之前版本

HookCont.sys 驱动派遣例程中,对 IoControlCode 为 0x83003C07 的处理中,对 UserBuffer 检查使用 ProbeForWrite() 不当和 try 的位置使用不当,造成本地拒绝服务漏洞。

其对 UserBuffer 检查使用 ProbeForWrite() 的方法不正确,ProbeForWrite() 的第二个参数为 OutputBufferLength,驱动中没有任何检查就直接信任用户输入的 OutputBufferLength,只要 OutputBufferLength 为 0,这个 ProbeForWrite() 检查就毫无意义,也就是说 UserBuffer 可以是一个非法内存地址。

另外,在做 ProbeForRead() 和 ProbeForWrite() 检查时,使用了 try,但是在最后给 UserBuffer 写数据时没有使用 try。所以只要躲过前面的检查,后面由于内存访问错误,就会造成蓝屏崩溃。

OD: Windows Driver Fuzz的更多相关文章

  1. 驱动开发利器Microsoft Windows Driver Kit 7.1.0下载

    在Windows 2000 与Windows XP 系统采用是WINDDK来开发WINDOWS驱动程序,我手头也有WINDDK,可是从Windows Vista开始之后,一般采用Microsoft W ...

  2. 微软职位内部推荐-SDE2 (Windows driver)

    微软近期Open的职位: SDE2 (Windows driver) Job title: Software Development Engineer 2 Location: Shanghai, Ch ...

  3. 和S5933比较起来,开发PLX9054比较不幸,可能是第一次开发PCI的缘故吧。因为,很多PCI的例子都是对S5933,就连微软出版的《Programming the Microsoft Windows Driver Model》都提供了一个完整的S5933的例子。 在这篇有关DDK的开发论文里。

    和S5933比较起来,开发PLX9054比较不幸,可能是第一次开发PCI的缘故吧.因为,很多PCI的例子都是对S5933,就连微软出版的<Programming the Microsoft Wi ...

  4. Windows SDK DDK WDK (Windows Driver Kit) 区别

    首先,先从基础的东西说起,开发WINDOWS下的驱动程序,需要一个专门的开发包,如:开发JAVA程序,我们可能需要一个JDK,开发WINDOWS应用程序,我们需要WINDOWS的SDK,现在开发WIN ...

  5. Windows Driver Kit Version 7.1.0 ( 也就是 7600.16385.1 ) 下载地址

    Windows Driver Kit Version 7.1.0 ( 也就是 7600.16385.1 ) 下载地址 http://download.microsoft.com/download/4/ ...

  6. windows driver 简单的驱动和通信

    sysmain.c #pragma once #pragma warning(disable: 4100) #include <ntifs.h> #include <ntddk.h& ...

  7. Windows Driver Frameworks

    MSDN原文:https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff557565(v=vs.85).aspx

  8. OD: Windows Kernel Debug

    内核调试入门 内核程序运行在内核态,因此不能像对用户态应用程序那样来调试.关于内核调试方面的知识请参考<软件调试>这本书.目前内核调试主要有以下三种方法. 一是使用硬件调试器,它通过特定的 ...

  9. OD: Windows Security Techniques & GS Bypassing via C++ Virtual Function

    Windows 安全机制 漏洞的万源之本在于冯诺依曼设计的计算机模型没有将代码和数据进行区分——病毒.加壳脱壳.shellcode.跨站脚本攻击.SQL注入等都是因为计算机把数据和代码混淆这一天然缺陷 ...

随机推荐

  1. TC2.0中怎样调用汇编程序

    转载于: TC2.0中怎样调用汇编程序 一.概述 TC是美国BORLAND 公司在IBM PC机上开发的一个高效.优化的C编译程序,它自带高效的全屏幕编辑程序,在集成开发环境下可支持编辑.编译.连接调 ...

  2. uboot main_loop函数分析

    一.概述    main_loop()函数做的都是与具体平台无关的工作.主要包括的工作如下: (1)初始化启动次数限制机制 (2)Modem功能 (3)设置软件版本号 (4)启动延迟 (5)读取命令, ...

  3. adb设备,根据serial获取vid pid

    使用adb devices命令,可以轻松获取到所有连接到PC的adb设备的serial值. 但是adb命令无法获取adb usb设备的vendor id和product id. 本程序根据adb协议, ...

  4. Tiling(递推+大数)

    Description In how many ways can you tile a 2xn rectangle by 2x1 or 2x2 tiles? Here is a sample tili ...

  5. 线性链表的双向链表——java实现

    .线性表链式存储结构:将采用一组地址的任意的存储单元存放线性表中的数据元素. 链表又可分为: 单链表:每个节点只保留一个引用,该引用指向当前节点的下一个节点,没有引用指向头结点,尾节点的next引用为 ...

  6. Microsoft Office 2013 激活方法

    Microsoft Office 2013 激活方法   Microsoft Office 2013是微软的新一代Office办公软件,全面采用Metro界面,包括Word.PowerPoint.Ex ...

  7. Linux目录树

    Linux目录树(directory tree) 分层结构(不同于数据库文件系统),单个文件/目录的最大长度为255个字符,完整路径为4096个字符 特殊的文件系统 文件系统 挂载点 说明 Root ...

  8. 「Poetize8」Divisible

    描述 Description 设F[i]为斐波那契数列的第i项,F[1]=1,F[2]=1,F[i]=F[i-1]+F[i-2](i>=3). 输入格式 InputFormat 输入包含若干行( ...

  9. SQL Server判断对象是否存在 (if exists (select * from sysobjects )(转)

    1 判断数据库是否存在Sql代码 if exists (select * from sys.databases where name = ’数据库名’)    drop database [数据库名] ...

  10. Unique Binary Search Trees——LeetCode

    Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For examp ...