2011年10月18日星期二

[轉載]MS11-081中IE9導致的一個CHM漏洞簡單分析


作 者: promsied
時 間: 2011-10-12,21:35:15
鏈接: http://bbs.pediy.com/showthread.php?t=141323

這個漏洞只存在於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 _CoMarshalInterThreadInterfaceInStream@12 (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的字符串時就不會產生問題了。
附件是編譯好的一個CHM,其中的1.rar是本人寫的一個小工具,說明見本人博客http://hi.baidu.com/promised_lu

没有评论:

发表评论