EnglishmansDentist漏洞利用分析
引言
我们继续分析ShadowBrokers在2017年4月发布的漏洞利用工具系列。继前两篇关于SMB漏洞利用EternalChampion和EternalSynergy的博客文章之后,这次我们将分析一个不同的工具,重点关注名为EnglishmansDentist的漏洞利用,该工具旨在针对Exchange Server 2003。
EnglishmansDentist通过底层(已停止支持)操作系统Windows Server 2003提供的共享库中的渲染漏洞,攻击Exchange 2003邮件服务器。该库在Exchange 2003的默认配置中使用。
较新的操作系统(Windows Server 2008及以上)和较新版本的Exchange Server(2007及以上)不受此漏洞利用的影响,因此使用这些较新平台的客户无需采取任何行动。
正如之前在MSRC博客上宣布的,在考虑了现成武器化代码的可用性并评估了威胁形势后,Microsoft决定在6月为已停止支持的平台(Windows XP和Server 2003)发布一个特别更新,以保护无法升级到新产品的客户。
本文将深入探讨漏洞的根本原因、对Microsoft产品的影响、利用方法以及现代缓解措施如何在较新的操作系统和产品中破坏此类漏洞利用。
概述
此漏洞的根本原因是共享库(OLECNV32.DLL)代码中的内存破坏错误,该库用于渲染以旧文件格式QuickDraw PICT编码的图像。此图形库默认存在于Windows XP和Windows Server 2003上。Exchange Server 2003使用此图形库来渲染以电子邮件附件形式传递的PICT内容。因此,虽然底层错误存在于操作系统中,但用于到达易受攻击代码的攻击向量是通过OLE调用调用的Exchange渲染例程,并由特制的电子邮件附件触发。
当Microsoft安全工程师分析共享组件(如图形库)中的漏洞时,会启动多个调查工作流,以回答两个非常重要的问题:
- 哪些仍在支持的产品可能使用或分发易受攻击的共享库?
- 易受攻击库的源代码是否在其他组件中被复制或重用?
对于第一个问题,我们确定易受攻击版本的OLECNV32.DLL库仅在已停止支持的平台(如Windows Server 2003和Windows XP)上分发并存在于磁盘上,其中第一个平台是Exchange Server 2003安装的默认平台,因此受到关注。在对受影响平台和Exchange Server的可能安装组合进行研究后,我们提出了以下矩阵,以帮助理解哪些产品组合最容易受到EnglishmansDentist的利用。
Exchange Server 2007产品不受此攻击影响,因为图形渲染引擎不再使用OLECNV32.DLL库来渲染PICT图像,即使该库可能存在于磁盘上(Windows Server 2003 + Exchange 2007的不常见情况)。较新版本的Exchange Server(如2010和2013)不受此错误的影响,因此不予考虑。
关于源代码调查,我们跟踪了PICT易受攻击功能如何集成并重用于某些不再支持的旧版Office中。在此调查过程中,我们很高兴地看到,虽然此错误最初由开发人员复制到Office的图形过滤器中,但同一错误后来被Microsoft安全审查和模糊测试发现,并在2006年内部修复,作为当时Microsoft发起的查找漏洞增加努力的一部分。这个例子代表了一个良好的错误碰撞故事,攻击者悄悄使用的武器化漏洞利用可能被供应商的内部渗透测试和模糊测试努力所消除。
EnglishmansDentist很可能最初是在2005年之前编写的,因为当针对Exchange Server 2003 SP2进行测试时,该漏洞利用似乎无法正常工作(以崩溃结束),并且仅针对32位操作系统目标,可能是因为十年前64位架构不够流行。
漏洞利用要求和传递机制
EnglishmansDentist要求攻击者至少在目标Exchange 2003邮件服务器上拥有一个有效的邮件帐户(用户名和密码)。实际上,漏洞利用将首先运行一系列验证和检查,以确保有效帐户可以成功登录并检查邮件。漏洞利用还需要一个次要的电子邮件帐户(欺骗或真实)作为源,该帐户将向有效帐户发送格式错误的PICT附件。
在将恶意PICT附件传递到目标邮件服务器后,该工具将使用有效帐户凭据登录,并强制Exchange Server使用可用协议之一(OWA、IMAP、POP3)解析和渲染恶意附件。由于渲染代码在服务器端执行,成功利用将导致在具有SYSTEM权限的Exchange Server进程上下文中执行任意代码。
利用后,EnglishmansDentist保持监听模式,等待shellcode连接回来。当这种情况发生时,该工具指示Exchange服务器删除传递漏洞利用的恶意电子邮件,从而移除攻击的法医证据。
漏洞:CVE-2017-8487
为了理解漏洞,读者必须熟悉PICT图形规范以及此文件格式定义的操作码。解析此旧文件格式的一些参考资料仍然在线可用,例如这里、这里和这里。另一个关于内部PICT操作码解析代码细节的良好参考也可用这里。
当针对Exchange Server 2003 SP2测试漏洞利用时,我们在测试环境中观察到以下崩溃;我们在此博客中仅包含与此漏洞分析相关的信息和模块,以红色标记攻击者控制的帧,以黄色标记有趣的函数名称。
应用程序异常发生: 应用程序:C:\Program Files\Exchsrvr\bin\store.exe (pid=2288) 时间:2017年4月15日 @ 00:27:11.078 异常编号:c0000005(访问冲突)
—-> 系统信息 <—- 计算机名:XXX 用户名:SYSTEM 终端会话ID:0 处理器数量:1 处理器类型:x86 Family 6 Model 62 Stepping 4 Windows版本:5.2 当前构建:3790 服务包:2
—-> 模块列表 <—- 0000000000400000 - 000000000091c000: C:\Program Files\Exchsrvr\bin\store.exe […] 000000006d580000 - 000000006d628000: C:\WINDOWS\system32\dbghelp.dll 0000000071db0000 - 0000000071dbc000: C:\WINDOWS\system32\OLECNV32.DLL
eax=4a85c948 ebx=00094850 ecx=00000000 edx=00000020 esi=000949c0 edi=4a85ca0c eip=6d8b1cfd esp=4a85c738 ebp=4a85ca50 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202 6d8b1cfd ?? ???
-> 针对DBGHELP.DLL + 0x00081cfd的ROP gadget
0:057> kp
ChildEBP RetAddr
警告:帧IP不在任何已知模块中。以下帧可能错误。 00 4a85c734 77c0f329 0x6d8b1cfd 01 4a85ca50 77c0f282 gdi32!iAnsiCallback+0x9d 02 4a85ca84 77c0f480 gdi32!EnumFontsInternalW+0x111 03 4a85cab4 77c265dc gdi32!EnumFontsInternalA+0x68 04 4a85cad4 71db2a0b gdi32!EnumFontsA+0x1a 05 4a85caf8 71db31c7 olecnv32!EnumFontFunc+0x3d1 06 4a85cb08 71db38d9 olecnv32!GdiOpenMetafile+0x335 07 4a85cb14 71db6290 olecnv32!GdiTextOut+0x22 08 4a85cc98 71db71c4 olecnv32!QDCopyBytes+0xd40 09 4a85ccb0 71db1375 olecnv32!QDConvertPicture+0xb4 0a 4a85ccc0 77760418 olecnv32!QD2GDI+0x3d 0b 4a85cd28 776fd79a ole32!QD2GDI+0xac 0c 4a85cd58 776cccf3 ole32!UtGetHMFFromMFStm+0x71 0d 4a85cd80 776ccb21 ole32!CMfObject::Load+0x4d 0e 4a85cdb4 776cc96a ole32!CCacheNode::Load+0xc5 0f 4a85ce60 007628f9 ole32!COleCache::Load+0x1b2 10 4a85ce80 00762e9b store!IMAGESTM::HrGetViewObject+0x87 11 4a85ce8c 0076304a store!IMAGESTM::HrAttachToImage+0x16 12 4a85ce98 0076320c store!IMAGESTM::HrEnsureImage+0x10 13 4a85cea8 6225dce2 store!IMAGESTM::Stat+0xf 14 4a85ced4 62258840 exmime!CStreamLockBytes::Stat+0x4a 15 4a85d0ac 6225d911 exmime!CBodyStream::HrInitialize+0x107 16 4a85d0f0 6225e4ca exmime!CMessageBody::GetDataHere+0xd4 […]
从调用堆栈跟踪中立即可见,漏洞存在于OLECNV32.DLL导出的例程QD2GDI()内部。此函数负责转换和渲染QuickDraw图像,并被Exchange Server 2003“store.exe”进程使用。当例如通过OWA自动解析附件以阅读新传入电子邮件时,会调用此例程;此解析器的攻击面可通过OLE32到达。QD2GDI()的内部代码在解析LongComment记录(通常由操作码0xA1标识)时存在内存破坏错误。攻击者可以通过创建格式错误的PICT文件来利用此错误,该文件包含一个LongComment记录,其中包含一个PP_FONTNAME子记录,其fontName字符串大于32字节,从而触发内存破坏,导致固定大小变量的越界覆盖。
EnglishmansDentist生成的格式错误的PICT图像将具有类似的布局。
图像总是以两个硬编码的标头开始。一个用于将PICT图像集成到TNEF OLE容器(Exchange使用的邮件附件格式)中,第二个代表适当的PICT标头。两个静态标头之后是一个虚拟标签TxFont记录和易受攻击的LongComment记录,该记录将触发内存破坏覆盖。
恶意PICT文件的准备在EnglishmansDentist中以偏移0x404621和0x404650的两个例程以编程方式完成。通过组装静态标头,后跟多个PICT记录,包括格式错误的0xA1操作码和其他用于传递ROP链和加密shellcode负载的记录。
QD2GDI()执行的标头和记录解码将立即命中格式错误的0xA1操作码并触发漏洞。
//由OLECNV32!QD2GDI()执行的内部解析 private void TranslateOpcode( opcodeEntry far * currOpcodeLPtr ) { Word function = currOpcodeLPtr->function; /* 根据功能代码执行适当的操作 / switch (function) { […] case LongComment: // 操作码0xA1 { […] / 确定应如何处理注释 */ switch (comment) { […] case picAppComment: // 注释0064 { […]
/* 确定如何处理指定的函数 */
switch (realFunc)
{
<b style="color:green">case PP_FONTNAME: // 函数0011</b>
{
Byte fontFamily;
Byte charSet;
<b style="color:green">Byte fontName[32]; // 固定大小的字符串缓冲区(32字节)</b>
/* 来自GDI2QD的字体名称 - 读取LOGFONT信息 */
GetByte( &fontFamily );
GetByte( &charSet );
<b style="color:red">// "fontName"参数由攻击者控制(格式错误的大小)
// GetString()不验证最大大小(32)并盲目使用它进行复制
// 导致越界覆盖</b>
<b style="color:red">GetString( fontName );</b>
length = 0;
// 调用Gdi模块以覆盖字体选择
GdiFontName( fontFamily, charSet, fontName );
如前所述,当此代码被移植并集成到某些旧版Office中时,Microsoft内部发现了此错误。因此,许多年前修改了函数GetString(),要求调用者传递缓冲区的长度并强制执行检查以避免越界覆盖数据,从而在每个可能的地方中和此漏洞。
利用:没有缓解措施的轻松工作
不幸的是,在像Windows Server 2003这样的环境中利用良好的越界覆盖错误是微不足道的,该环境缺乏基本的缓解措施,如ASLR和CFG。在Windows Server 2003上,由于缺乏ASLR,DEP很容易被攻击者绕过。没有ASLR的内存随机化,攻击者可以使用预先计算的ROP链调用VirtualAlloc,然后将shellcode传输到新分配的可执行缓冲区中运行而无需问题。
漏洞利用首先使用格式错误的0xA1记录触发内存破坏漏洞,并利用越界覆盖破坏托管其他对象的内部OLECNV32结构。具体来说,漏洞利用目标是全局fontTable[]数组中的字体条目,该条目稍后被复制到gdiEnv结构,并可用于覆盖函数指针并控制执行。
以下在利用过程中捕获的内存转储显示了fontTable[]数组的示例,其中一些条目被易受攻击的GetString()函数引起的内存覆盖破坏。可以在fontTable[]中识别出来自PICT文件的格式错误数据以及用作初始ROP gadget(0x6D8B1CFD)的偏移量,标记为红色。
在破坏fontTable[]之后,漏洞利用利用其他PICT操作码的解析来触发与最近格式错误的字体条目的进一步交互。这将导致OLECNV32再进行一次字符串复制操作,将格式错误的字体复制到OLECNV32!gdiEnv数据结构中,如以下代码片段所示(fontTable[newFont]已被破坏,现在由攻击者控制)。
if (GdiAttribHasChanged( GdiTxFont )) { Integer newFont;
/* 调用例程以查找匹配的GDI字体面名称 */
newFont = FindGdiFont();
/* 从字体查找表填充信息 */
gdiEnv.newLogFont.lfPitchAndFamily = fontTable[newFont].family | (Byte)DEFAULT_PITCH;
/* 复制正确的字体字符集 */
gdiEnv.newLogFont.lfCharSet = fontTable[newFont].charset;
<b style="color:green">/* 复制新的字体面名称 */</b>
lstrcpy( gdiEnv.newLogFont.lfFaceName, <b style="color:red">fontTable[newFont].gdiName</b> );
[…]
最终的字符串复制操作将导致覆盖一个函数指针,攻击者可以将其用作回调,以便在调用EnumFonts函数枚举字体时稍后控制。
0:000> dt olecnv32!gdiEnv
+0x000 metafile : 0xffffffffb8662029 Void
+0x004 newLogBrush : tagLOGBRUSH
+0x010 newLogFont : tagLOGFONTA
+0x04c newLogPen : tagLOGPEN
+0x05c clipRect : tagRECT
+0x06c drawingEnabled : 0n1
+0x070 sameObject : 0n0
+0x074 useGdiFont : 0n0
+0x078 hatchIndex : 0n-1
+0x07c lastPattern : [8] ""
+0x084 lastPatType : 0n0
+0x088 lastFgColor : 0
+0x08c lastBkColor : 0
+0x090 infoContext : 0x00000000
7c0133d1 HDC__
+0x094 fontFunction : 0x00000000`71db263a <— 被覆盖为0x6D8B1CFD
+0x098 state : [24] ""
利用:针对英语、德语、韩语和中文操作系统的ROP链
漏洞利用使用基于DBGHELP.DLL库构建的ROP gadget,该库通常加载到Exchange Server store.exe进程的内存空间中。漏洞利用的第一个版本可能反而是使用OLECNV32.DLL gadget开发的。即使缺乏ASLR随机化,获得此漏洞的可靠和通用利用也并非立即,因为DBGHELP.DLL是一个依赖于语言的库(存在多个版本用于不同的操作系统语言)。这引入了Windows Server 2003不同版本之间的某些差异。
攻击者通过预先计算他们感兴趣的目标每个操作系统版本的正确偏移量来解决此问题。实际上,EnglishmansDentist中包含的配置XML文件包含为英语Windows Server 2003开发的ROP gadget,但也为德语、韩语、简体中文和繁体中文开发,披露了攻击者感兴趣的所有潜在目标平台。
EnglishmansDentist中配置的ROP gadget的解码将映射到DBGHELP.DLL模块的这些代码块。
由函数指针覆盖(0x6d8b1cfd)执行的第一个gadget将进行一些堆栈对齐和重新平衡EBP(添加0x1A0),然后使用LEAVE/RET指令的组合将控制权转移到完整的ROP链。完整的ROP链(如在内存中看到)如下所示,右侧是等效的gadget