目录
漏洞简介
影响版本
Office基础
漏洞分析
获取POC
漏洞演示
漏洞定位
漏洞分析
解决方案
自制POC
.docx的POC
010Edit模板
2017年11月14日,微软发布了11月份的安全补丁更新,其中比较引人关注的莫过于悄然修复了长达17年的Office远程代码执行(CVE-2017-11882)陈年老洞。该漏洞属于缓冲区溢出类型漏洞,影响目前流行的所有Office版本,产生漏洞原因于EQNEDT32.EXE (微软office 自带公式编辑器)进程在读入包含 MathType 的 ole 数据时,在拷贝公式字体名称Font Name 数据)时没有对名称长度进行校验,导致缓冲区溢出,通过覆盖函数的返回地址,攻击者可以利用漏洞以当前登录的用户的身份执行任意命令。
该漏洞影响的版本:
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
在正式处理该漏洞前,我们必须对Office文档有着初步的了解。Office文档(如:.doc、.ppt、.xls等)很多是复合文档(OLE文件),所有文件数据都是存储在一个或多个流中。每个流都有一个相似的数据结构,用于存储元数据的数据结构。这些元数据有用户和系统的信息、文件属性、格式信息、文本内容、媒体内容。推荐阅读其他大佬的博客https://blog.csdn.net/qq_38474570/article/details/88389304
现在随便某度一搜,一大堆利用方式,github上找poc,方便快捷。下面例举几个:
https://github.com/embedi/CVE-2017-11882
https://github.com/unamer/CVE-2017-11882
https://github.com/Ridter/CVE-2017-11882
下载第一个仓库的poc,运行后如下所示,果然打开了计算器。
将poc文档拖进虚拟机,打开Process Monitor监视器,显示进程和线程的活动,然后执行poc文档,可以看到winword.exe创建了EQNEDT32.EXE,然后EQNEDT32.EXE启动了 cmd.exe,查看创建的调用栈,可以看到EQNEDT32.EXE使用 WinExec 创建的进程 cmd.exe,最后由cmd.exe打开了计算器。
这时已经知道了关键函数WinExec,那么进行多线程调试,进行准确定位。这里我采用注册表镜像劫持的方法。首先打开注册表,找到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options项。
然后找到EQNEDT32.EXE项,双击进入,然后新建值,字符串值,值名为Debugger,数据填你调试器路径,如下图:
此后,无论是在程序中通过 CreateProcess 或其他 API 创建的进程EQNEDT32.EXE ,还是用户手动双击执行程序EQNEDT32.EXE ,程序EQNEDT32.EXE 都不会得到直接的执行,而是会打开指定的调试器并附加进程EQNEDT32.EXE。再次运行POC,会自动打开调试器Ollydbg。
打开OD后,CTRL+G给WinExec下断点,然后运行一下,让程序断下来。
观察栈帧,找到最近的返回地址是0x4218e4,来自0x4115A7。
使用IDA打开QNEDT32.EXE,按快捷键g来到0x4115A7,万能F5一下,strlen 和 lstrcmpA 不可能造成缓冲区溢出,所以所以造成缓冲区溢出的点在函数sub_41160F中。
既然找到了函数,我们来观察一下,看到rep movsd这个重复拷贝的指令,这个指令的意思是将 ESI 处的内容拷贝到 EDI处,移动次数为 ECX 的大小,然而往上看,可以发现没有cmp之类的检验指令,怀疑这里是溢出点。strcpy把从src地址开始且含有 /0 结束符的字符串一起复制。
既然怀疑0x411658为溢出点,那么我们调试来看看,打开POC,自动打开OD,执行到0x411658,观察栈,发现基本没啥变化?难道是找错了,搞了半天,我才想起,sub_41160F这个函数可能不止执行一次,那么,我们第二次执行到0x411658,果然看到它进行了栈溢出,更改了返回地址。数据窗口跟随 ESI,可以看到熟悉的命令行。拷贝给EDI处的栈地址0x12F1A4,拷贝ECX=30h的大小。
拷贝之前的样子
拷贝过后的样子,可以看到栈地址0x12F1D0处的返回地址被改为了0x430C12
然后我们来看看0x430C12是什么东西,sub_41160F这个函数执行完之后就到了这,跳过去看看,这里居然是WinExec函数。
可以看到栈顶的返回地址已经修改为call WinExec指令的地址
ESP+4 为参数lpCmdLine cmd.exe /c calc.exe AAAAAAAAAAAAAAAAAAAAAAAA.C.
ESP+8 为参数uCmdShow SW_HIDE
查看公式编辑器(EQNEDT32.EXE)可以看到并没有开启 ASLR 和 DEP ,因此可以将固定的 call WinExec 指令的地址 (0x 430c12) 来覆盖函数的返回地址,达到命令执行的目的,并且通过命令来执行后续的恶意操作。(使用pestudio来查看)
函数的栈帧就不介绍了,一图解决。(后面补上)
再来看sub_41160F这个函数,先抬高栈帧来开辟新栈帧的空间。
可以看到,拷贝时预留的buff是24h,然后拷贝超过buff大小的数据向下淹没,将返回地址部分覆盖为0x430c12 (call WinExec指令的地址),来达到命令执行。所以我们得准备24h(buff大小)+4h(局部变量)+4h(EBP)+4h(返回地址)=30h的数据。
所以最后构造的二进制数据最终应该如下:
被选中的那部分是可控的,可以作为 WinExec 的命令来使用,利用方式多种多样。
1、微软已经对此漏洞做出了修复。
(1)下载https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2017-11882 更新补丁进行修补
(2)开启Windows Update功能,定期对系统进行自动更新
2、由于该公式编辑器已经17年未做更新,可能存在大量安全漏洞,建议在注册表中取消该模块的注册。
按下Win+R组合键,打开cmd.exe
输入以下两条命令:
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\Microsoft\Office\Common\COM Compatibility\{0002CE02-0000-0000-C000-000000000046} ” /v “Compatibility Flags” /t REG_DWORD /d 0x400
许多用户在新建word文档时会发现有两个选项,新建Microsoft Word 97 - 2003 文档和新建新建 Microsoft Word文档。当用户点击新建Microsoft Word 97 - 2003 文档时,就会创建出一个.doc文件;而用户点击新建Microsoft Word 文档时,就会创建出一个.docx文件,实际上Microsoft Word 2007及之后的Word版本还支持.docm文件,那么这三种文件有什么区别呢?.doc文件是一种普通的OLE文件(复合文件),能够包含宏。而.docx和.docm文件,实际上都是是压缩文件,
新建一个1.docx,然后选插入,选择对象,选择公式3.0,使用 4*4 的矩阵(占用的空间大有足够的空间存放 payload ,大于 0xc5 )。
同时插入一个 package 对象,文件选择 PE 文件,我选择了一个计算器,然后保存该文件(这一步用来选做,利用rtf文档在temp目录下释放文件的特性进行利用)。
使用7z打开1.docx文档,找到我们插入的两个对象,将其拖出来,然后用微软提供的工具 OffVis打开。
使用OffVis打开进行解析后,找到DirctoryEntries[8],下面的选项可以看到一个\Root Entry\Equation Native,这个就是公司编辑器,找到其对应的Data,可以看到其偏移是从900h开始的,然后使用010Edit打开oleObject1.bin。
找到900h偏移处,新建页面将其拷贝下来。
拷贝下来后
使用010模板将其打开,可以看到我们能改写的那30h字节的东西,最后的RetAddr是函数的返回地址,我们需要改写到这。
对象1我将其改为打开记事本,改写完成后如下图
然后我们再复制回去,替换原来的,然后保存,回到7z,将其进行替换。
然后打开构造好的1.docx,你会发现,没有触发漏洞,研究了一下,发现还需要构造一下头。构造成这样:
头改好以后,打开我们制作的1.docx,双击公式处,漏洞触发。
也可以另存为.rtf文档,打开直接触发,不需要双击(改成rtf文档后,再将其后缀改为.doc,也能达到相同效果)。
typedef struct
{
WORD cbHdr ;
DWORD version ;
WORD cf ;
DWORD cbObject ;
DWORD reserved1 ;
DWORD reserved2 ;
DWORD reserved3 ;
DWORD reserved4 ;
} EQNOLEFILEHDR;
typedef struct
{
BYTE MTEF_version ;
BYTE generating_plntform ;
BYTE generating_product ;
BYTE product_version ;
BYTE product_sub_version ;
} MTEF_header;
typedef struct
{
BYTE lsize ;
BYTE dsize ;
} SizeRecord;
typedef struct
{
BYTE bTag ;
BYTE bTypeeFace ;
BYTE bStyle ;
BYTE bFontName[24h];
} FontRecord;
LittleEndian();
Printf("Equation Native.bt Begin\n");
EQNOLEFILEHDR DosHeader ;
MTEF_header Mtef_header ;
SizeRecord srecord;
FontRecord frecoed ;
//overwrite
DWORD localval ;
DWORD EBP ;
DWORD RetAddr ;