十二年前的漏洞——对某旺控件栈溢出漏洞的学习
0x01、前言
如果单从挖掘角度来看,站在巨人的肩膀上,这个漏洞的发现难度并不算高
可还是值得学习一番
话不多说,开始学习
准备环境:阿里旺旺6.50.00C、winxp、OD(或dbg)、COMRaider
0x02、开始
来到软件的Pictool目录下,发现了ImageMan.dll,从漏洞描述我们可以知道,是AutoPic函数存在漏洞
那IE下的ActiveX控件如何下断点调试呢?
前置知识:
https://www.cnblogs.com/ichunqiu/p/8422987.html
3.3.分析方法-DispCallFunc下段
在网页中调用ActiveX组件,在浏览器背后都会先后调用GetIDsOfNames函数和Invoke函数。因为Invoke函数内部最终要调用OLEAUT32!DispCallFunc函数,因此可以在该函数上下断点。
业界普遍的方法是利用OLEAUT32!DispCallFunc函数来对调试函数进行跟踪分析,然后跟进 call ecx。
所以我来到dbg的符号列表,找到OLEAUT32.dll文件的DispCallFunc函数,果断下断点
0x03、复现 && 分析
运行,载入crash的poc,你会发现在call ecx的入口
按F7进入程序入口点
可以看到两个比较重要的点[ebp+C]和WideCharToMultiByte,尤其是后者,要考的
继续往下运行,可以看到[ebp+C]里存放的是你的buffer(也就是超长的AAAAAAAA...)
至于WideCharToMultiByte是干嘛的,我们暂时先不管,后面会讲,再往下运行,会发现一个不认识的函数sub1001C310
观察堆栈区已经被41填满了
这个函数是干什么的我也不知道(当然这里我已经写着注释了)
f8继续运行几下,就会发现eip已经指向41414141了,到此,复现流程结束
我们把imageMan.dll拖入ida,看看上方函数到底是何方神圣
这个函数本质上就是引用了_mbsnbcpy函数
看到cpy,基本上就能联想到strcpy,也能和栈溢出挂钩了
这是微软官方的描述:https://learn.microsoft.com/zh-cn/previous-versions/5377k1bk(v=vs.120)?redirectedfrom=MSDN
总之,这是一个不安全的函数
我们再回去看看AutoPic的伪代码
根据交叉引用可判断sub_1001AB7F为AutoPic函数
伪代码:
int __stdcall AutoPic(int a1, LPCWSTR lpWideCharStr, int a3)
{
const OLECHAR *v4; // eax
char v5; // [esp+Ch] [ebp-314h]
CHAR String; // [esp+10h] [ebp-310h]
char v7; // [esp+11h] [ebp-30Fh]
__int16 v8; // [esp+111h] [ebp-20Fh]
char v9; // [esp+113h] [ebp-20Dh]
char *v10; // [esp+114h] [ebp-20Ch]
CHAR MultiByteStr; // [esp+118h] [ebp-208h]
char v12; // [esp+119h] [ebp-207h]
__int16 v13; // [esp+219h] [ebp-107h]
char v14; // [esp+21Bh] [ebp-105h]
char v15; // [esp+21Ch] [ebp-104h]
char v16; // [esp+21Dh] [ebp-103h]
__int16 v17; // [esp+31Dh] [ebp-3h]
char v18; // [esp+31Fh] [ebp-1h]
MultiByteStr = 0;
memset(&v12, 0, 0x100u);
v13 = 0;
v14 = 0;
WideCharToMultiByte(0, 0, lpWideCharStr, -1, &MultiByteStr, 260, 0, 0);
String = 0;
memset(&v7, 0, 0x100u);
v8 = 0;
v9 = 0;
v10 = strrchr(&MultiByteStr, 92);
v15 = 0;
memset(&v16, 0, 0x100u);
v17 = 0;
v18 = 0;
mbsnbcpy((unsigned __int8 *)&v15, (unsigned __int8 *)&MultiByteStr, v10 - &MultiByteStr + 1);
sub_100271FE(&v15);
sub_10018BA1(&MultiByteStr, &String);
sub_1001BFE0(&String);
if ( a3 )
{
v4 = (const OLECHAR *)sub_1001C060(&v5);
*(_DWORD *)a3 = SysAllocString(v4);
}
sub_1001C040(&v5);
return 0;
}
接下来,我们需要注意的伪代码仅有三行,分别是23,28和33行
23:WideCharToMultiByte就是把宽字符串转换成指定的新的字符串,把lpWideCharStr赋给&MultiByteStr
28:strrchr作用是该函数返回 str 中最后一次出现字符 c 的位置。如果未找到该值,则函数返回一个空指针。92是字符串'\'的ascii码
说白了,就是把斜杠作为截止部分
你想想,最终内容=字符串长度-斜杠部分以后的长度,难道不就是以斜杠就结束吗?
那么第33行的作用也就显而易见了,字符串以斜杠结束,并把这部分内容给&v15
可我们的内容中全是A,没有斜杠。所以v10是一个空指针
33行的内容是null-起始地址+1,根据c的转换规则,这里必然是负值,那就是字符串全部复制过来给&v15了。也是为什么会造成栈溢出的原因
到此全部分析完毕
exp采用了堆喷射技术,不是此次文章的重点,不过多阐述最后来看看exp的运行结果
0x04、结语
站在前辈们的肩膀上
战战兢兢,砥砺前行
一点小插曲
说一个比较奇怪的点,这里我尝试用COMRaider去生成fuzz的poc,但却失败了,一模一样改写成js的poc,却能crash成功。调试了几次也没弄明白为什么,不太理解,要是知道的小伙伴,麻烦告诉我一声,必定感激不尽
下图是vbs的poc,是无法crash
下图是js的poc,因为会crash怕截不到图,所以先alert了个框,是能crash的
奇奇怪怪
还没有评论,来说两句吧...