當前位置:
首頁 > 新聞 > Windows內核漏洞利用

Windows內核漏洞利用

堆棧緩衝區溢出

在第一部分中,我們會從HackSysExtremeVulnerableDriver中的普通堆棧緩衝區溢出開始。

當堆棧上存在的緩衝區獲取的數據超出其存儲容量時(例如,在一個16位元組緩衝區中複製20個位元組,就可以是字元數組或類似對象),其餘數據將寫入附近位置,從而有效覆蓋或破壞堆棧。

其核心思想是控制此溢出,這樣我們可以覆蓋堆棧上保存的返回地址,並且在執行當前(易受攻擊的)函數後,它將返回我們的覆蓋值,其中包含我們的shellcode。

注意:執行完shellcode後,代碼執行必須返回到應用程序,在本例中是內核,否則將破壞應用程序。通常,應用程序崩潰了,我們可以重新啟動它,但是如果內核內存損壞,內核會發出內核恐慌,並且將顯示「藍屏死機」,這是我們最不希望發生的事情。

為了解決這個問題,我們需要恢復執行路徑,以便在執行完shellcode之後,它返回到執行易受攻擊的函數後應該返回的函數。

易受攻擊性

現在我們已經清除了它,讓我們看一下易受攻擊的代碼(位於StackOverflow.c中的函數TriggerStackOverflow)。最初,該函數創建可容納512個成員元素的ULONG數組(在common.h頭文件中,BufferSize設置為512)。

易受攻擊性的函數

然後,內核檢查緩衝區是否駐留在用戶區域中,然後在非頁面緩衝池中為其分配內存。

一旦完成,內核便將數據從用戶模式緩衝區複製到內核模式KernelBuffer,該模式實質上是一個ULONGs數組。

溢出

注意RtlCopyMemory的第三個參數,它本質上是memcpy,Size參數是用戶模式緩衝區的大小,而不是內核模式緩衝區的大小,這正是緩衝區溢出發生的地方。

漏洞驗證

現在,要驗證錯誤是否真正存在,我們將編寫一個函數,該函數調用函數StackOverflowIoctlHandler的IOCTL。IOCTL代碼在Exploit / common.h文件中給出。

注意:我們可以從編譯的驅動程序本身獲取IOCTL代碼,既然我們有自己的優勢,所以為什麼不使用它?

什麼是IOCTL代碼?

I/O控制代碼(IOCTL)用於用戶模式應用程序和驅動程序之間的通信,或用於堆棧中驅動程序內部的通信,I/O控制代碼是使用IRP發送的。

基本上,如果驅動程序具有與之關聯的IOCTL代碼,則可以直接在該驅動程序中調用內核函數。要使用IOCTL代碼,我們使用DeviceIoControl函數,函數可在此處找到。

DeviceIoControl函數的原型為:

DeviceIoControl的原型

我用C 編寫了一個函數,該函數調用DeviceIoControl來調用StackOverflowIoctlHandler,後者依次調用TriggerStackOverflow,這是易受攻擊的函數。

由於我們知道緩衝區有512個ULONG,因此可以肯定的是,此後,我們將添加Metasploit框架中pattern_create.rb生成的100位元組模式。

最後,將此緩衝區發送到HEVD,看看會發生什麼?

注意:此函數在標頭文件StackOverflow.h中,主函數調用它,你可以在我的代碼庫中找到整個代碼。

利用堆棧溢出的POC

利用堆棧溢出的POC

在Win7設備上編譯並執行二進位文件後,我們可以在WinDbg中獲得它:

在WinDbg中崩潰

我們可以看到有一個訪問衝突,EIP指向31624130。

在此模式上使用Metasploit的pattern_offset.rb之後,我們找到它的偏移量32,讓我們繼續進行開發。

利用溢出

現在剩下的就是使用HEVD中提供的TokenStealingPayloadWin7 shellcode覆蓋保存的返回地址,然後完成。

注意:你可能需要稍微修改shellcode,以免崩潰。

獲取Shell

首先驗證我們是否是普通用戶:

普通用戶

