【实战】再谈 IE Object Type Property 溢出漏洞

博客围绕 IE Object Type Property 溢出漏洞展开讨论,强调再次探讨该漏洞相关内容,聚焦信息技术领域的浏览器安全问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

再谈 IE Object Type Property 溢出漏洞


创建时间:2003-09-08
文章属性:原创
文章提交: eyas (eyas_at_xfocus.org)

再谈 IE Object Type Property 溢出漏洞

Author: ey4s
Email : eyas#xfocus.org
Site  : www.xfocus.net
Date  : 2003-09-08


    首先感谢Nanika在前段时间发布的关于此漏洞的研究心得,他的文章使我获益颇深。
    
    我的测试环境为
    windows 2000 server 英文版 + sp4(默认codepage是GB)
    IE 6.0 英文版 + sp1
    urlmon.dll 6.0.2800.1106

    假如html页面中包含如下字符:
    <object type="aaaa">xxxx</object>
    
    那么IE的处理流程如下:
    1.字符串"aaaa"(以后称这个字符串为m_buff_1)用MultiByteToWideChar函数转换成
unicode(以后称这个字符串为u_buff_1)。
    2.u_buff_1被截短为0x100字节(截短后的字符串称为u_buff_2)。
    3.u_buff_2作为函数urlmon!CoGetClassObjectFromURL的第5个参数,做进一步处理。
    4.u_buff_2用WideCharToMultiByte函数转换成多字节形式(w_buff_2)。
    5.w_buff_2作为函数urlmon!GetClassMime的第1个参数做进一步处理。
    6.w_buff_2作为函数urlmon!ComposeHackClsidFromMime的参数做进一步处理。
    
    处理流程函数调用关系如下:

    urlmon!CoGetClassObjectFromURL
        |_ urlmon!AsyncGetClassBitsEx
            |_ urlmon!AsyncGetClassBits2Ex
                |_ urlmon!GetClsidFromExtOrMime
                    |_ WideCharToMultiByte
                    |_ urlmon!GetClassMime(溢出)
                |_ urlmon!CCodeDownload::DoCodeDownload
                    |_ urlmon!CCodeDownload::GetNextOnInternetSearchPath
                        |_ urlmon!ComposeHackClsidFromMime(溢出)


    m_buff_1经过我们精心构造之后,可以分别使上述流程中的第5步和第6步都发生stack
溢出。网上现有的分析资料好像都只留意到了第6步的溢出,也许是我孤陋寡闻^_^。

    ok!我们先来看第一个。

urlmon!GetClassMime:
702cc586 55               push    ebp
702cc587 8d6c2494         lea     ebp,[esp-0x6c]
702cc58b 81eca4030000     sub     esp,0x3a4
//[ebp+0x74]即第一个参数,前面说的w_buff_2
702cc591 8b4574           mov     eax,[ebp+0x74]
....

//将0x7030a754处的"MIME/Database/Content Type/" copy到[ebp-0x38]中
702cc5b4 8a9154a73070     mov     dl,[ecx+0x7030a754]
702cc5ba 88540dc8         mov     [ebp+ecx-0x38],dl
702cc5be 41               inc     ecx
702cc5bf 84d2             test    dl,dl
702cc5c1 75f1             jnz     urlmon!GetClassMime+0x2e (702cc5b4)

//w_buff_2地址保存在edx
702cc5c3 8bd0             mov     edx,eax

//定位w_buff_2结束地址
702cc5c5 8a08             mov     cl,[eax]
702cc5c7 40               inc     eax
702cc5c8 84c9             test    cl,cl
702cc5ca 75f9             jnz     urlmon!GetClassMime+0x3f (702cc5c5)

//计算dest buffer的结束地址
702cc5cc 8d7dc8           lea     edi,[ebp-0x38]//dest buffer
702cc5cf 2bc2             sub     eax,edx//计算w_buff_2长度
702cc5d1 4f               dec     edi
702cc5d2 8a4f01           mov     cl,[edi+0x1]
702cc5d5 47               inc     edi
702cc5d6 84c9             test    cl,cl
702cc5d8 75f8             jnz     urlmon!GetClassMime+0x4c (702cc5d2)

