標籤:

CY-2017-011:深入分析Adobe Acrobat的類型混淆漏洞

概述

最近,我們的漏洞檢測平台發現了一個新的類型混淆漏洞,該漏洞影響到所有Acrobat Reader(Acrobat DC、Acrobat Reader DC、Acrobat 2017、Acrobat Reader 2017、Acrobat XI、Reader XI)的最新版本。該漏洞的編號為CVE-2017-16379/CY-2017-011。

這個漏洞的核心問題可以總結為一句話,「我們該如何檢查void *的類型?」。

我們都知道,由於void指針被定義為無類型,所以可以指向任何類型的對象,並且任何類型對象的指針都可以轉換為這種類型的指針。那麼,當我們把一個對象指針轉換為一個void指針後,仍然有可能通過某種方式檢測出它的原類型,對吧?這個問題的答案:不完全是這樣。

對象被轉換為void指針後,再檢測它的原來類型簡直就是不可能的。那麼,我們該如何檢查void *的類型?答案是別這樣做。因為當你這樣做的時候,可能會引發一個安全漏洞。

歸根到底,該漏洞是由AcroRd32.dll中的IsAVIconBundleRec6函數引起的。該函數會接收一個void指針,並嘗試用魔法(常量)值來確定它的類型。

實際上,這種做法不僅無法確定其類型,而且還會導致類型混淆漏洞,攻擊者可以利用這個漏洞對多種Adobe Reader產品實施遠程執行代碼攻擊。

漏洞分析

函數IsAVIconBundleRec6接收一個任意的void指針,並試圖確定它是否是一個指向AVIconBundleRec6對象的指針。

該函數假定,如果一個對象以特定的魔法值開頭的話,那麼它就是一個AVIconBundleRec6對象。

具體來說,該函數會進行相應測試看看是否滿足以下條件:

1.該對象是有效的可讀指針。

2.該對象的0-7位元組是魔術值「CIVAUBNO」。

3.該對象的8-11位元組是一個版本號(必須>= 0x5000)。

在大多數情況下,該函數會接收的是一個指向AVIconBundleRec6對象的有效指針,並且能夠成功識別,這不會引起任何問題。

但有些時候,函數會接收到一個HBITMAP類型的對象。 與大多數的Windows句柄(通常是有效指針,例如HMODULE)相反,HBITMAP可以是0x0-0xffffffff之間的任意值,並且不被視為有效的指針。

由於HBITMAP可以是0x0-0xffffffff之間的任意值,所以,有時它可能會在無意中指向有效的內存位置,從而滿足第1項測試(在0x601141D2處的測試)。

一旦通過了第1項測試,類型混淆就會發生,因為該函數混淆了HBITMAP的類型,並假定它是一個有效的指針,而不管它到底是不是有效指針。

那麼,在什麼情況下,用戶才會因為使用類型為HBITMAP的對象來調用這個函數而受到攻擊呢?實際上,AcroRd32Res.dll中就有一組圖標資源,這些資源將被渲染器作為HBITMAP對象來載入。所以,這些HBITMAP對象每次被渲染時(每秒渲染多次),都會作為參數發送給IsAVIconBundleRec6。

渲染器在進行初次渲染時,會從資源中載入圖標。並且,渲染器只會載入一次圖標,當它再次渲染圖標時,將使用第一次渲染時載入的HBITMAP(即渲染器緩存的HBITMAP)。這意味著,如果攻擊者能夠渲染其中一個圖標,那麼渲染器就會將其載入為HBITMAP對象,並且在每一秒內都會調用IsAVIconBundleRec6許多次。

如果HBITMAP對象無意中指向了一個有效的內存位置,那麼IsAVIconBundleRec6會把它當做一個指針,從而導致類型混淆問題。

漏洞利用

為了利用這個漏洞,我們需要:

1.創建一個指向處於我們控制下的內存位置的HBITMAP。

2.以HBITMAP為參數調用IsAVIconBundleRec6。

3.利用IsAVIconBundleRec6搞定相應測試,使其返回true值(即,使其將指向處於我們控制下的存儲器位置的HBITMAP驗收為有效的AVIconBundleRec6對象)。