可以看出,我只是一個普通的用戶。運行漏洞利用程序後,我成為了NT許可權/系統。

NT Authority/SYSTEM Shell

類型混淆

在第二部分中,我們將繞過常見的內存損壞漏洞(在我們正在利用的驅動程序中,內存損壞漏洞佔大多數)。因為利用起來很容易,我還要使其成為本文的第一部分。

什麼是類型混淆?

類型混淆是一個漏洞,其中應用程序不驗證對象的類型(函數,數據類型等),然後按預期方式對其進行處理,但傳遞的對象是其他對象。

漏洞

現在我們已經清除它,讓我們看一下易受攻擊的代碼(位於TypeConfusion.c中的函數TriggerTypeConfusion)。

內核首先檢查緩衝區是否駐留在用戶域中,然後在非頁面緩衝池中為其分配內存。完成此操作後,內核將用戶模式緩衝區中的ObjectID分配給內核模式緩衝區,並對對象類型執行相同的操作。

分配ObjectID和ObjectType

完成之後,內核在對象(內核模式而不是用戶模式)上調用TypeConfusionInitializer函數。

在對象上調用TypeConfusionInitializer

讓我們來看看這個函數:

函數類型ConfusionObjectInitializer

該函數接收對象並調用對象內部存在的函數指針,下面,讓我們看一下TypeConfusion.h標頭文件中存在的KERNEL_TYPE_CONFUSION_OBJECT的結構(本質上是一個結構)。該標頭文件包含用戶模式對象以及內核模式對象的定義,這使得利用這個漏洞比利用堆棧溢出更容易。

對象原型

首先,讓我們看看用戶模式對象包含什麼。用戶模式對象是一個包含2個成員的結構:

1.對象ID;

2.對象類型。

對於內核模式對象,它也是一個包含2個成員的結構:

1.對象ID;

2.第二個成員是UNION,它本身包含:

2.1對象類型;

2.2回調(函數指針);

現在,如果你還記得,一個UNION一次可以容納一個成員,在這裡它可以是Object Type或指向由TypeConfusionInitializer函數調用的函數的指針。

當函數TriggerTypeConfusion函數無法驗證第二個成員是ObjectType還是Callback時,就會發生混淆。

利用混淆情況

要利用混淆情況,我們所要做的就是發送一個結構,該結構的第二個成員是我們要從內核領域調用的函數的地址。

在漏洞已經被利用的情況下,它將成為我們的令牌竊取Shellcode的地址,並替換我們進程的令牌,因此當創建一個新進程時,將使用該令牌創建它。

但是有一個問題,HEVD附帶的shellcode(TokenStealingPayloadWin7無法正常工作並導致設備崩潰)。

修改shellcode

由於函數TypeConfusionInitializer會像調用函數一樣調用回調指針,因此我們需要設置函數序言和結尾,並將ret 8更改為ret。

注意:我會將shellcode函數編譯為裸函數,但如果你不這樣做,則可以直接使用提供的shellcode。我只是不希望編譯器將額外的代碼添加到我的shellcode中。

你可以點此,找到漏洞利用代碼。

獲得Shell

首先驗證我們是否是一個普通用戶。

普通用戶

可以看出,我只是一個普通用戶。運行漏洞利用程序後,我會擁有NT許可權/系統

通過利用Type Confusion開發SYSTEM Shell

整數溢出

在這一部分中,我們將利用HackSysExtremeVulnerableDriver中的整數溢出。

什麼是整數溢出?

對於那些不知道整數溢出的人,他們可能會想到整數如何溢出?實際的整數不會溢出。CPU會將整數存儲在固定大小的內存分配中。如果你熟悉C / C 編程語言或類似語言,則可能會想起數據類型以及每種數據類型具有特定的固定大小。

在大多數設備和操作系統上,char是1個位元組,int是4個位元組長。這意味著char數據類型可以容納8位大小的值,範圍從0到255,或者在有符號值的情況下從-128到127。整數也是如此,在int大小為4位元組的設備上,它可以保存0到232 – 1之間的值(無符號值)。