//将w_buff_2 copy到堆栈,溢出!
702cc5da 8bc8             mov     ecx,eax
702cc5dc c1e902           shr     ecx,0x2//w_buff_2长度除于4
702cc5df 8bf2             mov     esi,edx//source buffer
702cc5e1 f3a5             rep     movsd

//w_buff_2除于4后余下的继续copy到堆栈  
702cc5e3 8bc8             mov     ecx,eax
702cc5e5 8d4568           lea     eax,[ebp+0x68]
702cc5e8 50               push    eax
702cc5e9 83e103           and     ecx,0x3
702cc5ec 6a01             push    0x1
702cc5ee f3a4             rep     movsb
......
702cc67d 83c56c           add     ebp,0x6c
702cc680 c9               leave
702cc681 c20c00           ret     0xc

    从上述的汇编代码中我们可以看出,堆栈的buffer总长度是0x38+0x6c=0xA4。

    还原成C代码的话,应该是类似如下吧:

    char *str = "MIME/Database/Content Type/";
    GetClassMime(char *w_buff_2,...)
    {
        char buff[0xa4];
        strcpy(buff, str);
        strcat(buff, w_buff_2);
        ......
    }

    str长度固定为0x1B,0xA4-0x1B=0x89,所以我们提供的w_buff_2只要大于等于0x89,
便可使IE溢出,控制程序流程。0x100字节的u_buff_2转换成多字节的w_buff_2后, 长度
大于等于0x80,小于等于x100,具体长度取决于你构造的buff以及系统的codepage。

    系统默认codepage是GB时,w_buff_1构造如下:

    [哈*68][a][AAAA][BBBB][CCCCDDDDEEEE][FFFF]

    68怎么来的?68*2+1=137,即0x89。

    IE溢出后,ebp=0x41414141,eip=0x42424242,esp指向的是"FFFF"起始的地方。溢出
时SEH离stack buffer比较远,覆盖不到,溢出后函数ret时也就只有esp指向我们的
buffer附近,所以大概只能用的jmp esp的方式来得到控制。jmp esp地址比较难找通用的,
所以exp的通用性会比较低。
    
    我们可以这样构造w_buff_1:
    [sc(0x89+4 bytes)][jmp esp][nop * 0xC][jmp_back_to_sc]

    要满足几个条件:
    1)w_buff_1经过两次转换后不会被改变。
    2)要保证w_buff_1转换成unicode后,长度小于等于0x100。

    sc最长可以有0x89+4=0x8d,即141字节。141字节可以干些什么?写复杂功能的sc
可能不够,但用来搜索内存中真正发挥功能的shellcode便足够了。

    另外,溢出发生后,函数ret之前,sc中有几个字节会被改变,这点也要注意到。

    由以上的分析可以看出,利用这个溢出的exp要依赖于jmp esp地址以及系统语言平台。
如果你有更好的利用方法,请不吝赐教^_^。


    接下来我们来看第2个发生溢出的地方。

    ComposeHackClsidFromMime函数的原型类似为:
    ComposeHackClsidFromMime(char *pOutBuf, int iOutBufSize, char *w_buff_2)

urlmon!ComposeHackClsidFromMime:
702f1b7a 55               push    ebp
702f1b7b 8bec             mov     ebp,esp
702f1b7d 81ec04010000     sub     esp,0x104
702f1b83 8b4d10           mov     ecx,[ebp+0x10]
702f1b86 56               push    esi
702f1b87 8bf1             mov     esi,ecx
702f1b89 8a09             mov     cl,[ecx]
702f1b8b 84c9             test    cl,cl
702f1b8d 8d85fcfeffff     lea     eax,[ebp-0x104]
702f1b93 888dfcfeffff     mov     [ebp-0x104],cl
702f1b99 741e             jz      702f1bb9
//判断是否为"/",是的话扩展为"_2F_",然后写入到stack buffer中
702f1b9b 80f92f           cmp     cl,0x2f
702f1b9e 750f             jnz     702f1baf
702f1ba0 c6005f           mov     byte ptr [eax],0x5f
702f1ba3 40               inc     eax
702f1ba4 c60032           mov     byte ptr [eax],0x32
702f1ba7 40               inc     eax
702f1ba8 c60046           mov     byte ptr [eax],0x46
702f1bab 40               inc     eax
702f1bac c6005f           mov     byte ptr [eax],0x5f
702f1baf 46               inc     esi
702f1bb0 8a0e             mov     cl,[esi]
702f1bb2 40               inc     eax
702f1bb3 84c9             test    cl,cl
//不是"/"则直接写入到stack buffer中
702f1bb5 8808             mov     [eax],cl
702f1bb7 75e2             jnz     702f1b9b

