十二年前的漏洞——对某旺控件栈溢出漏洞的学习
字数 1841 2025-08-25 22:58:20
阿里旺旺ImageMan.dll控件栈溢出漏洞分析与复现
漏洞概述
本文详细分析阿里旺旺6.50.00C版本中ImageMan.dll控件的AutoPic函数栈溢出漏洞。该漏洞存在于一个ActiveX控件中,通过构造特殊的参数可导致栈缓冲区溢出,最终实现任意代码执行。
环境准备
- 目标软件:阿里旺旺6.50.00C
- 操作系统:Windows XP
- 调试工具:OllyDbg(OD)或x64dbg
- 辅助工具:COMRaider(用于ActiveX控件Fuzz测试)
- 漏洞文件:
Pictool/ImageMan.dll
漏洞定位
漏洞存在于ImageMan.dll中的AutoPic函数,具体问题出在该函数对输入参数的处理不当,导致栈缓冲区溢出。
调试方法
ActiveX控件调试技巧
-
关键断点设置:
- 在OLEAUT32.dll的
DispCallFunc函数下断点 - 网页调用ActiveX组件时,浏览器会先后调用
GetIDsOfNames和Invoke函数 Invoke函数内部最终会调用OLEAUT32!DispCallFunc
- 在OLEAUT32.dll的
-
调试流程:
- 在
DispCallFunc的call ecx指令处中断 - F7单步进入函数入口点
- 观察
[ebp+C]参数和WideCharToMultiByte调用
- 在
漏洞分析
关键函数伪代码
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;
}
漏洞触发流程
-
字符串转换:
- 使用
WideCharToMultiByte将宽字符参数转换为多字节字符串 - 转换结果存储在
MultiByteStr缓冲区(260字节)
- 使用
-
路径处理:
- 调用
strrchr查找最后一个反斜杠''(ASCII码92) - 如果输入字符串中没有反斜杠,
v10返回NULL
- 调用
-
危险复制操作:
mbsnbcpy((unsigned __int8 *)&v15, (unsigned __int8 *)&MultiByteStr, v10 - &MultiByteStr + 1);- 当
v10为NULL时,v10 - &MultiByteStr + 1计算结果为负值 - 由于参数类型为
unsigned __int8,负值会被解释为很大的正数 - 导致
mbsnbcpy复制过多数据到v15缓冲区(仅260字节),造成栈溢出
- 当
关键点分析
-
mbsnbcpy函数:- 类似
strcpy的不安全函数 - 微软文档指出其存在安全隐患
- 函数原型:
errno_t mbsnbcpy(unsigned char *strDest, const unsigned char *strSource, size_t count);
- 类似
-
缓冲区大小:
MultiByteStr和v15缓冲区大小均为260字节- 但复制长度计算错误时,可以写入远超缓冲区大小的数据
-
漏洞触发条件:
- 输入字符串长度超过260字节
- 输入字符串中不包含反斜杠''
漏洞复现
POC构造
-
JavaScript POC:
// 创建ActiveX对象 var obj = new ActiveXObject("ImageMan.ImageMan.1"); // 构造超长无斜杠字符串 var payload = "A".repeat(1000); // 调用漏洞函数 obj.AutoPic(0, payload, 0); -
调试观察:
- 在
DispCallFunc的call ecx处中断 - 单步跟踪到
mbsnbcpy调用 - 观察栈区域被'A'(0x41)填充的情况
- 最终EIP被覆盖为0x41414141,验证漏洞存在
- 在
漏洞利用
虽然本文未详细讨论利用细节,但实际利用可能涉及以下技术:
-
堆喷射(Heap Spraying):
- 在内存中布置大量包含shellcode的块
- 增加跳转到shellcode的概率
-
ROP链构造:
- 绕过DEP保护
- 组合现有代码片段实现任意功能
-
ASLR绕过:
- 寻找未随机化的模块
- 使用信息泄露获取模块基址
注意事项
-
COMRaider测试问题:
- 使用COMRaider生成的VBS POC可能无法触发崩溃
- 相同逻辑的JS POC可以成功触发
- 可能原因:两种语言对ActiveX控件的调用方式存在差异
-
防护绕过:
- 现代系统有DEP、ASLR等防护机制
- 实际利用需要结合多种绕过技术
修复建议
-
输入验证:
- 检查输入字符串长度
- 确保路径格式合法
-
安全函数替换:
- 使用
mbsnbcpy_s等安全版本 - 或改用
strncpy并明确指定最大长度
- 使用
-
缓冲区大小检查:
- 在复制前验证源字符串长度
- 确保不超过目标缓冲区大小
总结
该漏洞是典型的栈缓冲区溢出案例,由于对用户输入缺乏充分验证,加上使用了不安全的字符串复制函数,导致攻击者可以控制程序执行流程。通过分析此类漏洞,我们可以学习到:
- ActiveX控件的分析方法
- 不安全字符串函数的危害
- 栈溢出漏洞的调试技巧
- 实际漏洞利用中的各种挑战
对于安全研究人员,理解这类漏洞的原理和利用方式,有助于更好地发现和防范类似安全问题。