Chinaunix首页 | 论坛 | 博客
  • 博客访问: 181401
  • 博文数量: 55
  • 博客积分: 207
  • 博客等级: 入伍新兵
  • 技术积分: 320
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-23 19:33
文章分类
文章存档

2012年(53)

2011年(2)

分类:

2012-03-29 09:54:12

详细说明:

ImageMa2 ActiveX IDL文件如下:
[
uuid(D81C6073-919F-4F3A-B12C-7EAF0F6B1F90),
helpstring("ImageManager2 Class")
]
coclass ImageManager2 {
[default] interface IImageManager2;
[default, source] dispinterface _IImageManager2Events;
};

[
odl,
uuid(F068E587-4F89-4949-8FA5-82EF935F688A),
helpstring("IImageManager2 Interface"),
dual,
oleautomation
]
interface IImageManager2 : IDispatch {
[id(0x00000001), helpstring("method ManualPic")]
HRESULT ManualPic(BSTR szFileName);
[id(0x00000002), helpstring("method AutoPic")]
HRESULT AutoPic(
BSTR szFileName,
BSTR* szOut);
[id(0x00000003), propget, helpstring("property url")]
HRESULT url([out, retval] BSTR* pVal);
[id(0x00000003), propput, helpstring("property url")]
HRESULT url([in] BSTR pVal);
[id(0x00000004), propget, helpstring("property containerType")]
HRESULT containerType([out, retval] BSTR* pVal);
[id(0x00000004), propput, helpstring("property containerType")]
HRESULT containerType([in] BSTR pVal);
[id(0x00000005), propget, helpstring("property functionCallback")]
HRESULT functionCallback([out, retval] BSTR* pVal);
[id(0x00000005), propput, helpstring("property functionCallback")]
HRESULT functionCallback([in] BSTR pVal);
[id(0x00000006), propget, helpstring("property draw")]
HRESULT draw([out, retval] BSTR* pVal);
[id(0x00000006), propput, helpstring("property draw")]
HRESULT draw([in] BSTR pVal);
[id(0x00000007), propget, helpstring("property action")]
HRESULT action([out, retval] BSTR* pVal);
[id(0x00000007), propput, helpstring("property action")]
HRESULT action([in] BSTR pVal);
[id(0x00000008), propget, helpstring("property secureKey")]
HRESULT secureKey([out, retval] BSTR* pVal);
[id(0x00000008), propput, helpstring("property secureKey")]
HRESULT secureKey([in] BSTR pVal);
[id(0x00000009), propget, helpstring("property company")]
HRESULT company([out, retval] BSTR* pVal);
[id(0x00000009), propput, helpstring("property company")]
HRESULT company([in] BSTR pVal);
[id(0x0000000a), propget, helpstring("property loginId")]
HRESULT loginId([out, retval] BSTR* pVal);
[id(0x0000000a), propput, helpstring("property loginId")]
HRESULT loginId([in] BSTR pVal);
[id(0x0000000b), propget, helpstring("property picid")]
HRESULT picid([out, retval] BSTR* pVal);
[id(0x0000000b), propput, helpstring("property picid")]
HRESULT picid([in] BSTR pVal);
[id(0x0000000c), propget, helpstring("property Response")]
HRESULT Response([out, retval] BSTR* pVal);
[id(0x0000000c), propput, helpstring("property Response")]
HRESULT Response([in] BSTR pVal);
[id(0x0000000d), propget, helpstring("property PicFileName")]
HRESULT PicFileName([out, retval] BSTR* pVal);
[id(0x0000000d), propput, helpstring("property PicFileName")]
HRESULT PicFileName([in] BSTR pVal);
[id(0x0000000e), propget, helpstring("property xmlParam")]
HRESULT xmlParam([out, retval] BSTR* pVal);
[id(0x0000000e), propput, helpstring("property xmlParam")]
HRESULT xmlParam([in] BSTR pVal);
};


ImageMa2 ActiveX在处理AutoPic方法时存在一个off-by-one的栈溢出漏洞,因为我在修补过的版本AliIM2010_taobao 6.50.10C的ImageMa2.dll中看到程序员在AutoPic的处理函数中加入了2个返回值检查的地方:

1) 调用WideCharToMultiByte()转换unicode字符串时做了返回值检测,这样限制了传入的参数不超过260个字节。

WideCharToMultiByte(0, 0, lpWideCharStr, -1, &FullPath, 260, 0, 0)

2) 同样在调用strrchr查找'\'时也做了返回值检测,确保了返回值不为NULL。因为后面mbsnbcpy函数的第三个(size)的参数是strrchr的返回值减去FullPath的起始地址然后加一.
strrchr(&FullPath, "\\"))

但是显然程序员忽略了在sub_100105EB()调用的子函数存在一个off-by-one的栈溢出漏洞。

sub_100105EB() -> sub_100103FA() (建议用IDA分析ImageMa2的时候把dll的基地址rebase成0x10001000,这样就能方便定位到我描述的问题所在处了。)

sub_100103FA():

...

//首先调用splitpath分解传入的FullPath到本地变量
splitpath(FullPath, &Drive, &Dir, &Filename, &DestStr);
...

char *filesuffix= (char *)_mbsupr(&DestStr);
if ( _mbscmp(filesuffix, ".GIF") )
name = ".jpg";
else
name = ".gif";
strcpy(&DestStr, name);

