CVE-2014-1767分析

  一、简介

  1. 在著名黑客大赛 Pwn20wn2014 上, Siberas 安全团队利用CVE - 2014 - 1767 Windows AFD.sys 双重释放漏洞进行内核提权,以此绕过Windows8.1平台上的 IE11 沙箱(本次分析采用 win7 系统进行),随后该漏洞也因此获得2014 pwnie Awards "最佳提权漏洞",后来 Siberas 团队再其官网公布了漏洞细节及利用方法,他是 AFD.sys 驱动上的一处双重释放漏洞,影响较大。特定情况下攻击者可以通过该悬垂指针造成内存的 double free 漏洞。实现对漏洞的有效利用,攻击者利用成功可导致权限提升。AFD.sys是内核用来管理 socket 的模块。

    二、影响范围

    Windows Server 2003

    Windows Vista

    Windows Server 2008

    Windows 7

    Windows 8 & Windows 8.1

    Windows Server 2012

    三、漏洞分析

    3.1、分析环境

    3.2、编译poc

    首先,在 vc6 上编译用于触发漏洞的 poc 代码,然后在虚拟机中运行生成的 poc.exe ,同时挂载内核调试器进行分析。

    Poc 代码如下图 1所示(要在vc编译器里面编译)。POC 主要做了这么两件事:

    1. 初始化了一个本地socket连接。

    2. 给这个socket发送了两个控制码:0x1207F0x120C3

    图 1

     

    3.3、配置windbg+vmware+win7双机调试

    首先去微软官网下载 windbghttps: //docs. Microsoft.com/zh-cn/ windows - hardware/drivers/debugger/debugger-download-tools ,在本机安装, VMware 中安装win7,然后在虚拟机中安装 VMware Tools 。然后把target 这个文件夹拖入虚拟机(这个后面会给出,也可以百度双机调试教程)。在虚拟机中,打开这个文件夹,运行 vminstall.exe ,然后关机。如下图 2所示。

    开启虚拟机软件,进入虚拟机设置,添加命名管道,如下图 3所示。一般来说,没有修改的选项都是由如下图 4所示。添加时,要先将打印机删除,然后在添加。如下图 5所示。点击下一步,选择输出到命名管道,在点击下一步,命名如图3所示,然后点击完成。

    图 2

    图 3

     

    图 4

    图 5

    物理机,使用 vmmon64.exe ,如下图 6所示。然后选择打开虚拟机运行我们安装的 win7 .

    图 6

    运行后虚拟机后,会出现如下图 7所示,选择启动调试程序,然后 windbg会弹出并断下来,如下图 8所示。然后我们在命令行窗口,使用 g 命令,虚拟机正常启动,说明安装成功。

    图 7

    图 8

    现在已经可以,调试系统了。但是我们还需要微软的符号。WinDbg 可以通过加载 Symbol 文件(*.pdb),即时的调试程序,WinDbg 首先在 .exe 或者 .dll 所在目录下寻找同名的. pdb 文件。如果找不到,WinDbg Symbol File Path中查找。Symbol File Path 可以通过多种方式设置:
    1
    、通过WinDbg菜单File->Symbol File Path(Ctrl+S)然后把SRV*c:\mysymbol* http://msdl.microsoft.com/download/symbols输入如下 9所示。

    图 9


    2windbg 访问符号需要两个文件(SYMSRV.DLL SYMSTORE.EXE)所以添加主Path 环境变量中它们的路径进去,:你的windbg安装目录.

    操作方法:在桌面我的电脑点右键--属性--高级--环境变量,在系统变量列表框中找到

    Path 双击,在变量值最后面加一个分号再把你的安装目录写上.点确定. 这一步是告诉 windbg 那两个文件放在什么地方.新建一个环境变量_NT_SYMBOL_PATH 值为: SRV*c: \mysymbol *http : //msdl. Microsoft . com/ download / symbols

    还有一种新的方法是:设置值为  cache *c:\mysymbol ;srv*http : //msdl . microsoft . com/download/symbols 这两个的不同点在于第一个只能缓存符号服务器形式的符号文件,但是第二种可以缓存远程共享形式的符号文件。

    操作方法:桌面我的电脑点右键--属性--高级--环境变量 ,点击新建,把上面的变量名和变量值填上.这一步的意思是说告诉 windbg ,我的符号文件存放在c:mysymbol (当然其实里面什么也没有,甚至这个文件夹也不存在,不过没关系,系统找不到的话会给你创建一个,并在上面的网址中去帮你下载符号文件放在里面)重启计算机,再运行运行 windbg 打开一个 exe 文件或者附加到一个进程里去, 你会看到 Symbol search path is: SRV*c : \mysymbol * http: //msdl. Microsoft . com/download/symbols 打开 c 盘看到有一个新目录 mysymbol ,里面有 windbg 新下载的文件.恭喜说明配置成功了.还要把我们vc6 编译 poc.exe 的目录和 pdb 路径也要写在上面,方便调试。

    3.4、基于IOCTL处理函数自动追踪记录的分析方法

    将我们上边,编译生成的 poc.exe 在虚拟机中运行。运行后 windbg 断下来。然后我们使用 !analyze -v 命令分析如下图 10 11所示。

    图 10

    图 11

    我们在使用 lmvn afd 查看一下信息,如下图 12所示。

    图 12

    然后运行 g 命令,发现系统蓝屏,如下图 13所示。

    图 13

    根据上面的提示,我们可以知道,由于此处重复释放一块已经释放的内存,导致双重释放才引起的崩溃。在 poc 中程序两次调用 DeviceIoControl 分别向IO控制码 0x1207f 0x120c3 发送数据,因此我们可以直接从这两个 IO 控制码的分发函数入手。

    3.4.1、IO控制码0x1207f

    为了跟踪,IO控制码 0x1207f 对应的处理函数,首先在 WinDbg 中针对 ntNtDeviceIoControlFile 设置条件断点,当其处理IO控制码0x1207f时断下,由于IO控制码位于 NtDeviceIoControlFile 第六个参数,即 esp+18 ,因此条件断点如下图 14所示。

    图 14

    重启电脑,注意不要蓝屏直接关机,如果直接关机需要重新编译poc(有很大几率)。然后启动电脑的时候 windbg ,回和上面一样断下来,然后下上面的断点,g 命令运行,然后再次点击 poc.exe 发现程序断下,然后使用dd esp+18 l1命令查看参数,如下图 15所示。

    图 15

    发现果然是1207f ,然后使用wt 命令,追踪后续各个函数的调用过程。使用命令后需要快速点击如下图16所示,否则停不下来就直接进入蓝屏。

    图 16

    使用wt命令后,得到的结果如下图 17所示。

    图 17

    可以看到当 IOCTL 0x1207f 时, afd 驱动中的 AfdTransmitFile 函数会被调用,通过Google可以搜索到函数原型为NTSTATUS AftTransmitFile(pIRP,pIoStackLocation ),IRPIoStackLocation结构各个字段定义可通过dt命令查看,如下图 18所示。

    图 18

    使用IDAf5插件反编译 Afd.sys 中的 AfdTransmitFile 函数,并分别将a1a2的参数重命名为 pIRP pIoStackLocation 代码分析如下图 19所示。

     

     

    图 19

    Windows内存管理中,系统存在一个叫 LookasideList 在《软件调试》一书中,将其称为"旁视列表",在《 oday安全:软件漏洞分析技术》中将其称为"块表"的结构,其作用是提高系统内存分配效率。在 Lookaside 列表初始化时,他会向系统申请一块比较大的内存,之后程序每次申请内存时,都会优先从块表中申请,只有当 Lookaside 中的内存不够的时候,才向系统申请更多的内存,这样既可以节省分配时间,又能够避免产生过多的内存碎片。关于 lookaside 的信息可以参考上面的两本书和《使用Lookaside List分配内存》接下来,要调用的AfdTliGetTpInfo函数,正是使用了上面讲到的Lookaside List,在AfdTliGetTpInfo函数上下断点,然后逐步跟踪下去。重启虚拟机,下bu AfdTliGetTpInfo断点,为了方便观察这里直接使用u命令查看反汇编,如下图 20所示。

    图 20

    AfdAllocateTpInfo 函数原型为, TpInfo* AfdAllocateTpInfo(POOL_TYPE PoolType,SIZE_T NumberOfBytes,ULONG Tag) 用于分配 TpInfo 结构查看 afdAfdAllocateTpInfo 调用的参数,当前栈顶数据,可以看到分配的TpInfo结构大小为 0x108 ,如下图 21所示。

    图 21

    可以看出, ExAllocateFromNPagedLookasideList 函数是分配 TpInfo 结构内存的,因此我们可以在IDAf5反编译代码中将 ExAllocate From NP aged Lookas ide List返回值v2重命名为tpinfo,而AfdTliGetTpInfo函数最终返回设置成TpInfo结构指针如下图 22所示。

     

    图 22

    继续分析 AfdTransmitFile 函数接下来的代码,如下图 23所示。

    图 23

    根据上面的代码信息,我们可以大致绘制出 TpInfoElement 的数据结构如下图 24所示。

    图 24

    AfdTransmitFile 函数中调用 IoAllocateMdl 分配完内存之后,单步跟踪下去,他会调用MmProbeAndLockPages去锁定内存范围0x13371000~0x13371000+0x16ecca (都是由poc中的代码设置的值),该内存地址属于无效地址,因此会触发异常,如下图 25所示。

    图 25

     

    触发异常后,程序回去调用 AfdReturnTpInfo 函数,在 AfdReturnTpInfo 下断点,然后单步执行MmProbeAndLockPages函数后,确定会触发异常直接断下来,如下图 26图图 27所示。

    图 26

     

     

    图 27

    下面是 AfdReturnTpInfo 的一段逆向代码,如下 28所示。针对我们这次执行流,AfdReturnTpInfo 执行的效果就是 free 掉了刚刚申请的 MDL 源,并且将 tpInfo 指针 push lookaside list 中去了!

    Double free 的第一次 freefree mdl 后,存放在 tpInfo 中的 Mdl 指针并没有清空,tpInfo elemCount 也维持原始值,未做改动,如果此时AfdReturnTpInfo再次被调用,那么TpInfoElement+0xc将会被IoFreeMdl函数用于释放内存,最终造成Double Free双重释放漏洞。

    怎么样再次调用一次 AfdReturnTpInfo

    考虑到 afd.sys AfdReturnTpInfo 是在大多是在异常处理程序中使用的,因此考虑再制造一次异常当然要想命中 double free 必须保证在发生异常时候, tpInfo 的值不能被破坏

     

    图 28

    3.4.2、IO控制码0x120c3

    采用前面的方法,追踪IO控制码0x120c3对应的处理函数,可以发现他调用的是afd!AfdTransmitOackets函数,如下图 29所示。

    图 29

    afd!AfdTransmitPackets 函数的两个参数分别为 pIRPpIoStackLocation ,因此 IDA 中将其 a1 a2 参数分别重命名为 pIRP pIoStackLocation (鼠标选中变量,然后按 n 可以重命名),f5反编译的代码可以发现它与AfdTransmitFile 函数开头部分有些类似,如下图 30 31所示。

     

     

    图 30

    图 31

    通过 WinDb g 动态调试判断上面一些条件语句的跳转情况,再结合IDA静态分析,可以知道若要成功调用到 AfdTdiGetTpInfo 函数(之所以要调用该函数,主要是用于实现 AfdReturnTpInfo 的再次调用,已造成双重释放漏洞)必须满足以下条件。如下图 32所示。

    图 32

    关于 AfdTliGetTpInfo 函数,前面已经逆向分析过,他会调用ExAllocatePoolWithQuotaTag 分配* Type3InputBuffer+4)个 TpInfoElement 所需的内存。在poc中是设置为0xAAAAAAATpInfoElement ,而每个TpInfoElement结构占0x18字节,因此共需要申请内存0x18* 0xAAAAAAA=0xFFFFFFF0 ,这么大的内存申请在32位显然是不会成功的,会触发异常再次进入AfdReturnTpInfo函数中。在AfdTliGetTpInfoAfdReturnTpInfobu afdTliGetTpinfo bu AfdReturnTpInfo断点,然后单步跟踪上述过程,如下图 33所示,然后运行程序在第二次断下就是我们要查看的地方。

    图 33

    单步跟踪,一直执行到 IOFreeMdl 函数,使用 dd 命令查看 esp ,然后用dt _MDL 查看结构体,赫然发现和上面一样,然后再次访问 13371000 地址,触发异常。如下图 34所示。

    图 34

    然后运行, Windbg 断下给出一些提示信息,如下图 35所示。使用 g 命令继续运行,发现虚拟机蓝屏如下图 36所示。

    图 35

     

    图 36

    3.5、原理总结

    第一次 DeviceIoControl IoControlCode = 0x1207F, afd.sys 内部调 AfdTransmitFileAfdTransmitFile 首先会调用 AfdTliGetTpInfo 获得一个 TpInfo 结构体。然后依照我们输入 buffer 中提供的 virtualAddres length 去申请一个 MDL申请 MDL 后,将 MDL 的地址填入到 TpInfo 的数组域内。调用 MmProbeAndLockPages 尝试锁定这块内存,由于我们提供的是无效的地址范围,此时抛出异常,异常处理程序调用 AfdReturnToInfo 释放刚刚申请的 TpInfo lookaside list。同时释放掉刚刚申请的 MDL 问题是被释放的 TpInfo 的值没有被清空,elemCount pMdl 都没有清理,pMdl 此时就是 dangling pointer

    第二次 DeviceIoControl, IoControlCode =0x120c3, afd.sys 内部调用

    AfdTransmitPacketsAfdTransmitPackets 内部调用 AfdTliGetTpInfo 获得一个 TpInfo 结构体,而调用 AfdTliGetTpInfo 时的参数是由我们的输入指定的! AfdTliGetTpInfo 首先从 lookaside list 中拿出一个 TpInfo 指针,这个指针正是第一次 IoControl 时候申请的那个!,然后因为我们指定的参数 elemCount 大于 3 AfdTliGetTpInfo 尝试 Alloc 额外的内存,因为我们可以恶意指定很大的内存申请,这导致了申请内存过程中发生异常,程序执行流再次进入异常处理,异常处理程序调 AfdReturnToInfo 尝试释放刚刚申请的 TpInfo,因为此时 TpInfo 中完全保留的是第一次 IoControl 时填充的"过时"的值,因此造成 pMdl dangling pointer 的二次释放,导 double-free crash !

  2. 漏洞利用

    4.1、思路

  3. 调用 DeviceIoControl IoControlCode = 0x1207F, 造成一次 MDL free。创建一个对象去"占坑"填充第一次释放的内存,但是该对象的大小必须与释放内存的大小是一致的(但是MDL大小是可以被用户控制的因此不成问题)pwn20wn比赛上 Siberas 团队使用的是 WokerFactory ,其大小是0xA0.
  4. 然后调用 DeviceIoControl, IoControlCode =0x120c3,再次释放,释放掉刚才新申请的对象。
  5. 覆盖被释放掉的对象为可控数据,将可控数据(shellcode)覆盖到已释放内存Siberas使用包含memcpy的内核函数NtQueryEaFile实现该操作。
  6. 尝试调用能够操作此对象的函数,让函数通过操作我们刚刚覆盖的可控数据,实现一个内核内存写操作,这个写操作最理想的就是"任意地址写任意内容",这样我们就可以覆写 HalDispatchTable 的某个单元为我们 ShellCode 的地址,这样就可以劫持一个内核函数调用
  7. 在用户层调用NtQueryIntervalProfile函数执行shellcode以实现提权。
  8. 用户层触发刚刚被 Hook HalDispatchTable 函数,使得内核执shellcode,提权

    4.2选择合适的对象

    1、这个对象的大小要等于第一次被释放的mdl内存的大小(uaf

    2、这个对象应该有这样一个操作函数,这个函数能够操作我们的恶意数据,使得我们简介实现任意地址写任意内容

    经过逆向,第一次释放的是一个MDL对象,且MDL对象的大小是由VritualAddress length 共同决定的(IoAllocateMdl函数),而virtualAddresslength是由用户控制的参数)大小相同的要求就不必担心了,如下图 37所示。

    图 37

    WorkerFactory 对象存在一个函数 NtSetInformationWorkerFactory ,该函数位于C:\windows\system32\ntoskrnl.exeSiberas 团队之所以使用 WokerFactory对象,是因为他刚好存在NtSetInformationWorkerFactory 操作函数能够帮助实现任意内容写任意地址,即上面的操作,使用WinDbg u命令,反汇编NtSetInformationWorkerFactory 函数,如下图 38- 40所示。

    图 38

    图 39

    图 40

    然后我们使用WinDbg动态调试,查看句柄值及其对象,下bu ntNtSetInformationWorkerFactory然后g,(这次调试需要使用exp,下面会给出)。WinDbg断下然后执行到nt!ObReferenceObjectByHandle,使用dd ebp+8 l1查看参数句柄,在使用!Handle命令查看句柄的详细信息。如下图 41所示。

     

    图 41

    接下来,我们继续向下查看 NtSetInformationWorkerFactory 函数,注意直接下 NtSetInformationWorkerFactory 函数断点会不停的断下,可以先下0x1207f的断点,点击 exp.exe 然后 windbg断下然后在在NtSetInformationWorkerFactory函数的断点。多调试几遍,总会找到的。如下图 42所示。

    图 42

    继续向下单步跟踪,到NtSetInformationWorkerFactory+0x16b 发现mov dword ptr[eax+1ch],edi这条指令,根据上面的分析可以得出,这里实现任意地址写任意内容,即*(*(*object+0x10)+0x1c)=*arg3,这里可用于将shellcode地址写入HaliQuerySystemInformation以供后续调用shellcode执行,如下图 43所示。

    图 43

    可以发现当 ( arg2 == 8 && arg3 !=0)时,*(*(* object+0x10 )+0x1c)=*arg3就实现的任意地址写任意内容,因此可令 arg3 = shellcode ( * ( object + 0x 10 ) + 0x 1c ) = ( HalDispatchTable+0x4)=HaliQuerySystemInformation,这样就可以将shellcode地址写入 HaliQuerySystemInformation 供后续调用。

    4.3将shellcode复制到内核地址

    我们分析知道被释放的 MDL 属于 NonPagedPool,而用户空间的 VirtualAlloc 并没有能力为我们在 NonPagedPool 上分配空间从而让我们覆盖我们的数据!这就又要采取类似使用 NtSetInformationWorkerFactory 的方法,找那样一个 Nt* 系列函数,它的内部操作能够为我们完成一次 ExAllocatePool 并且是 NonPagedPool ,并且还有能复制我们的数据到它新申请的这个内存中去!就是完成一次内核 Alloc 并且 memcpy 的操作!我们使用NtQueryEaFile这个函数。该函数原型如下 44所示。

    图 44

     

    WinDbg 反汇编 NtQueryEaFile函数,使用uf NtQueryEaFile,如下图 45所示。

    图 45

    继续跟踪下去,发现其长度长度给了esi,如下图 46所示。

    图 46

    然后发现其调用 ExAllocatePoolWithQuotaTag , push 了三个参数分别为tagNumberofBytesPoolType,如下图 47所示。

     

    图 47

    这里还有一个坑,ExAllocatePoolWithQuotaTag会再次调用ExAllocatePoolWithTag,其长度值会在加4即实际上ExAllocatePoolWithQuotaTag分配的长度是EaLength+4,在释放的对象内存进行占坑时,应该将对象大小objectsize-4,才能使大小相等,占坑成功,我们跟进ExAllocatePoolWithQuotaTag函数,会发现如下图 48所示。

    图 48

    然后继续跟踪下去,发现其调用 memcpy 拷贝 shellcode ,如下图 49所示。

    图 49

    因此使用 NtQueryEaFile 时候,字节数=EaLength=objSize-0x4 才可以正常利用堆缓冲机制使得申请的内存正好占据原本对象的空间。以及NtQueryEaFile函数之后会把分配的内存释放掉,不过除了堆头部那些东西剩下的数据不会改变,不会影响到我们接下来的利用。

    到这里真的对想出漏洞利用方法的人五体投地,也意识到自己的局限和漫长的道路。可以看到前面涉及到了很多冷僻的 windows 函数,类,以及对windows内核函数的逆向,真的是一个很长的积累的过程。

    4.4伪造WorkerFactory对象

     

    现在已经可以利用第二次调用 DeviceIoControl ,并利用 uaf 的方法修改WorkerFactory 对象的内存数据。为了保证之后调用其方法函数时不会出奇怪的错误,需要考虑对象原本的数据结构取巧的方法就是直接把正常对象的头部复制过来.发现 ExAllocatePoolWithTag 申请的字节数是 0xA0 字节!,但是返回到 NtCreateWorkerFactory 时候,对象指针是 p+0x28 p Ex Allocate Pool WithTag 返回的指针。这也是可以解释的,因为每个对象都有一个 Header,这个可以从 dt _OBJECT_HEADER 看出来,body header 偏移 0x18 字节,另外 ObpAllocateObject 也附加了一层信息 0x10 字节因此总共就是偏移原始内存+0x28 节。知道这个我们才可以布局我们的 fake object,实现内核写。

    另外,在 ObjHeader 中有许多域的值很重要,我们需要提前设置,因为

    NtSetInformationWorkerFactory 中调用 ObReferenceObjectByHandle,

    通过句柄获得对象地址,这里要校验 objHeader 里面的内容才可以成功获得 Obj 地址(这里就是 p+0x28 处)。HalDispatchTable 劫持我们依然选择 HalDispatchTable+sizeof(PVOID) 的位置劫持,用户层使用 Nt Query Interval Profile 触发。这样就可以往常见的内核漏洞利用方式,借助Nt Query Interval Profile 函数执行shellcode ,将系统进程的 token 赋予当前进程,最终实现本地提权。

    4.5、exp设计

    4.5.1首次释放

    首先第一次释放,通过 WorkerFactory 对象的大小0xa0反推inbuf1中的length参数,保证二者大小一致,满足uaf的条件,如下图 50所示。

    图 50

    4.5.2、创建对象

    接着创建一个 WorkerFactory 对象,如下图 51所示。

    图 51

    此时 WorkerFactory 对象将会被分配到之前释放的位置。

    4.5.3二次释放

    然后第二次释放,如下图 52所示。

    图 52

     

    4.5.4伪造对象并拷贝到原本WorkerFactory对象的位置

    首先伪造对象,如下图 53所示。

    图 53

     

    使用 NtQueryEaFile 再次申请一块内存,如下图 54所示。

    图 54

    4.5.5、dword write to HalDispatchTable

    图 55

    4.5.6、恢复蓝屏

    实际操作发现,当结束提权程序时候,会直接 crash 蓝屏,我们已经破坏了 WorkerFactory 对象,但是系统并不知道,在进程退出时要清理对象,于是蓝屏也可以理解。因为蓝屏发生在提权之后,因此我们完全可以在内核态 shell code 实现 hack,让系统不知道这个已经 corrupt 的对象!通过逆向 Ex Sweep Handle Table 发现了解决方法,如下 56所示。

    图 56

    我们要做的就是 hWorkerFactory 对应的 HandleTableEntry Object 域置为 NULL !,这样就越过了本句柄的释放步骤!逆向 Ex pLook up Handle Table Entry 得出 Handle HandleTableEntry 的关系: HandleTableEntry = *(DWORD*)ObjectTable + 2*(Handle & 0xFFFFFFC0) 因此通过将对应的 HandleTableEntry Object 域清为 NULL 就可以了,此外 HandleCount 也要记得减 1. 另外,恢复 HalDispatchTable 的项也是必要的,否则有可能因为被其他进程调用而蓝屏。

    4.6、shellcode

    我们可以先在Windbg中下 IO 控制码 0x1207f 断点,然后点击exp.exe,上面有 shellcode 的地址,然后我们使用u命令查看一下,然后在 shellcode 地址上面也下一个执行断点,如下图 57所示。

    图 57

    发现程序的执行流程果然,执行到 shellcode 。跟踪执行,查看进程 token ,如下图 58所示。

    图 58

    继续执行发现其修改进程 token 值实现提权,如下图 59所示。

    图 59

    WinDbg 清除断点,使用bc 0,然后使用g命令,运行结果如下 60所示。提权成功。

    图 60

    五、补丁分析

    由于微软并未提供,此次分析漏洞的 win7补丁,所以只能通过升级到win7sp1系统版本,在打相应的补丁,可以从微软官方站点下载相应的sp1升级包,然后在从官网下载MS14-040Windows7 sp1漏洞补丁。这里给出官网地址

    https://docs.microsoft.com/zh-cn/security-updates/Securitybulletins/2014/ms14-040

    补丁文件是一个 msu 文件,直接双击运行就可。(选择与自己对应的版本)。

    使用 IDA 加载补丁后 afd.sys ,然后定义到漏洞函数 AfdReturnTpInfo进行分析。由于只有TpInfoElementCount > 0时,才会调用到 IoFreeMdl 函数,因此补丁在第一次调用完 IoFreeMdl 后,将 TpInfoElementCount 清零,使得他不会再次调用 IoFreeMdl ,从而避免造成双重释放漏洞。如下图 61 62所示。

    图 61

     

    图 62

     

    六、总结

    本次漏洞是 windows 内核漏洞进行分析,并介绍了漏洞利用的原理和分析技巧,其中颇具艺术的漏洞利用技巧进行探究。理解 windows 平台上的内核漏洞的原理,掌握一些内核漏洞的常用攻击手法,只有理解漏洞及其攻击手法,才能定制更加完善的漏洞检测与拦截规则

    内核漏洞的调试相对于普通应用的调试会更麻烦,而且一旦蓝屏,就要重启系统再来,所废时间更多。结合一定驱动开发经验,在调试分析的时候会更加顺手,更快的找到漏洞的根源。

      参考文章

      《漏洞战争》

     https://www.jianshu.com/p/6b01cfa41f0c

     https://bbs.pediy.com/thread-194457.htm

     https://www.cnblogs.com/flycat-2016/p/5450275.html

     

     

     

     

     

     

     

     

     

     

     

posted @ 2019-07-18 09:57  一生热爱  阅读(969)  评论(0)    收藏  举报