CVE-2017-0038:GDI32越界读漏洞从分析到Exploit
在这篇文章中,我将首先对CVE-2017-0038这个GDI32.dll的Out-of-bound Read漏洞进行分析;随后,我将首先将分享用JS编写一个浏览器可用的Exploit,随后我将和大家一起来看一下这么做的一个限制(为什么无法用浏览器进行Info leak),也是在0patch文章中提到的0xFF3333FF到底是怎么回事;然后,我将和大家分享用C语言完成Exploit,一起来看看真正泄露的内存内容;最后我将把JS和C的Exploit放在github上和大家分享。
调试环境是:
Windows 10 x86_64 build 10240
IE 11
GDI32.dll Version 10.0.10240.16384
请大家多多交流,感谢阅读!
CVE-2017-0038 PoC与漏洞分析
如我在第一章分享的测试环境的图片,同样在0patch的文章中也能看到,在浏览器每次加载poc.emf的时候,都会产生不同的图片,这张图片只有左下角的一个小红点是固定不变的,其实除了左下角四个字节,其他的内容都是泄露的内存,这点在后面的分析中我们可以获得。
那么现在我们需要解决的一个问题就是如何加载这个图片,这样我们需要用JS的画布功能来完成对PoC的构造,并且成功加载PoC.emf。
首先,我们定义一个canvas画布,之后通过js的getElementById来获得画布对象,之后我们通过Image()函数来初始化image对象,加载poc.emf,最后,我们通过drawImage来读取poc.emf,将poc.emf打印在画布上。drawImage后两个参数是image在canvas画布上的坐标,这里我们设置为0,0。
完成构造后,我们稍微修改一下poc.emf的文件结构,然后打开IE11浏览器,通过Windbg附加进程,并且在gdi32!MRSETDIBITSTODEVICE::bPlay函数位置下断点,这个过程会在poc.emf映射在画布上时发生,允许js执行之后,Windbg命中函数入口。
0:022> x gdi32!MRSETDIBITSTODEVICE::bPlay
00007ff8`2a378730 GDI32!MRSETDIBITSTODEVICE::bPlay =
0:022> bp gdi32!MRSETDIBITSTODEVICE::bPlay
Breakpoint 0 hit
GDI32!MRSETDIBITSTODEVICE::bPlay:
00007ff8`2a378730 48895c2408 mov qword ptr [rsp+8],rbx ss:00000034`93cef6f0={GDI32!MRMETAFILE::bPlay (00007ff8`2a320950)}
0:027> kb
RetAddr:ArgstoChild: Call Site
00007ff8`2a2ff592 : 00007ff8`2a320950 00007ff8`2a2f8ed1 00000000`00000008 ffffffff`8f010c40 : GDI32!MRSETDIBITSTODEVICE::bPlay//到达目标断点
00007ff8`2a2ff0a8 : 0000002c`8f00be8c 00000000`00000000 00000000`00000000 00000000`00000000 : GDI32!PlayEnhMetaFileRecord+0xa2
00007ff8`2a327106 : 00000034`92acee00 00007ff8`2a2ff8f3 00000034`90380680 00000034`93cef988 : GDI32!bInternalPlayEMF+0x858
00007ff8`08650a70 : 00007ff8`08061010 00007ff8`08061010 00000034`93cefa10 00000000`000000ff : GDI32!PlayEnhMetaFile+0x26//关键函数调用PlayEnhMetaFile
现在我们开始单步跟踪这个关键函数的执行流程,之后我放出整个函数的伪代码,相应的注释,我已经写在//后面,首先单步执行,会到达一处参数赋值,在64位系统中,参数是靠寄存器传递的。
0:027> p
GDI32!MRSETDIBITSTODEVICE::bPlay+0x1b:
00007ff8`2a37874b 488bd9 mov rbx,rcx
0:027> r rcx
rcx=0000002c8f00be8c
0:027> dt vaultcli!EMRSETDIBITSTODEVICE 0000002c8f00be8c
+0x000 emr : tagEMR
+0x008 rclBounds : _RECTL
+0x018 xDest : 0n0
+0x01c yDest : 0n0
+0x020 xSrc : 0n0
+0x024 ySrc : 0n0
+0x028 cxSrc : 0n1
+0x02c cySrc : 0n1
+0x030 offBmiSrc : 0x4c
+0x034 cbBmiSrc : 0x28
+0x038 offBitsSrc : 0x74
+0x03c cbBitsSrc : 4
+0x040 iUsageSrc : 0
+0x044 iStartScan : 0
+0x048 cScans : 0x10
这里rcx传递的指针是MRSETDIBITSTODEVICE::bplay的第一个参数,这个参数是一个非常非常非常重要的结构体EMRSETDIBITSTODEVICE,正是对这个结构体中几个成员变量的控制没有进行严格的判断,从而导致了越界读漏洞的发生。
首先我们来看一下EMF文件格式。
在这篇文章中,我将首先对CVE-2017-0038这个GDI32.dll的Out-of-bound Read漏洞进行分析;随后,我将首先将分享用JS编写一个浏览器可用的Exploit,随后我将和大家一起来看一下这么做的一个限制(为什么无法用浏览器进行Info leak),也是在0patch文章中提到的0xFF3333FF到底是怎么回事;然后,我将和大家分享用C语言完成Exploit,一起来看看真正泄露的内存内容;最后我将把JS和C的Exploit放在github上和大家分享。
调试环境是:
Windows 10 x86_64 build 10240
IE 11
GDI32.dll Version 10.0.10240.16384
请大家多多交流,感谢阅读!
CVE-2017-0038 PoC与漏洞分析
如我在第一章分享的测试环境的图片,同样在0patch的文章中也能看到,在浏览器每次加载poc.emf的时候,都会产生不同的图片,这张图片只有左下角的一个小红点是固定不变的,其实除了左下角四个字节,其他的内容都是泄露的内存,这点在后面的分析中我们可以获得。
那么现在我们需要解决的一个问题就是如何加载这个图片,这样我们需要用JS的画布功能来完成对PoC的构造,并且成功加载PoC.emf。
首先,我们定义一个canvas画布,之后通过js的getElementById来获得画布对象,之后我们通过Image()函数来初始化image对象,加载poc.emf,最后,我们通过drawImage来读取poc.emf,将poc.emf打印在画布上。drawImage后两个参数是image在canvas画布上的坐标,这里我们设置为0,0。
完成构造后,我们稍微修改一下poc.emf的文件结构,然后打开IE11浏览器,通过Windbg附加进程,并且在gdi32!MRSETDIBITSTODEVICE::bPlay函数位置下断点,这个过程会在poc.emf映射在画布上时发生,允许js执行之后,Windbg命中函数入口。
0:022> x gdi32!MRSETDIBITSTODEVICE::bPlay
00007ff8`2a378730 GDI32!MRSETDIBITSTODEVICE::bPlay =
0:022> bp gdi32!MRSETDIBITSTODEVICE::bPlay
Breakpoint 0 hit
GDI32!MRSETDIBITSTODEVICE::bPlay:
00007ff8`2a378730 48895c2408 mov qword ptr [rsp+8],rbx ss:00000034`93cef6f0={GDI32!MRMETAFILE::bPlay (00007ff8`2a320950)}
本文来自无奈人生安全网
0:027> kb
RetAddr:ArgstoChild: Call Site
00007ff8`2a2ff592 : 00007ff8`2a320950 00007ff8`2a2f8ed1 00000000`00000008 ffffffff`8f010c40 : GDI32!MRSETDIBITSTODEVICE::bPlay//到达目标断点
00007ff8`2a2ff0a8 : 0000002c`8f00be8c 00000000`00000000 00000000`00000000 00000000`00000000 : GDI32!PlayEnhMetaFileRecord+0xa2
00007ff8`2a327106 : 00000034`92acee00 00007ff8`2a2ff8f3 00000034`90380680 00000034`93cef988 : GDI32!bInternalPlayEMF+0x858
00007ff8`08650a70 : 00007ff8`08061010 00007ff8`08061010 00000034`93cefa10 00000000`000000ff : GDI32!PlayEnhMetaFile+0x26//关键函数调用PlayEnhMetaFile
现在我们开始单步跟踪这个关键函数的执行流程,之后我放出整个函数的伪代码,相应的注释,我已经写在//后面,首先单步执行,会到达一处参数赋值,在64位系统中,参数是靠寄存器传递的。
0:027> p
GDI32!MRSETDIBITSTODEVICE::bPlay+0x1b:
00007ff8`2a37874b 488bd9 mov rbx,rcx
0:027> r rcx
rcx=0000002c8f00be8c
0:027> dt vaultcli!EMRSETDIBITSTODEVICE 0000002c8f00be8c
本文来自无奈人生安全网
+0x000 emr : tagEMR
+0x008 rclBounds : _RECTL
+0x018 xDest : 0n0
+0x01c yDest : 0n0
+0x020 xSrc : 0n0
+0x024 ySrc : 0n0
+0x028 cxSrc : 0n1
+0x02c cySrc : 0n1
+0x030 offBmiSrc : 0x4c
+0x034 cbBmiSrc : 0x28
+0x038 offBitsSrc : 0x74
内容来自无奈安全网
+0x03c cbBitsSrc : 4
+0x040 iUsageSrc : 0
+0x044 iStartScan : 0
+0x048 cScans : 0x10
这里rcx传递的指针是MRSETDIBITSTODEVICE::bplay的第一个参数,这个参数是一个非常非常非常重要的结构体EMRSETDIBITSTODEVICE,正是对这个结构体中几个成员变量的控制没有进行严格的判断,从而导致了越界读漏洞的发生。
首先我们来看一下EMF文件格式。
www.wnhack.com
[1] [2] [3] [4] [5] [6] [7] 下一页
无奈人生安全网