DWORD count = 9999;
while ( 1 )
{
DWORD rd = rand();
sprintf((char *)&Dest, "%s%s%s_%04d%s", &Drive, &Dir, &Filename, rd % 10000, &DestStr);
if (!GetFileAttributesA(&Dest))
break;
count--;
if ( !count )
return 0;
}

当我们传入的路径不包含后缀名时,该函数会自动帮忙添加.jpg或者.gif的后缀,当我们传入的数据到达260字节后,sprintf打印的文件名为:
"[我们传入的路径]_1234.jpg",然后这里程序员忽略了sprintf会自动在缓冲区末尾添加00做截断,从而也就导致了一个stack off-by-one的问题,导致了保存的
ebp最后一个字节被覆盖成0的字节,当函数返回时就会跳转至缓冲区内的内容处执行,而这个内容是我们可控的。

漏洞证明:

PoC:








测试环境
Windows XP SP3 CN + AliIM2010_taobao 6.50.10C

调试输出:
sprintf后的内容:
0:005> d 01e3f1ac L 110
01e3f1ac 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f1bc 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f1cc 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f1dc 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f1ec 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f1fc 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f20c 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f21c 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f22c 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f23c 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f24c 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f25c 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f26c 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f27c 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f28c 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 0c ................
01e3f29c 0c 0c 0c 0c 0c 0c 0c 0c-0c 0c 0c 0c 0c 0c 0c 5f ..............._
01e3f2ac 39 39 37 38 2e 6a 70 67-00 f5 e3 01 04 06 03 03 9978.jpg........


当上层函数返回后,我们可以看到eip被修改成我们控制的内容了:

eax=00000000 ebx=00000000 ecx=00000210 edx=00000210 esi=03193748 edi=01e3f4ec
eip=03030604 esp=01e3f2cc ebp=01e3f500 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ImageMa2!DllUnregisterServer+0x9f34:
03030604 c20800 ret 8
0:005> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
01e3f500 0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c ImageMa2!DllUnregisterServer+0x9f34
01e3f5fc 77105cd9 03193748 001d70f4 022e1a2c +0xc0c0bfb
01e3f61c 771062e8 03193748 00000020 00000004 OLEAUT32!DispCallFunc+0xc3
01e3f6ac 03027660 02345f04 03193748 00000000 OLEAUT32!DispCallFunc+0x6d2
01e3f6d4 3db58b4f 03193748 00000002 3db31234 ImageMa2!DllUnregisterServer+0xf90
01e3f714 3dd64167 03193748 00000002 00000409 mshtml!DllGetClassObject+0xc9c81
01e3f754 3dd63bc8 002201d0 00000002 00000409 mshtml!ConvertAndEscapePostData+0x89660
01e3f788 75be29d7 002201d0 00000002 00000409 mshtml!ConvertAndEscapePostData+0x890c1
01e3f7c0 75be2947 009ac210 02a81450 00000002 jscript!DllCanUnloadNow+0x6a0e
01e3f7f8 75be31e5 009ac210 02a81450 00000002 jscript!DllCanUnloadNow+0x697e
01e3f868 75be1c0a 009ac210 02a81450 00000002 jscript!DllCanUnloadNow+0x721c
01e3f8b0 75be1211 009ac210 01e3f8d0 00000001 jscript!DllCanUnloadNow+0x5c41
01e3f8f0 75be11c6 009ac210 00000001 00000000 jscript!DllCanUnloadNow+0x5248
01e3f914 75be311d 009ac210 00000000 00000001 jscript!DllCanUnloadNow+0x51fd
01e3f9cc 75be1123 01e3fa10 00000000 009ad6b0 jscript!DllCanUnloadNow+0x7154
01e3f9e4 75be0f8a 01e3fa10 00000000 00000000 jscript!DllCanUnloadNow+0x515a
01e3fa54 75bd3777 009ad6b0 01e3fc04 00000000 jscript!DllCanUnloadNow+0x4fc1
01e3faa4 75bcc357 01e3fc04 01e3fbe4 009ac00c jscript!DllGetClassObject+0x5728
01e3fb08 75bcc1a8 022dc56c 0023034c 00000000 jscript+0xc357
01e3fb34 3dad2af5 009ac00c 022dc56c 0023034c jscript+0xc1a8

当然在完全返回之前还有一个读写内存的异常:
(dfc.638): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=022e38f4 ebx=00000000 ecx=03194208 edx=00000022 esi=0c0c0c0c edi=01e3f4ec
eip=03031d01 esp=01e3f2d8 ebp=01e3f500 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
ImageMa2!DllUnregisterServer+0xb631:
03031d01 8906 mov dword ptr [esi],eax ds:0023:0c0c0c0c=????????
我们只需要在Heap Spray中填充这个地址的内容即可,时间仓促就暂不提供working的PoC了。

修复方案:

编译器选项加入 /GS
把sprintf换成可限制长度的如snprintf,或者用更安全的API代替。

 

阿里巴巴也作出了回应: 我们在第一时间对此漏洞做出响应,修复了该漏洞,发布了安装包和升级包。 对于提交漏洞给我们安全信箱的同仁,我们都会提交一份小礼物,聊表谢意。感谢所有给阿里巴巴集团报过漏洞的安全人员,感谢所有的关注阿里巴巴安全的人,谢谢你们的关注,鞭策着我们前行,我们一直在努力,致力于创造安全的阿里巴巴。

阅读(1070) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~