Windows 核心攻擊

wyzsk發表於2020-08-19
作者: netwind · 2015/05/20 13:51

0x00 引言


作者:Ashfaq Ansari

本文總結了目前windows核心攻擊的各種攻擊技術.描述並演示了一些常見的繞過windows核心防護的方法,並舉一反三地介紹瞭如何透過核心缺陷找到類似的繞過方法。 透過對核心攻擊和記憶體結構的理解將會進一步豐富基於使用者模式應用程式的緩衝溢位知識。

透過大量核心漏洞的研究表明,特定的核心程式碼執行可能大多由使用者模式的應用程式引起。因此,針對使用者模式的應用程式,作業系統增加了大量的保護機制,用以保護和檢測這類的攻擊,比如:隨機化、執行保護、記憶體防護等等。然而,針對作業系統溢位攻擊,目前所做的工作還遠遠不夠。 本文將討論交流各種核心攻擊技術和一些可能的核心攻擊方法

0x01 環境配置


所有的演示都基於Windows 7 x86 SP1環境下編譯的特意存在漏洞的驅動,本文將透過該驅動存在的漏洞來展示核心缺陷以及如果透過核心攻擊技術來進行本地許可權提升。

所需工具:

  • Windows 7 作業系統

  • 虛擬機器

  • 一個存在漏洞的驅動

  • Windows 核心偵錯程式 – WinDBG

備註: 設定偵錯程式管道名為 \.\pipe\com1 ,同時被除錯端也同樣設定.

0x02 Windows 核心結構


在開始攻擊之旅之前,我們先了解一下核心基本結構和windows程式空間的記憶體分配和執行方式。Windows作業系統有兩個模式:核心模式和使用者模式。任何一個程式都是在其中一個模式裡執行。

enter image description here

圖 1: Windows 結構 來自: logs.msdn.com

HAL: Hardware Abstraction Layer 硬體抽象層 –一組程式例程,使軟體可跨平臺移植; HalDispatchTable 儲存著一些 HAL例程的地址。

0x03 堆疊溢位


當複製使用者輸入資料到事先分配的一個緩衝空間裡時,如果沒有做邊界檢查,就會發生棧溢位。 memcpy()函式在進行記憶體複製的時候不會做長度檢查,如果複製過長的資料到預先定義的緩衝變數裡,就會導致溢位的發生。

以下是一個用了 memcpy() 函式的程式。

enter image description here

圖 2: StackOverflow.c

首先我們用大量的資料溢位它並且覆蓋掉返回地址。 這樣我們就會控制了程式後面要執行的指令。 我們用大量字元‘A’成功使棧發生了崩潰。 然而, 為了找到返回地址的精確位置,我們需要傳送一組特定模式的資料來匹配到返回地址(譯者注:可以是這樣AAAABBBBCCCCDDDD…)。

透過溢位程式碼構造了一組輸入資料,我們找到了返回地址的偏移如圖:

enter image description here

圖 3: 定位EIP

如上所示, EIP被 72433372 覆蓋(記憶體地址左高位,右低位,對於字元是 72334372 ).然後定位到覆蓋EIP的位置是字串長度為2080的地方。

在我們的溢位程式碼裡, 我們透過變數ring0_shellcode’定義了 shellcode 如下:

enter image description here

圖 4:  Shellcode

我們把shellcode地址放入我們溢位程式碼的緩衝區裡,透過使shellcode地址覆蓋返回地址,這樣SHELLCODE得以執行以後,我們以使用者模式啟動的程式最終將以核心模式執行。

備註: 首先, 我們用Python指令碼找到shellcode在記憶體的地址,例如:

#!python
ring0_shellcode_address = id(ring0_shellcode) + 20 //id(var) + 20

接著,把SHELLCODE地址放到可以覆蓋返回地址的地方(上述找到的EIP偏移)。溢位程式碼執行後會呼叫SHELLCODE,這時會開啟一個以系統許可權執行的命令列SHELL,如圖:

enter image description here

0x04 堆疊保護繞過


