IE安全系列之——昨日黃花:IE中的ActiveX(I)
IX.1 ActiveX的歷史和簡單的介紹
說到ActiveX,則不得不提到COM(元件物件模型)。COM出現時要解決的問題是,“能否把軟體做到和硬體一樣”,硬體的理想情況是比如有人規定了USB的規範,(Server)提供一個USB介面之後,(Client)只要正確實現了USB就可以讓二者相聯絡,擴充套件出更多的功能(USB鍵鼠,隨身碟,攝像頭,等等)。這之中Server(集線器)並不需要知道另一頭Client(鍵盤?滑鼠?)具體做啥的,只是知道我(Server)提供給你(Client)一個符合USB規範的介面,你(Client)弄上個東西連線成功就能用,至於你(Client)如何實現就不是我(Server)的事情了。
最初COM的出現也是為了解決類似的問題,例如我在IE裡面如何開啟一個WORD文件?針對它的解決方案稱為OLE(物件連線與嵌入)。1993年微軟釋出了OLE2,在這(ole32.dll)中提供的API也被日後認為是COM API。有了這些支援之後,微軟用它創造了OLE控制元件,並最終發展成為了在IE中常見的ActiveX控制元件。如果你用過VB的話,在VB裡就能發現大量此類控制元件的身影,如內嵌的Microsoft Viso等等。
每個ActiveX控制元件都由一個GUID(全域性唯一識別符號)來標識自己,GUID和UUID(全球唯一識別符號)差不多,只不過後者是OSF(開源軟體基金會)維護,前者是微軟自己的實現。
GUID是一個128位的數字,理論上是極大機率時間空間唯一的(隨機數生成的空間有2122的大小,按照類似生日問題的演算法,如果正確生成的話,和其他人生成的偶然重複機率為1/261)。
GUID演算法包括1490年開始到現在的分鐘數(保證時間唯一性),一個偽隨機數,和MAC地址(保證空間唯一性,沒有網路卡的話會使用另一個隨機常量),API CoCreateGuid可以生成GUID。GUID的一般形式類似於{AFEE063C-05BA-4248-A26E-168477F49734}
這樣。
在IE裡或者WSF或者HTA等支援OBJECT標籤的地方,可以透過它來載入ActiveX,OBJECT標籤的具體用法請見參考資料(1)。
圖:iDefense ComRaider ActiveX Fuzzer生成的WSF測試指令碼使用了Object標籤來載入被測ActiveX控制元件
IX.2 IE中的ActiveX
預設情況下,要在IE瀏覽器中執行ActiveX外掛,ActiveX外掛必須同時擁有Safe For Scripting/Safe For Init
標記才可以執行。在IE發現HTML網頁中有ActiveX控制元件時,IE會依次檢查如下動作來確定控制元件是否可以安全載入和運用於程式碼中。
(1) IE會先檢查ActiveX控制元件是否設定了killbit,如果設定了Killbit,IE將不會載入這個控制元件;
(2)IE會確定這個控制元件是否派生了IObjectSafety,如果有的話,IE會透過這個介面檢查是否有設定Safe for Scripting/Safe For Init,如果沒有派生IObjectSafety,IE會在登錄檔檢查{7DD95802-9882-11CF-9FA9-00AA006C42C4} (Safe for Initialization)
和 {7DD95801-9882-11CF-9FA9-00AA006C42C4}(Safe For Scripting).
兩項。
這裡的具體內容在之前的一篇文章/papers/?id=5673有介紹,所以不重複敘述了。為了後續實驗方便,我們可以使用環境自己先弄個ActiveX,這裡以Microsoft Visual C++ 2010為例建立一個ActiveX控制元件。
首先,如圖建立一個新工程,簡單起見,在後一個視窗直接完成即可。
生成的對外介面定義檔案(XXX.idl)檔案是和該控制元件資訊有關的一個重要檔案,許多資訊都可以在此看到。例如“類資訊”中uuid就是ActiveX控制元件待會兒在IE中載入時所要用到的Classid。
由於我們只是演示,因此我們簡單的新增一個函式foo(): 在類檢視的介面處點選右鍵,選擇新增->方法
然後,新增一個void foo(),填寫之後點選完成:
這時VS會在多個地方新增這個函式的資訊,不過簡單起見,回到剛才的idl檔案中我們就可以看到新增了個新函式
在MSVC中直接F12過去:
這個位置就是新加函式的位置,為了方便演示,我們在裡面隨便彈一個對話方塊好了:
::MessageBox(0, L"hello wooyun", L"blast", MB_OK);
然後,我們右鍵選擇工程,編譯一個Release版的ocx控制元件:
之後,使用regsvr32 testActivex.ocx。
此時,該ActiveX就已經被註冊了,我們建立一個測試用的htm檔案吧,
<HTML>
<OBJECT ID="test" WIDTH=300 HEIGHT=300 classid="CLSID:2D9835F7-9534-46C2-AE7A-C75098AA6105">
</OBJECT>
</HTML>
CLSID請換成你的idl裡面的那個uuid。由於我們的ActiveX控制元件並未設定Safe For Scripting和Safe For Init,所以在本地域開啟時IE做了這個提示,點選是之後,就可以看到外掛執行起來了。
此時,我們也可以測試呼叫我們加入的foo()函式,在SCRIPT標籤中呼叫test.foo(),即可呼叫成功,可見IE中彈出了一個對話方塊:
要實現Safe For Scripting、Init,請這麼做: 標頭檔案(例如我的工程是testActivexCtrl.h)中加入#include <objsafe.h>,然後將 DECLARE_INTERFACE_MAP()
#!c++
BEGIN_INTERFACE_PART(ObjSafe, IObjectSafety)
STDMETHOD_(HRESULT, GetInterfaceSafetyOptions) (
/* [in] */ REFIID riid,
/* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
/* [out] */ DWORD __RPC_FAR *pdwEnabledOptions
);
STDMETHOD_(HRESULT, SetInterfaceSafetyOptions) (
/* [in] */ REFIID riid,
/* [in] */ DWORD dwOptionSetMask,
/* [in] */ DWORD dwEnabledOptions
);
END_INTERFACE_PART(ObjSafe);
加入class CtestActiveXCtrl : public COleControl塊中。
在對應CPP檔案的最後加入下列程式碼,記得將CtestActiveXCtrl換成你自己的類名。
#!c++
BEGIN_INTERFACE_MAP(CtestActiveXCtrl,COleControl)
INTERFACE_PART(CtestActiveXCtrl,IID_IObjectSafety,ObjSafe)
END_INTERFACE_MAP()
ULONG FAR EXPORT CtestActiveXCtrl::XObjSafe::AddRef()
{
METHOD_PROLOGUE(CtestActiveXCtrl,ObjSafe)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CtestActiveXCtrl::XObjSafe::Release()
{
METHOD_PROLOGUE(CtestActiveXCtrl,ObjSafe)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT CtestActiveXCtrl::XObjSafe::QueryInterface(REFIID iid,void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CtestActiveXCtrl,ObjSafe)
return (HRESULT)pThis->ExternalQueryInterface(&iid,ppvObj);
}
const DWORD dwSupportedBits = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
const DWORD dwNotSupportedBits=~dwSupportedBits;
HRESULT STDMETHODCALLTYPE
CtestActiveXCtrl::XObjSafe::GetInterfaceSafetyOptions(
/*[in]*/ REFIID riid,
/*[out]*/ DWORD __RPC_FAR *pdwSupportedOptions,
/*[out]*/ DWORD __RPC_FAR *pdwEnabledOptions)
{
METHOD_PROLOGUE(CtestActiveXCtrl,ObjSafe)
HRESULT retval = ResultFromScode(S_OK);
IUnknown FAR* punkInterface;
retval = pThis->ExternalQueryInterface(&riid, (void **)&punkInterface);
if(retval != E_NOINTERFACE)
{
punkInterface->Release();
}
*pdwSupportedOptions=*pdwEnabledOptions=dwSupportedBits;
return retval;
}
HRESULT STDMETHODCALLTYPE
CtestActiveXCtrl::XObjSafe::SetInterfaceSafetyOptions(
/*[in]*/ REFIID riid,
/*[in]*/ DWORD dwOptionSetMask,
/*[in]*/ DWORD dwEnabledOptions)
{
METHOD_PROLOGUE(CtestActiveXCtrl, ObjSafe)
IUnknown FAR* punkInterface;
pThis->ExternalQueryInterface(&riid, (void **)&punkInterface);
if(punkInterface)
{
punkInterface->Release();
}
else
{
return ResultFromScode(E_NOINTERFACE);
}
if(dwOptionSetMask & dwNotSupportedBits)
{
return ResultFromScode(E_FAIL);
}
dwEnabledOptions&=dwSupportedBits;
if((dwOptionSetMask&dwEnabledOptions)!=dwOptionSetMask)
{
return ResultFromScode(E_FAIL);
}
return ResultFromScode(S_OK);
}
重新編譯,再次開啟IE時,這個控制元件就會直接載入起來而不會再彈出對話方塊了。
IX.3 Windows 10中ActiveX外掛變成了什麼樣
另一個大家比較關注的可能是Windows 10裡面的ActiveX情況,有一個好訊息是Microsoft Edge已經不支援ActiveX了,不過Windows 10同樣自帶的IE11則依然和Win7、Win8的IE11一樣,繼續支援ActiveX。
在Windows 10中讓我們做同樣的事情,
首先,Win10提供了IE和Edge瀏覽器,選擇使用Edge瀏覽器開啟時,頁面中並未載入該ActiveX控制元件:
可以看到test物件事實上只是一個CObjectElement而已,它並沒有載入ActiveX控制元件。使用工具檢視Edge的記憶體也可得出同樣結論——這個OCX並沒載入到記憶體。
再換用IE開啟這個頁面,在Win10自帶的IE11中,我們看到外掛正常執行了。
另外,在原先的IE中,Flash外掛也是靠ActiveX的形式活著的。在Edge中應該也考慮到了這個問題,Edge自帶一套Flash,所以使用者不需要額外去網站上下載安裝,這套Flash的形式是什麼呢?我們可以簡單看一下:
首先我們可以看到FLASH的載入程式碼依然和之前一樣,採用Object的方式載入:
不過之前的經歷我們知道Object在Edge中是不能像之前一樣簡單載入ActiveX的,那這裡是什麼呢?參考程式列表可以發現,Edge在執行到包含有Flash的頁面時,會啟動一個FlashUtil_ActiveX.exe 程式,這個程式名字十分奇怪,在仔細檢視Edge的程式模組後,我們可以發現,Edge其實還是保留著載入ActiveX控制元件的能力的,只不過控制在一個比較小的範圍內而已:
本章節只是介紹了ActiveX的歷史和一個示例ActiveX的編譯方法,而並沒有介紹有關Activex安全的部分,關於Activex漏洞的挖掘等內容將在後續章節介紹。
參考資料
(1] http://www.w3school.com.cn/tags/tag_object.asp
(2] http://www.ffri.jp/assets/files/monthly_research/MR201503_Windows_10_Technical_Preview_Security_Overview_ENG.pdf
相關文章
- IE安全系列之——IE中的ActiveX(II)2020-08-19
- IE安全系列:IE的自我介紹 (I)2020-08-19
- IE安全系列:指令碼先鋒(I)2020-08-19指令碼
- IE安全系列之——RES Protocol2020-08-19Protocol
- IE安全系列:IE的自我介紹 (II)2020-08-19
- IE安全系列之:中流砥柱(I)—Jscript 5處理淺析2020-08-19JS
- IE安全系列之——RES Protocol與列印預覽(II)2020-08-19Protocol
- IE安全系列:指令碼先鋒(II)2020-08-19指令碼
- IE安全系列:指令碼先鋒(III)--網馬中的Shellcode2020-08-19指令碼
- IE安全系列:指令碼先鋒(IV)—網馬中的Shellcode2020-08-19指令碼
- IE安全系列之:中流砥柱(II)—Jscript 9處理淺析2020-08-19JS
- 一行程式碼解決各種IE相容問題,IE6,IE7,IE8,IE9,IE102019-02-16行程IE9IE10
- IE沙箱拖拽安全策略解析2020-08-19
- Javascript 實現 Textarea 自動伸縮,相容IE6、IE7、IE8、IE9...2019-01-06JavaScriptIE9
- Magicodes.IE之花式匯出2020-09-28
- windows10系統下IE瀏覽器怎麼開啟activex控制元件2020-03-27Windows瀏覽器控制元件
- 噁心的相容問題:完美解決IE(IE6/IE7/IE8)不相容HTML5標籤的問題2019-02-16HTML
- JavaScript 判斷IE瀏覽器的版本包括IE112018-12-21JavaScript瀏覽器IE11
- ie 居中方案2024-03-18
- Bypass IE XSS Filter2020-08-19Filter
- IE功能彙總2020-04-06
- Use IE userdata behavior2021-09-09
- SAP PM入門系列21 - IE07 Equipment List (Multilevel)2021-01-25UI
- 小技巧系列:html或js判斷IE瀏覽器2021-02-05HTMLJS瀏覽器
- placeholder如何在相容IE?2024-11-28
- 仿querySeletor 相容IE 672018-07-13
- IE瀏覽器相容2018-07-18瀏覽器
- CSS實現文字豎排顯示(相容IE6/IE7)2018-08-02CSS
- Magicodes.IE之匯入匯出篩選器2020-09-24
- ie怎麼設定主頁 簡述設定ie瀏覽器的主頁方法2020-10-17瀏覽器
- 你經歷過老闆要求相容IE嗎?IE幾?有什麼感悟?2024-11-21
- React、Vue在IE的相容問題2019-08-29ReactVue
- 針對IE及其它的css hack2018-10-24CSS
- IE瀏覽器版本的判斷2018-04-09瀏覽器
- 黃花崗2024-04-05
- IE 涼了?怎麼可能!2021-06-15
- windos IE密碼檢視2020-12-07密碼
- 關於ie中實現彈性盒模型-我的css2019-05-13模型CSS