CVE2015-0057漏洞樣本構造探索

wyzsk發表於2020-08-19
作者: cssembly · 2015/02/15 10:15

0x00 前言


微軟最新的補丁包修補了CVE2015-0057的提權漏洞,同一天,漏洞的發現者發表了分析文章《One-Bit To Rule Them All: Bypassing Windows’ 10 Protections using a Single Bit》,看完文章,想嘗試構造一下樣本,原本以為很簡單,結果期間遇到了幾個問題,分享出來,希望能與大家一起討論。

0x01 分析


由於分析文章裡提到漏洞是由xxxEnableWndSBArrows引起的,就透過CreateWindowEx建立ScrollBar,然後呼叫EnableScrollBar,執行到xxxDrawScrollBar,按照分析文章裡的說明,完整流程如下:

enter image description here

結果發現可以執行到xxxGetColorObjects,但是總是沒法走到xxxDefWindowProc,因為(*((_WORD *)P + 0x15) & 0x3FFF) == 0x29A總是成立,最後google了一下,發現這裡是判斷當前窗體是不是ScrollBar。

enter image description here

*((_WORD *)P + 0x15)表示FNID,是透過NtUserSetWindowFNID在建立窗體時設定的,可以在reactos的程式碼中看到,windows包含了如下的FNID。

#!c++
+// FNID's for NtUserSetWindowFNID
+#define FNID_BUTTON      0x02A1
+#define FNID_COMBOBOX    0x02A2
+#define FNID_COMBOLBOX   0x02A3
+#define FNID_DIALOG      0x02A4
+#define FNID_EDIT        0x02A5
+#define FNID_LISTBOX     0x02A6
+#define FNID_MDICLIENT   0x02A7
+#define FNID_STATIC      0x02A8
+#define FNID_IME         0x02A9

NtUserSetWindowFNID中,可以看到這裡會對(_WORD *)(v2 + 0x2A)處的值進行設定,(_WORD *)P + 0x15與等價(_WORD *)(v2 + 0x2A)。

enter image description here

看來直接透過建立ScrollBar是不能執行到xxxDefWindowProc的。透過核心偵錯程式,在此處設定斷點,在螢幕上點動各種窗體,當開啟工作管理員,點選顯示所有使用者程式時,觸發了斷點。檢視此時的呼叫棧,看到了CListView!!!看來可能可以透過MFC的CListCtrl來觸發xxxDefWindowProc函式的執行。

enter image description here

過載了CListCtrl,當ListCtrl顯示的東西過多時,就會出現ScrollBar,這樣在CListCtrl裡處理一下afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)訊息,就能夠處理CListCtrl裡的ScrollBar的訊息,進而釋放掉ScrollBar窗體。當點選CListCtrl裡的橫向ScrollBar時,就會觸發CListCtrlEx::OnHScroll,這次再呼叫EnableScrollBar,就能執行到xxxDefWindowProc函式。

#!c++
void CListCtrlEx::OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )
{
    hScroll = this->m_hWnd; 
    BOOL bEnable = ::EnableScrollBar( this->m_hWnd , SB_HORZ , ESB_DISABLE_BOTH );
    CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
}

enter image description here

不過又遇到了新的問題,signed int __stdcall xxxLoadUserApiHook()函式里總是沒法執行到xxxLoadHmodIndex,顯然這個函式是與UserApiHook相關的,(1 << gihmodUserApiHook) & (_DWORD *)(((_DWORD *)gptiCurrent + 46) + 0xBC)的條件總是成立,好吧,斷點設定在win32k!xxxLoadUserApiHook+0x2b處,結果程式啟動的時候,載入user32.dll,呼叫InitUserApiHook,最終會執行幾次xxxLoadHmodIndex,之後就不再呼叫了。

enter image description here

enter image description here

重新看了一下分析文章,核心就是在使用者態回撥時,釋放掉窗體,因此只要找到另一條路徑,在xxxEnableWndSBArrows返回前,將窗體釋放就可以了。在xxxDefWindowProc裡,會呼叫到SfnDWORD,該函式中就存在一個回撥,如下圖。KeUserModeCallback的第一個引數2表示的是ApiNumber,也就是說最終會透過使用者態的KiUserCallbackDispatcher呼叫USER32!__fnDWORD函式,如果能夠在呼叫該函式的時候,將窗體釋放掉,也是能夠達到觸發漏洞的效果的。

enter image description here

定義一個forFree函式,在KeUserModeCallback回撥到USER32!__fnDWORD時,呼叫這個函式將窗體物件釋放掉,第一次呼叫DestroyWindow( hScroll )釋放窗體,第二次則對窗體是否被釋放進行驗證。透過在USER32!__fnDWORD處呼叫forFree,可以看到呼叫EnableScrollBar最終觸發了forFree執行。注意USER32!__fnDWORD會被頻繁呼叫,因此要進行區分。

#!c++
void forFree()
{
    DestroyWindow( hScroll );
    DestroyWindow( hScroll );
    return ;
}

enter image description here

第一次呼叫DestroyWindow後,可以看到函式執行成功,返回值eax=1。再次呼叫DestroyWindow後,win32k!ValidateHwnd就無法根據hScroll的值來獲取到對應的核心窗體結構,返回值eax=0。從xxxDefWindowProc返回之後,實際上窗體已經不再與之前傳遞給EnableScrollBar的控制程式碼對應了。

enter image description here

enter image description here

不過我在32位win7上,並沒有找到分析文章裡提到的OR操作和AND操作。

enter image description here

0x02 結語


上面就是我對CVE2015-0057漏洞樣本構造過程的探索,與分析文章文章裡的內容存在差異,有什麼不對的地方,希望能與大家交流,我的郵箱:[email protected]

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

相關文章