Hacking Team安卓瀏覽器攻擊過程中的漏洞分析Stage0
一、漏洞簡介
Hacking team今年爆出了針對android4.0.x-4.3.x android瀏覽器的漏洞攻擊利用代碼。該漏洞攻擊代碼,通過連續利用多個瀏覽器與內核漏洞,完成通過javascript向虛擬內存寫數據,執行代碼,提升至root權限,并最終達到向目標手機中植入惡意程序的目的。
該利用過程分為5個復雜的Stage,本文首先分析了第1個Stage,即Stage0。 攻擊代碼的Stage0階段通過一個0Day地址泄露漏洞,為后續數據填充操作完成定位地址定位的任務。此漏洞位于android-src\external\libxslt模塊中。
二、漏洞詳細信息
概述
Stage0利用的0Day漏洞原理如下:
該漏洞屬于未經正確性檢查,就直接錯誤地進行強制類型轉換,從而導致一個用于內存讀(實際用于字符串比較)的指針可以被操控。漏洞利用的思路是:通過在JS分配的大片內存空間中,填充字符串:http://www/w3.org/1999/XSL/Transform,程序的后續邏輯會將該字符串會與那個可控內存指針所指向的字符串進行比較,一旦字符串對比不成功,則javascript的一個對象會記錄下“Error”,由于指針所指向的地址是可控制的,一旦發現 “Error”,就重新調整地址,直到沒有發生Error,這樣就得到了javascript開辟的可控空間的內存地址信息。
1. 數據結構背景
圖1展示了hacking team所使用的觸發漏洞代碼:
圖1 漏洞觸發代碼與其內存結構
在瀏覽器中,我們可以使用javascript引用如圖1所示的xsl文件,通過此文件,即可引發stage0所使用的漏洞。圖1中的xsl語句,在libxml2解析后,會形成如圖1中右圖所示結構。其中,xsl描述的cdent節點,即為觸發漏洞的ENTITY類型節點。
此漏洞發生在瀏覽器引擎對xsl文件的解析過程中。因此,我們先簡述一下圖1中代碼,與右圖節點的對應關系。右圖的myDoc節點為虛的根節點,在左圖xsl描述中并沒有對應。xsl描述的最外層adoc和ata節點,同為根節點的下的一級子節點,由于adoc是第一個子節點,被myDoc的數據結構中得children指針指向,ata則被adoc的next指針指向。同理,x節點,cdent節點和y節點,同為adoc的子節點一級,形成如上圖所示結構。#p#
2. 漏洞成因
程序出現異常的根本原因是由于libxslt在對圖1中的cdent(xmlEntity類型)節點進行操作時,并未對此節點的類型進行比較,導致對cdent節點進行了不正確的類型轉換(轉換為xmlNode類型),并對轉換后的節點進行了非法操作。libxslt(android瀏覽器在對xsl進行解析時所使用的模塊)在對xsl操作的過程中,會對大部分節點的namespace進行比較,判斷節點是否為一個合法的xsl節點。
但當節點類型為xmlEntity類型時,由于xmlEntity沒有ns(用來比較namespace信息的數據結構)字段,所以不對xmlEntity類型進行比較namespace操作(xmlEntity類型、xmlNode類型的詳細信息請看圖5)。而libxslt在判斷節點類型是否為xmlEntity時,libxslt的判斷并不完全,最終導致xmlEntity可被轉換為xmlNode進行操作。從而引發程序崩潰。
圖2 未對所有節點的類型進行判斷
觸發崩潰的第一步,是由于對節點類型的比較不完全導致的。libxslt在成功構建節點樹(如圖2中右圖)后,會循環對myDoc的子節點進行namespace比較操作,圖2中左側代碼,是在循環中當對當前節點的所有操作完成時,將循環操作中的節點指針指向下一個需要操作的節點的代碼。根據圖2中第4967行的代碼,我們可以發現,libxslt是希望當目標節點子節點或next節點的類型不為xmlEntity類型時,將目標節點子節點或next節點賦值給cur指針,再由cur指針進入下一次循環。但是,libxslt只對cur指針的第一個子節點進行了數據類型的比較操作,并沒有對cur指針的next節點進行數據類型的比較。而在我們構建的節點結構中,cdent(xmlEntity類型)節點,正是被x的next指針指向的,導致cdent節點不正確的進入了循環。

