来源:http://blog.vulnhunt.com/index.php/2011/12/12/cve-2011-2462-pdf-0day-analysis/
Author: instruder of Code Audit Labs of vulnhunt.com
测试pdf 版本:9.4.0
测试系统:win7
0 Affected Prodects
软件版本:<=adobe reader 9.4.6
CVE ID :2011-2462
1 crash info
eax=52520026 ebx=1e282ea8 ecx=00000024 edx=00000000 esi=00000000 edi=00000000
eip=1a73f2e3 esp=0012f4fc ebp=0012f548 iopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010286
rt3d!QUAT::QUAT+0×5cf:
1a73f2e3 80b8fc09000000 cmp byte ptr +0×9fb (000009fc)[eax],0 ds:0023:52520A22=??
2 Analysis
这是个pdf 0day漏洞没有任何漏洞描述的相关细节,只知道是u3d格式文件出了问题。用已有的010脚本查看u3d格式也没有发现什么异常。 只能一步步跟踪分析。
从上面的crash info中,必须要找出是什么原因导致eax变成了非法的值,从而触发崩溃
出问题的地方是在u3d格式的node节点出,当显示pdf时,e3_NODE__ChildsDraw函数进行绘制视图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
C in rt3d.dll int __stdcall e3_NODE__ChildsDraw(struc_1 *a1, int a2, int a3, int a4) { struc_1 *node; // esi@1 int result; // eax@2 for ( node = (struc_1 *)a1->first_node; node; node = (struc_1 *)node->next_node ) { result = (*(int (__stdcall **)(_DWORD, _DWORD, _DWORD, _DWORD))(node->cobject + 0xC4))(node, a2, a3, a4);// rt3d!e3_NODE::Draw if ( result < 0 ) return result; } return 1; } |
e3_NODE::Draw函数中会调用sub_ 101819E7(命名为Take_Fill_Node)函数,该函数会申请sizeof(struct1)* node_count大小的内存,sizeof(struct1)=0xa0 ,然后循环(这里总共5个节点,从0-4)将将node+0×68处的一个对象指针赋给申请的内存结构中。此时这个对象指针+0×54偏移处已经是被修改的非法值52520026,因此需要知道这个对象是从哪来的。
node+0×68的对象指针从哪来的呢,这里就要看node节点的分配情况。从rt3d.dll中看到有关于e3_NoDE:类,其中有e3_NODE__AddChild和e3_NODE__Create等节点操作函数,很自然的在节点的分配出下断点。
1
2
3
4
5
|
bu !rt3d+165CCA ".if(1){.echo addchild;gc}" bu !rt3d+181A56 ".if(1){.echo malloc base;db eax;}" bu !rt3d+168050 ".if(1){.echo create new child node;r eax;gc}" bu rt3d!e3_NODE::ChildsDraw+0x19 ".if(1){.echo ChildsDraw childnode ;r esi;dd esi+0x48} l4" bu !rt3d+166EB0 ".if(1){.echo call Take_Fill_Node;dd esp l4;dd poi(esp+4)+0x48}" |
node节点的分配情况
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
create new child node eax=03217ac8 --allocate root node addchild ModLoad: 668a0000 66a63000 C:\Windows\system32\d3d9.dll ModLoad: 70be0000 70be6000 C:\Windows\system32\d3d8thk.dll ModLoad: 6b400000 6b421000 C:\Windows\system32\vm3dum.dll ModLoad: 67ed0000 67fd5000 C:\Windows\system32\d3d8.dll *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Adobe Reader 9.4.0\Reader 9.0\Reader\plug_ins3d\3difr.x3d - create new child node eax=0321c918 --allocate node1 ---second break addchild create new child node eax=0321d3b8 --allocate node2 addchild create new child node eax=0321d488 --allocate node3 addchild create new child node eax=0321d558 --allocate node4 addchild create new child node eax=0321d628 --allocate node5 addchild ModLoad: 69fa0000 6a00c000 C:\Program Files\Adobe Reader 9.4.0\Reader 9.0\Reader\AdobeXMP.dll ModLoad: 6f8d0000 70350000 C:\Windows\system32\ieframe.dll ModLoad: 718a0000 718dc000 C:\Windows\system32\OLEACC.dll ADOBE_READLOGGER_CMD:PAUSE_LOG ModLoad: 6b3d0000 6b3f1000 C:\Windows\system32\vm3dum.dll ChildsDraw childnode esi=03217ac8 ---root node 03217b10 0321c918 00000000 00000000 00000000 ChildsDraw childnode esi=0321c918 ---node 1 0321c960 00000000 03217ac8 0321d3b8 0321d3b8 ChildsDraw childnode esi=0321d3b8 ---node 2 0321d400 00000000 00000000 0321d488 0321d488 ChildsDraw childnode esi=0321d488 ---node 3 0321d4d0 00000000 00000000 0321d558 0321d558 ChildsDraw childnode esi=0321d558 ---node 4 0321d5a0 00000000 00000000 0321d628 0321d628 ChildsDraw childnode esi=0321d628 ---node 5 0321d670 00000000 00000000 00000000 00000000 call Take_Fill_Node 0016e860 0321d628 03213ba0 0016e87c 00000000 ---node5 *(node5+0x68) offset48 03213be8 00000000 0321ba70 00000000 00000000 03213bf8 00000000 41700000 00000000 00000000 03213c08 3f800000 3f800000 00000000 00000000 03213c18 00000011 00000000 18bd34db 88000000 03213c28 0321c788 00000000 00000000 00000000 03213c38 00000000 00000000 00000000 00000000 03213c48 00000000 00000000 00000000 00000000 03213c58 00000000 00000000 00000000 00000000 call Take_Fill_Node 0016e9b4 0321d558 03213870 0016e9d0 00000000 ---node4 *(node4+0x68) offset48 032138b8 00000000 0321b9e0 00000000 00000000 032138c8 00000000 41200000 00000000 00000000 032138d8 3f800000 3f800000 00000000 00000000 032138e8 00000011 00000000 18bd3441 88000000 032138f8 0321c788 00000000 00000000 00000000 03213908 00000000 00000000 00000000 00000000 03213918 00000000 00000000 00000000 00000000 03213928 00000000 00000000 00000000 00000000 call Take_Fill_Node 0016eb08 0321d488 032135c8 03213298 00000000 ---node3 *(node3+0x68) offset48 03213610 00000000 0321b950 00000000 00000000 03213620 00000000 00000000 00000000 00000000 03213630 3f800000 3f800000 00000000 00000000 03213640 00000011 00000000 18bd3596 88000000 03213650 0321c788 00000000 00000000 00000000 03213660 00000000 00000000 00000000 00000000 03213670 00000000 00000000 00000000 00000000 03213680 00000000 00000000 00000000 00000000 call Take_Fill_Node 0016ec5c 0321d3b8 03213320 03213298 00000000 ---node2 *(node2+0x68) offset48 03213368 00000000 0321b8c0 00000000 00000000 03213378 00000000 00000000 00000000 00000000 03213388 3f800000 3f800000 00000000 00000000 03213398 00000011 00000000 18bd352b 88000000 032133a8 0321c788 00000000 00000000 00000000 032133b8 00000000 00000000 00000000 00000000 032133c8 00000000 00000000 00000000 00000000 032133d8 00000000 00000000 00000000 00000000 call Take_Fill_Node 0016edb0 0321c918 03213fe0 032140f0 00000000 ---node1 *(node1+0x68) offset48 03214028 0321d1e8 0321c788 00000000 00000014 03214038 00000000 00000000 00000000 00000000 03214048 03208ff8 00000014 0320c008 03214178 03214058 0321bdd0 00000000 18bd3b53 88000000 03214068 0321c918 00000000 00000000 00000000 03214078 00000000 00000000 00000000 00000000 03214088 00000000 00000000 00000000 00000000 03214098 00000000 00000000 00000000 00000000 eax=00000000 ebx=00000000 ecx=03216d58 edx=0016ecc0 esi=03216d58 edi=00000004 eip=68881a6b esp=0016eda0 ebp=0016eee4 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216 rt3d!e3_LAYER::DeleteThis+0x351: 68881a6b 69ffa0000000 imul edi,edi,0A0h 0:000> dd 0321d1e8+54 0321d23c 52520026 13b80100 00140307 00000000 ---52520026 非法的值 0321d24c 00000000 00000000 1e080000 00300322 0321d25c 00000000 00000000 00000000 00000000 0321d26c 00000000 00000000 00000000 00000000 0321d27c 63380000 00000306 64680000 00000306 0321d28c b3bc0000 00240206 00000000 00030000 0321d29c 00000000 00000000 00000000 00000000 0321d2ac 00000000 00000000 fa3a0000 4d24c105 |
初步从上面的打印日志来看,是第一个node节点出了问题unkown_class=*(node1+0×68) ; *(*(unkown_class+0×48)+0×54)=0×52520026
Node+0×68是什么时候初始化的呢,恢复虚拟机快照,重新来过,在第一个node子节点分配成功后断下来 然后下 ba w 1 (node+0×68)的访问断点。
(这里分享个调试的技巧 可以用虚拟机来保存开始调试时候的状态,这里以后重新调试的时候直接恢复虚拟机快照,堆分配的地址都是一样的,可以直接下访问断点。)
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
|
char __userpurge e3_NODE__SetObject(int a1, int node, int a3) { int v3; // eax@1 int v4; // ebx@2 int v6; // [sp-4h] [bp-Ch]@2 v3 = *(_DWORD *)(node + 0x68); if ( a3 != v3 ) { v6 = a1; v4 = *(_DWORD *)(node + 0x68); if ( v3 ) (*(void (__stdcall **)(int, int))(*(_DWORD *)v3 + 48))(v3, node); *(_DWORD *)(node + 0x68) = a3; a3=unkown_class 这里进行的初始化 if ( a3 ) { (*(void (__stdcall **)(int, int))(*(_DWORD *)a3 + 44))(a3, node); (*(void (__stdcall **)(_DWORD))(**(_DWORD **)(node + 104) + 4))(*(_DWORD *)(node + 104)); } (*(void (__stdcall **)(int, signed int, int, int))(*(_DWORD *)node + 52))(node, 1006, v4, v6); if ( v4 ) (*(void (__stdcall **)(int))(*(_DWORD *)v4 + 8))(v4); (*(void (__cdecl **)(int))(*(_DWORD *)node + 224))(node); sub_1013C568(*(_DWORD *)(node + 32)); } return 1; } |
将a3赋给node+0×68偏移处,此时*(a3+48)+54已经是非法值了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
eax=00000000 ebx=00000000 ecx=03372b58 edx=688d078c esi=03166560 edi=03373360 eip=68855496 esp=002dd5b0 ebp=03373360 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 rt3d!e3_NODE::SetObject+0x24: 68855496 7410 je rt3d!e3_NODE::SetObject+0x36 (688554a8) [br=0] 0:000> dd 03373360+54 033733b4 52520034 57b80100 00140337 00000000 ------此时已经是52520034 了 033733c4 00000000 00000000 86580000 00300337 033733d4 00000000 00000000 00000000 00000000 033733e4 00000000 00000000 00000000 00000000 033733f4 98580000 00000337 98f00000 00000337 03373404 bef40000 00240329 00000000 00030000 03373414 00000000 00000000 00000000 00000000 03373424 00000000 00000000 00000000 00000000 |
继续往上追
asm in 3difr.x3d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
text:10002DBD mov edi, [esp+8+arg_0] .text:10002DC1 mov esi, [esp+8+arg_4] .text:10002DC5 mov edx, [edi] .text:10002DC7 mov eax, [edx+0C8h] .text:10002DCD push esi ; esi 为某个对象首地址 .text:10002DCE push edi .text:10002DCF call eax //e3_NODE__SetObject 3difr!E3DLLFunc+0xb3f xt:1000415B push edx .text:1000415C push eax ////--- .text:1000415D push ebp .text:1000415E push esi .text:1000415F call sub_10002D00 .text:10004164 add esp, 10h |
bu 3difr!E3DLLFunc+0xb3f
bu !3difr+415F
bu !3difr+401F
bu !3difr+2b91 “.if(1){db poi(poi(esp))}”
流程太复杂 前面追踪的都不太记得了。。。
//猜测那个03373360 也是一个OBJ对象,因此直接在这里下断点 这里是obj分配内存然后初始化的地方。()
bu !rt3d+158DF8
这里为什么会猜测这个03373360是以OBJ对象呢,看下面
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
|
Rt3d!dll .text:101594DD sub_101594DD proc near ; DATA XREF: .rdata:101DFA20o .text:101594DD .text:101594DD arg_0 = dword ptr 4 .text:101594DD arg_4 = dword ptr 8 .text:101594DD .text:101594DD push esi .text:101594DE push edi .text:101594DF push 158h ; unsigned int .text:101594E4 call ??2@YAPAXI@Z ; operator new(uint) 分配一个OBJ对象 eax=033784a8 ebx=033751c8 ecx=00000158 edx=03378608 esi=033751c8 edi=00000000 eip=688494e9 esp=002ddd40 ebp=002de0c8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 rt3d!QUAT::QUAT+0xcb8d: 688494e9 85c0 test eax,eax 0:000> dd 033784a8+54 033784fc bf7fffff 00000000 00000000 00000000 刚申请时的内存里面填充了随机的数据 0337850c bf7fffff 00000000 3f7fffff 00000000 0337851c 00000000 13000013 0029590f 0337f570 0337852c 01fff998 00000001 00000003 00000000 0337853c 00000001 00000001 00000002 00000006 0337854c 00000004 00000001 00000000 00000002 0337855c 00000008 00000000 00000000 00000001 0337856c 00000002 00000009 00000001 00000001 .text:101594E9 test eax, eax .text:101594EB mov edi, [esp+0Ch+arg_0] .text:101594EF pop ecx .text:101594F0 jz short loc_10159500 .text:101594F2 push dword ptr [edi+20h] .text:101594F5 mov ecx, eax .text:101594F7 call sub_10158DF8 .text:101594FC mov esi, eax .text:101594FE jmp short loc_10159502 .text:10159500 ; --------------------------------------------------------------------------- .text:10159500 .text:10159500 loc_10159500: ; CODE XREF: sub_101594DD+13j .text:10159500 xor esi, esi .text:10159502 .text:10159502 loc_10159502: ; CODE XREF: sub_101594DD+21j .text:10159502 push 0 .text:10159504 push [esp+0Ch+arg_4] .text:10159508 mov ecx, edi .text:1015950A push esi .text:1015950B call sub_10155AA3 从参数一对象中直接拷贝了0x54偏移的成员给予这个OBJ 因此此时需要追踪这个参数一对象什么时候初始化的+54偏移成员变量,而这个参数一 就是 03373360 ,因此猜测也是一个OBJ对象 .text:10159510 test eax, eax .text:10159512 jge short loc_10159528 .text:10159514 test esi, esi .text:10159516 jz short loc_10159526 .text:10159518 mov ecx, esi .text:1015951A call sub_10155E10 .text:1015951F push esi ; void * .text:10159520 call ??3@YAXPAX@Z ; operator delete(void *) .text:10159525 pop ecx .text:10159526 .text:10159526 loc_10159526: ; CODE XREF: sub_101594DD+39j .text:10159526 xor esi, esi .text:10159528 .text:10159528 loc_10159528: ; CODE XREF: sub_101594DD+35j .text:10159528 pop edi .text:10159529 mov eax, esi .text:1015952B pop esi .text:1015952C retn 8 .text:1015952C sub_101594DD endp |
Rt3d!dll //这里进行OBJ对象的初始化 OBJ对象大小0×158
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
int __thiscall sub_10158DF8(void *OBJ, int a2) { int Temp_OBJ; // esi@1 Temp_OBJ = (int)OBJ; e3_OBJECT__e3_OBJECT(OBJ); *(_DWORD *)Temp_OBJ = &off_101DF9BC; e3_GENERIC__Init(Temp_OBJ, 0x158u); if ( a2 ) sub_1014D0F6(Temp_OBJ, a2); *(_DWORD *)(Temp_OBJ + 0x50) = 7; *(_BYTE *)(Temp_OBJ + 0x58) = 0; *(_BYTE *)(Temp_OBJ + 0x59) = 1; return Temp_OBJ; } |
在分配OBJ对象之后 ,此时在这下访问断点ba w 1 03373360+0×54
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
|
addchild Breakpoint 9 hit eax=52520034 ebx=00717498 ecx=00747a70 edx=007479f0 esi=00000024 edi=03373360 eip=69d9b785 esp=002dd4f8 ebp=01ff0708 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 3difr!E3DLLFunc+0x94f5: 69d9b785 e86e460200 call 3difr!e3_SORTEDCOLLECTION::Create+0xc4 (69dbfdf8)//上一条指令修改了03373360+0x54 0:000> dd 03373360+54 033733b4 52520034 56000100 00140337 00000000 033733c4 00000000 00000000 69b00000 00300337 033733d4 00000000 00000000 00000000 00000000 033733e4 00000000 00000000 00000000 00000000 033733f4 a7a00000 00000337 a8380000 00000337 03373404 bef40000 00240329 00000000 00030000 03373414 00000000 00000000 00000000 00000000 03373424 00000000 00000000 00000000 00000000 .text:1000B759 mov ecx, [esp+78h+var_5C] .text:1000B75D push edi .text:1000B75E call sub_10008780 .text:1000B763 mov ebx, eax .text:1000B765 mov eax, [esp+78h+var_60] .text:1000B769 cmp dword ptr [eax+18h], 1 .text:1000B76D jnz short loc_1000B7B7 .text:1000B76F test ebx, ebx .text:1000B771 jz short loc_1000B799 .text:1000B773 cmp dword ptr [ebx], 1 .text:1000B776 jnz short loc_1000B799 .text:1000B778 mov ecx, [ebx+4] .text:1000B77B mov edx, [esp+78h+var_58] .text:1000B77F mov eax, [ecx] .text:1000B781 push edx ; void * .text:1000B782 mov [edi+54h], eax .text:1000B785 call ??_V@YAXPAX@Z ; operator delete[](void *)0:000> db ecx 00747a70 34 00 52 52 52 00 80 3f-b7 48 9c 4a 64 4d 00 88 4.RRR..?.H.JdM.. 00747a80 42 6f 78 30 31 52 58 00-a9 48 9c 4a 00 00 00 88 Box01RX..H.J.... 00747a90 42 6f 78 30 31 52 58 00-ab 48 9c 4a 00 00 00 8c Box01RX..H.J.... 00747aa0 90 64 16 03 00 00 00 00-ad 48 9c 4a 00 00 00 8c .d.......H.J.... 00747ab0 e0 c6 36 03 58 e8 29 03-af 48 9c 4a 00 00 00 8c ..6.X.)..H.J.... 00747ac0 00 00 00 00 ec 41 0e 02-a1 48 9c 4a 00 00 00 88 .....A...H.J.... 00747ad0 c0 63 16 03 f0 63 16 03-a3 48 9c 4a 64 4d 00 88 .c...c...H.JdM.. 00747ae0 70 00 72 00 63 00 00 00-a5 48 9c 4a 00 00 00 88 p.r.c....H.J.... |
这里突然想到了一个跟踪数据流的好办法 对于地址不固定的堆来说(哈哈)利用前面的虚拟机快照 直接对 00747a70 下访问断点ba w 1 00747a70 ba w 1 033684c8
第二次断下后
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
Asm in 3difr .text:100045CE push edx ; Src .text:100045CF push eax ; Dst .text:100045D0 mov [esp+34h+var_4], 0FFFFFFFFh .text:100045D8 call memcpy edx指向 // 0337343a 52 52 52 52 52 01 00 00-00 a6 04 a8 96 b9 3f c5 RRRRR.........?. // 0337344a 43 b2 df 2a 31 b5 56 93-40 00 01 00 00 00 00 00 C..*1.V.@....... // 0337345a 00 05 00 52 52 52 52 52-01 00 00 00 01 00 2e 01 ...RRRRR........ // 0337346a 00 76 00 00 00 00 45 ff-ff ff 23 00 00 00 00 00 .v....E...#..... // 0337347a 00 00 09 00 43 43 43 43-42 6f 78 30 31 02 00 00 ....CCCCBox01... // 0337348a 00 00 00 00 00 01 00 00-00 00 00 00 00 06 00 42 ...............B // 0337349a 6f 02 00 00 00 00 16 ff-ff ff 30 00 00 00 00 00 o.........0..... // 033734aa 00 00 01 00 52 01 00 00-00 a6 04 a8 96 b9 3f c5 ....R.........?. 拷贝长度是0x5 |
在继续
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
|
0:000 g Breakpoint 9 hit 0:000> r eax=00550034 ebx=0000001a ecx=00000056 edx=00000055 esi=00776940 edi=00747a68 eip=77262d75 esp=002dd41c ebp=002dd450 iopl=0 ov up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000a02 ntdll!RtlpLowFragHeapFree+0xa6: 77262d75 2b7df4 sub edi,dword ptr [ebp-0Ch] ss:0023:002dd444=007478a8 0:000> kb ChildEBP RetAddr Args to Child 002dd450 77262ce8 00747a70 00717570 00000000 ntdll!RtlpLowFragHeapFree+0xa6 //00747a70指向的内存被释放 002dd468 757cc3d4 007e0000 00000000 00747a70 ntdll!RtlFreeHeap+0x105 002dd47c 71664c39 007e0000 00000000 00747a70 kernel32!HeapFree+0x14 002dd4c8 69da181d 00747a70 00000000 002dde98 MSVCR80!free+0xcd WARNING: Stack unwind information not available. Following frames may be wrong. 002dd518 69d9372b 00000000 002dde98 00000002 3difr!E3DLLFunc+0xf58d 002dd530 69da039a 002dde90 176fc977 002dde90 3difr!E3DLLFunc+0x149b 002dd550 77262fe7 77262e82 00000020 176fc953 3difr!E3DLLFunc+0xe10a 002dd5d4 687219e8 03373360 0000017c 69d92f36 ntdll!RtlpLowFragHeapAllocFromContext+0xaec 00000000 00000000 00000000 00000000 00000000 rt3d!V4CUnloadRT+0x2b278 此时 0:000> dd 00747a70 00747a70 52520034 3f800052 4a9c48b7 88004d64 00747a80 30786f42 00585231 4a9c48a9 88000000 00747a90 30786f42 00585231 4a9c48ab 8c000000 00747aa0 03166490 00000000 4a9c48ad 8c000000 00747ab0 0336c6e0 0329e858 4a9c48af 8c000000 00747ac0 00000000 020e41ec 4a9c48a1 88000000 00747ad0 031663c0 031663f0 4a9c48a3 88004d64 00747ae0 00720070 00000063 4a9c48a5 88000000 |
内存释放掉之后 下面又重新申请了这个地方的内存00747a70
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
|
10009DEB or ecx, eax .text:10009DED push ecx ; unsigned int .text:10009DEE call j_??2@YAPAXI@Z ; operator new(uint) .text:10009DF3 add esp, 4 .text:10009DF6 test esi, esi .text:10009DF8 mov [ebp+4], eax //eax = 00747a70 .text:10009DFB jbe loc_10009E89 .text:10009E01 .text:10009E01 loc_10009E01: ; CODE XREF: sub_10009D00+183j .text:10009E01 push 1 .text:10009E03 push 4 .text:10009E05 mov ecx, edi .text:10009E07 call sub_10002A00 .text:10009E0C test eax, eax .text:10009E0E jz short loc_10009E7E .text:10009E10 mov eax, [eax] .text:10009E12 test eax, eax .text:10009E14 jbe short loc_10009E7E .text:10009E16 mov [esp+28h+var_10], eax .text:10009E1A lea ebx, [ebx+0] .text:10009E20 .text:10009E20 loc_10009E20: ; CODE XREF: sub_10009D00+178j .text:10009E20 mov ecx, edi .text:10009E22 call sub_10004520 .text:10009E27 mov esi, eax .text:10009E29 mov eax, [esi] .text:10009E2B test eax, eax .text:10009E2D jz short loc_10009E34 .text:10009E2F cmp byte ptr [eax], 0 .text:10009E32 jnz short loc_10009E38 .text:10009E34 .text:10009E34 loc_10009E34: ; CODE XREF: sub_10009D00+12Dj .text:10009E34 xor eax, eax .text:10009E36 jmp short loc_10009E45 .text:10009E38 ; --------------------------------------------------------------------------- .text:10009E38 .text:10009E38 loc_10009E38: ; CODE XREF: sub_10009D00+132j .text:10009E38 mov eax, [esi+4] .text:10009E3B push 0 ; float .text:10009E3D push eax ; wchar_t * .text:10009E3E mov ecx, edi .text:10009E40 call sub_100084B0 .text:10009E45 .text:10009E45 loc_10009E45: ; CODE XREF: sub_10009D00+136j .text:10009E45 mov ecx, [ebp+4] .text:10009E48 mov [ecx+ebx*4], eax .text:10009E4B mov eax, [esi] .text:10009E4D test eax, eax .text:10009E4F jz short loc_10009E5A .text:10009E51 push eax ; void * .text:10009E52 call ??_V@YAXPAX@Z ; operator delete[](void *) .text:10009E57 add esp, 4 .text:10009E5A .text:10009E5A loc_10009E5A: ; CODE XREF: sub_10009D00+14Fj .text:10009E5A mov eax, [esi+4] .text:10009E5D test eax, eax |
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
|
c in 3difi v10 = sub_10002A00(4, 1); if ( v10 ) { v11 = *(_DWORD *)v10; v10=03373493 if ( v11 ) //这里v11=0 直接跳过了初始化 导致后面使用了已经释放掉的内存 { v18 = v11; do { v14 = sub_10004520(v2); v13 = v14; v12 = *(_DWORD *)v14; if ( v12 && *(_BYTE *)v12 ) v15 = sub_100084B0(*(wchar_t **)(v13 + 4), 0.0); else v15 = 0; *(_DWORD *)(*(_DWORD *)(v5 + 4) + 4 * v1) = v15;// 这里初始化刚刚分配的内存 if ( *(_DWORD *)v13 ) operator delete__(*(void **)v13); if ( *(_DWORD *)(v13 + 4) ) operator delete__(*(void **)(v13 + 4)); operator delete((void *)v13); } while ( v18-- != 1 ); v7 = v17; } } ++v1; } while ( v1 < v7 ); |
Summary
从上面的分析可以知道,漏洞成因是对新分配的内存没有正确的初始化,导致重用了之前分配的内存空间,而刚好之前分配的内存空间的数据来自文件offset =0×10a 。而未初始化的变量刚好是某个对象的首地址,从而有机会导致任意代码执行。
The Final Reason
这里分析为什么上面的初始化被绕过
对10002A00函数下断点
Bu !3difr+2a00
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
|
eax=00747a70 ebx=00000000 ecx=002dde98 edx=00680048 esi=00000001 edi=002dde98 eip=69d92a00 esp=002dd4e8 ebp=00717498 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 3difr!E3DLLFunc+0x770: 69d92a00 56 push esi 0:000> dd ecx+40 002dded8 00000133 00000000 ffffff14 0000017c //133是偏移 002ddee8 0000011c 00000000 00000001 031ea1b8 002ddef8 03299108 03298c28 03372378 033723a8 002ddf08 033723d8 03372408 03372438 0329be18 002ddf18 0329be58 00000000 00000000 031ea398 002ddf28 00000000 002de6e0 69dc0deb 00000000 002ddf38 6887e073 00000001 002de678 0336b970 002ddf48 03363920 00000001 002de678 0336b970 0:000> dd ecx+34 002ddecc 03373360 ffffff45 00000024 00000133 //03373360 指向文件中offset=30h 002ddedc 00000000 ffffff14 0000017c 0000011c 002ddeec 00000000 00000001 031ea1b8 03299108 002ddefc 03298c28 03372378 033723a8 033723d8 002ddf0c 03372408 03372438 0329be18 0329be58 002ddf1c 00000000 00000000 031ea398 00000000 002ddf2c 002de6e0 69dc0deb 00000000 6887e073 002ddf3c 00000001 002de678 0336b970 033639200:000> 0:000> db 03373360 03373360 09 00 43 43 43 43 42 6f-78 30 31 00 00 00 00 00 ..CCCCBox01..... 03373370 00 00 00 00 05 00 00 00-22 ff ff ff 5e 00 00 00 ........"...^... 03373380 00 00 00 00 09 00 43 43-43 43 42 6f 78 30 31 01 ......CCCCBox01. 03373390 00 00 00 00 00 00 00 81-3f 00 00 00 00 00 00 00 ........?....... 033733a0 00 00 00 00 00 00 00 00-00 00 00 81 3f 00 00 00 ............?... 033733b0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 81 ................ 033733c0 3f 00 00 00 00 54 8a 55-c0 a2 02 7c c2 00 00 00 ?....T.U...|.... 033733d0 00 00 00 81 3f 07 00 42-6f 78 30 31 52 58 01 00 ....?..Box01RX.. 0:000> db 03373360 +133 03373493 00 00 00 00 06 00 42 6f-02 00 00 00 00 16 ff ff ......Bo........ 033734a3 ff 30 00 00 00 00 00 00-00 01 00 52 01 00 00 00 .0.........R.... 033734b3 a6 04 a8 96 b9 3f c5 43-b2 df 2a 31 b5 56 93 40 .....?.C..*1.V.@ 033734c3 00 01 00 00 00 00 00 00-01 00 52 01 00 00 00 01 ..........R..... 033734d3 00 2e 01 00 76 00 00 00-00 00 00 00 00 00 00 00 ....v........... 033734e3 00 00 00 00 00 ee 0d f6-58 2d 59 29 08 80 2e 35 ........X-Y)...5 033734f3 03 68 f0 2c 03 0c 00 00-00 c0 d0 e0 f0 98 66 b6 .h.,..........f. 03373503 49 00 00 00 80 1e 00 00-00 00 00 00 00 05 00 04 I............... |
将shader_list_count改成1 发现漏洞就不触发了,上面那地方就可以正常初始化了。
010检测该漏洞
Shader_list_count!=0
Sls.shader_count=0
Exploit
自己分析去
POC
REF http://www.9bplus.com/file/tester.pdf
评论关闭。