4.一旦該函數驗收了HBITMAP,它就會將它作為一個有效的AVIconBundleRec6對象來使用,包括使用AVIconBundleRec6對象的AVIconHandler成員(一個類似vtable的指針)來執行各種函數調用。這樣,攻擊者就能夠接管這個類vtable的成員,從而在下一次調用該函數時完全控制EIP。

第1步

為了創建一個HBITMAP對象,我們只需渲染上面列出的一個圖標就行了。

為此,我們創建一個PDF文件,並將相應的圖標放到該文件的起始頁面即可。

一旦這個圖標被渲染,渲染器就會載入相應的圖標資源,並為其創建一個HBITMAP對象。

這個HBITMAP對象可以包含0x0-0xffffffff之間的任意值。

然後,利用處於我們控制之下的內存塊進行堆噴射,從統計上來說,我們就有機會讓HBITMAP指向處於我們控制下的一個內存塊。

由於每個圖標只能作為HBITMAP載入一次,所以我們可以渲染所有圖標,這樣就能得到8個不同的HBITMAP值,並且每個值都指向一個隨機位置。如果至少有一個指向處於我們控制之下的內存位置,我們就可以繼續執行我們接下來的漏洞利用流程。

生成8個隨機值後,其中一個或多個值很可能指向處於我們控制之下的內存位置——我們的第1步就算完成了。

第2步

渲染器會自動使用8個HBITMAP對象來調用IsAVIconBundleRec6,並且每秒都會執行許多次。

如果HBITMAP無法通過IsAVIconBundleRec6的各項測試,則該函數會「優雅地」結束。這意味著,只要圖標正處於渲染過程中,IsAVIconBundleRec6就會重複調用這8個HBITMAP值。

即使我們最初的堆噴射錯過了其中一個HBITMAP,但是由於我們會連續進行堆噴射和釋放動作,並且每秒重複多次,所以,我們很有可能會捕獲到一個HBITMAP對象。這裡不必擔心崩潰,因為任何失敗的嘗試都會「優雅地」結束。

只要有一個以上的HBITMAP指向有效的用戶模式地址,我們就能「捕獲」到它。 如果所有HBITMAP都指向我們無法控制的內存位置(例如內核空間),那麼該攻擊就會以失敗而告終。

第3步

這一步需要做的就是,設法滿足IsAVIconBundleRec6的檢查條件,以確保堆噴中包含符合AVIconBundleRec6對象結構要求的內存塊(即以「CIVAUBNO」開頭)。

第4步

IsAVIconBundleRec6一旦上當,即相信我們的內存塊是一個有效的AVIconBundleRec6對象,(在IsAVIconBundleRec6被調用之後不久)它就會使用AVIconHandler成員來調用一個函數調用。當我們控制了整個對象,包括AVIconHandler成員後,就可以將其替換,這樣在下一次調用函數時就能夠完全控制EIP了。

POC

我們的POC代碼可以根據要求再現這個漏洞(而不是利用這個漏洞)。

結束語

我們知道,根據void指針的定義來說,它是無類型的。

如果您確實需要使用void指針並且想知道該指針的類型,只需另外添加一個參數來說明其類型,或者將該指針包裝到自定義結構中,然後通過一個結構成員來說明其類型即可。

如果應用程序無視「void指針是無類型的」這一事實,而試圖檢測其類型的話,肯定會引起不必要的麻煩,在最糟糕的情況下,甚至會導致可以被攻擊者利用的安全漏洞。

備註

您一定想知道引發該漏洞的8個圖標長什麼樣吧?那好,請看:

如若轉載,請註明原文地址: 4hou.com/vulnerable/850 更多內容請關注「嘶吼專業版」——Pro4hou

推薦閱讀:

coolfire 的第一篇文章中的遠程登錄進入主機用的是win系統中的 「Telnet」 嗎?
為遏制猖獗的刷榜,蘋果把十年前的技術也搬出來用了…
HackerOne年度報告:安全眾測推出四年,成果幾何?
獨立觀點:小米科技物流訂單數據」泄露」究竟誰之過

TAG:信息安全 |