//把扩展过后的buffer,按照一定格式写入到pOutBuf
702f1bb9 8d85fcfeffff     lea     eax,[ebp-0x104]
702f1bbf 50               push    eax
702f1bc0 8b450c           mov     eax,[ebp+0xc]
702f1bc3 68e01b2f70       push    0x702f1be0
702f1bc8 48               dec     eax
702f1bc9 50               push    eax
702f1bca ff7508           push    dword ptr [ebp+0x8]
702f1bcd ff15fc132b70     call dword ptr [urlmon!_imp__wnsprintfA]
702f1bd3 83c410           add     esp,0x10
702f1bd6 33c0             xor     eax,eax
702f1bd8 5e               pop     esi
702f1bd9 c9               leave
702f1bda c20c00           ret     0xc
    

    从以上汇编代码中我们可以看到,stack buffer长度是0x104。从前面的分析我们知
道,w_buff_2长度要控制在0x89内,不然在urlmon!GetClassMime就溢出了,就到不了
这里了。在测试的时候,某些平台下,w_buff_2的长度好像必须控制在0x80内,不然到
不了这里。我们姑且把w_buff_2最大长度限制为0x80吧。


    有两种办法可以利用此处溢出漏洞。

    第一,jmp esp。这样构造w_buff_1:

    [/*64][BBBB][AAAA][CCCC][write_addr][write_len][A*4][shellcode40bytes]

    上述字符串加一起一共128字节,即0x80。溢出后,函数会做如下操作:

    wnsprintf(write_addr, write_len-1,0x702f1be0,[ebp-0x104])

    0x702f1be0处的字符串是"clssid=%s"。
  
    所以write_addr必须为一个可以写入不包含00的地址,而且要符合宽字符编码。不然
在wnsprintfA调用的时候就会发生异常,函数无法返回,加上seh我们无法覆盖,所以程
序流程我们就会得不到控制。

    函数返回后,ebp=0x41414141,eip=0x43434343,esp指向shellcode。

    这样看来,第二个溢出比第一个溢出在利用起来更麻烦:
    1)要提供一个可写的不带0的地址
    2)sc只能有40字节

    其实wnsprintfA函数很容易绕过,给它提供一个负数的size就ok了^_^,而且这个
size是我们可以控制的。但是,只有在IE6+sp1及以后的版本中,调用的才是wnsprintfA,
以往的版本调用的都是wsprintfA。

    用另外一种方法来构造w_buff_1可以得到多一点的空间来放置shellcode:
    
    [sc(x bytes)][/(y bytes)][eip][write_addr][write_len][A*4][jmp_back_to_sc]

    x和y要满足以下关系:
    x+y+20=0x80   <-保证buff不会被截短
    x+y*4=0x104+4 <-用于保证buff扩展后能触发溢出

    ==>x=56 y=52

    

    山穷水尽?NO!我们为什么不充分利用wsprintfA函数呢。

    
    第二,利用wsprintfA。构造以下buffer,
    
    [sc(x bytes)]["/"(y bytes)][eip][write_addr]

    注意:我们所构造的buffer都必须要保证经过两次转换后不被改变。

    x和y要满足以下关系:
    (1)x+y*4=0x104+4 <-用于保证buff扩展后能触发溢出
    (2)x+y+8=0x80    <-保证buff不会被截短

    很简单可以算出,x=72,y=48。

    寻找一处不为0的,可以写入的地址作为write_addr。wsprintfA调用完成之后,
write_addr+7指向的就是sc了。所以可以直接把write_addr+7作为eip。
    sc最长可以有72字节,用来写搜索内存中真正功能的shellcode足够了。可以先
接管异常,然后从0x1000开始往内存高处搜索,100%能搜索到^_^。

    所以利用第2个溢出,写个针对某种语言平台的通用的exp是完全可以实现的。


    补丁是如何修补上述漏洞的?以urlmon.dll 6.0.2800.1226为例:

urlmon!GetClassMime:
1a41ca51 55               push    ebp
1a41ca52 8d6c2494         lea     ebp,[esp-0x6c]
1a41ca56 81eca4030000     sub     esp,0x3a4
......
1a41ca7f 689b000000       push    0x9b//<--长度限制
1a41ca84 688ca7451a       push    0x1a45a78c//"MIME/Database/Content Type/"
1a41ca89 8d45c8           lea     eax,[ebp-0x38]
1a41ca8c 50               push    eax
1a41ca8d ff15e411401a     call  dword ptr [urlmon!_imp__lstrcpynA (1a4011e4)]
1a41ca93 8d45c8           lea     eax,[ebp-0x38]
1a41ca96 50               push    eax
1a41ca97 ff15d411401a     call   dword ptr [urlmon!_imp__lstrlenA (1a4011d4)]
1a41ca9d b99a000000       mov     ecx,0x9a
1a41caa2 2bc8             sub     ecx,eax//<--长度限制
1a41caa4 51               push    ecx
1a41caa5 57               push    edi
1a41caa6 8d45c8           lea     eax,[ebp-0x38]
1a41caa9 50               push    eax
1a41caaa ff157813401a     call   dword ptr [urlmon!_imp__StrNCatA (1a401378)]


urlmon!ComposeHackClsidFromMime:
1a441d62 55               push    ebp
1a441d63 8bec             mov     ebp,esp
1a441d65 81ec04010000     sub     esp,0x104
1a441d6b 8b5510           mov     edx,[ebp+0x10]
1a441d6e 56               push    esi
1a441d6f 8d85fcfeffff     lea     eax,[ebp-0x104]
1a441d75 33f6             xor     esi,esi
1a441d77 8a0a             mov     cl,[edx]
1a441d79 84c9             test    cl,cl
1a441d7b 8808             mov     [eax],cl
1a441d7d 742a             jz  urlmon!ComposeHackClsidFromMime+0x47 (1a441da9)
1a441d7f 80f92f           cmp     cl,0x2f
1a441d82 751a             jnz urlmon!ComposeHackClsidFromMime+0x3c (1a441d9e)
1a441d84 81fe00010000     cmp     esi,0x100//<--长度检查
1a441d8a 7d1d             jge urlmon!ComposeHackClsidFromMime+0x47 (1a441da9)
1a441d8c c6005f           mov     byte ptr [eax],0x5f
1a441d8f 40               inc     eax
1a441d90 c60032           mov     byte ptr [eax],0x32
1a441d93 40               inc     eax
1a441d94 c60046           mov     byte ptr [eax],0x46
1a441d97 40               inc     eax
1a441d98 c6005f           mov     byte ptr [eax],0x5f
1a441d9b 83c603           add     esi,0x3
1a441d9e 46               inc     esi//长度
1a441d9f 42               inc     edx//src buffer addr
1a441da0 40               inc     eax//dest buffer addr
1a441da1 81fe03010000     cmp     esi,0x103//<--长度检查
1a441da7 7cce             jl  urlmon!ComposeHackClsidFromMime+0x15 (1a441d77)
1a441da9 802000           and     byte ptr [eax],0x0
1a441dac 8d85fcfeffff     lea     eax,[ebp-0x104]
1a441db2 50               push    eax
1a441db3 8b450c           mov     eax,[ebp+0xc]
1a441db6 68d01d441a       push    0x1a441dd0
1a441dbb 48               dec     eax
1a441dbc 50               push    eax
1a441dbd ff7508           push    dword ptr [ebp+0x8]
1a441dc0 ff15fc13401a     call dword ptr [urlmon!_imp__wnsprintfA (1a4013fc)]
1a441dc6 83c410           add     esp,0x10
1a441dc9 33c0             xor     eax,eax
1a441dcb 5e               pop     esi
1a441dcc c9               leave
1a441dcd c20c00           ret     0xc

参考资料:
<>Internet Explorer Object Type Property Overflow 的研究心得
http://www.xfocus.net/articles/200306/551.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值