


MS11-011漏洞分析
早就想分析一下傳說中的長老漏洞,不過因為開學的原因,各種事情,一直沒有時間,這兩天抽時間把漏洞的分析做完了,本來還計劃研究一下利用代碼和補丁,但是現在不得不放棄了,現把自己的分析過程貼出來,逆向和語文能力都不怎么樣,有描述不清之處,請見諒,同時歡迎各位大牛拍磚,但請盡量溫柔!
以下內容全部是個人理解,無法保證其正確性,僅供參考!!!
測試環境:Windows 7
測試工具:VMWare + Windbg + IDA
首先下載漏洞的利用程序,在虛擬機中測試一下,發現程序可以正常運行:
代碼:
C:\>whoami
q-test\qever
C:\>poc
C:\>whoami
nt authority\system
下面開始尋找漏洞的成因。
為了減少工作量,應該盡可能地確定漏洞產生的準確位置,在這里采用的方法是在poc的源代碼的shellcode起始位置添加0xcc,對應的是"int 3"指令,這樣shellcode一運行,就會立刻斷下來,然后就可以進行分析了。
修改過程就不廢話了,直接運行修改后的程序,當windbg斷下來之后,查看調用堆棧,卻發現調用堆棧被破壞了
代碼:
kd> k
ChildEBP RetAddr
WARNING: Frame IP not in any known module. Following frames may be wrong.
00000000 00000000 0x3d0000
此時可以通過對當前棧進行分析粗略估計出錯位置。當然,還有一種比較好的方法,考慮到程序可以正常執行,故shellcode運行完畢后必定會返回調用位置,那么在shellcode返回位置下斷,運行再次斷下來之后查看堆棧可以得到
代碼:
kd> k
ChildEBP RetAddr
WARNING: Frame IP not in any known module. Following frames may be wrong.
92639d14 994bb8d0 0x3d0096
92639d28 83c7f42a win32k!GreEnableEUDC+0x7c
92639d28 772964f4 nt!KiFastCallEntry+0x12a
看到上面的信息,再結合poc源碼中的漏洞觸發代碼,就能確定問題就是出現在win32k!GreEnableEUDC函數里面了,那么就從它開始分析查找漏洞成因吧!
為了減少工作量,這里采用了一種比較笨的方法,多次嘗試來準確判定出錯原因及位置。過程如下:
在win32k!GreEnableEUDC處下斷點,運行修改后的程序,然后單步跟蹤,直至觸發shellcode中"int 3"指令,多次嘗試之后可以確定如下調用信息:
代碼:
win32k!GreEnableEUDC+0x77 : call win32k!BuildAndLoadLinkedFontRoutine+0xeb
win32k!BuildAndLoadLinkedFontRoutine+0x19d : call win32k!bAppendSysDirectory+0x209
win32k!bAppendSysDirectory+0x334 : ret 8 //出錯!
即在調用win32k!bAppendSysDirectory+0x209函數之后返回時跳入shellcode,同時在返回時查看堆棧可以發現返回地址被修改了,也就是說在該函數運行過程中棧空間被修改,即棧溢出。
結合網上的信息,多次嘗試后可以確定整個漏洞的產生流程:
代碼:
nt!KiFastCallEntry+0x128 : call ebx (win32k!GreEnableEUDC)
win32k!GreEnableEUDC+0x77 : call win32k!BuildAndLoadLinkedFontRoutine+0xeb
win32k!BuildAndLoadLinkedFontRoutine+0x19d : call win32k!bAppendSysDirectory+0x209
win32k!bAppendSysDirectory+0x2de : call dword ptr [win32k!_imp__RtlQueryRegistryValues (9972f104)]
nt!RtlQueryRegistryValues+0x318 : call nt!RtlpCallQueryRegistryRoutine (83e2ab81)
nt!RtlpCallQueryRegistryRoutine+0x290 : call nt!RtlpQueryRegistryDirect (83e33997)
nt!RtlpQueryRegistryDirect+3D : call nt!memcpy (83c797a0) //溢出
win32k!bAppendSysDirectory+0x334 : ret 8 //出錯!
那么只要分析上面所列出函數的行為,就應該能確定漏洞的成因了。
接下來我們挨個來分析以上函數,實際分析過程中是Windbg動態調試和IDA靜態分析同時進行的,在此為了書寫方便,僅對Windbg代碼進行分析。
對于win32k!GreEnableEUDC,涉及到一些不知道什么意思的變量,不過并不影響分析過程。
代碼:
win32k!GreEnableEUDC+0x37:
9956b88b 33f6 xor esi,esi //esi清零
9956b88d 46 inc esi //esi == 1
……
win32k!GreEnableEUDC+0x75:
9956b8c9 56 push esi //參數壓棧
9956b8ca 56 push esi //參數壓棧
9956b8cb e8b8faffff call win32k!BuildAndLoadLinkedFontRoutine+0xeb (9956b388)
在此只簡單提一下,調用參數均為1,畢竟漏洞產生的原因并不在此。
這個函數應該是對應poc源碼中的EnableEUDC(TRUE);一句,EUDC就不解釋了,因為沒找到好的中文資料,附上微軟的介紹:
http://msdn.microsoft.com/zh-cn/library/ms900737.aspx
根據前面的分析,要關注win32k!BuildAndLoadLinkedFontRoutine+0xeb函數,所以這里重點列出該函數的兩個參數,均為1。
下面來看BuildAndLoadLinkedFontRoutine+0xeb函數,這個函數中也沒有什么重點內容,依舊是列出參數,和調用語句。
代碼:
995cb393 be08020000 mov esi,208h
995cb398 56 push esi
995cb399 8d4dfc lea ecx,[ebp-4]
995cb39c e8a6030000 call win32k!MALLOCOBJ::MALLOCOBJ (995cb747) //生成MALLOCOBJ對象
……
995cb3aa 8b5dfc mov ebx,dword ptr [ebp-4]
……
995cb434 6804010000 push 104h
995cb439 53 push ebx
995cb43a e8a0050000 call win32k!bAppendSysDirectory+0x209 (995cb9df)
win32k!bAppendSysDirectory+0x209 函數的兩個參數,依次是MALLOCOBJ對象指針和0x104。
關于win32k!MALLOCOBJ,個人感覺就像一個字符串的類,而在整個漏洞分析過程中,該對象也是扮演了一個字符串的角色,同時在內存起始位置記錄了字符串信息。
下面這個win32k!bAppendSysDirectory+0x209函數就比較關鍵了,最終出錯也是在這個函數當中,先看代碼:
代碼:
win32k!bAppendSysDirectory+0x209:
9955b9df 8bff mov edi,edi
9955b9e1 55 push ebp
9955b9e2 8bec mov ebp,esp
9955b9e4 83ec20 sub esp,20h
9955b9e7 53 push ebx
9955b9e8 56 push esi
9955b9e9 57 push edi
9955b9ea be08020000 mov esi,208h
9955b9ef 56 push esi
9955b9f0 8d4df4 lea ecx,[ebp-0Ch] //ebp-0Ch為MALLOCOBJ對象指針
9955b9f3 e84ffdffff call win32k!MALLOCOBJ::MALLOCOBJ (9955b747)
9955b9f8 56 push esi
9955b9f9 8d4dfc lea ecx,[ebp-4] //ebp-4為MALLOCOBJ對象指針
9955b9fc e846fdffff call win32k!MALLOCOBJ::MALLOCOBJ (9955b747)
9955ba01 8b4df4 mov ecx,dword ptr [ebp-0Ch]
9955ba04 33f6 xor esi,esi //esi == 0
9955ba06 3bce cmp ecx,esi
9955ba08 0f84e6000000 je win32k!bAppendSysDirectory+0x31e (9955baf4)
win32k!bAppendSysDirectory+0x238:
9955ba0e 8b7dfc mov edi,dword ptr [ebp-4]
9955ba11 3bfe cmp edi,esi
9955ba13 0f84db000000 je win32k!bAppendSysDirectory+0x31e (9955baf4)
win32k!bAppendSysDirectory+0x243:
9955ba19 33c0 xor eax,eax
9955ba1b 8975f0 mov dword ptr [ebp-10h],esi
9955ba1e 8975ec mov dword ptr [ebp-14h],esi
9955ba21 668901 mov word ptr [ecx],ax
9955ba24 668907 mov word ptr [edi],ax
9955ba27 668945e0 mov word ptr [ebp-20h],ax
9955ba2b b804010000 mov eax,104h
9955ba30 50 push eax
9955ba31 8bd0 mov edx,eax
9955ba33 57 push edi
9955ba34 8975e8 mov dword ptr [ebp-18h],esi
9955ba37 668955e2 mov word ptr [ebp-1Eh],dx
9955ba3b 894de4 mov dword ptr [ebp-1Ch],ecx
9955ba3e e8d7feffff call win32k!GrePolyPolyline+0xa2 (9955b91a) //返回"\REGISTRY\USER\S-1-5-18\EUDC\936"
9955ba43 3bc6 cmp eax,esi
9955ba45 8945f8 mov dword ptr [ebp-8],eax
9955ba48 7c7c jl win32k!bAppendSysDirectory+0x2f0 (9955bac6)
上面這段代碼,首先生成MALLOCOBJ對象,通過調用win32k!GrePolyPolyline+0xa2函數,返回"\REGISTRY\USER\S-1-5-18\EUDC\936",即需要查詢的注冊表項。
代碼:
win32k!bAppendSysDirectory+0x274:
9955ba4a 8d45e8 lea eax,[ebp-18h]
9955ba4d 50 push eax
9955ba4e 8d45ec lea eax,[ebp-14h]
9955ba51 50 push eax
9955ba52 8d45f0 lea eax,[ebp-10h]
9955ba55 50 push eax
9955ba56 57 push edi
9955ba57 e850010000 call win32k!AutoResource<&ExFreePool>::~AutoResource<&ExFreePool>+0x177 (9955bbac)
9955ba5c 85c0 test eax,eax
9955ba5e 745f je win32k!bAppendSysDirectory+0x2e9 (9955babf)
win32k!bAppendSysDirectory+0x28a:
9955ba60 3975e8 cmp dword ptr [ebp-18h],esi
9955ba63 745a je win32k!bAppendSysDirectory+0x2e9 (9955babf)
這段代碼是打醬油的~~
代碼:
win32k!bAppendSysDirectory+0x28f:
9955ba65 56 push esi
9955ba66 56 push esi
9955ba67 68e0887599 push offset win32k!SharedQueryTable (997588e0)
9955ba6c 57 push edi //"\REGISTRY\USER\S-1-5-18\EUDC\936"
9955ba6d 8d45e0 lea eax,[ebp-20h]
9955ba70 56 push esi
9955ba71 8935e0887599 mov dword ptr [win32k!SharedQueryTable (997588e0)],esi //0
9955ba77 c705e488759924000000 mov dword ptr [win32k!SharedQueryTable+0x4 (997588e4)],24h //24h
9955ba81 c705e888759964a67399 mov dword ptr [win32k!SharedQueryTable+0x8 (997588e8)],offset win32k!`string' (9973a664) //"SystemDefaultEUDCFont"
9955ba8b a3ec887599 mov dword ptr [win32k!SharedQueryTable+0xc (997588ec)],eax //指向函數棧的指針,最終出錯也是因為這個參數
9955ba90 8935f0887599 mov dword ptr [win32k!SharedQueryTable+0x10 (997588f0)],esi //0
9955ba96 8935f4887599 mov dword ptr [win32k!SharedQueryTable+0x14 (997588f4)],esi //0
9955ba9c 8935f8887599 mov dword ptr [win32k!SharedQueryTable+0x18 (997588f8)],esi //0
9955baa2 8935fc887599 mov dword ptr [win32k!SharedQueryTable+0x1c (997588fc)],esi //0
9955baa8 893500897599 mov dword ptr [win32k!SharedQueryTable+0x20 (99758900)],esi //0
9955baae 893504897599 mov dword ptr [win32k!SharedQueryTable+0x24 (99758904)],esi //0
9955bab4 ff1504f17299 call dword ptr [win32k!_imp__RtlQueryRegistryValues (9972f104)]
上面是關鍵的RtlQueryRegistryValues函數調用,我們可以查到RtlQueryRegistryValues的定義:
代碼:
NTSTATUS
RtlQueryRegistryValues(
IN ULONG RelativeTo,
IN PCWSTR Path,
IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
IN PVOID Context,
IN PVOID Environment OPTIONAL
);
結合反匯編的結果,該函數的調用參數:RelativeTo為0,即RTL_REGISTRY_ABSOLUTE,表示絕對路徑,Path值為"\REGISTRY\USER\S-1-5-18\EUDC\936",由win32k!GrePolyPolyline+0xa2函數返回。QueryTable參數的類型為PRTL_QUERY_REGISTRY_TABLE其定義如下:
代碼:
typedef struct _RTL_QUERY_REGISTRY_TABLE {
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
ULONG Flags;
PWSTR Name;
PVOID EntryContext;
ULONG DefaultType;
PVOID DefaultData;
ULONG DefaultLength;
} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
可能在Win7下對此結構有一定的擴充,不過并不影響分析。
Name值為"SystemDefaultEUDCFont",即要查詢的內容。DefaultType會存儲查詢結果,其值為ebp-20h。其余參數為0。
事實上,對于了解RtlQueryRegistryValues函數的人來說,看到這里就已經知道問題所在了,但是作為一次漏洞分析,如果僅僅止步于此的話,并不足以說明問題,按就讓我們接著看下去吧!
下面是RtlQueryRegistryValues函數,這個函數內容比較多,分段來解釋:
代碼:
kd> uf nt!RtlQueryRegistryValues
nt!RtlQueryRegistryValues:
83e32d85 8bff mov edi,edi
83e32d87 55 push ebp
83e32d88 8bec mov ebp,esp
83e32d8a 83e4f8 and esp,0FFFFFFF8h
83e32d8d 83ec4c sub esp,4Ch
83e32d90 8b4d0c mov ecx,dword ptr [ebp+0Ch] //exc == Path
83e32d93 53 push ebx
83e32d94 56 push esi
83e32d95 8b7508 mov esi,dword ptr [ebp+8] //esi == RelativeTo
83e32d98 57 push edi
83e32d99 8d442420 lea eax,[esp+20h] //eax == ebp - 0x3c esp == 9240fc30
83e32d9d 50 push eax
83e32d9e 33ff xor edi,edi //edi == 0
83e32da0 57 push edi
83e32da1 8bd6 mov edx,esi //edx == RelativeTo
83e32da3 e89f0a0000 call nt!RtlpGetRegistryHandle (83e33847) //打開"\REGISTRY\USER\S-1-5-18\EUDC\936"返回,返回值放入[ebp - 0x3c](KeyHandle)
83e32da8 3bc7 cmp eax,edi //eax ntStatus
83e32daa 8944240c mov dword ptr [esp+0Ch],eax //ebp=9240fc8c esp=9240fc30
83e32dae 0f8cf7030000 jl nt!RtlQueryRegistryValues+0x426 (83e331ab) 0
上面這一段,調用nt!RtlpGetRegistryHandle,跟進之后可以發現,函數內部打開了注冊表"\REGISTRY\USER\S-1-5-18\EUDC\936"項,并將句柄放入[ebp - 0x3c]中,為了表示方便,將其命名為KeyHandle。
代碼:
nt!RtlQueryRegistryValues+0x2f:
83e32db4 8974242c mov dword ptr [esp+2Ch],esi // esp + 2c == ebp - 30
83e32db8 8164242c00000040 and dword ptr [esp+2Ch],40000000h
83e32dc0 8d442438 lea eax,[esp+38h] // esp + 38 == ebp - 24
83e32dc4 7505 jne nt!RtlQueryRegistryValues+0x46 (83e32dcb)
nt!RtlQueryRegistryValues+0x41:
83e32dc6 ff750c push dword ptr [ebp+0Ch]
83e32dc9 eb01 jmp nt!RtlQueryRegistryValues+0x47 (83e32dcc)
//nt!RtlQueryRegistryValues+0x46:
//83e32dcb 57 push edi
nt!RtlQueryRegistryValues+0x47:
83e32dcc 50 push eax //ebp - 24
83e32dcd e81661e4ff call nt!RtlInitUnicodeString (83c78ee8) //ebp - 24 == Unicode_String_Path
83e32dd2 8d44240c lea eax,[esp+0Ch] //eax == ebp-50 status
83e32dd6 50 push eax
83e32dd7 57 push edi
83e32dd8 8d74242c lea esi,[esp+2Ch] //esi == ebp-38
83e32ddc c744242c84000000 mov dword ptr [esp+2Ch],84h
83e32de4 e8d782ffff call nt!RtlpAllocDeallocQueryBuffer (83e2b0c0) //用esi傳參,函數內執行ExAllocatePoolWithTag(1,0x84,0x76727152)
83e32de9 8bf0 mov esi,eax //esi指向申請空間首地址
83e32deb 3bf7 cmp esi,edi
83e32ded 7518 jne nt!RtlQueryRegistryValues+0x82 (83e32e07)
以上內容調用了nt!RtlpAllocDeallocQueryBuffer函數,其內部執行ExAllocatePoolWithTag(1,0x84,0x76727152),即申請大小為0x84的內存空間,返回內存空間的首地址。
代碼:
nt!RtlQueryRegistryValues+0x82:
83e32e07 8b5d10 mov ebx,dword ptr [ebp+10h] //ebx == QueryTable
83e32e0a 897e08 mov dword ptr [esi+8],edi
83e32e0d 8b442420 mov eax,dword ptr [esp+20h] //eax == KeyHandle
83e32e11 c744242882000000 mov dword ptr [esp+28h],82h //ebp - 34
83e32e19 8944241c mov dword ptr [esp+1Ch],eax //ebp - 40
nt!RtlQueryRegistryValues+0x98:
83e32e1d 8b0b mov ecx,dword ptr [ebx] //ecx == QueryTable->QueryRoutine
83e32e1f 3bcf cmp ecx,edi
83e32e21 750a jne nt!RtlQueryRegistryValues+0xa8 (83e32e2d)
nt!RtlQueryRegistryValues+0x9e:
83e32e23 f6430421 test byte ptr [ebx+4],21h // byte ptr [ebx+4] = 21h
83e32e27 0f8446030000 je nt!RtlQueryRegistryValues+0x3ee (83e33173)
nt!RtlQueryRegistryValues+0xa8:
83e32e2d 8b4304 mov eax,dword ptr [ebx+4]
83e32e30 a820 test al,20h
83e32e32 7419 je nt!RtlQueryRegistryValues+0xc8 (83e32e4d)
nt!RtlQueryRegistryValues+0xaf:
83e32e34 397b08 cmp dword ptr [ebx+8],edi
83e32e37 0f841b030000 je nt!RtlQueryRegistryValues+0x3d3 (83e33158)
nt!RtlQueryRegistryValues+0xb8:
83e32e3d a801 test al,1
83e32e3f 0f8513030000 jne nt!RtlQueryRegistryValues+0x3d3 (83e33158)
nt!RtlQueryRegistryValues+0xc0:
83e32e45 3bcf cmp ecx,edi
83e32e47 0f850b030000 jne nt!RtlQueryRegistryValues+0x3d3 (83e33158)
nt!RtlQueryRegistryValues+0xc8:
83e32e4d a803 test al,3
83e32e4f 7418 je nt!RtlQueryRegistryValues+0xe4 (83e32e69)
nt!RtlQueryRegistryValues+0xe4:
83e32e69 8b4b04 mov ecx,dword ptr [ebx+4] //ecx == QueryTable->Flags
83e32e6c 8b4308 mov eax,dword ptr [ebx+8] //eax == QueryTable->Name
83e32e6f f6c101 test cl,1
83e32e72 0f8438010000 je nt!RtlQueryRegistryValues+0x22b (83e32fb0) 1
nt!RtlQueryRegistryValues+0x22b:
83e32fb0 3bc7 cmp eax,edi
83e32fb2 0f8417010000 je nt!RtlQueryRegistryValues+0x34a (83e330cf)
nt!RtlQueryRegistryValues+0x233:
83e32fb8 50 push eax
83e32fb9 8d442434 lea eax,[esp+34h]
83e32fbd 50 push eax
83e32fbe e8255fe4ff call nt!RtlInitUnicodeString (83c78ee8)
83e32fc3 897c2414 mov dword ptr [esp+14h],edi
nt!RtlQueryRegistryValues+0x242:
83e32fc7 8b442414 mov eax,dword ptr [esp+14h]
83e32fcb ff442414 inc dword ptr [esp+14h]
83e32fcf 83f804 cmp eax,4
83e32fd2 0f8f8a010000 jg nt!RtlQueryRegistryValues+0x3dd (83e33162)
上面這些內容并不重要,之所以貼出了是為了用來確定后面寄存器的值。
代碼:
nt!RtlQueryRegistryValues+0x253:
83e32fd8 8d442410 lea eax,[esp+10h] //eax == ebp-4c
83e32fdc 50 push eax //ebp - 4c
83e32fdd ff74242c push dword ptr [esp+2Ch] //0x82
83e32fe1 8d442438 lea eax,[esp+38h] //
83e32fe5 56 push esi //通過nt!RtlpAllocDeallocQueryBuffer申請空間的內存空間首地址
83e32fe6 6a01 push 1 //1
83e32fe8 50 push eax //ebp-2c
83e32fe9 ff742430 push dword ptr [esp+30h] //KeyHandle
83e32fed e86a9ee4ff call nt!ZwQueryValueKey (83c7ce5c)
83e32ff2 8944240c mov dword ptr [esp+0Ch],eax
83e32ff6 bf230000c0 mov edi,0C0000023h
83e32ffb 3d05000080 cmp eax,80000005h
83e33000 7504 jne nt!RtlQueryRegistryValues+0x281 (83e33006)
調用nt!ZwQueryValueKey,通過前面獲得的KeyHandle來讀取鍵值信息,返回的信息放入前面通過nt!RtlpAllocDeallocQueryBuffer函數申請的內存空間中。
根據nt!ZwQueryValueKey的參數,可以得知返回的信息為KEY_VALUE_FULL_INFORMATION結構,其定義如下:
代碼:
typedef struct _KEY_VALUE_FULL_INFORMATION {
ULONG TitleIndex;
ULONG Type;
ULONG DataOffset;
ULONG DataLength;
ULONG NameLength;
WCHAR Name[1]; // Variable size
} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;
這個結構在后面會用到!
代碼:
nt!RtlQueryRegistryValues+0x281:
83e33006 33c0 xor eax,eax
83e33008 3944240c cmp dword ptr [esp+0Ch],eax
83e3300c 7d69 jge nt!RtlQueryRegistryValues+0x2f2 (83e33077)
nt!RtlQueryRegistryValues+0x2f2:
83e33077 837e0407 cmp dword ptr [esi+4],7
83e3307b 750e jne nt!RtlQueryRegistryValues+0x306 (83e3308b)
nt!RtlQueryRegistryValues+0x306:
83e3308b 8b442428 mov eax,dword ptr [esp+28h]
83e3308f ff7514 push dword ptr [ebp+14h] //Context == 0
83e33092 89442414 mov dword ptr [esp+14h],eax
83e33096 53 push ebx //QueryTable
83e33097 8d4c2418 lea ecx,[esp+18h] //ebp-4c == 0x82
83e3309b 8bc6 mov eax,esi //esi指向申請內存空間
83e3309d e8df7affff call nt!RtlpCallQueryRegistryRoutine (83e2ab81)
這就是關鍵調用了,nt!RtlpCallQueryRegistryRoutine為問題函數,雖然只有兩個參數壓棧,但是還有部分參數是通過寄存器傳遞的,所以都做了一些標示。
其參數為nt!RtlQueryRegistryValues函數的參數Context和QueryTable,以及儲存前面返回的鍵值信息的內存空間指針。
接下來看nt!RtlpCallQueryRegistryRoutine函數:
代碼:
nt!RtlpCallQueryRegistryRoutine+0xc8:
83e2ac49 8b7e08 mov edi,dword ptr [esi+8]
83e2ac4c 8b4604 mov eax,dword ptr [esi+4]
83e2ac4f 03fe add edi,esi
83e2ac51 8b760c mov esi,dword ptr [esi+0Ch]
83e2ac54 894508 mov dword ptr [ebp+8],eax
83e2ac57 eb7b jmp nt!RtlpCallQueryRegistryRoutine+0x153 (83e2acd4)
這里修改了ebp+8處的值,即將QueryTable的值修改為[esi+4],對應的是KEY_VALUE_FULL_INFORMATION結構中的Type。
代碼:
nt!RtlpCallQueryRegistryRoutine+0x282:
83e2ae03 ff730c push dword ptr [ebx+0Ch] //QueryTable->EntryContext
83e2ae06 f6c120 test cl,20h
83e2ae09 7436 je nt!RtlpCallQueryRegistryRoutine+0x2c0 (83e2ae41)
nt!RtlpCallQueryRegistryRoutine+0x28a:
83e2ae0b 8b5508 mov edx,dword ptr [ebp+8] //edx的值為KEY_VALUE_FULL_INFORMATION結構中的Type值
83e2ae0e 57 push edi //edi指向KEY_VALUE_FULL_INFORMATION結構中的Name
83e2ae0f 8bc6 mov eax,esi //eax的值為KEY_VALUE_FULL_INFORMATION結構中的DataLength值
83e2ae11 e8818b0000 call nt!RtlpQueryRegistryDirect (83e33997)
這個函數對傳進來的參數做了一定的處理,然后傳給nt!RtlpQueryRegistryDirect函數,上面有較詳細的注釋,這個應該就不用多說了吧。
然后是nt!RtlpQueryRegistryDirect函數:
代碼:
kd> uf nt!RtlpQueryRegistryDirect
nt!RtlpQueryRegistryDirect:
83e33997 8bff mov edi,edi
83e33999 55 push ebp
83e3399a 8bec mov ebp,esp
83e3399c 53 push ebx
83e3399d 8b5d08 mov ebx,dword ptr [ebp+8]
83e339a0 56 push esi
83e339a1 8b750c mov esi,dword ptr [ebp+0Ch] //esi == QueryTable->EntryContext
83e339a4 57 push edi
83e339a5 83fa01 cmp edx,1
83e339a8 7445 je nt!RtlpQueryRegistryDirect+0x56 (83e339ef)
nt!RtlpQueryRegistryDirect+0x13:
83e339aa 83fa02 cmp edx,2
83e339ad 7440 je nt!RtlpQueryRegistryDirect+0x56 (83e339ef)
nt!RtlpQueryRegistryDirect+0x18:
83e339af 83fa07 cmp edx,7
83e339b2 743b je nt!RtlpQueryRegistryDirect+0x56 (83e339ef)
nt!RtlpQueryRegistryDirect+0x1d:
83e339b4 83f804 cmp eax,4
83e339b7 770c ja nt!RtlpQueryRegistryDirect+0x2c (83e339c5)
nt!RtlpQueryRegistryDirect+0x22:
83e339b9 3bf3 cmp esi,ebx
83e339bb 7476 je nt!RtlpQueryRegistryDirect+0x9a (83e33a33)
nt!RtlpQueryRegistryDirect+0x26:
83e339bd 85c0 test eax,eax
83e339bf 7510 jne nt!RtlpQueryRegistryDirect+0x38 (83e339d1)
nt!RtlpQueryRegistryDirect+0x2a:
83e339c1 eb70 jmp nt!RtlpQueryRegistryDirect+0x9a (83e33a33)
nt!RtlpQueryRegistryDirect+0x2c:
83e339c5 8b0e mov ecx,dword ptr [esi]
83e339c7 85c9 test ecx,ecx
83e339c9 7d13 jge nt!RtlpQueryRegistryDirect+0x45 (83e339de)
nt!RtlpQueryRegistryDirect+0x45:
83e339de 8d7808 lea edi,[eax+8]
83e339e1 3bcf cmp ecx,edi
83e339e3 725d jb nt!RtlpQueryRegistryDirect+0xa9 (83e33a42)
以上內容意義不大,主要是一些判斷。
代碼:
nt!RtlpQueryRegistryDirect+0x4c:
83e339e5 8906 mov dword ptr [esi],eax //esi指向win32k!bAppendSysDirectory+0x209函數的棧空間
83e339e7 895604 mov dword ptr [esi+4],edx //溢出!,edx的值為KEY_VALUE_FULL_INFORMATION結構中的Type值
83e339ea 83c608 add esi,8
83e339ed ebe2 jmp nt!RtlpQueryRegistryDirect+0x38 (83e339d1)
nt!RtlpQueryRegistryDirect+0x38:
83e339d1 50 push eax //eax的值為KEY_VALUE_FULL_INFORMATION結構中DataLength值
83e339d2 53 push ebx //ebx指向KEY_VALUE_FULL_INFORMATION結構中的Name
83e339d3 56 push esi //QueryTable->EntryContext + 8
83e339d4 e8c75de4ff call nt!memcpy (83c797a0) //溢出!
從這里就能看到棧的溢出了。函數起始位置將esi指向QueryTable->EntryContext,這個變量的值為win32k!bAppendSysDirectory+0x209函數中ebp-0x20,也就是函數棧地址。上面的操作會將棧上的信息覆蓋掉,覆蓋的值一次為KEY_VALUE_FULL_INFORMATION結構中的DataLength和Type,然后是通過memcpy將KEY_VALUE_FULL_INFORMATION結構中的Name復制到棧中。
通過上面的代碼可以看到,棧溢出了!如果要利用的話,需要計算偏移量,然后修改“\REGISTRY\USER\S-1-5-18\EUDC\936\SystemDefaultEUDCFont”鍵值的信息,將函數的返回地址覆蓋為shellcode的地址。
關健詞:MS11-011
新文章:
- CentOS7下圖形配置網絡的方法
- CentOS 7如何添加刪除用戶
- 如何解決centos7雙系統后丟失windows啟動項
- CentOS單網卡如何批量添加不同IP段
- CentOS下iconv命令的介紹
- Centos7 SSH密鑰登陸及密碼密鑰雙重驗證詳解
- CentOS 7.1添加刪除用戶的方法
- CentOS查找/掃描局域網打印機IP講解
- CentOS7使用hostapd實現無AP模式的詳解
- su命令不能切換root的解決方法
- 解決VMware下CentOS7網絡重啟出錯
- 解決Centos7雙系統后丟失windows啟動項
- CentOS下如何避免文件覆蓋
- CentOS7和CentOS6系統有什么不同呢
- Centos 6.6默認iptable規則詳解