現在,讓我們考慮使用一個無符號整數,其最大值可以是232 – 1或0xFFFFFFFF。如果加1時會發生什麼?由於所有的32位都設置為1,因此加1將使它成為33位的值,但是由於存儲區只能容納32位,因此將這32位設置為0。

在執行操作時,CPU通常將數字載入到32位寄存器中(這裡說的是x86),添加1將設置Carry標誌,寄存器保存值0,因為所有32位現在都是0。

現在,如果進行大小檢查,則該值是否大於(例如10),則檢查將失敗,但是如果沒有大小限制,則比較操作將返回true。

為了更詳細地了解它,讓我們看一下該漏洞,看看如何利用HEVD中的整數溢出漏洞來獲得在Windows內核中的執行代碼。

易受攻擊性

現在我們已經清除了它,讓我們看一下易受攻擊的代碼(函數IntegerOverflow.c中的TriggerIntegerOverflow)。

最初,該函數創建可容納512個成員元素的ULONG數組(在common.h頭文件中,BufferSize設置為512)。

IntegerOverflow.c中的漏洞函數

然後,內核檢查緩衝區是否駐留在用戶區域中,然後為我們列印一些信息,這對整數溢出很有幫助。

完成此操作後,內核將檢查數據大小(以及終止符的大小,終止符為4位元組)是否大於KernelBuffer的大小。如果是這,則它退出時不會在kernel-land緩衝區中複製user-land緩衝區。

大小檢查

但是,如果不是這種情況,那麼它將繼續進行,然後將數據複製到內核緩衝區。

這裡要注意的另一件事是,如果它在用戶區域緩衝區中遇到BufferTerminator,它將停止複製並繼續前進。因此,我們需要將BufferTerminator放在用戶模式緩衝區的末尾。

將用戶模式數據複製到內核模式函數堆棧

溢出

IntegerOverflow.c的第100行中的問題在於,如果我們將size參數設置為0xFFFFFFFC,然後添加BufferTerminator的大小(為4個位元組),則有效大小為– 0xFFFFFFFC 4 = 0x00000000,小於KernelBuffer的大小。因此,我們通過了數據大小檢查,然後將緩衝區複製到內核模式。

漏洞驗證

現在,為了驗證這一點,我們將緩衝區發送到HEVD,但是要傳遞0xFFFFFFFC作為緩衝區的大小。現在,我們將不會放置巨大的緩衝區並使內核崩潰,而只是發送一個小緩衝區並進行確認。

觸發整數溢出的PoC

因為我們知道緩衝區有512個ULONG,所以我們將發送此數據,並查看內核會做什麼?

注意:這裡的重點是DeviceIoControl的第4個參數,而不是實際的數據。

最後,將此緩衝區發送到HEVD,看看會發生什麼。

成功觸發整數溢出漏洞

如你在圖片中看到的,UserBuffer Size顯示為0xFFFFFFFC,但我們仍然設法繞過了大小有效性檢查並觸發了整數溢出。

我們確認了通過放置0xFFFFFFFC,可以繞過檢查大小,現在剩下的就是在UserBuffer之後放置一個模式(唯一的模式),然後在其後放置終止符以查找保存的返回指針覆蓋。

如果你不知道如何執行此操作,請閱讀本文的第1部分。

利用溢出漏洞

剩下的就是使用HEVD中提供的TokenStealingPayloadWin7 shellcode覆蓋保存的返回地址,然後完成就可以了。

注意:你可能需要稍微修改shellcode,以免崩潰。

獲取shell

首先驗證我們是否是普通用戶:

普通用戶

可以看出,我只是普通用戶。

運行漏洞利用程序後,我成為了NT許可權/系統。

成功利用整數溢出漏洞

你可以在我的代碼庫中,找到整個代碼。

本文翻譯自:https://pwnrip.com/windows-kernel-exploitation-part-1-stack-buffer-overflows/ https://pwnrip.com/windows-kernel-exploitation-part-2-type-confusion/ https://pwnrip.com/windows-kernel-exploitation-part-3-integer-overflow/

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

安全更新、升級到最新版也不安全