CVE-2018-0798及利用样本分析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: •成因:EQNEDT32.exe在解析Matrix record时,并未检查长度,从而造成栈溢出。无论打不打CVE-2017-11882补丁都可以成功触发,使得攻击者可以通过刻意构造的数据内容及长度覆盖栈上的函数返回地址,从而劫持程序流程。

CVE-2018-0798及利用样本分析





1.本篇文章系Gcow安全团队复眼小组的ERFZE师傅原创,未经许可禁止转载.2.本篇文章从CVE-2018-0798漏洞的基础分析入手,分析了其漏洞分成因.以及演示了蔓灵花APT组织以及某样本组织在实际攻击活动之中所使用的样本的超级详细的分析,十分值得样本分析人员以及刚刚接触本漏洞的分析人员学习.3.本篇文章大约2700多字,103张图片,预计阅读时间9分钟.

0x01 漏洞描述

成因EQNEDT32.exe在解析Matrix record时,并未检查长度,从而造成栈溢出。无论打不打CVE-2017-11882补丁都可以成功触发,使得攻击者可以通过刻意构造的数据内容及长度覆盖栈上的函数返回地址,从而劫持程序流程。影响版本:Microsoft Office 2007, Microsoft Office 2010, Microsoft Office 2013,Microsoft Office 2016POC:CVE-2018-0798—— https://github.com/houjingyi233/office-exploit-case-study/blob/master/CVE-2017-11882%26CVE-2018-0802%26CVE-2018-0798/cve-2018-0802%20poc%20with%20comments.rtf

0x02 漏洞分析

笔者复现及分析环境:Windows 7 Service Pack 1、Microsoft Office 2010、x64Dbg、IDA 7.0(EQNEDT32.exe已打CVE-2017-11882补丁,但笔者分析时关闭了ASLR)

0x02.1 静态分析

漏洞位于sub_443E34内:


图片1 sub_443E34


其调用了两次sub_443F6C,但sub_443F6C在复制数据时并未检查传递进来的参数:


图片2 sub_443F6C


其中的数据长度可通过a1控制,具体计算方法是(2 * a1 + 9) >> 3,而其目的地址是由sub_443E34传递过来位于其开辟栈空间内的局部变量(int型):


图片3 栈


如此一来,便可通过精心构造的数据,覆盖sub_443E34函数的返回地址,进而控制执行流。

0x02.2 动态调试

POC地址已于上文给出。直接于sub_443E34处设断,成功断下后,直接执行到调用sub_443F6C前查看其传递参数:


图片4 传递参数


跟进查看,可以看到其计算后的实际复制数据长度:


图片5 计算后的复制长度


跟进其调用的sub_416352可以查看要复制数据:


图片6 要复制数据


直接执行到sub_443F6C结束处,可以看到:


图片7 已覆盖栈上的数据


sub_443E34再次调用sub_443F6C,其执行流程同上:


图片8 传递参数



图片9 计算后的复制长度



图片10 要复制数据


可以看到,已经覆盖栈上sub_443E34的返回地址,劫持了执行流:


图片11 已覆盖栈上的数据


回到sub_443E34,直接执行到结束处:


图片12 sub_443E34结束处


通过ROP跳转到WinExec()


图片13 ROP


成功弹出计算器:


图片14 calc


0x03 Bitter组织某样本分析

样本名称:Urgent Action.docx

样本MD5:02C2A68CE9A35F5F0E1B3456E09D6CC9

通过远程模板注入的方式下载一RTF格式文档:


图片15 远程URL


使用WinHex查看,确为RTF格式:


图片16 WinHex查看


添加.rtf后缀后打开文档。直接来到sub_443E34调用sub_443F6C处:


图片17 调用sub_443F6C及传递参数


此次调用sub_443F6C并未发生溢出,其复制数据长度如下:


图片18 复制数据长度


复制内容:


图片19 复制内容


其第二次调用sub_443F6C,发生溢出:


图片20 复制数据长度


复制内容:


图片21 复制内容


接下来直接执行到sub_443E34结束处,可以看到其劫持执行流:


图片22 sub_443E34结束处


通过ROP跳转到Shellcode:


图片23 ROP


Shellcode如下:


图片24 Shellcode


下面开始分析其功能。首先是计算跳转地址:


图片25 跳转


跳转之后,通过与计算出的EAX值比较的方式移动指针指向要复制的Shellcode,复制后跳转到Shellcode上执行:


图片26 复制Shellcode


通过PEB手动符号解析定位到kernel32.dll


