内核漏洞概述

内核漏洞的分类

运行在 Ring0 上的操作系统内核、设备驱动、第三方驱动能共享同一个虚拟地址空间,可以完全访问系统空间的所有内存,而不像用户态进程那样拥有独立私有的内存空间。由于内核程序的特殊性,内核程序漏洞类型也更加丰富。(书中收集了近年内公布的内核漏洞,并将相关的分析资料整理打包)

可以从漏洞的严重程度和漏洞的利用原理两个角度来对内核漏洞进行分类。漏洞的严重程度是指漏洞利用后所造成的危害;漏洞的利用原理是指漏洞利用过程中使用的原理和技术。

按照漏洞严重程度可分为以下 4 类:远程拒绝服务、本地拒绝服务、远程任意代码执行和本地权限提升。拒绝服务指能够利用来使得远程系统崩溃或资源耗尽的内核程序 bug 或缺陷。

按照漏洞利用原理可分为以下 4 类:拒绝服务、缓冲区溢出、内存篡改和设计缺陷。

内存篡改又可以分成以下 3 个子类:任意地址写任意数据、固定地址写任意数据、任意地址写固定数据。

内核漏洞的研究过程

漏洞重现环节,需要搭建测试环境,通常为虚拟机环境;另外需要注意有漏洞的内核文件或驱动文件的版本,如果版本不对,是不可能重现的;还要确认该漏洞暂时还未打补丁;最后,如果该漏洞公布有 POC 源码,还需要对 POC 源码进行编译。在漏洞重现环节中,如果最终重现失败,不能说明漏洞不存在,如果环境搭建的没有问题,那可以考虑是否 POC 源码有误,或者该漏洞还依赖于其他条件。因此,建议先进行漏洞分析环节,通过漏洞分析可以加深对漏洞的理解,这样边分析边重现,往往问题就迎刃而解了。从漏洞重现到漏洞分析,是一个"由表及里"的过程。

漏洞分析环节,是整个漏洞学习的核心环节,如果分析不清漏洞的前因后果,那么漏洞利用也无从入手。漏洞分析过程其实是一个"刨根究底"的过程,也可以说是"打破沙锅问到底"的过程,只不过是"问"自己而已。漏洞分析有很多方法,如果有源码的话,可以先对源码进行白盒分析;如果没有源码可以对内核或驱动 PE 文件反汇编分析;如果漏洞公布中有 POC 源码的话,还可以对 POC 源码进行分析(通过阅读 POC 源码和注释,可以很快地对该漏洞有一个准确的认识);如果该漏洞的补丁已经发布了,还可以在打补丁后,提取新版本的内核或驱动文件,通过对比进行分析;另外还可以通过给有漏洞的内核或驱动文件下断点进行调试分析;如果能触发有漏洞的内核或驱动蓝屏,还可以针对蓝屏后的 Memory Dump(完整转储、内核转储、小型内存转储)文件进行蓝屏分析。

漏洞利用环节,是在漏洞分析的基础上,编写出能够利用该漏洞实现特定目标的代码,并进行测试的过程。对于内核漏洞利用而言,主要有 5 种目标:特权提升、远程溢出、本地溢出、远程 DOS 和本地 DOS。在实际漏洞利用过程中,最终达到的目标不外乎这 5 种,但是漏洞利用的细节各有不同,"各显神通"。

漏洞总结环节,是在完成了漏洞重现、漏洞分析和漏洞利用过程后,回过头来审视造成该漏洞的根本原因,并提出修补方法的过程。如果把以上环节比喻为攻击,那么漏洞总结必须站在攻击与防御的对立面,才能有所体会和感悟,才能寻求到突破。通过漏洞总结,能够将学习过程中获取到的知识升华为一种经验和能力。

内核漏洞挖掘的过程实际上就是,通过工具挖掘或手工挖掘,达到触发漏洞的目标,可能是一个蓝屏,也可能是一个内核异常,然后对此进行详细分析和测试,最终编写漏洞 POC 的过程。

