Cve 2011-2462 pdf 0day 漏洞分析

来源: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

 

 

评论关闭。