Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86384090

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

Windows DSE(Driver Signature Enforcement)即任何驅動程序或第三方程式都要經過微軟簽名才能確保為正版、安全的程序。代碼完整性是15 年前由Microsoft 首次推出的威脅防護功能。在基於x64 的Windows 版本上,內核模式驅動程序必須在每次加載到內存時進行數字簽名和檢查,這也被稱為驅動強制簽名(DSE),檢測是否將未簽名的驅動程序或系統文件加載到內核中,或系統文件是否被修改(可能由具有管理權限的惡意軟件運行),可以提高操作系統的安全性。

為了克服這些限制,攻擊者使用有效的數字證書(無論是頒發給他們的還是他們竊取的)或者他們在運行時禁用DSE。獲得證書的難度很大,但篡改證書則純粹是一個技術上的挑戰。

儘管微軟近年來一直在致力於解決驅動強制簽名方面存在的問題,並提供了一系列解決方案,但利用眾所周知,篡改DSE的方法越來越多,用此方法攻擊的案例也明顯增加,這促使我們要深入地研究這個問題。

我們會在本文分享我們的研究結果,以及兩種DSE篡改方法的細節。

DSE實現過程j00ru是谷歌項目Zero的一名安全研究員,他層發表了一篇關於Windows 7中代碼完整性實現的介紹。

ntoskrnl.exe與附加的內核庫CI.dll(代碼完整性)一起工作。在操作系統初始化階段,內核設置nt!g_CiEnabled 並使用指向nt!g_CiCallbacks 結構的指針調用CI!CiInitialize 例程來初始化CI.dll。它依次設置CI!g_CiOptions 並在返回內核之前填充CI!CiValidateImageHeader、CI!CiValidateImageData 和CI!CiQueryInformation 回調的地址。

要使用回調函數,包裝器函數存在於ntoskrnl.exe中。他們檢查那個nt!g_CiEnabled設置為TRUE,適當的回調不是NULL,然後調用它。

當內核加載驅動程序時,執行通過nt!MmLoadSystemImage 到nt!MmCreateSection 並最終到nt!MiValidateImageHeader 例程。這樣,依次調用nt!SeValidateImageHeader 和nt!SeValidateImageData 包裝器。每個回調都應在成功時返回零,否則返回非零值。

fig1.webp.jpg

驅動程序加載時的調用堆棧

“Rootkits and Bootkits: Reversing Modern Malware and Next Generation Threats”一書詳細說明了Windows 8 中的實現更改過程:刪除nt!g_CiEnabled 變量,因此DSE 狀態僅由CI!g_CiOptions 確定,更多回調函數被添加到CI.dll提供的接口中。書中沒有描述的另一個變化是,如果驗證標頭成功,那麼驗證數據回調將不會被調用。

在Windows 8.1上,回調結構的符號名稱被更改為nt!SeCiCallbacks。

內核模式簽名策略除了簽名的加密有效性之外,微軟強制簽名證書只能由支持CA 的交叉證書頒發。這可以防止攻擊者簡單地在每台計算機上安裝自己的CA證書。

從Windows 10Redstone開始(2016年8月發布),驅動程序簽名策略有所改變,需要微軟自己進行第二次簽名。這是通過一個web門戶網站完成的,在那裡開發人員上傳他們的簽名二進製文件,並將它們發送給微軟。從攻擊者的角度來看,這意味著將你的有效載荷傳播給防御者,這與他們通常想要的相反。至少有一個記錄在案的案例表明,這種新措施沒有阻止攻擊者。

內核補丁保護KPP 或PatchGuard 於2005 年首次推出,是x64 版Windows 的一項功能,可防止修補內核。 “修補內核”是指修改ntoskrnl.exe 和其他關鍵系統驅動程序和數據結構(SSDT、IDT、GDT 等)的代碼。

它通過定期檢查這些受保護區域是否被修改而工作。如果檢測到系統被修改,則會觸發藍屏,使系統停止。 PatchGuard在每一個新的Windows版本中都會更新,這使得攻擊者很難開發出適用於所有版本的通用繞過技術。

ntoskrnl.exe中的回調結構和CI!g_CiOptions變量分別從Windows 8和Windows 8.1開始受PatchGuard保護。

DSE在野外被篡改儘管j00ru 得出結論,重寫nt!g_CiEnabled 或CI!g_CiOptions 等私有符號可能相對困難,但這正是攻擊者選擇的方向。眾所周知,臭名昭著的Turla APT 開發了這種技術,安全研究人員對其進行了逆向工程並發布了他們的代碼。

這些私有符號通過簡單的模式匹配來定位,幾乎不需要任何更改:

