CVE-2016-0143 漏洞分析(2016.4)

CVE-2016-0143漏洞分析算法

0x00 背景

420日,Nils Sommerexploitdb上爆出了一枚新的Windows内核漏洞PoC。该漏洞影响全部版本的Windows操做系统,攻击者利用成功后可得到权限提高,微软在4月补丁日修复了该漏洞。shell

 

0x01 漏洞分析

Nils Sommer并无说明该漏洞为什么种类型的漏洞,咋看崩溃场景会认为是NULL Pointer dereference或者UAF漏洞,粗略分析后,以为是整数溢出漏洞,可是最后仍是将其定义为特殊的NULL Pointer dereference漏洞。下面对漏洞成因进行简单分析。函数

 

In xxxRealDrawMenuItem spa

崩溃的地方是在win32k!xxxRealDrawMenuItem函数内,在windbg中查看崩溃时的内存状态:操作系统

 

崩溃上下文代码的IDA截图,将其命名为过程A(最后说明时会用到): code

 

crash以前,eax会和[ebp+arg_8]作有符号乘法,并将结果和ebx作比较,来肯定是否执行crash的指令。blog

此时的eaxPoCr.bottomr.top运算后的结果,具体操做在win32k!xxxDrawMenuBarTemp内,算法为:eax= r.bottom-r.top-1; 内存

[ebp+arg_8]PoC中的info.bmiHeader.biSize; it

 

PoC 给的值会让"imul eax,[ebp+arg_8]"产生溢出,走向crash流程。这里看起来是因为整数溢出形成的漏洞,其实正常流程都会走这个流程的,这并非漏洞成因所在。io

 

所操做的ecx[ebp+var_28]获取,原始值为1[ebp+var_28]本应该为DIBObject的地址,可是在为其分配内存的函数win32k!SURFMEM::bCreateDIB中,并无为其分配内存空间,漏洞的关键在这里

下面分析建立DIBObject失败的缘由。

 

In SURFMEM::bCreateDIB

SURFMEM::bCreateDIB的函数调用栈:

xxxDrawMenuBarTemp

    à GreCreateDIBitmapReal

        àSURFMEM::bCreateDIB

 

SURFMEM::bCreateDIB函数内有这样一段代码,将其命名为过程B:

 

此时eax等于xxxRealDrawMenuItem函数中的edi[ebp+arg_0]PoC中的info.bmiHeader.biSize*4,按照PoC中设定的值,二者分别为0x7fffff690x274

当二者进行乘法运算后,一样发生了溢出,但因为是无符号运算,因此edx!=0。调用函数ULongLongAdd后,[ebp+AllocationSize+4]=edx=139h!=0所以便走向了失败的流程,不会为DIBObject分配内存,也致使GreCreateDIBitmapReal函数的返回值为0

 

若是未发生溢出,而且二者的乘积(+0x154)小于7FFFFFFFh, SURFMEM::bCreateDIB函数就会根据这个乘积(+0x154)DIBObject分配一块内存。分配内存的代码在IDA中的截图:

分配成功后,会将AllocateObject的返回值做为GreCreateDIBitmapReal函数返回值,而且赋值给xxxRealDrawMenuItem 函数中的[ebp+var_28]

 

0x02 补丁对比

来看看微软是怎么来补这个漏洞的,补丁后的部分xxxRealDrawMenuItem函数代码在IDA中的截图:

能够看到,补丁后,xxxRealDrawMenuItem函数在调用GreCreateDIBitmapReal函数后,对返回值作了检查:若是返回值等于0,表示建立DIBObject失败,则不会再进入到操做DIBObject的流程,也就是过程A中了。

0x03 可能的利用

目前尚未人公开本身的利用代码,下面对该漏洞存在的可能利用方式作一个说明。

crash处是一个对ecx进行循环操做的代码段,循环次数为"imul eax,[ebp+arg_8]"的乘积。正常状况下是对申请的DIBObject进行操做。

这个循环操做中,存在一个可控的写入操做指令,在IDA中的截图:

红框中的指令就是所说的写入操做指令,edx虽然经历多条指令操做后才获得,可是参与操做的都是ecx相关内存值,由于ecx也就是零页地址的内容可控,因此edx也是可控的。

那么理论状况下,在win8以前的系统中,是能够将这条指令操做转变为:

mov [HalDispatchTable+4],shellcodeAddress

以后用户层再触发一下就完成了提权。

0x04 其余

通过深刻分析后,要触发漏洞,r.bottomr.topinfo.bmiHeader.biWidth知足必定的约束就好了,不必定须要和做者给出PoC的数值彻底相同。r.bottomr.topinfo.bmiHeader.biWidth的值能知足下面两个条件就能够致使crash

  1. 过程B分配DIBObject失败。
  2. 过程A走向crash流程。

过程B和过程A要知足这两个条件,具体状况以下。

 

过程B
1.
过程B未发生溢出,而且乘积后的值 < 0x7FFFFFFF,形成AllocateObject调用失败。

2. 过程B未发生溢出,而且乘积后的值 > 0x7FFFFFFF,不走调用AllocateObject的流程。

3. 过程B发生溢出,不走调用AllocateObject的流程。

 

过程A

1.未溢出。

2.溢出后的结果为负数,而且改变sf位为1(有符号数比较)。

根据上面分析给出的过程A和过程B会致使crash的状况,这里给出两种具体的组合,有兴趣的能够修改原PoC中对应的值尝试一下,都会crash的。

组合1

过程B状况1+过程A的状况1两个地方都没有溢出,可是仍是crash了,也说明了不是整数溢出漏洞。

组合2

过程B状况3+过程A状况2:

by:会飞的猫转载请注明:http://www.cnblogs.com/flycat-2016

相关文章
相关标签/搜索