编写安全的驱动程序

站在开发者的角度,内核漏洞的原因大体可以归结为:未验证输入和输出未验证调用者代码逻辑错误系统设计存在安全缺陷等。在驱动开发的过程中,注意这些方面就可以大大提高驱动程序的安全性。

输入输出检查

输入输出检查是指对不可信的输入输出地址及数据长度进行合法性检查的过程。这种方法在 Windows 内核 API 中应用的十分广泛。

例如,在 NtReadFile 函数中,如果 PreviousMode 不是 KernelMode,即 NtReadFile 函数是从用户态被调用的,可以使用 ProbeForWrite 函数检测输入输出缓冲区是否可写,参见 ReactOS 中的代码如下:

 NTSTATUS NTAPI NtReadFile(IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER ByteOffset OPTIONAL,
IN PULONG Key OPTIONAL)
{
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
//省略部分代码......
/* Validate User-Mode Buffers */
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
/* Probe the status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe the read buffer */
ProbeForWrite(Buffer, Length, );
//省略部分代码......

类似地,在 NtWriteFile 函数中当发现 PreviousMode 不是 KernelMode 时,即从用户态调用过来的,可以使用 ProbeForRead 函数进行检测。

此外,在 IoControl 中如果 IoControlCode 指定的 Method 为 METHOD_NEITHER 时,也应当对输入和输出地址使用 ProbeForRead 和 ProbeForWrite 函数进行检验。

验证驱动的调用者

有很多驱动程序加载后,会在驱动程序入口函数 DriverEntry 中创建驱动设备,并创建符号链接,同时还会指定派遣例程。这样一来,所有用户态程序都可以通过 DeviceIoControl 函数,调用该驱动的派遣例程。即存在 Ring3 恶意调用 Ring0 驱动派遣例程的问题,Ring0 程序应该对这种调用进行验证和过滤。

作为不够健壮的第三方驱动程序,更容易因为这种恶意调用被干扰,发生逻辑错误,甚至触发可能存在的内核漏洞。因此需要考虑驱动程序的通信对象和调用来源,在派遣例程中对此进行必要的安全验证和过滤。

验证和过滤的方法有很多,例如检查调用者进程的 PEPROCESS,进程文件的 MD5,等等。除此之外,还可以考虑用户态程序和驱动程序的通信加密,对于解密失败或非法通信数据的情况可以不予处理。

白名单机制的挑战

目前有很多安全软件,为了防止病毒木马进入 Ring0 而提高权限,这样已经防止加载驱动了。然而为了避免影响第三方驱动的正常运行,安全软件大多开设了白名单机制,在白名单中的驱动加载时是不会被拦截的。但是如果白名单中的驱动存在内核漏洞呢?

虽然病毒木马很难加载他们自己的驱动,但是只要白名单中的驱动存在漏洞,利用漏洞进行提权等操作,同样可以实现需要的功能,甚至完全瓦解软件的防御体系,这便是 "白名单机制的挑战"。

要解决这个问题,需要对白名单设立"准入制度"。只有通过了安全评估、检测、分析的驱动才能被加入白名单列表中。另一方面,我们还需要对白名单中的驱动进行定期审计,一旦发现该驱动的漏洞或外部公布了该驱动的漏洞,需要在第一时间通知用户,提供补丁升级服务。

OD: Kernel Vulnerabilities的更多相关文章

  1. OD: Kernel Vulnerabilities Analyze

    内核漏洞大多出没于 ring3 到 ring0 的交互中.从 ring3 进入 ring0 的通道,以及操作系统提供的 API 都有可能存在漏洞.例如:驱动程序中 IoControl 的处理函数,SS ...

  2. OD: Kernel Exploit - 2 Programming

    本节接前方,对 exploitme.sys 进行利用. exploitme.sys 存在任意地址写任意内容的内核漏洞,现在采用执行 Ring0 Shellcode 的方式进行利用. 获取 HalDis ...

  3. OD: Kernel Exploit - 1

    第 22 章,内核漏洞利用技术 首先编写具有漏洞的驱动 exploitme.sys,再展开内核漏洞利用思路和方法: /***************************************** ...

  4. OD: ActiveX Vulnerabilities

    通过一个精心构造的页面 exploit 第三方软件中的 ActiveX 已经成为一种惯用攻击手段,众多知名软件公司都曾被发现其注册的 ActiveX 中存在严重的缓冲区溢出漏洞,一个被广泛使用的第三方 ...

  5. OD: File Vulnerabilities & Protocols & Fuzz

    IE.Office 等软件有个共同点,即用文件作为程序的主要输入,但攻击者往往会挑战程序员的假定和假设. 文件格式 Fuzz 就是利用畸形文件测试软件的稳健性,其流程一般包括: * 以一个正常文件作为 ...

  6. Windows Kernel Security Training Courses

    http://www.codemachine.com/courses.html#kerdbg Windows Kernel Internals for Security Researchers Thi ...

  7. iOS安全相关学习资料

    https://github.com/zhengmin1989/iOS_ICE_AND_FIRE  (冰与火代码) http://weibo.com/zhengmin1989?is_hot=1 (蒸米 ...

  8. Topics

    Topics Introduction (starting with old devices) How to handle a new Firmware How to set up your Mac ...

  9. Android privilege escalation to mediaserver from zero permissions (CVE-2014-7920 + CVE-2014-7921)

    墙外通道:http://bits-please.blogspot.com/2016/01/android-privilege-escalation-to.html In this blog post ...

随机推荐

  1. 【转】Spring注解详解

    http://blog.csdn.net/xyh820/article/details/7303330/ 概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类 ...

  2. ios新特征 ARC详解

    IOS ARC 分类: IOS ARC2013-01-17 09:16 2069人阅读 评论(0) 收藏 举报   目录(?)[+]   关闭工程的ARC(Automatic Reference Co ...

  3. linux直接启动到字符界面或从字符界面启动到图形化界面

    修改/etc/inittab文件 将内容为:"id:5:initdefault"的行的数字5改为3,保存重启即可直接进入字符界面 PS:3和5分别表示运行级别 从字符界面启动到图形 ...

  4. js singleton

    方案一:利用闭包的两个作用,可以变通地读到内部的变量. 方案二: 是可以让这些变量始终在内存中. 方案一 var SingletonTester = (function () { //单例方法 fun ...

  5. db2索引创建和删除

    在表trpt_jv_rpt_log_td的tim列上创建索引 create index dw_rpt.irpt_jv_rpt_log_td_tim on dw_rpt.trpt_jv_rpt_log_ ...

  6. #include< >和#include""的区别

    Answer 1:#include 会将指定文件的内容插入到源程序文件中.当使用的格式时,编译器会从环境变量INCLUDE所指定的路径中寻找file-name 文件,如果没有定义INCLUDE,C 编 ...

  7. java学习之运算符

    学习完了变量+常量,现在只能简单的声明变量+赋值+打印变量. 但是程序要做的就是去处理数据,把原本散乱的数据,处理成有意义的数据,供我们来使用,这就涉及到了运算符的应用. 算数运算符常用的种类: 加法 ...

  8. C#:ref和out的联系及区别

    一:ref 关键字使参数按引用传递. 其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中.若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字. ...

  9. 快速了解常用XHTML基础

    运行效果: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w ...

  10. JavaScript交换两个变量值的七种解决方案

    前言 这篇文章总结了七种办法来交换a和b的变量值 1 2 var a = 123; var b = 456; 交换变量值方案一 最最最简单的办法就是使用一个临时变量了,不过使用临时变量的方法实在是太l ...