fig2.webp.jpg

常規PTE 順著SLAT PTE 突出顯示差異

在x86架構上,SLAT pte (Page Table Entries)處理權限不同於常規的PTE:讀\寫權限是分開的,執行權限需要顯式設置,並且只能為ring 0(內核模式)授權。 hypervisor使用SLAT 頁表來強制VTL 之間的隔離並使VTL1 可以訪問它們,所以安全內核使用它們來實現VBS特性,而hypervisor本身並不為這些功能本身實現任何代碼/邏輯。

受HyperVisor 保護的代碼完整性HVCI,最初稱為Device Guard,是隨著VBS 的引入而發布的,這是完整性執行的另一層。

加載新驅動程序後,安全內核也會被觸發並使用其自己的代碼完整性庫SKCI.dll(安全內核代碼完整性)實例。在Secure World (VTL1) 中的當前策略中驗證並檢查數字簽名以得到授權。只有這樣才能將可執行和不可寫權限應用於相應GPA 的SLAT 頁表。因此,NT 內核(VTL0) 不能修改任何以前加載的代碼或運行任何新代碼,而無需在進程中使用安全內核。

fig3.webp.jpg

Windows 10 SKCI.dll 中SkciInialize 及其自身CiOptions 變量的反彙編

內核數據保護KDP 旨在保護在Windows 內核(即操作系統代碼本身)中運行的驅動程序和軟件免受數據驅動的攻擊。它最初是在Windows 10 20H1 中引入的。

使用KDP,在內核模式下運行的軟件可以靜態(其自身映像的一部分)或動態(只能初始化一次的池內存)保護只讀內存。 KDP 僅在VTL1 中為支持受保護內存區域的GPA 建立寫保護,使用SLAT 頁表供管理程序強制執行。這樣,在NT 內核(VTL0) 中運行的任何軟件都不能擁有更改內存所需的權限。

KDP並不強制如何轉換受保護區域的GVA範圍映射,根據開發人員的介紹,KDP目前只定期驗證受保護的內存區域是否轉換為適當的GPA。

從Windows 11 開始,CI.dll 選擇使用靜態KDP (MmProtectDriverSection API) 來強化自身,將所有相關的CI 策略變量放置在名為“CiPolicy”的單獨部分中。

fig4.webp.jpg

Windows 11 中CI.dll 中CiInitializePolicy 和CiPolicy 部分的反彙編

驅動程序阻止列表這是通過Windows Defender 應用程序控制(WDAC) 或HVCI 策略強制執行的,目前已有一些第三方安全產品供應商也採用了這種做法。可以在此處找到最新的阻止列表。

阻止列表拒絕攻擊者輕鬆訪問內核寫入原語。雖然它非常有效,但它不是一種主動措施,只能處理以前發現的驅動程序。因此,這種緩解措施對驅動程序中的零日漏洞無效,防御者必須不斷追踪它們,始終落後於攻擊者一步。

新的篡改發現技術從上面的描述中,敏銳的讀者可以看到,如果沒有啟用HVCI,則可能在不進行任何代碼修補的情況下篡改DSE。

方法一:“頁面交換”

僅僅因為不再可能寫入CI!CiOptions 並不意味著它的值不能改變。該變量仍被虛擬地址訪問,並且每次都會發生到物理地址的轉換過程。因此,我們將改為更改翻譯結果。

通過將物理頁面從受KDP 保護的頁面交換到我們擁有的頁面,我們重新獲得了對內存的完全控制權。交換GPA 僅意味著更改PTE(頁表條目)中的PFN(頁幀號),它本質上只是另一個指針。

我們可以為任何給定的虛擬地址計算PTE 的虛擬地址,避免每次遍歷所有頁表。頁表位於Windows 內核用來管理分頁結構的虛擬內存區域中,稱為“PTE 空間”。 PTE Base 由KASLR(內核地址空間佈局隨機化)隨機化,從Windows 10 Redstone 開始。在之前的研究中,我們展示了一種可靠的方法來找到它。

除了寫入之外,執行此方法還需要內核讀取和內存分配原語。以下是C 偽代碼的分步實現過程:

fig5.webp.jpg

頁面交換的C偽代碼

可以使用來自用戶空間的頁面,因此內核內存分配原語變得多餘。對於CI.dll,可以使用變量的默認值而不是複制頁面。結果,內核空間的讀取次數顯著減少,因為只剩下少數必要的PTE 讀取。

方法二:“回調交換”有一段時間,KDP 似乎提高了防止DSE 篡改的門檻,因為頁面交換也需要內核讀取原語。我們再次查看了CI.dll 和ntoskrnl.exe 是如何集成的,然後我們想,“為什麼要使用CI.dll 呢?讓我們使用自己的回調而不是CI!CiValidateImageHeader”。