图片27 定位kernel32.dll


定位kernel32.dll中的GetProcAddress()函数:


图片28 寻址GetProcAddress()


跳转后执行GetProcAddress()


图片29 call调用



图片30 获取CreateDirectory调用地址


之后通过call调用的形式给CreateDirectory()传递参数:


图片31 调用CreateDirectory


于C盘创建一名为Temp的文件夹。获取LoadLibrary()调用地址:


图片32 获取LoadLibrary调用地址


之后在call调用的同时传递参数:


图片33 call调用并传递参数



图片34 LoadLibrary(urlmon.dll)


接着再次call调用,先修正内存中的字符串,接着获取URLDownloadToFile()函数调用地址:


图片35 修正字符串



图片36 获取URLDownloadToFile()函数调用地址


通过两次call调用来给URLDownloadToFile()函数传递参数:


图片37 传递参数



图片38 未修正的参数



图片39 修正参数


之后调用URLDownloadToFile()函数从http://maq[.]com[.]pk/wehs下载文件到创建的Temp文件夹内,文件名为`smss`:


图片40 URLDownloadToFile


call调用的同时向GetProcAddress()传递参数,获取MoveFile()调用地址:


图片41 获取MoveFile()调用地址


两处call调用向MoveFile()传递参数:


图片42 调用MoveFile


smss重新命名为smss.exe。之后获取LoadLibrary()调用地址:


图片43 获取LoadLibrary调用地址


call调用的同时传递参数:


图片44 LoadLibrary(shell32.dll)


获取ShellExecute()调用地址:


图片45 获取ShellExecute()调用地址


通过三次call调用来给ShellExecute()传递参数,最后调用之:


图片46 调用ShellExecute


接下来执行的smss.exe,非本文重点,故不分析。

0x04 xx组织某样本分析

写文章截图的时候中途断过两次,故前后文某些地址(使用这些地址只是为了方便说明)不对应,望读者谅解。另,此样本在打了CVE-2017-11882补丁的机器上无法被成功利用。

直接定位到漏洞触发点:


图片47 第一次调用sub_443F6



图片48 复制数据长度



图片49 复制内容


第二次调用sub_443F6过程如下:


图片50 第二次调用sub_443F6



图片51 复制数据长度



图片52 复制内容


可以看到,栈上函数返回地址已经被覆盖:


图片53 已覆盖栈上的数据


但其并未直接执行到sub_443E34结束处,而是通过给其后调用的函数传参,再次执行sub_443E34(其调用函数的具体功能可结合IDA进行分析):


图片54 调用sub_4428F0



图片55 调用sub_437C9D



图片56 调用sub_416352



图片57 调用sub_43A78F



图片58 再次执行sub_443E34


下面来看第二次执行sub_443E34时调用sub_443F6的情况:


图片59 第三次调用sub_443F6



图片60 复制数据长度



图片61 复制内容



图片62 第四次调用sub_443F6



图片63 复制数据长度



图片64 复制内容


直接执行到sub_443E34结束处:


图片65 sub_443E34结束处


其后执行流程:


图片66 其后执行流程


此处的jmp 2911D4值得说明一下,2911D4后20字节是在调用sub_4428F0时由qmemcpy((void *)(v5 + 50), a4, 20u);复制而来,其中源地址是0x18F3EC(可见图片54)。

计算接下来的跳转地址:


图片67 计算跳转地址


跳转到解密Shellcode部分:


图片68 跳转到解密Shellcode


解密Shellcode:


图片69 解密Shellcode


其后执行流程见下图(图中序号仅为表明顺序,并无他意):


图片70 定位msvcrt.dll


手动符号解析定位msvcrt.dll(由cmp语句比较的ASCII码可计算出)。


图片71 定位kerner32.dll


手动符号解析定位kerner32.dll(图中序号接上一张图片)

之后其调用的sub_299122如下:


图片72 sub_299122


通过遍历msvcrt.dll的输入表查找GetProcAddress,它并非调用kernel32.dllGetProcAddress(),而是ntdll.dllLdrGetProcedureAddress()


图片73 LdrGetProcedureAddress


再一次调用sub_299122,此次查找的是VirtualProtect()


图片74 VirtualProtect()



图片75 其后执行流程



图片76 保存到栈中局部变量


调用GetProcAddress()返回msvcrt.clearerr的地址:


图片77 GetProcAddress


调用VirtualProtect()修改msvcrt.clearerr页属性为0x40(PAGE_EXECUTE_READWRITE),大小是0x50:


图片78 VirtualProtect


msvcrt.clearerr进行Inline Hook,修改指令长度为0x50,这解释了之前的修改页属性操作:


图片79 Inline Hook


其实msvcrt.clearerr要实现的功能与sub_6492C6相同(详见图片77、78):


图片80 VirtualProtect


调用VirtualProtect()修改msvcrt.clearerr页属性为0x20(PAGE_EXECUTE_READ),大小是0x50。


图片81 GetProcAddress(GetTempPath)


将返回的调用地址加5后,通过遍历msvcrt.dll的输入表查找CreateFile


图片82 查找CreateFile



图片83 GetProcAddress(GetFileSize)


此次是查找VirtualAlloc


图片84 查找VirtualAlloc


接下来所查找函数不一一截图,依次是ReadFileWriteFileCloseHandleCreateProcessGetModuleFileNameResumeThreadTerminateProcess


图片85 GetProcess(GetThreadContext)


其后传递给GetProcess的参数不再一一截图,依次是ReadProcessMemoryVirtualQueryExVirtualProtectExGetModuleHandleVirtualAllocExWriteProcessMemorySetThreadContextZwUnmapViewOfSection

调用GetTempPath()


图片86 GetTempPath


之后将其于临时文件夹内释放的文件名拼接到路径后:


图片87 拼接路径


打开该文件:


图片88 CreateFile


其后行为不再一一截图,依次是GetFileSize(获取该大小)、VirtualAlloc(0,0x3E000,0x3000,0x40)(分配空间)、ReadFile(读取文件到分配的空间内)。

解密内存中的文件内容:


图片89 解密


遍历文件句柄,找到符合下列条件的文件:


图片90 遍历



图片91 遍历结果


调用VirtualAlloc分配空间并写入内容(并非解密后的文件内容):


图片92 分配空间



图片93 WriteFile



图片94 CloseHandle


复制解密后的文件内容:


图片95 复制文件内容


之后创建一同名进程:


图片96 创建进程



图片97 创建完成


其后的部分行为见下图:


图片98 GetThreadContext



图片99 ReadProcessMemory



图片100 VirtualQueryEx


将解密后的文件内容写入创建的进程:


图片101 写入到创建的进程


最终,结束原进程:


图片102 结束原来的进程


解密后的文件会在临时目录释放两个文件[白加黑]并运行白exe以执行下一步的恶意行为:


图片103 释放文件


0x05 参考链接

手把手教你复现office公式编辑器内的第三个漏洞——https://www.anquanke.com/post/id/94841


相关文章
|
Python
简易评分系统
如果用户名及口令不合法,用户名或口令最多可输入3次,验证错误超过3次以后,自动退出系统。
130 0
|
机器学习/深度学习 算法 数据挖掘
Sentieon | 应用教程: 使用DNAscope对HiFi长读长数据进行胚系变异检测分析
Sentieon | 应用教程: 使用DNAscope对HiFi长读长数据进行胚系变异检测分析
119 0
|
存储 安全 JavaScript
CVE-2017-12824及利用样本分析(二)
笔者于书写此文之前从未接触过InPage,该文权当笔者于学习过程中的文章学习笔记,其中如有不当或错误之处,望读者不吝赐教,笔者感激不尽。
|
存储 数据安全/隐私保护
CVE-2017-8291及利用样本分析(二)
CVE-2017-8291及利用样本分析
|
安全 Windows
CVE-2017-12824及利用样本分析(一)
笔者于书写此文之前从未接触过InPage,该文权当笔者于学习过程中的文章学习笔记,其中如有不当或错误之处,望读者不吝赐教,笔者感激不尽。
|
存储 安全 JavaScript
CVE-2017-11882及利用样本分析
Windows的公式编辑器EQNEDT32.EXE读入包含MathType的OLE数据,在拷贝公式字体名称时没有对名称长度进行校验,使得攻击者可以通过刻意构造的数据内容覆盖栈上的函数返回地址,从而劫持程序流程。
|
存储 NoSQL 安全
CVE-2017-8291及利用样本分析
CVE-2017-8291及利用样本分析
|
存储 安全 虚拟化
CVE-2017-0261及利用样本分析
CVE-2017-0261及利用样本分析
|
机器学习/深度学习 数据采集 运维
基于支持向量机的网络⼊侵检测系统的全面调查和分类
基于支持向量机的网络⼊侵检测系统的全面调查和分类
|
SQL 安全 JavaScript
常见漏洞分类
常见漏洞分类
339 0
常见漏洞分类