欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]cve-2016-0051简要分析

[原创]cve-2016-0051简要分析

cve-2016-0051为基于webdav的windows本地提权漏洞
先大概描述一下漏洞。
漏洞是在mrxdav.sys这个驱动程序里面的mrxdav!MRxDAVDevFcbXXXControlFile函数。
在发送畸形的web请求时候,这个函数里面验证不严的话会调用这个函数MRxDAVCreateContinuation,大概是在MRxDAVCreateContinuation+0x254位置处。会造成固定地址写入固定值类型的漏洞,具体看ida的代码吧。
-----------------------------------------------------------------------------------------------------
代码片段1:
  

  DevObj__ = *(v5 + 104);

    if ( !*(pRelevantSrvOpen + 32) )

    {

         v21 = ExAllocatePoolWithTag(v14, 0x40ui64, 0x6F535644u);

         *(pRelevantSrvOpen + 32) = v21;

         if ( !v21 )

         {

               v8 = -1073741670;

               v18 = &WPP_GLOBAL_Control;

               if ( WPP_GLOBAL_Control == &WPP_GLOBAL_Control )

                      return v8;

               if ( !_bittest(WPP_GLOBAL_Control + 11, 0xDu) )

                      goto LABEL_254;

               LODWORD(v19) = PsGetCurrentThreadId(v17, v16);

               v20 = 61i64;

               goto LABEL_15;

         }

         memset(v21, 0, 0x40ui64);

-------------------------------------------------------------------------------------------------
代码片段2:
   if ( !*(*(pprx_context + 80) + 40i64) )

    {

         *(*(pprx_context + 80) + 40i64) =  ExAllocatePoolWithTag(PagedPool, 0x820ui64, 0x6F465644u);

         v100 = *(*(pprx_context + 80) + 40i64);

         if ( v100 )

         {

                memset(v100, 0, 0x820ui64);

         }

                ..........
-------------------------------------------------------------------------------------------------------
代码片段3:   
   v68 = ExAllocatePoolWithTag(PagedPool, 0x40ui64, 0x69465644u);

    v31 = 0;

    v9 = v68;

    if ( !v68 )

    {

           v8 = -1073741670;

           v17 = &WPP_GLOBAL_Control;

           if ( WPP_GLOBAL_Control != &WPP_GLOBAL_Control &&  

                    _bittest(WPP_GLOBAL_Control + 11, 0xDu) )

           {

                  LODWORD(v69) = PsGetCurrentThreadId(&WPP_GLOBAL_Control, v16);

                  WPP_SF_qd(*(WPP_GLOBAL_Control + 3), 65i64, &qword_3207580, v69);

           }

           goto LABEL_245;

    }

    memset(v68, 0, 0x40ui64);

----------------------------------------------------------------------------------------------------
就是v100这个变量,这是rx_context结构体的 PMRX_SRV_OPEN pRelevantSrvOpen字段,32位的环境是偏移0x38,64位的是0x58,这个东西的有一个pdevice_object的双向链表,64为的是在0x20偏移位置处。
在这里是给链表的第一个节点置0了,这个双向链表反复赋值至零的作用下最后导致pRelevantSrvOpen的设备链表的第二个节点为pdevice_object=o;我下写入断点跟踪这个位置的写入情况是在代码片段1,也就是:
fffff880`03442cc8 fffff880`0320f2cc mrxdav!memset+0x97

fffff880`03442cd0 fffff880`032222a1 mrxdav!MRxDAVCreateContinuation+0x254

fffff880`03442e50 fffff880`0320d6a8 mrxdav!UMRxAsyncEngOuterWrapper+0x199

fffff880`03442eb0 fffff880`052eb532 mrxdav!MRxDAVCreate+0xbc

fffff880`03442ef0 00000000`00000000 0xfffff880`052eb532

在把设备对象指针指向0后,就可以在0处写我们做的假的设备对象,通过NtFsControlFile再次调用这个程序就调用我们做的假的设备对象里面的假的驱动irp函数,就可以执行任意代码了
MRxDAVDevFcbXXXControlFile具体的rx_context结构的校验也没有细看,只是做了下补丁的对比,大概的感觉的是在看进程的eprocess的token时候的判断时候少判断了一种情况,补丁后的mrxdav!MRxDAVDevFcbXXXControlFile,专门开了个MRxDavIsCallerPrivileged函数做令牌获取。
-------------------------------------------------------------------------------------------------------
说一下调试方案吧:
把样本直接放在64位的win7里面跑,会在 mrxdav!MrxDAVEfsControl里面崩掉
栈:
    fffff880`035d7180 fffff880`0320b56b mrxdav!MrxDAVEfsControl+0x477

    fffff880`035d7250 fffff880`052e9b99 mrxdav!MRxDAVFsCtl+0x93

    fffff880`035d7290 fffff880`052ef025 rdbss!RxLowIoSubmit+0x291

    fffff880`035d72f0 fffff880`052eec15 rdbss!RxLowIoFsCtlShell+0x1c5

    fffff880`035d7360 fffff880`052c7684 rdbss!RxCommonFileSystemControl+0xe45

    fffff880`035d74b0 fffff880`052e4b44 rdbss!RxFsdCommonDispatch+0x870  创建RX_CONTEXT

    fffff880`035d75a0 fffff880`03212b89 rdbss!RxFsdDispatch+0x224   和硬件联系用的驱动

    fffff880`035d7610 fffff880`01bb3271 mrxdav!MRxDAVFsdDispatch+0x6c0  分发那种irp

    fffff880`035d76e0 fffff880`01bb1138 mup!MupiCallUncProvider+0x161

    fffff880`035d7750 fffff880`01bb29e3 mup!MupStateMachine+0x128

    fffff880`035d77a0 fffff880`01098bcf mup!MupFsControl+0x7f

    fffff880`035d77e0 fffff880`010b895e fltmgr!FltpLegacyProcessingAfterPreCallbacksCompleted+0x24f

    fffff880`035d7870 fffff800`041b9f97 fltmgr!FltpFsControl+0xee,


蹦处的代码:
   
 *(_QWORD *)(v30 + 56) = MrxDAVEfsControlCompletion;


抽取关键代码就是:
    v6 = *(_QWORD *)(a1 + 0x58);

    v7 = *(_QWORD *)(v6 + 32);

    DeviceObject = *(PDEVICE_OBJECT *)(v7 + 32);

    LOBYTE(v23) = DeviceObject->StackSize;

    LODWORD(v24) = RxCeAllocateIrpWithMDL_0(v23, 0i64, 0i64);

    v3 = v24;

    v29 = *(_QWORD *)(v3 + 184);

    v30 = *(_QWORD *)(v3 + 184) - 72i64;

    *(_QWORD *)(v30 + 56) = MrxDAVEfsControlCompletion;

用windbg看可以看出:
    LOBYTE(v23) = DeviceObject->StackSize;结果是255
因为人家给的是win7 32位的exploit,放在win7 64只能蓝屏,对照win7 32位的可以看出是0x30处有个10,也就是StackSize字段是10,但是在64位的系统偏移是在4c处,后面的
“ v2 = IofCallDriver(DeviceObject, (PIRP)v3); ” 就是提权的利用代码了。
我直接用汇编拼64位系统上可以运行的exploit拼了好久,拼不出来,最后卡在kernel32的这个dll的GetCurrentProcessId上面,一跑到这个函数就崩溃,内核里面的指令集是不兼容的,我不知道怎么处理了。
附上我的拼的结果吧,最后可以进shellcode函数,但是shellcode不兼容。那个shellcode_17.dll名字要改成shellcode.dll,我是直接在16进制编辑器上面改的,也附上源作者的eop吧。
调试时候,直接在bp mrxdav!MRxDAVDevFcbXXXControlFile,MRxDAVCreateContinuation,MrxDAVEfsControl三个函数上面下断,找到rx_context结构体,然后就在pRelevantSrvOpen这个指针上面下写入断点,在到它的设备链表上面下断点,就行了,就可以找到做手脚的地方,shellcode做的假的device_object是放在00地址处,这个结构体有指向shellcode的提权函数指针,64位是在d8处指向提权代码,我的exp,shellcode不兼容,可以进提权函数,但是提权函数会在内核里面崩溃,源作者的在32位里面可以完美提权。

上传的附件 新建文件夹.zip
CVE-2016-0051.zip

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功