為了抵禦堆疊溢位攻擊,產生了一種保護機制:Stack Guard. 這種機制使得執行函式增加了兩個元素:function_prologue和function_epilogue。Stack Guard 實際是透過編譯時在這個兩個元素處增加程式碼以設定和檢驗棧資訊(儲存在Canary裡)。

Function prologue

enter image description here

圖 6: _except_handler4

Function Epilogue

enter image description here

enter image description here

圖8: Security Cookie效驗

參照上面的程式,我們發現每次透過傳統方式覆蓋堆疊的時候, 我們也不得不同時覆蓋掉Stack Cookie。 除非我們用正確的棧資訊來覆蓋Canary, 否則在函式尾的檢查將失敗並且程式會終止。

解決方法

我們將透過溢位覆蓋異常處理函式地址的方法來繞過 Stack Cookie保護。 異常處理函式地址存放在堆疊裡,我們可以任意的覆蓋堆疊,當從使用者空間傳遞大量資料到核心緩衝區的時候,我們把SHELLCODE地址覆蓋掉異常處理函式的地址,這時觸發異常並跳轉去執行我們的SHELLCODE程式碼。

enter image description here

圖 9: 堆疊溢位防護繞過

根據攻擊程式碼,繞過 Stack Guard 後執行INT 3指令,觀察除錯資訊如圖:

enter image description here

圖 10: 繞過 stack Guard

enter image description here

圖11: 執行shellcode並停止在斷點

0x05 任意改寫


這個漏洞也被稱作: WRITE_WHAT_WHERE,可以使攻擊者可以在任意記憶體寫任意內容。 如果操作不當會導致程式崩潰(使用者模式)或者藍色畫面(核心模式BSOD)。

通常這裡會有一些現限制

  • Value – 可以寫什麼樣的內容

  • Size – 可寫記憶體的大小

  • 而且有時只能遞增或遞減記憶體

這類漏洞相比其他已知型別漏洞比較難以發現, 但是對於惡意程式碼執行非常有用。 這裡有許多可改寫導致程式碼執行的地方,比如: HalDispatchTable+4, 系統中斷表Interrupt Dispatch Table, 系統服務表System Service Dispatch Table等等。

如下是 WRITE_WHAT_WHERE 漏洞的結構:

enter image description here

既然漏洞允許我們自定義上述結構中的What和Where屬性, 我們把我們的shellcode地址寫在‘What’處,把 HalDispatchTable0x4 的地址寫在‘Where’ 處,如下:

enter image description here

圖 13: 部署shellcode 地址和HAL Dispatch Table地址

我們在核心偵錯程式中斷程式,檢查HalDispatch Table 函式地址如下:

enter image description here

enter image description here

圖 15: Write_What_Where執行演示

Exploit執行後,我們在偵錯程式檢查記憶體發現, HalDispatchTable+4處地址被SHELLCODE地址覆蓋, 然後SHELLCODE被執行。 下面對話方塊顯示程式在斷點處中斷。

enter image description here

enter image description here

圖 17: 改寫後斷點處的EIP

最後PAYLOAD裡的shellcode將利用任意改寫漏洞得以執行.

0x06 Use After Free 漏洞利用


當一個程式使用已經被釋放後的記憶體時,會導致意外的系統行為,如異常或可以用來獲得任意程式碼執行。此類漏洞需要如下條件:

enter image description here

某些時候一個物件被建立,同時與一個虛表關聯,然後程式會透過某個方法來呼叫這個物件。如果在程式呼叫物件之前,我們把這個物件釋放,當程式呼叫該物件時就會導致程式崩潰。

這種情況下, 攻擊者佈置好記憶體。然後, 分配類似大小的物件。接著, 攻擊者嘗試釋放一些物件來製造一個記憶體“孔”。 然後, 然後分配和釋放弱點物件,最後攻擊者填充這些“孔”,來接管弱點物件的記憶體空間。這類漏洞難以被發現和利用,並且需要一定條件:

  • Shellcode指標必須放在被釋放的物件的記憶體空間。

  • 建立的“孔”的大小必須和釋放的物件的大小相等。

  • 不應有相鄰的記憶體塊被釋放以防止Coalescing。

Coalescing: 當兩個獨立且相鄰的記憶體塊被釋放,作業系統會連線這些小記憶體塊,以建立一個大的記憶體塊,用以防止記憶體碎片。 這個過程叫Coalescing,它使Use After free漏洞攻擊變得更加困難。因此,記憶體管理器不會分配特定的記憶體,攻擊者獲得相同記憶體空間的機會很少。

如下給出了一個存在該漏洞的案例(核心下C函式):

首先我們讓被除錯端/目標以guest許可權執行。 我們首先必須在核心池分配一個弱點物件,以觸發Use After free漏洞, 然後釋放它並強制使程式使用這個被釋放的物件。

enter image description here

圖 18:Use After Free 物件被分配.等待釋放.

接下來, 我們釋放物件以建立記憶體“孔”.最後,我們填充所有被釋放的記憶體塊以控制被釋放物件的記憶體,需要花費一定的時間來實現記憶體控制,大概需要嘗試100次左右。 我們通常透過一個FakeObject來重新分配 UaF物件。

enter image description here

圖 19: 釋放並重新分配 UAF 物件

enter image description here

圖 20: 釋放並重新分配 UAF 物件

同時, 這些記憶體塊會被攻擊者控制的物件填充。這個時候我們看一下記憶體池, 我們會發現我們已經成功地重新分配了我們建立的記憶體“孔”。

enter image description here

圖 21: 所有連續的記憶體塊都被 IoCo填充以確保記憶體被均勻噴射

最後觸發使用被釋放的UaF物件,導致漏洞產生。 攻擊程式碼執行後,會生成一個系統許可權的SHELL, 如圖:

enter image description here

圖 22: 攻擊者程式碼以系統許可權執行

0x07 用核心偵錯程式偷令牌


另一個有趣的漏洞是,可以利用核心缺陷透過程式令牌來提升許可權。

下面的部分,我們說明了攻擊者如何從一個更高的或者不同特權的級別偷取令牌 ,然後進行許可權提升或者使自身擁有和其他程式一樣的許可權。儘管有很多已知的核心防護機制,比如ASLR、 DEP、 Safe SHE、SEHOP等等,但在核心中使用這些漏洞, 任何一個程式都可以被賦予系統許可權。

下面將一步一步針對許可權較低的使用者 ‘Guest‘,來說明利用令牌漏洞進行許可權提升的過程。 我們將用核心偵錯程式會話來提升cmd.exe 程式的許可權,使它從Administrator許可權到SYSTEM 許可權。

用核心偵錯程式找到當前正在執行的程式和他們的屬性,如下-

For cmd.exe
For SYSTEM

現在我們知道了系統程式的令牌, 我們可以切換到 cmd.exe 程式 並找到這個程式令牌的位置。

  • 從上面找到的地址中獲得KPCR 結構

  • 在偏移 +0x120 獲得KTHREAD成員 CurrentThread的地址

  • 獲得KAPC_STATE成員 ApcState的地址。 它包含一個指向 KPROCESS的指標

  • 獲得KPROCESS成員 Process的地址。 它包含令牌值,在KTHREAD 基址偏移+0x40處

enter image description here

圖 23: KAPC List Entry

  • 從 EPROCESS 結構獲得Token 成員的偏移。 KPROCESS是EPROCESS的第一個結構

  • 獲得Token值

實際的令牌值需要把最後3位和0進行與操作,然後令牌值0x953b6037變為 0x953b6030
現在我們用系統令牌替換掉程式令牌。

enter image description here

圖 24: 令牌值被替換

令牌被替換後,程式馬上就被賦予了系統許可權。 在被攻擊者電腦裡驗證如下:

enter image description here

圖 25: 透過令牌漏洞提升Guest到系統許可權

enter image description here

圖 26: 一個例子: 利用令牌漏洞對Guest使用者進行許可權提升

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章