CVE-2016-0040 濫用GDI 核心提權漏洞

Editor發表於2018-08-28

漏洞背景

本人技術有限,有很多可能沒有分析到位的地方請各位大佬指點。

GDI利用技術很早就流行了,不過在國內 文章搜出來基本就幾篇。正好前段時間看到了利用GDI 提權漏洞,趕緊學習一波。

在2016年 2月份 微軟 修復了 CVE-2016-0040 核心級別的特權提升漏洞。該漏洞成因為 在 ntoskrnl 的WMI子系統中利用未初始化的堆疊變數

CVE-2016-0040 濫用GDI 核心提權漏洞

漏洞分析

一般分析一個CVE 我都會先去Kali 裡面看看

CVE-2016-0040 濫用GDI 核心提權漏洞 

雖然 微軟 說影響情況很多 不過在kali中只提供了 Win7 sp0 /sp1 X64的利用。最後在GitHub上找到了 EXP 和利用的原始碼

利用成功情況

CVE-2016-0040 濫用GDI 核心提權漏洞 

先對EXP 進行 裁剪 造成崩潰

CVE-2016-0040 濫用GDI 核心提權漏洞 

可以看到裁剪 POC 在3環 通過控制碼 對0環 WMIDataDevice進行通訊

而傳送 的資料為 WMIRECEIVENOTIFICATION 這個結構

CVE-2016-0040 濫用GDI 核心提權漏洞 

剛開始再 32位下 分析

CVE-2016-0040 濫用GDI 核心提權漏洞 


CVE-2016-0040 濫用GDI 核心提權漏洞 

可以看到觸發了漏洞 檢視 堆疊 是在 nt!WMIPRECEIVENOTIFICATIONS函式中。之後在wrk 原始碼中發現了此函式 (為分析漏洞已刪除 無關程式碼)

