欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

MS11-081中IE9导致的一个CHM漏洞简单分析

程序员文章站 2022-05-01 18:42:13
这个漏洞只存在于IE9,会导致无法下载CHM中内嵌的文件,在没有安装KB2586448更新的机器上测试 首先新建一个1.html文件,内容如下

这个漏洞只存在于IE9,会导致无法下载CHM中内嵌的文件,在没有安装KB2586448更新的机器上测试
首先新建一个1.html文件,内容如下

<a href = "1.rar">1.rar</a>


然后和一个1.rar文件用HTML Help Workshop一起编译成CHM
打开CHM点击1.rar链接,也可以在IE地址栏输入mk:@MSITStore:XXX(具体路径)\1.chm::/1.rar,报错调试
停在CDownloadUtilities::MarshalBindContextToStream函数内,这个函数为下载1.rar文件做一些准备工作
声明如下
HRESULT CDownloadUtilities::MarshalBindContextToStream(CInterThreadMarshal **ppITM<eax>, CDownloadThreadParam *pDTP, wchar_t *szURL, IBindCtx *pBC)


简单分析下其代码

CDownloadUtilities::MarshalBindContextToStream(CInterThreadMarshal **ppITM<eax>, CDownloadThreadParam *pDTP, wchar_t *szURL, IBindCtx *pBC):
7003D23A  mov         edi,edi 
7003D23C  push        ebp 
7003D23D  mov         ebp,esp 
7003D23F  sub         esp,0Ch  ;HRESULT hr<[ebp-4h]>, IUnknown *pUnk<[ebp-8h]>, IEUserBroker *pIEUB<[ebp-0Ch]>
7003D242  push        ebx 
7003D243  push        esi 
7003D244  push        edi 
7003D245  lea         edx,[ebp-8]  ;edx = &pUnk
7003D248  push        edx  ;&pUnk
7003D249  mov         edi,eax  ;edi = ppITM
7003D24B  mov         eax,dword ptr [ebp+10h]  ;eax = pBC
7003D24E  mov         ecx,dword ptr [eax]  ;ecx = pBC->lpVtbl
7003D250  push        offset __GUID_0000000e_0000_0000_c000_000000000046 (6FF65DA8h)  ;&IID_IUnknown
7003D255  push        eax  ;pBC
7003D256  call        dword ptr [ecx]  ;eax = pBC->lpVtbl->QueryInterface(pBC, &IID_IUnknown, &pUnk)
7003D258  xor         ebx,ebx 
7003D25A  mov         dword ptr [ebp-4],eax  ;hr = eax
7003D25D  cmp         eax,ebx 
7003D25F  jl          CDownloadUtilities::MarshalBindContextToStream+0C6h (7003D300h)  ;if (FAILED(hr)) goto 7003D300h
7003D265  push        3 
7003D267  push        offset string L"mk:" (70019BB4h) 
7003D26C  push        dword ptr [ebp+0Ch] 
7003D26F  call        dword ptr [__imp___wcsnicmp (6FE91364h)] 
7003D275  add         esp,0Ch 
7003D278  test        eax,eax 
7003D27A  jne         CDownloadUtilities::MarshalBindContextToStream+74h (7003D2AEh)  ;if (_wcsnicmp(szURL, L"mk:", 3)) goto 7003D2AEh
7003D27C  mov         eax,dword ptr [ebp-8]  ;eax = pUnk
7003D27F  mov         ecx,dword ptr [eax]  ;ecx = pUnk->lpVtbl
7003D281  push        eax  ;pUnk
7003D282  call        dword ptr [ecx+8]  ;pUnk->lpVtbl->Release(pUnk)
7003D285  push        ebx  ;0
7003D286  lea         eax,[ebp+10h]  ;eax = &pBC
7003D289  push        eax  ;&pBC
7003D28A  push        ebx  ;0
7003D28B  push        ebx  ;0
7003D28C  push        ebx  ;0
7003D28D  push        ebx  ;0
7003D28E  mov         dword ptr [ebp-8],ebx  ;pUnk = 0
7003D291  call        dword ptr [__imp__CreateAsyncBindCtxEx@24 (7023B14Ch)]  ;eax = CreateAsyncBindCtxEx(0, 0, 0, 0, &pBC, 0)
7003D297  mov         esi,dword ptr [edi]  ;esi = *ppITM
7003D299  mov         dword ptr [ebp-4],eax  ;hr = eax
7003D29C  cmp         esi,ebx 
7003D29E  je          CDownloadUtilities::MarshalBindContextToStream+74h (7003D2AEh)  ;if (*ppITM == 0) goto 7003D2AEh
7003D2A0  call        CInterThreadMarshal::~CInterThreadMarshal (701D7894h)  ;(*ppITM)->~CInterThreadMarshal()(this<esi>)
7003D2A5  push        esi 
7003D2A6  call        operator delete (6FEA35D9h)  ;delete *ppITM
7003D2AB  pop         ecx 
7003D2AC  mov         dword ptr [edi],ebx  ;*ppITM = 0
7003D2AE  cmp         dword ptr [ebp-4],ebx 
7003D2B1  jl          CDownloadUtilities::MarshalBindContextToStream+0C6h (7003D300h)  ;if (FAILED(hr)) goto 7003D300h
7003D2B3  mov         eax,dword ptr [edi]  ;eax = *ppITM
7003D2B5  cmp         eax,ebx 
7003D2B7  je          CDownloadUtilities::MarshalBindContextToStream+89h (7003D2C3h)  ;goto 7003D2C3h
7003D2B9  mov         ecx,dword ptr [ebp+8]  ;ecx = pDTP
7003D2BC  mov         dword ptr [ecx+18h],eax  ;*(pDTP + 18h) = eax
7003D2BF  mov         dword ptr [edi],ebx  ;*ppITM = 0
7003D2C1  jmp         CDownloadUtilities::MarshalBindContextToStream+0BDh (7003D2F7h) 
7003D2C3  push        4 
7003D2C5  call        operator new (6FE9E771h)  ;eax = new LPSTREAM
7003D2CA  pop         ecx 
7003D2CB  cmp         eax,ebx 
7003D2CD  je          CDownloadUtilities::MarshalBindContextToStream+99h (7003D2D3h)  ;if (eax == 0) goto 7003D2D3h
7003D2CF  mov         dword ptr [eax],ebx  ;[eax] = 0
7003D2D1  jmp         CDownloadUtilities::MarshalBindContextToStream+9Bh (7003D2D5h) 
7003D2D3  xor         eax,eax 
7003D2D5  mov         ecx,dword ptr [ebp+8]  ;ecx = pDTP
7003D2D8  mov         dword ptr [ecx+18h],eax  ;*(pDTP + 18h) = eax
7003D2DB  mov         dword ptr [ebp-4],8007000Eh  ;hr = 8007000Eh
7003D2E2  cmp         eax,ebx 
7003D2E4  je          CDownloadUtilities::MarshalBindContextToStream+0BDh (7003D2F7h)  ;if (eax == 0) goto 7003D2F7h
7003D2E6  push        eax 
7003D2E7  push        dword ptr [ebp-8]  ;pUnk
7003D2EA  push        offset _IID_IBindCtx (6FF2AB8Ch) 
7003D2EF  call        (701FF7F2h)  ;eax = CoMarshalInterThreadInterfaceInStream(&IID_IBindCtx, pUnk, eax)
7003D2F4  mov         dword ptr [ebp-4],eax  ;hr = eax
7003D2F7  mov         eax,dword ptr [ebp-8]  ;eax = pUnk
7003D2FA  mov         ecx,dword ptr [eax]  ;ecx = pUnk->lpVtbl
7003D2FC  push        eax  ;pUnk
7003D2FD  call        dword ptr [ecx+8]  ;pUnk->lpVtbl->Release(lpVtbl)
7003D300  call        LCIEUnifiedFrame (6FF9CD1Fh) 
7003D305  test        al,al 
7003D307  je          CDownloadUtilities::MarshalBindContextToStream+128h (7003D362h) 
7003D309  lea         eax,[ebp-0Ch] 
7003D30C  push        eax 
7003D30D  call        dword ptr [__imp_CoCreateUserBroker (6FE925A4h)] 
7003D313  test        eax,eax 
7003D315  js          CDownloadUtilities::MarshalBindContextToStream+128h (7003D362h) 
7003D317  lea         eax,[ebp+0Ch] 
7003D31A  push        eax 
7003D31B  push        dword ptr [ebp-0Ch] 
7003D31E  push        offset _IID_IEUserBroker (6FF37F6Ch) 
7003D323  call        dword ptr [__imp__CoMarshalInterThreadInterfaceInStream@12 (6FE91FECh)] 
7003D329  mov         dword ptr [ebp-4],eax 
7003D32C  cmp         eax,ebx 
7003D32E  jne         CDownloadUtilities::MarshalBindContextToStream+11Fh (7003D359h) 
7003D330  mov         edi,dword ptr [ebp+8] 
7003D333  mov         eax,dword ptr [edi+14h] 
7003D336  mov         esi,dword ptr [ebp+0Ch] 
7003D339  cmp         eax,ebx 
7003D33B  je          CDownloadUtilities::MarshalBindContextToStream+109h (7003D343h) 
7003D33D  mov         ecx,dword ptr [eax] 
7003D33F  push        eax 
7003D340  call        dword ptr [ecx+8] 
7003D343  mov         dword ptr [edi+14h],esi 
7003D346  cmp         esi,ebx 
7003D348  je          CDownloadUtilities::MarshalBindContextToStream+116h (7003D350h) 
7003D34A  mov         eax,dword ptr [esi] 
7003D34C  push        esi 
7003D34D  call        dword ptr [eax+4] 
7003D350  mov         eax,dword ptr [ebp+0Ch] 
7003D353  mov         ecx,dword ptr [eax] 
7003D355  push        eax 
7003D356  call        dword ptr [ecx+8] 
7003D359  mov         eax,dword ptr [ebp-0Ch] 
7003D35C  mov         ecx,dword ptr [eax] 
7003D35E  push        eax 
7003D35F  call        dword ptr [ecx+8] 
7003D362  mov         eax,dword ptr [ebp-4] 
7003D365  pop         edi 
7003D366  pop         esi 
7003D367  pop         ebx 
7003D368  leave 
7003D369  ret         0Ch 
7003D36C  nop 
7003D36D  nop 
7003D36E  nop 
7003D36F  nop 
7003D370  nop 

