1. 程式人生 > >CVE-2018-8897 調試分析

CVE-2018-8897 調試分析

cve-2018-8897

技術分享圖片

漏洞說明

系統內核通過Mov到SS(stack segment)或Pop到SS指令進行堆棧切換操作後處理異常情況時發現了一個缺陷.在堆棧切換操作期間,處理器沒有傳送中斷和異常,而是在堆棧切換後面的第一條指令執行完傳送.一個沒有特權的系統用戶可以利用這個漏洞來破壞系統內核,導致拒絕服務.實際上MOV到SS會延遲一些調試異常(例如一個硬件斷點)直到下條指令完成;如果跟隨MOV到SS或者POP到SS後面的指令是SYSCALL 、SYSENTER、INT 3之類的指令,調試異常被捕獲之後將轉移到Ring0執行.

樣本環境

首先從https://github.com/can1357/CVE-2018-8897 下載POC源代碼,用vs2015新建立一個win32控制臺工程;POC裏面有個64位匯編的asm文件,使用VC++自帶的匯編編譯器編譯Native.asm 為一個obj文件[ml64.exe/FlNative /c /Zi Native.asm],再把obj添加到工程裏面[右擊工程名字,點擊屬性;點擊配置屬性→鏈接器→輸入→附加依賴項;輸入obj名字],然後編譯得到一個POC,編譯POC一步算完了.

技術分享圖片

樣本是Win7x64位的,接下來搭建一個Win7x64的VMWar環境,運行poc.exe嘗試觸發一次,POC顯示失敗了.

技術分享圖片

POC失敗問題先暫停.關於WinDBG的內核調試,WinDBG與VMWare雙機內核調試工具的配置請使用VirtualKD.如何安裝使用請自行搜索.

技術分享圖片

修復樣本

回看一下上面的問題,樣本為什麽會失敗?看下前面錯誤提示之前的代碼,這段代碼與KeBugCheckEx與PsGetCurrentProcess函數有關.

技術分享圖片

在IDA中打開目標系統的ntoskrnl.exe文件,看KeBugCheckEx的匯編代碼,代碼應該搜尋0x53E0這個偏移,gs:20h是一_KPRCB結構的變量_KPCR→CurrentPrcb,這些結構一般是公開的,利用搜索引擎很容易獲得.0x53EO偏移處保存的一個CONTEXT結構,也就是Prcb.Context.

技術分享圖片

PsGetCurrentProcess的匯編代碼,代碼應該是搜尋0x70值.GS寄存器等於32位系統FS寄存器,其實這裏指向內核結構_KPCR結構.0x188的偏移位置是_KTHREAD結構,0x70的偏移位置是_KTHREAD結構,也就是KThread.ApcStateFill.Process

技術分享圖片

技術分享圖片

PsGetCurrentProcess函數的有關實現.

技術分享圖片

現在說下修復方法,找到自己系統上這兩個函數數據結構的偏移,如果發現沒有這兩個數據結構的偏移,那麽請找一個函數修復這個偏移.測試系統上Prcb.Context對應不上,需要修復偏移.

技術分享圖片

打開WinDBG進行雙機內核調試,輸入命令dt _KPRCB查找_CONTEXT的偏移地址,測試系統偏移為0x4bd8.

技術分享圖片

修改POC裏面的偏移地址,然後運行POC測試

技術分享圖片

在vmware裏面運行到漏洞觸發那裏還是崩潰了?為什麽呢?原因是讀取GS的基址失敗了.原因很有可能就是vmware不支持rdgsbase之類的指令,嘗試了二進制翻譯功能,仍然提示錯誤.怎麽解決呢?請看下面.

技術分享圖片

如果本機打了補丁的請卸載名字為KB4103712 與KB4103718的補丁,卸載補丁後再次運行.運行結果是直接重啟.WHAT?說明已經觸發了漏洞,但是例如ROP與Shellcode之類的可能還需要修復.先看一下攻擊過程.

攻擊過程

源碼中首先檢測內核頁表隔離(KPTI,kernel page table isolation, Windows內核中又叫KvaShadow)是否被啟用,這好像與一個INTEL漏洞相關.

技術分享圖片

使用VirtualLock函數把兩個函數的代碼鎖定在物理頁面,供內核使用.

技術分享圖片

得到內核基址並加載(LoadLibrary)內核ntoskrnl.exe到自身進程.

技術分享圖片

分配4個內核對象(_KPCR,_KTHREAD,_KPROCESS,_KPRCB)供內核使用.

技術分享圖片

內核結構_KPCR的偏移0x180處是_KPRCB結構.

技術分享圖片

解析內核模塊,查找一些用於ROP技術的小組件.

技術分享圖片

找到內核結構_KPRCB成員Context的偏移地址,找到進程_EPROCESS的偏移地址.前面講過,不重復講.

填充_KPCR,_KPRCB,_KTHREAD結構體,相關成員的偏移地址在不同的系統可能會一樣,請自己修復.

技術分享圖片

讀取堆棧段寄存器保存到變量SavedSS.

技術分享圖片

創建一個線程,獲得填充_KPRCB對象的成員_CONTEXT的偏移地址,並等待RtlCaptureContext函數調用獲得泄漏的RSP,漏洞觸發前會一直等待,實際上異常才會進入這個函數.等待第二次RtlCaptureContext被調是計算兩次RSP的差異值來預測下一次RSP的值,並預測返回指針的位置,並建立RtlCaptureContext需要的上下文.第一條ROP的RETN位置放在XMM13寄存器.

技術分享圖片

設置輔助線程的優先級為最高並分離當前線程與創建的輔助線程,讓它們在不同的CPU上執行,接著獲取了一些內核函數的地址.

技術分享圖片

給線程設置兩個異常,一個在SS段寄存器為讀寫異常,另一個寫異常位於結構_KPRCB→ProcessorState(_KPROCESSOR_STATE)→SpecialRegisters(_KSPECIAL_REGISTERS)→Cr8.

技術分享圖片

WinDBG輸入u KeBugCheckEx,紅色部分,如果偏移不一樣則需要修復這個結構.

技術分享圖片

開始填充rop到XMM寄存器.

技術分享圖片

最後讀取gs段寄存器基址,重設基址指向自己填充的_KPCR結構,然後觸發漏洞,恢復GS段寄存器,並使用SS段寄存器去觸發漏洞.

技術分享圖片

先使用mov ss指令切換堆棧,並且會產生前面的ss調試異常,但mov ss切換後不會立即發送異常要等下一條指令執行完成後才發送;緊接著是一個int 3指令,由於前面會改變了gs段寄存器的基址,進入內核之後要使用SWAPGS指令交換gs段寄存器.

技術分享圖片

可能需要修復的一些數據偏移,根據不同的系統偏移不同.

技術分享圖片

小結

由於無法使用WinDBG對本機進行內核調試驗證,修復POC裏面的數據偏移,如果數據偏移沒有修改正確就測試POC,可能會造成系統重啟.快點自己動手試下吧.

原文地址:https://mozhe.cn/news/detail/285請添加鏈接描述

CVE-2018-8897 調試分析