IE安全系列:IE的自我介紹 (I)
前言
系列將簡單介紹一下IE的相關內容,篇幅和自己的認知有限,其中必然有不足之處,如果有寫得不對的地方歡迎大家指出。
文章佈局:每篇文章最多含有3個部分,這3個部分介紹的是相關內容,但並不一定是同一系列的東西,望見諒。
第一部分通常是背景介紹
第二部分是總結性的描述
第三部分則是詳細介紹或者實踐。
I.1 Internet Explorer的歷史變遷
在記憶中,從1999年開始接觸網路,從那時跟隨著Windows 95一起而來的Internet Explorer 4算起,微軟已經發布了8個不同版本的IE了(如果Spartan姑且算做是Internet Explorer 12的話)。這之中Internet Explorer(以下簡稱IE)都做了哪些變更呢?里程碑可以數一數:
·IE1、IE2(1995年):家族中最簡單的“瀏覽器”,只支援靜態的頁面,現在你能用得到的許多功能,它都不支援。現在你用到的許多功能他卻有了雛形。
·IE3 (1996年):對早期版本的改進,支援了ActiveX控制元件,支援了JavaScript和VBScript(當時稱為Microsoft JScript和Microsoft VBScript,不為啥,就因為商標問題)。而且從這時開始就支援WebBrowser這個被人熟知的ActiveX控制元件了,這保證了瀏覽器的可重用性。
·IE4(1997年):引入了DHTML功能,支援資料繫結,同時增強了WebBrowser的功能,添加了一些新特性,增加了側邊欄,以及BHO。
·IE5(1999年):隨著Windows 98一起發售,支援持久會話,緊接著誕生了XMLHttpRequest,促使了AJAX的發展(儘管此時AJAX一詞都還沒誕生……),引入了HTA,還有自動填表等功能。IE 5.5版本起還支援了128位的加密。
·IE6(2001年):緊接著Windows XP一起發售,可能是給大家留下印象最深刻的瀏覽器,在2002-2003年中,IE6的市場份額達到了90%,IE全家族的市場份額達到了95%。 同時,這也是最飽受詬病的瀏覽器,因為它的安全問題實在是很嚴重。這一版本中增加的大多是網頁渲染相關的,例如CSS1 、DOM1等的部分支援。
·IE7(2006年)、IE8(2009年):IE6市場份額被火狐搶走之後微軟推出的新版本瀏覽器,這兩個版本大部分都是效能調整和渲染修整以及增強。
·IE9(2011年),穩定版本,效能提升和HTML5支援,多程序支援,這使得網頁假死或者崩潰時不會影響到其他頁面。
不放截圖了,IE9之後這些版本大家很容易就能搜到。
·IE10(2011年)/IE11(2013年),效能較大的增強了,以及渲染以及相容增強,增加DNT支援,IE10開始效能真的已經和之前有較大的不同了,但是頂著IE的名號,還是承受著IE6帶來的深刻影響。
·Spartan(2015年),代號IE12。整合了語音助手,效能提升等,估計微軟此舉也是要丟掉IE的牌子另起爐灶,從程式上看,至少它確實和IE用的不是同一套DLL庫了。
I.2 IE的構成
在早期的單程序IE中,IE的結構大致如:
圖:以 IE6 為代表的單程序無 tab 模式
隨著多程序的引入,IE 的網頁部分結構還是類似這樣,但是介面宿主已經有變化了,看起來像是:
請注意上圖中外殼網頁分屬於不同程序。
在IE7中,一個程序中可以執行一組網頁視窗了,但是新視窗不代表在新程序裡面執行。(比如你用Ctrl+N新建視窗,其實它還是在當前程序裡面建立的),可以自己安裝一個IE7來試驗,如果沒用過的話看我這個描述應該會很奇怪。開啟了保護模式的程序會執行在低完整性級別下,通過一個代理程序來進行通訊。
簡化的程序模型如下:
圖:IE7 的程序模式
在 IE8 中,微軟引入了 IE8 鬆散耦合程序框架(LCIE),它使用 Jobs 來限制程序許可權(吐槽 一下,自己試著用Jobs控制權限,實際應用在IE中的話深知不易,微軟也是下了不少功夫), 這個時候,開啟了保護模式與未開啟保護模式的 IE8 的結構類似於:
可以看到的是這個版本中 IE 的 UI Frame 和一些管理功能所在的程序執行在中完整性級 別上,而保護模式下,Tab 和網頁程序執行在低完整性級別中(禁用保護模式的域下依然是 中完整性級別)。
如上,HTML 和 ActiveX 控制元件都在網頁程序裡面,還有一個比較特殊的是工具欄,它也 在網頁程序裡面。
採用這種模式的好處都有啥?首先是每個 TAB 都獨立出去了,其中一個崩了也不會影 響其他的;至於把 UI Frame 移動到了代理程序那邊,理由是加快啟動速度。
而且由於採用了網頁分程序的模式,所以不同完整性級別的網頁、tab 都可以歸屬於同 一個 UI Frame,管理起來也比較方便。 如果你使用過 morden ie,metro ie,你會發現也許它的網頁程序都是 64 位的,這是因為 這個版本中啥外掛都不載入。即使現在許多外掛都有 64 位版本了,比如 Adobe Flash Player, 但是如果一味的追求 64 位化還是會導致各種外掛不相容。 所以在 IE10、IE11 的 64 位版本中,瀏覽器的 UI Frame 以 64 位執行,而網頁程序為了保 證外掛的相容性,所以依然預設採用了 32 位程序。即使你開啟的是 64 位的 ie,最後網頁進 程還是 32 位的。
所以,也許你會看到有 64 位的 IE 和 32 位 IE 同時存在你電腦裡面的樣子:
以及,啟動 IE 後出現一個 64 位程序和 n 個 32 位程序的樣子:
圖: IE11 64bit Frame 程序和 32bit Content 程序
相對於 IE7 的模式,可以看出來 IE11 中,即使你手動執行兩次 iexplore http://www.wooyun.org , 出來的也僅僅只有一個 64 位的 UI 程序。
圖:IE11 的程序模式
當然,如果你開啟了增強保護模式,那網頁程序也會變成 64 位的。
圖:IE11 啟用增強保護模式
在 Windows 7 下開啟這個模式,唯一一個用處就是把程序變成了 64 位,但是 Windows 8 下則會引入 AppContainer 這個程序隔離模式,具體的可以參考參考資料(1)。
限於篇幅,與之相關的內容之後再敘述。
I.3 重要概念:什麼是 Markup Service?
回到 IE 的核心功能上來,作為網頁的渲染器,超文字標記語言 HTM(Markup)L 想必 是離不開 Markup,那這個 Markup 到底是什麼呢?歷史上來說,Markup 其實是給演員看的, 簡單的說就是劇本,通常還會給它畫一道藍色的標記,標明這個東西應該誰怎麼演才合適, 在瀏覽器中,Markup通常可以看作是一個個的標籤。關於Markup Service的內容,建議大 家最開始只瞭解個大概即可。
圖:Markup Script,當然,這個是演員用的,影象來自Google Image
圖:IE 可以識別的 Hyper Text Markup Langauge
例如,一個 HTML 檔案可能有如下內容:
<DIV>blast<DIV>off
當瀏覽器解析這個文字時,瀏覽器會對內容做一次標準化(我比較習慣這麼稱呼),之 後,DOM 內容看起來像是:
<HTML><HEAD><TITLE></TITLE></HEAD><BODY><DIV>blast<DIV>off</DIV></D IV></BODY></HTML>
這個過程你可以自己去網頁 DOM 看:
圖:IE11 的文件標準化
由於有元素的插入,因此這一項功能可能會引入額外的安全風險,例如我之前發的:
http://wooyun.org/bugs/wooyun-2010-033834
或者可以說,解析器經過這一輪後,將 HTML 文字轉為了元素。而且為了內容的完整, 有一些原來沒有的元素也加進去了,例如 html、head、title、body 會自動的被解析器構造出 來。
同時,解析器遇到第二個 div(分塊)的時候,會自動的把第一個 div 給封閉起來(怎 麼封閉要取決於瀏覽器的實現)。還有之前加入的必要(但是你沒寫)的標籤,比如 <html>
、 <body>
,都會自動的被
IE 添上並封閉。
第二個需要注意的概念是 tree 和 stream(樹、流)的區別,比如:
This <B>is</B> a test
這組“this is a test”和一對 b 標籤的例子,將會被轉化為如下的樹。text 被當為樹葉,element 被作為內節點。
ROOT | +-------+--------+ | | | "this" B "a test" | "is"
把文件轉為tree之後,所有的操作都會變為類似對樹的操作,例如增刪子節點。提供此類操作的API被稱為Tree Service。
當然,自IE4.0之後,元素的模型操作比簡單的樹更強悍,比如這個例子:
An <B>exmaple <I> of </B> elements </I> cross
B、I的範圍互相交叉,在HTML裡面這個很常見,用樹來描述則十分困難。因此,Markup Services對這個內容不再提供類似樹的操作,而是為方便控制內容暴露了一個基於流操作的模型。
圖:相互交叉的範圍
因此,Markup Service 它的作用實際上是用來避免產生這種讓人覺得迷惑的模型層間的。
當無法用 Tree Service 時,瀏覽器就轉而使用 Markup Service 來控制基於流操作的模型。
在基於樹的模型中,網頁內容被當作樹的節點來處理,每個元素,或者一塊 Text 都是 一個節點。節點通過這種類似對樹的操作方式來操作,例如從父節點中增刪一個子節點。
在基於流的模型的內容操作方式中(比如通過 Markup Service 來操作),文件的內容會 通過使用類似迭代器的物件來操作。 這個就像是在處理上面那個元素交叉的例子一樣,這 些帶有部分重疊的元素通過兩個 Markup Pointer 來區分,每個 Markup Pointer 指定著 Tag 從 哪兒開始,Tag 到哪兒結束。所以,基於流的模型是基於樹的模型的一個超集。
說了這麼多,要引入我們的 Markup Pointer 了。在這之前,舉一個類似的例子,C++中, 比如如果要操作一個 vector,使用迭代器是非常方便的做法:
圖:使用迭代器向 vector 插入一個元素
也如你所見,Markup Pointer也有些許神似迭代器。可以通過建立和操作無效文件的過程來理解一下。
注意之前“This is a test”的例子,瀏覽器可能都不會被認為這是一個有效的 HTML 文件。
最小的有效HTML文件至少要有html、head、title和body四個元素,當你提供的內容中沒有這些元素時,解析器會自動建立,然後把它們放到合適的位置上。
在文件解析過程中,使用Markup Service即可刪除或者重新排列DOM。例如,你可以整塊刪除html、body元素。你可以把head移動到body裡面(但是這麼做的話,文件會被當作是無效文件)。
在IE中,提供這個服務的類有很多,最普遍的類即CMarkup,負責“指向元素、區域”的Markup 指標類名字是CMarkupPointer,它們都派生自CBase。
如果有關注類似的內容的話,之前發的一個CMarkupPointer空指標引用的問題其實就與這相關(http://wooyun.org/bugs/wooyun-2010-079690 )。
關於 CMarkupPointer,有一些需要注意,也是可能會導致 IE 崩潰或者出其他錯的問題,
分別是:
(1) Markup Pointer 剛建立,或者以一個無效物件為建構函式的引數建立的時候是未指 向狀態,也就是說啥都沒指,通常這個值是 0,這個很可能會導致空指標引用;
(2)Markup Pointer 設定了指標粘滯(噹噹前指標所在區域發生移動之後,區域內的指 針是否也跟著計算新位置)的時候,如果同時也設定重力(重力分為左右重力, 簡單來說,就是在指標處插入一個內容,操作完之後,指標是應該貼著左邊的內 容還是右邊的內容),且在經過某些操作後發生了歧義,在對 Markup Pointer 指向的部分進行移動、刪除過程後,Markup Pointer 有可能會重新變成未指向狀態。這是因為指標指向的內容不存在或無效了,指標已經從文件中移除(注意是 remove)了,但是指標自身還沒有被刪除(delete),以後如果重用這個指標又沒做 校驗的話,很可能就會出事兒。
(3)Markup Pointer 左右移動的時候也有可能移動出錯。
還有就是一個經驗條例,IE 中程式碼很依賴比較上層的有效性檢查,所以一旦中底層程式碼接收到了無效資料,IE 就很可能會出現異常。
還是重提一下關於Markup Service的內容,如果之前沒接觸過的話,最開始只瞭解個大概即可,之後等了解了更多IE相關的內容時,這一塊的東西才容易和其他部分聯絡起來,只是這個屬於基礎性的設施,所以才放在比較前面來介紹,老實說最開始我看這個東西感覺也是相當的頭疼……所以看著比較迷糊的話也不用太在意,有個印象就可以了。