简单改写成C++代码

HRESULT CDownloadUtilities::MarshalBindContextToStream(CInterThreadMarshal **ppITM<eax>, CDownloadThreadParam *pDTP, wchar_t *szURL, IBindCtx *pBC)
{
 IEUserBroker *pIEUB;
 IUnknown *pUnk;
 HRESULT hr;
 if (SUCCEEDED(hr = pBC->QueryInterface(&IID_IUnknown, &pUnk)))
 {
  if (!_wcsnicmp(szURL, L"mk:", 3))
  {
   pUnk->Release();
   pUnk = NULL;
   hr = CreateAsyncBindCtxEx(0, 0, 0, 0, &pBC, 0);
   if (*ppITM)
   {
    (*ppITM)->~CInterThreadMarshal();
    delete *ppITM;
    *ppITM = NULL;
   }
  }
  if (SUCCEEDED(hr))
  {
   if (*ppITM)
   {
    *(pDTP + 18h) = *ppITM;
    *ppITM = NULL;
   }
   else
   {
    IStream **ppStm = new LPSTREAM;
    if (ppStm)
    {
     *ppStm = 0;
    }
    else
    {
     ppStm = NULL;
    }
    *(pDTP + 18h) = ppStm;
    hr = 8007000Eh;
    if (ppStm)
    {
     hr = CoMarshalInterThreadInterfaceInStream(&IID_IBindCtx, pUnk, ppStm);
    }
   }
   pUnk->Release();
  }
 }
 //omit
 return hr;
}