圖3 對namespace進行比較的函數
觸發崩潰的第二步,是xmlEntity節點被轉換為xmlNode節點。圖3為第一步中所說的循環的開始位置(圖3代碼的4893行),我們可以清晰的看到第一步所用的cur指針的數據類型為xmlNode類型。而第一步的xmlEntity類型被賦值給了xmlNode類型的指針,這就導致了類型轉換的錯誤。
圖4 IS_XSLT_ELEM宏的定義
觸發崩潰的第三步,是對不正確的數據類型進行了非法操作。圖4為圖3中IS_XSLT_ELEM宏的展開。IS_XSLT_ELEM宏的操作是比較節點的namespace,判斷xmlNode結構體中的ns字段(此字段指向一個xmlNs的數據類型)中的href字段所指向的地址是否存儲了字符串“http://www.w3.org/1999/XSL/Transform”。
圖5 相互轉換的兩種數據類型
當IS_XSLT_ELEM宏的輸入參數為一個xmlEntity類型時,宏就會將orig字符串當作xmlNs類型的數據結構來操作。由于程序中的orig字符串存儲的是xmlEntity節點內的字符串信息,所以在觸發漏洞的代碼這個例子中,此處存儲的字符串為:
'XX';
toascii(addr); // ns->href
toascii(addr); // ns->prefix
'XXXX' // ns->_private
'XXXX' // ns->context
' xmlns:xsl=\'http://www.w3.org/1999/XSL/Transform\' terminate=\'yes\'/>
而在宏中,會把這串字符串當作xmlNs類型來操作。
圖6 xmlNs的數據結構
因此可以通過此漏洞達到地址泄漏的目的。可以注意到,當宏將字符串當作xmlNs節點來處理時,代碼中轉換為ascii碼的addr就可以被當作比較的字符串指針(href)來處理(詳細信息見圖4)所以我們可以將任何可以轉化為ascii碼的地址寫入href指針,從而讓這些指針所指向的字符串與“http://www.w3.org/1999/XSL/Transform”進行比較。
如果比較結果為真,則繼續后續操作,否則,libxslt將返回一個可被javascript接收的error信息。攻擊者通過接受的error信息,就可判定輸入的地址是否有指定的字符串,再結合大量的數據填充,就可以打到地址泄漏的目的。(詳見“三、利用方式”)#p#
3. 調試過程
調試過程在nexus 7+android4.3上進行。
由于在webkit解析xsl文件時,如果標簽為
圖7 程序在xmlParseEntityDecl停下時的狀態
myDoc節點:0x400d9768最終程序崩潰時,調用棧中會顯示是由于處理這個對象而導致崩潰。
Input:0x59988c18通過查看input信息,可知對xsl對象所解析到那個節點。
查看input信息:
圖8 Input中的信息
圖9 程序的解析狀態
如圖9顯示,正在解析!ENTITY節點。(base表示所解析的字符串,cur表示當前解析到的位置。)
函數entityDecl會創建引發錯誤的ENTITY對象:
圖10 xmlEntity節點的創建(此時節點的數據類型為xmlNode)
如圖10中所示,新生成的next節點,為通過entityDecl函數所得到的entity節點(type=0×11,0×11表示為entity節點,為圖2中XML_ENTITY_DECL的實際值)。此時此節點的compression字段(在xmlEntity中此字段為orig字段)為0。
函數xmlParseEntityValue會將節點中的字符串存儲于orig字符串指針中。
圖11 獲取xmlEntity節點中的字符串信息
如圖11所示,程序將從!ENTITY節點中解析出的字符串傳給了orig。(input中的cur(當前值)已向后移動,而之前的部分存入了orig中)
之后,函數會將orig賦值給xmlEntity對象的orig。
圖12 將字符串存入xmlEntity的orig字段中
函數通過cur對目標xmlEntity節點的orig字段進行賦值。
圖13 將之前出問題的節點轉換為xmlEntity類型
如圖13所示,被賦值的cur正是之前創建的xmlEntity節點。
而當程序運行到cur->orig=orig時,目標位置指針被重置:
圖14 字符串的傳入
如圖14所示,此時的compission字段被置為orig指針,存儲著可控的對象。而當對此節點進行namespace比較時,節點會類型轉換為xmlNode類型,而xmlEntity->orig字符串字段則會被當成xmlNs類型來解釋,最終達到任意地址比較的操作。
圖15 程序崩潰時的狀態
如圖15所示,程序最終在字符串比較時發生段錯誤,此時的棧中xsltParseTemplateContext的第二個參數,正是為我們在xmlParseEntityDecl停下時,myDoc所指向的地址。#p#
三、利用方式
1.向內存中填充330頁的寫有namespace信息的頁。通過大量的數據填充,在觸發漏洞時就有更大的可能匹配成功,只有匹配成功,才能進一步的地址泄漏。如果觸發漏洞時的addr值指向未被分配的頁,則會出現段錯誤導致程序崩潰。
圖16 內存填充
圖17 填充namespace信息
2.通過漏洞,可以在xsl對象生成時,修改href指針的值(詳見圖6),將地址改為一個在填充過程中,有很大幾率會被填充到的地址。
圖18 漏洞利用代碼1
圖19 漏洞利用代碼2
3.函數內部會自動對xsl對象的namespace指針進行匹配,以確定xsl對象是否為一個合法的xsl元素。如果為非法元素,則會被javascript捕獲到異常。
圖20 javascript可獲取的異常狀態
4.若進入if,則字符串匹配成功,之后進入二分法查找具體頁的過程,addr為觸發漏洞時所寫入的地址。若進入else,將猜測的地址addr進行變化,再次進行比較過程(此函數名即為find_spray_addr進入else后,則會迭代查找地址)。
5.二分法查找:
a.將填充的330頁數據的前一半(165頁)數據進行清空。
b.再次調用漏洞,判斷是否發生異常,若異常,則addr所指向的地址在前一半填充的頁中。否則,addr所指向的地址在后一半填充的頁中。
c.繼續對前一半或后一半進行a、b兩步,直到僅剩一頁時,則可判定addr指向的是此頁中的地址。
圖21 二分法查找addr所在頁的代碼1
圖22 二分法查找addr所在頁的代碼2
6.通過獲取頁信息,即可得到一個泄露的內存地址addr以及周圍4mb的可控內存,達到本階段的漏洞利用目的。
