NTSTATUS WMIPRECEIVENOTIFICATIONS(
    PWMIRECEIVENOTIFICATION RECEIVENOTIFICATION,
    PULONG OUTBUFFERSIZE,
    PIRP IRP
    )
{   
    #DEFINE MANY_NOTIFICATION_OBJECTS 16
    ULONG I;
    PWMIGUIDOBJECT GUIDOBJECT;
    ULONG HANDLECOUNT;
    PHANDLE3264 HANDLEARRAY;
    OBJECT_EVENT_INFO *OBJECTARRAY;
    OBJECT_EVENT_INFO STATICOBJECTS[MANY_NOTIFICATION_OBJECTS];  //本地
 
#ENDIF
 
    HANDLECOUNT = RECEIVENOTIFICATION->HANDLECOUNT;          //攻擊點  r14d
    HANDLEARRAY = RECEIVENOTIFICATION->HANDLES;
 
    //
    // CREATE SPACE TO STORE THE OBJECT POINTERS SO WE CAN WORK WITH THEM
    //
 
    IF (HANDLECOUNT > MANY_NOTIFICATION_OBJECTS)
    {
        OBJECTARRAY = WMIPALLOC(HANDLECOUNT * SIZEOF(OBJECT_EVENT_INFO));
        IF (OBJECTARRAY == NULL)
        {
            RETURN(STATUS_INSUFFICIENT_RESOURCES);
        }
    } ELSE {
        OBJECTARRAY = STATICOBJECTS;
    }       
#IF DBG
    RTLZEROMEMORY(OBJECTARRAY, HANDLECOUNT * SIZEOF(OBJECT_EVENT_INFO));
#ENDIF
 
        } ELSE IF (RECEIVENOTIFICATION->ACTION == RECEIVE_ACTION_CREATE_THREAD) {
 
                    GUIDOBJECT = OBJECTARRAY[0].GUIDOBJECT;//
                    GUIDOBJECT->USERMODECALLBACK = (PUSER_THREAD_START_ROUTINE)(ULONG_PTR)RECEIVENOTIFICATION->USERMODECALLBACK.HANDLE;
                    GUIDOBJECT->EVENTQUEUEACTION = RECEIVE_ACTION_CREATE_THREAD;
                    GUIDOBJECT->USERMODEPROCESS = USERMODEPROCESS;
                    GUIDOBJECT->STACKSIZE = STACKSIZE;
                    GUIDOBJECT->STACKCOMMIT = STACKCOMMIT;
 
                    THREADLISTHEAD = &GUIDOBJECT->THREADOBJECTLIST;
                    INITIALIZELISTHEAD(THREADLISTHEAD);

從函式原始碼 可以看到 如果 當傳入的HandleCount 為0時 就會使用本地一個陣列 。可以看到 這個陣列並沒進行 初始化 ,往下看 看到 在CHK 版本中進行了 初始化(。。。) 之後函式 會進行檢查一些操作 當action 為RECEIVE_ACTION_CREATE_THREAD 時 看到 對 ObjectArray 進行了使用 ,不過當設定 HandleCount 為0 時 ObjectArray 是未初始化 ,在下面部分 又對這個初始化的指標 進行了使用。在利用之後 就造成了典型的核心 任意記憶體 讀寫

GDI利用

GdiShareHandleTable Win32k!gpentHmgr的部分 對應程式中每個GDI物件

 CVE-2016-0040 濫用GDI 核心提權漏洞

CVE-2016-0040 濫用GDI 核心提權漏洞 

而其中每一項都使用 GDICELL64 此結構

CVE-2016-0040 濫用GDI 核心提權漏洞 

而通過 一個GDI Handle 我們就可以知道表中的地址

CVE-2016-0040 濫用GDI 核心提權漏洞 

在GDICELL64 結構中 pKernelAddress 指向 SURFACE

CVE-2016-0040 濫用GDI 核心提權漏洞

 

CVE-2016-0040 濫用GDI 核心提權漏洞 

在 SURFOBJ 結構中 ,sizlBitmap 它是一個SIZEL 結構 系統 通過 該變數 來確定 bitMap點陣圖的長和寬 而 pvScan0和pvBits成員變數都表示 指向bitMap 點陣圖的指標

在該利用 還有兩個 關鍵的 函式 GetBitmapBits 該函式 主要用於 讀取 pvScan0 或者 pvBits 指標指向 的cBytes位元組 的Bitmap點陣圖內容 相反 SetBitmapBits 函式 則是對指向的bitMap點陣圖 進行寫入

CVE-2016-0040 濫用GDI 核心提權漏洞 

CVE-2016-0040 濫用GDI 核心提權漏洞 

在一些 paper 中 利用技巧為 建立兩個BitMap物件 (Manager/Worker) 之後通過 控制 Manager Bitmap 物件 的 sizelBitmap或者 pvScan0 成員 去 控制 Worker BitMap 物件 pvScan0 成員 的目的 最終實現核心任意記憶體 讀寫

總結 來說 就是 Manager 控制 著 Worker 讀取 和 寫入 的地址,而Worker 則通過 Set和Get BitmapBits 去對 該地址 進行 讀寫

最關鍵一點 需要 把Manager 的 pvScan0 指向 Worker的 pvScan0 一般通過漏洞去設定

CVE-2016-0040 濫用GDI 核心提權漏洞 

漏洞利用

結合 GDI 利用基本原理 去分析 該漏洞 (分析時 藍屏真痛苦) 直接 對 nt!WmipReceiveNotifications 下斷

CVE-2016-0040 濫用GDI 核心提權漏洞 

結合原始碼 去看 很容易去理解 可以看到 RSI 為本地陣列 因為又利用 核心棧噴射技巧 剛開始 調的時候 到後一直 BSOD 浪費了好長時間

CVE-2016-0040 濫用GDI 核心提權漏洞 

CVE-2016-0040 濫用GDI 核心提權漏洞 

可以看到 棧被噴成 HmangerAddress

CVE-2016-0040 濫用GDI 核心提權漏洞 

在 該地址 加 50 的位置 就是 pvScan0

CVE-2016-0040 濫用GDI 核心提權漏洞 

跟進去看一下 就是 利用程式碼中 建立的 點陣圖

CVE-2016-0040 濫用GDI 核心提權漏洞 

在當初尋找相關文章的時候,我一直在想漏洞與 該 利用技術 的關係 。文章都說 利用 漏洞 去寫 pvScan0 。之後我一直除錯去找這個地方 。一直沒找到。最終還是在此漏洞 該EXP 並沒有這麼做 .

CVE-2016-0040 濫用GDI 核心提權漏洞

在 這位置 它把 pvBits 給了 pvScan0 .可以在看一下 SURFOBJ64結構

CVE-2016-0040 濫用GDI 核心提權漏洞 

CVE-2016-0040 濫用GDI 核心提權漏洞 

注意 現在 操作的Manager 結構

之後 走幾步 該函式 就結束了

CVE-2016-0040 濫用GDI 核心提權漏洞 

而此時 的情況 為 pvBits 裡為它本身, pvScan0 為pvBits

那在哪把 hManger 的pvScan0 寫成 hWorker 的 ,直接對 pvScan0 下寫入斷點

有時候雙擊去除錯 列印的資訊都不顯示

CVE-2016-0040 濫用GDI 核心提權漏洞 

因為除錯過 ,為方便除錯 插入了 _debugbreak

CVE-2016-0040 濫用GDI 核心提權漏洞

CVE-2016-0040 濫用GDI 核心提權漏洞 

CVE-2016-0040 濫用GDI 核心提權漏洞

 

命中 了 硬體斷點 檢視 下 堆疊 是在 SetBitmapBits 中 進行了 memcopy 。此時看一下 hManger 和hWorker

CVE-2016-0040 濫用GDI 核心提權漏洞 

可以看到 已經 寫進去了

這裡關於為什麼能 改變 hManger pvScan0 扯一下

在核心函式 離開之後 可以看到上面的圖 當時的 hManger pvScan0 為pvBits 而pvBits 裡面又是它自己

當呼叫 setBitmapBits 時 會先去找到 hManger 的pvScan0---->pvBits--->pvBits 所以在寫的時候 會直接 從pvBit地址覆蓋 也把pvScan0 覆蓋掉了

CVE-2016-0040 濫用GDI 核心提權漏洞

之後 的利用 就是 讀取 system token 內容 寫入 當前 程式 token 就不在詳細 寫了

 CVE-2016-0040 濫用GDI 核心提權漏洞

最後

分析有錯的地方 請大佬指點下 。之後 把 搜到的 paper 和 原始碼 附上

核心噴射技術



本文作者:Cestlavie呀(看雪ID)

原文連結:https://bbs.pediy.com/thread-246433.htm



看雪推薦閱讀:

1、[翻譯]繞過資料執行保護

2、[原創]某Unity3D遊戲加固產品分析

3、Nexus6P 7.1.2 核心編譯修改 TracerPid

4、[原創]階乘演算法效能分析與 DOUBLE FAULT 藍屏故障排查 PART I

5、[翻譯]VR頭戴(HTC Vive)裝置內的現實危險



相關文章