首先函数调用pBC->QueryInterface获得pBC对象的IUnknown接口pUnk,由于IBindCtx只继承自IUnknown,所以IUnknown接口和IBindCtx接口地址实际相同,当下载CHM内嵌的文件时,CDownloadUtilities::MarshalBindContextToStream函数的szURL参数为形如mk:XXX的字符串,所以函数调用pUnk->Release又设pUnk=NULL,而pUnk原本的计数应为1,pUnk->Release彻底释放了pBC对象,于是函数调用CreateAsyncBindCtxEx重新获得pBC对象,pBC是更新了但pUnk仍然为NULL,此外函数又彻底释放了*ppITM对象并设*ppITM=NULL,于是之后函数会调用CoMarshalInterThreadInterfaceInStream列集接口指针,但调用时第二个参数为pUnk,但pUnk=NULL,实际应为pBC,这还不是大问题,紧跟着的pUnk->Release才是祸根,由于pUnk=NULL,取pUnk的虚函数表指针造成访问违例,程序报错,不过幸好之前pUnk设为了NULL,不然后果就更糟糕了,解决方法应该是换用pBC。当szURL参数不是形如mk:XXX的字符串时就不会产生问题了。

KB2586448把CreateAsyncBindCtxEx(0, 0, 0, 0, &pBC, 0);改成了CreateAsyncBindCtxEx(0, 0, 0, 0, &pUnk, 0);解决了问题
函数声明改成了HRESULT CDownloadUtilities::MarshalBindContextToStream(IBindCtx *pBC<eax>, CInterThreadMarshal **ppITM<ecx>, CDownloadThreadParam *pDTP, wchar_t *szURL)

 

作者:Recycle Bin