fig6.webp.jpg

回調交換演示

上圖證明無需讀取任何內核空間數據即可找到所有必要的地址,具體過程如下:

首先,在ntoskrnl.exe 中找到回調結構。該結構作為參數傳遞給CI!CiInitialize,這樣我們就可以從調用中獲得它的地址。內核只調用該函數一次,因此我們查找使用其導入表條目的CALL或JMP指令。找到調用站點後,返回到“.data”部分中指向未初始化內存的參數的寄存器分配。

fig7.webp.jpg

在Windows 11的ntoskrnl.exe中反彙編SepInitializeCodeIntegrity和SeCiCallbacks

接下來,尋找要使用的替換回調函數。我們需要一個不帶參數並返回零的函數。幸運的是,ntoskrnl.exe 有一些符合此要求的導出函數,例如FsRtlSyncVolumes 或ZwFlushInstructionCache,因此只需調用GetProcAddress 即可。

最後,找到要恢復的原始回調函數。回調由CI!CipInitialize 在結構中設置,因此它將引用所有回調。所有回調都設置在所有Windows 構建的單個基本代碼塊中。搜索這種指令模式,如下圖所示,並從lea 指令中提取偏移量。要驗證偏移量是否確實導致函數,遍歷PE 的異常目錄以查找具有相同起始地址的RUNTIME_FUNCTION 條目。

fig8.webp.jpg

Windows 11中CI.dll中CipInitialize的反彙編

KDP 保護被“設計”繞過,因為ntoskrnl.exe 沒有選擇使用回調結構。更改回調的另一個優點是篡改通過記錄的查詢系統信息API 不可見。

雖然解析地址可能需要多行代碼,但它是在用戶空間中完成的,因此只需要內核寫入原語,這與當前眾所周知的DSE 篡改方法相同。儘管PoC 向內核空間寫入了8 個字節(64 位指針的大小),但可以通過在CI.dll 中查找回調目標來減少這個數字。在撰寫本文時,來自TrustedSec的Adam Chester也發布了一篇最新的研究文章,他選擇了一種替代方法,通過掃描他創建的二進制簽名來找到原始回調。

緩解措施HVCI 涵蓋了所有篡改方法,因為它在加載驅動程序時執行自己的驗證。儘管HVCI 已經存在多年,但直到最近才在新的Windows 安裝中默認啟用。因此,我們一定要想出一個替代方案。

我們試圖找到一種方法來在驅動程序加載期間確認DSE 的狀態。此外,一個將支持程序的阻塞。在這一點上,如何獲得DSE 狀態的可見性應該是顯而易見的,防御者可以利用攻擊者用來查找內部變量的相同策略。畢竟,它已被證明是穩定的。

考慮到一個被篡改的狀態只能持續很短的時間,假設我們開始運行時系統狀態是有效的是合理的。此時,將保留內部變量的副本。

有3個選項可以攔截驅動程序加載:

1.在NtLoadDriver API 的用戶空間中放置一個鉤子。

2.使用註冊表回調來監視驅動程序註冊表項路徑上的操作。

3.使用文件系統微過濾器回調來創建驅動程序文件的部分(IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION)。

要知道回調是否作為驅動程序加載的一部分被觸發,它需要檢查當前進程是SYSTEM 並且調用堆棧源自ntoskrnl.exe 而不是任何其他驅動程序。

一旦驅動程序加載被攔截,通過檢查任何變量的變化來檢測DSE 篡改。此時,可以簡單地通過使用錯誤狀態代碼阻止I\O 請求或將變量恢復到其保存狀態來進行預防。

總結我們在本文中介紹了微軟如何嘗試在運行時保護DSE,並介紹了兩種新方法來篡改它並成功加載未簽名的驅動程序。

雖然HVCI 提供了最強大的解決方案,但我們共享了一種額外的方法來檢測和防止DSE 在運行時篡改。在內核模式下執行代碼對攻擊者仍然具有吸引力,因為它通常是破壞計算機上更高特權元素(例如管理程序、UEFI 和SMM)或擊敗終端安全產品的必備手段。我們可能會看到TTP 的轉變,由於驅動程序阻止列表,攻擊者會轉向使用更多的內核1日漏洞來利用未修補的漏洞。

隨著硬件輔助的安全功能變得越來越普遍,以及微軟致力於利用它們的努力,攻擊者利用DSE 篡改可能會在可預見的未來逐漸消失。儘管如此,配置錯誤和老舊系統仍將存在這種攻擊。