欢迎来到 无奈人生 安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

0patch一个0day漏洞:Windows gdi32.dll内存披露(CVE-2017-0038

来源: 作者: 时间:2019-02-24 19:29 点击: 我要投稿
广告位API接口通信错误,查看德得广告获取帮助

你可能已经注意到,上一个补丁星期二并没有到来。结果导致大量0day漏洞的文章正在发表,而CVE-2017-0038无疑名列头榜。别着急,每个云里都有一个隐藏的线索。我上周正好有一些空闲时间来解决这个问题,所以,我可以给你0day漏洞的第一个0patch。
针对CVE-2017-0038的分析
CVE-2017-0038是EMF图像格式解析逻辑中的漏洞,它无法充分检查图像中指定的图像尺寸与文件提供的像素数量之间的关系。如果图像尺寸足够大,则解析器被欺骗去读取超过被解析存储器映射的EMF文件内容。攻击者可以使用此漏洞来窃取应用程序在内存中保存的敏感数据,或者辅助其他漏洞绕过ASLR的需求。
在此,我必须感谢Google Project Zero的Mateusz Jurczyk,因为他简短而准确的报告使我能够快速了解漏洞的原因并进行0patch。
以Mateusz的PoC来做为教材,通过启动IE 11的一个实例,并插入poc.emf,以下是我得到的结果:

图像必须放大到最大值,才能通过彩色像素看到惊人的堆数据泄漏。它确实泄漏:重新加载的PoC使得每个加载过的区域内出现了不同的图像。
为了看到像素值我把poc.emf放到HTML画布上,并用JavaScript打印出来。连续PoC重载后的不同结果表明,唯一没有改变的像素是左下角的像素(如果你真正仔细看上面的截图,你会发现一个红色的污点)。
换句话说就是:
FF 33 33 FF
这与报告一致(需要你仔细阅读)。因此,唯一像素是从EMF文件提供的实际数据中的一个(由4个字节表示),其他的堆数据都是从图像像素数据的边界外读取到的。
现在让我们继续修补。在我们继续之前,我们需要了解易受攻击的代码在哪里。幸运的是,报告里清楚地说到了易受攻击的函数名为MRSETDIBITSTODEVICE :: bPlay。这是很重要的,因为PoC不会产生崩溃或异常,它可以被调试器捕获进行深入分析。有了这条信息在手,我们可以附加WinDbg到iexplore.exe并设置断点bp MRSETDIBITSTODEVICE :: bPlay 。
根据报告,这正是问题所在之处。它说cbBitsSrc不检查“预期位图的字节数”,而是从cxSrc和cySrc计算出图像尺寸的数字。
到这里我们需要MSDN的一点帮助:
cxSrc
源矩形的宽度,以逻辑单位表示。
cySrc
源矩形的高度,以逻辑单位表示。
cbBitsSrc
源位图位的大小。
在向WinDbg中输入EMRSETDIBITSTODEVICE类型的符号后(解释如下),报告中的解释终于清晰了。

当处理EMF格式的PoC文件时,EMRSETDIBITSTODEVICE结构(在上面截图的右下方框中详述)作为第一个参数传递到MRSETDIBITSTODEVICE :: Play函数(rcx寄存器存储到rbx,标记为蓝色),其中包含的cbBitsSrc等于4,将与由cxSrc和cySrc定义的0x10 * 0x10图像尺寸不匹配(这些尺寸为256像素或1024字节)。
因此,为了解决缺陷,必须在任何数据被盗之前添加检查。主要需要做的是在任何图像像素被复制之前添加检查,无论cbBitsSrc是否小于cxSrc *cySrc * 4。一个合适的位置似乎是在第一系列检查之前,验证EMRSETDIBITSTODEVICE属性(请参阅上述代码截图中的cmp - jg对,代码结束于一个到函数退出的跳转,以防任何检查失败)。但是,选择确切的补丁位置不仅仅是在逻辑上适合我们要应用的修改位置。补丁的工作方式是从原始位置跳转到补丁代码,然后再返回来。在原始代码中的补丁位置处,写入jmp指令(消耗5个字节的原始指令空间),将其执行重定向到指定用于补丁指令的存储器块。由jmp指令替换的原始指令被重新定位到该补丁码块的末尾,接着是最后的jmp指令,指示在补丁位置之后立即执行回原始代码。因此,还需要满足一些额外的要求:
1、在补丁位置的指令需要可重定位(例如,没有短跳转);
2、在补丁位置,必须有一条指令或属于同一个执行流的几条指令(交叉引用不能指向它们之间的任何地方)。
考虑到这一点,我选择了确切的补丁位置。为了尽可能写少一点的补丁代码,我在第一个分支指令设置了补丁,进而跳转到函数退出(避免处理图像数据),以便我可以返回。在上面的代码截图上,补丁位置标记为红色,而重用的跳转指令标成粉红色。pvClientObjGet调用的结果是在补丁位置处检查是否为0,随后是jne以便跳转到函数退出(如果rax为0)。同样一个提供此逻辑的jne可以帮助我们的补丁代码退出函数:如果cbBitsSrc小于cxSrc * cySrc * 4  ,我们只需要将rax设置为0。
可能选择000007fe`feeae3b8作为第一个补丁位置看起来会令人满意,但是test RAX,RAX只需要3个字节,以便补丁也能包含JNE(不要重定位),因为受限于5字节的要求。然而,在当前选择的位置,修补影响两个3字节指令 - mov rsi,rax和test rax,rax - 它们都是可重定位的。
选择了补丁位置后,我们可以最终写入实际的补丁。下面是一个.0pp补丁文件的内容,可以使用包含在0patch Agent for Developers中的0patch Builder进行编译- 我们在上一篇文章中已经讨论过了。
 在code_start部分的开头有一个cxSrc * cySrc * 4计算,存储在rcx中。这两个乘法之后是溢出检查,所以我们不会得到一个似乎在边界内,但是由超大因素产生的产品。如果检测到无效的图像尺寸,则调用我们0patch代理的特殊功能,以便显示“Exploit Blocked”弹出窗口,最重要的是rax寄存器设置为0,以便执行接下去的test rax,rax指令可以为标为粉色到JNE设置跳转条件(导致函数退出)。
;目标平台:Windows 7 x64
;
RUN_CMD C:\ Program Files \ Internet Explorer \ iexplore.exe C:\ 0patch \ Patches \ ZP-gdi32 \ poc.emf
MODULE_PATH“C:\ Windows \ System32 \ gdi32.dll”
PATCH_ID 259
PATCH_FORMAT_VER 2
VULN_ID 2135
PLATFORM win64

[1] [2]  下一页

你可能已经注意到,上一个补丁星期二并没有到来。结果导致大量0day漏洞的文章正在发表,而CVE-2017-0038无疑名列头榜。别着急,每个云里都有一个隐藏的线索。我上周正好有一些空闲时间来解决这个问题,所以,我可以给你0day漏洞的第一个0patch。
针对CVE-2017-0038的分析
CVE-2017-0038是EMF图像格式解析逻辑中的漏洞,它无法充分检查图像中指定的图像尺寸与文件提供的像素数量之间的关系。如果图像尺寸足够大,则解析器被欺骗去读取超过被解析存储器映射的EMF文件内容。攻击者可以使用此漏洞来窃取应用程序在内存中保存的敏感数据,或者辅助其他漏洞绕过ASLR的需求。
在此,我必须感谢Google Project Zero的Mateusz Jurczyk,因为他简短而准确的报告使我能够快速了解漏洞的原因并进行0patch。
以Mateusz的PoC来做为教材,通过启动IE 11的一个实例,并插入poc.emf,以下是我得到的结果:

图像必须放大到最大值,才能通过彩色像素看到惊人的堆数据泄漏。它确实泄漏:重新加载的PoC使得每个加载过的区域内出现了不同的图像。 本文来自无奈人生安全网
为了看到像素值我把poc.emf放到HTML画布上,并用JavaScript打印出来。连续PoC重载后的不同结果表明,唯一没有改变的像素是左下角的像素(如果你真正仔细看上面的截图,你会发现一个红色的污点)。
换句话说就是:
FF 33 33 FF
这与报告一致(需要你仔细阅读)。因此,唯一像素是从EMF文件提供的实际数据中的一个(由4个字节表示),其他的堆数据都是从图像像素数据的边界外读取到的。
现在让我们继续修补。在我们继续之前,我们需要了解易受攻击的代码在哪里。幸运的是,报告里清楚地说到了易受攻击的函数名为MRSETDIBITSTODEVICE :: bPlay。这是很重要的,因为PoC不会产生崩溃或异常,它可以被调试器捕获进行深入分析。有了这条信息在手,我们可以附加WinDbg到iexplore.exe并设置断点bp MRSETDIBITSTODEVICE :: bPlay 。
根据报告,这正是问题所在之处。它说cbBitsSrc不检查“预期位图的字节数”,而是从cxSrc和cySrc计算出图像尺寸的数字。
到这里我们需要MSDN的一点帮助:
cxSrc
源矩形的宽度,以逻辑单位表示。
cySrc
源矩形的高度,以逻辑单位表示。
cbBitsSrc
源位图位的大小。
在向WinDbg中输入EMRSETDIBITSTODEVICE类型的符号后(解释如下),报告中的解释终于清晰了。

无奈人生安全网



当处理EMF格式的PoC文件时,EMRSETDIBITSTODEVICE结构(在上面截图的右下方框中详述)作为第一个参数传递到MRSETDIBITSTODEVICE :: Play函数(rcx寄存器存储到rbx,标记为蓝色),其中包含的cbBitsSrc等于4,将与由cxSrc和cySrc定义的0x10 * 0x10图像尺寸不匹配(这些尺寸为256像素或1024字节)。
因此,为了解决缺陷,必须在任何数据被盗之前添加检查。主要需要做的是在任何图像像素被复制之前添加检查,无论cbBitsSrc是否小于cxSrc *cySrc * 4。一个合适的位置似乎是在第一系列检查之前,验证EMRSETDIBITSTODEVICE属性(请参阅上述代码截图中的cmp - jg对,代码结束于一个到函数退出的跳转,以防任何检查失败)。但是,选择确切的补丁位置不仅仅是在逻辑上适合我们要应用的修改位置。补丁的工作方式是从原始位置跳转到补丁代码,然后再返回来。在原始代码中的补丁位置处,写入jmp指令(消耗5个字节的原始指令空间),将其执行重定向到指定用于补丁指令的存储器块。由jmp指令替换的原始指令被重新定位到该补丁码块的末尾,接着是最后的jmp指令,指示在补丁位置之后立即执行回原始代码。因此,还需要满足一些额外的要求:
copyright 无奈人生

1、在补丁位置的指令需要可重定位(例如,没有短跳转);
2、在补丁位置,必须有一条指令或属于同一个执行流的几条指令(交叉引用不能指向它们之间的任何地方)。
考虑到这一点,我选择了确切的补丁位置。为了尽可能写少一点的补丁代码,我在第一个分支指令设置了补丁,进而跳转到函数退出(避免处理图像数据),以便我可以返回。在上面的代码截图上,补丁位置标记为红色,而重用的跳转指令标成粉红色。pvClientObjGet调用的结果是在补丁位置处检查是否为0,随后是jne以便跳转到函数退出(如果rax为0)。同样一个提供此逻辑的jne可以帮助我们的补丁代码退出函数:如果cbBitsSrc小于cxSrc * cySrc * 4  ,我们只需要将rax设置为0。
可能选择000007fe`feeae3b8作为第一个补丁位置看起来会令人满意,但是test RAX,RAX只需要3个字节,以便补丁也能包含JNE(不要重定位),因为受限于5字节的要求。然而,在当前选择的位置,修补影响两个3字节指令 - mov rsi,rax和test rax,rax - 它们都是可重定位的。
选择了补丁位置后,我们可以最终写入实际的补丁。下面是一个.0pp补丁文件的内容,可以使用包含在0patch Agent for Developers中的0patch Builder进行编译- 我们在上一篇文章中已经讨论过了。 无奈人生安全网
 在code_start部分的开头有一个cxSrc * cySrc * 4计算,存储在rcx中。这两个乘法之后是溢出检查,所以我们不会得到一个似乎在边界内,但是由超大因素产生的产品。如果检测到无效的图像尺寸,则调用我们0patch代理的特殊功能,以便显示“Exploit Blocked”弹出窗口,最重要的是rax寄存器设置为0,以便执行接下去的test rax,rax指令可以为标为粉色到JNE设置跳转条件(导致函数退出)。
;目标平台:Windows 7 x64
;
RUN_CMD C:\ Program Files \ Internet Explorer \ iexplore.exe C:\ 0patch \ Patches \ ZP-gdi32 \ poc.emf
MODULE_PATH“C:\ Windows \ System32 \ gdi32.dll”
PATCH_ID 259
PATCH_FORMAT_VER 2
VULN_ID 2135
PLATFORM win64
本文来自无奈人生安全网

[1] [2]  下一页 本文来自无奈人生安全网

。 (责任编辑:admin)
【声明】:无奈人生安全网(http://www.wnhack.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱472701013@qq.com,我们会在最短的时间内进行处理。