7

CVE2015-0057漏洞样本构造探索 | WooYun知识库

 6 years ago
source link:
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

CVE2015-0057漏洞样本构造探索

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]


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK