新聞中心
【.com獨(dú)家特稿】隨著惡意PDF文件日益增多,人們對(duì)這種文檔的惡意代碼分析技術(shù)也越來(lái)越感興趣。本文將教您如何分析一種特殊類型的惡意PDF文件:它們可以利用內(nèi)嵌JavaScript解釋器的安全漏洞。通過(guò)閱讀本文,還有助于分析其他類型的惡意PDF文件,如利用PDF解析器內(nèi)的安全漏洞的情形。雖然幾乎所有的惡意PDF文檔的攻擊目標(biāo)都是Windows操作系統(tǒng),但是這里介紹的PDF語(yǔ)言是獨(dú)立于操作系統(tǒng)的,它同時(shí)適用于在Windows、Linux和OSX上的PDF文檔。

一、PDF中的Hello World
現(xiàn)在,我們從手工制作一個(gè)最簡(jiǎn)單的PDF文檔開(kāi)始入手,該文檔只是在一個(gè)頁(yè)面中顯示文字Hello World而已。您很可能從未見(jiàn)過(guò)如此簡(jiǎn)陋的文檔,但是它很適合于本文的需要,因?yàn)槲覀冎粚?duì)一個(gè)PDF文檔的內(nèi)部構(gòu)造感興趣。我們的文檔僅僅包含顯示一個(gè)頁(yè)面所必需的最基本元素,如果您為該文件添加更多的格式的話,可讀性會(huì)更好一些。該文檔的特性之一是,只包含有一些ASCII字符,因此即使使用記事本這樣最簡(jiǎn)單的編輯器,同樣也能閱讀它的內(nèi)容。另一個(gè)特性是,其中含有大量(多余的)空格和縮排,這使得這個(gè)PDF的結(jié)構(gòu)更加突出。最后一個(gè)特性是,其中的內(nèi)容沒(méi)有進(jìn)行壓縮處理。
二、頭部
每個(gè)PDF文檔必須以標(biāo)明其為PDF文檔的一行代碼(即幻數(shù))開(kāi)頭;它還規(guī)定了用于描述這個(gè)文檔的PDF語(yǔ)言規(guī)范版本號(hào):%PDF-1.1。
在一個(gè)PDF文檔中,以符號(hào)%開(kāi)頭的行都是注釋行,注釋行的內(nèi)容將被忽略,但是有兩個(gè)例外:?
文檔的開(kāi)頭:%PDF-X.Y?
文檔的結(jié)尾:%%EOF
三、對(duì)象
在第一行之后,我們開(kāi)始為我們的PDF文檔添加對(duì)象,對(duì)象是PDF語(yǔ)言的基本元素。這些對(duì)象在文件中的出現(xiàn)順序?qū)?yè)面顯示時(shí)的布局沒(méi)有任何影響。不過(guò)為簡(jiǎn)單起見(jiàn),我們將按照邏輯順序來(lái)介紹這些對(duì)象。需要注意的是,PDF語(yǔ)言是大小寫(xiě)敏感的。
我們首先介紹的是catalog(即目錄)對(duì)象,它告訴PDF閱讀程序(例如Adobe的Acrobat Reader),為了裝配這個(gè)文檔,需要從哪里開(kāi)始查找對(duì)象:
這實(shí)際上是一個(gè)間接對(duì)象,因?yàn)樗哂幸粋€(gè)編號(hào),并且可以通過(guò)該編號(hào)來(lái)引用該對(duì)象。其語(yǔ)法很簡(jiǎn)單:一個(gè)編號(hào)、一個(gè)版本號(hào)、單詞obj、對(duì)象本身,最后是單詞endobj,如下所示:
通過(guò)聯(lián)合使用對(duì)象編號(hào)和版本號(hào),我們就能夠唯一地引用一個(gè)對(duì)象。
我們第一個(gè)對(duì)象catalog的類型是字典類型,字典類型在pdf文檔中非常常見(jiàn)。該類型以符號(hào)<<開(kāi)頭,并以符合>>作為結(jié)束,如下所示:
字典的元素由鍵和值兩部分組成,也就是說(shuō)一個(gè)元素就是一個(gè)名/值對(duì),即數(shù)據(jù)有一個(gè)名稱,還有一個(gè)與之相對(duì)應(yīng)的值;字典不僅可以存放元素,而且還能存放對(duì)象甚至其他字典。 大部分字典都是利用第一個(gè)元素來(lái)聲明自身的類型,該元素以/type為鍵,其后跟一個(gè)類型本身的名稱(對(duì)本例而言就是/Catalog)為值:
對(duì)象catalog必須給出在這個(gè)PDF中能找到的頁(yè)面(對(duì)應(yīng)于pages對(duì)象)和大綱(對(duì)應(yīng)于outline對(duì)象),如下:
2 0 R和3 0 R 分別表示引用間接對(duì)象2和間接對(duì)象3。間接對(duì)象2描述大綱,間接對(duì)象3描述頁(yè)面。
下面開(kāi)始為我們的PDF文檔添加第二個(gè)間接對(duì)象:
通過(guò)前面對(duì)間接對(duì)象1的說(shuō)明,您現(xiàn)在應(yīng)該對(duì)這個(gè)對(duì)象的語(yǔ)法并不陌生了。這個(gè)對(duì)象是一個(gè)/Outlines類型的字典。它具有一個(gè)鍵為/Count、值為0的元素,這意味著這個(gè)PDF文檔沒(méi)有大綱。我們可以通過(guò)編號(hào)2和版本0來(lái)引用這個(gè)對(duì)象。
讓我們總結(jié)一下我們的PDF文檔已有的內(nèi)容:?
PDF標(biāo)識(shí)行?
間接對(duì)象1:catalog?
間接對(duì)象2:outline
在添加文字頁(yè)面之前,讓我們演示PDF語(yǔ)言的另一個(gè)特性。我們的1號(hào)對(duì)象catalog引用了我們的2號(hào)對(duì)象outline,如圖1所示。
| 圖1 引用間接對(duì)象 |
PDF語(yǔ)言還允許我們把2號(hào)對(duì)象直接嵌入到1號(hào)對(duì)象中,如圖2所示。
| 圖2 被嵌入到對(duì)象中的間接對(duì)象 |
事實(shí)上,outline對(duì)象的長(zhǎng)度只有一行,并且對(duì)語(yǔ)義也沒(méi)有什么影響,現(xiàn)在只是為了可讀性才加上。先不管它,我們繼續(xù)組裝我們的PDF文檔。我們前面定義了catalog(目錄)和outlines(大綱)對(duì)象,接下來(lái)還得定義我們的頁(yè)面。
除/Kids元素之外,下面的代碼應(yīng)該很容易理解。Kids 元素是一個(gè)頁(yè)面列表;一個(gè)列表必須用方括弧括住。因此依據(jù)這個(gè)Pages對(duì)象來(lái)看,我們的文檔中只有一個(gè)頁(yè)面;這個(gè)頁(yè)面的具體規(guī)定,見(jiàn)間接對(duì)象4(注意引用4 0 R ):
要描述頁(yè)面,我們必須規(guī)定頁(yè)面的內(nèi)容、用于顯示這個(gè)頁(yè)面的資源以及頁(yè)面的大小。這些任務(wù)可由下面的代碼來(lái)完成:
頁(yè)面內(nèi)容是由間接對(duì)象5來(lái)規(guī)定的。/MediaBox 是頁(yè)面的尺寸。這個(gè)頁(yè)面所用的資源是字體和PDF文字繪制例程。我們?cè)陂g接對(duì)象6中將字體規(guī)定為[F1]。
間接對(duì)象5中存放的是頁(yè)面內(nèi)容,它是一種特殊的對(duì)象,即流對(duì)象。流對(duì)象可以用來(lái)保存由單詞stream和endstream包圍的對(duì)象內(nèi)容。流對(duì)象的好處是允許使用多種類型的編碼技術(shù)(在PDF語(yǔ)言中稱為過(guò)濾器),例如壓縮(例如zlib FlateDecode編碼)。考慮到易讀性,我們沒(méi)有在這個(gè)流中實(shí)施壓縮處理:
這個(gè)流的內(nèi)容是一組PDF文字繪制指令。這些指令是由BT和ET括起來(lái)的,實(shí)際上就是命令繪制例程做下面的事情:?
使用大小為24的F1字體?
轉(zhuǎn)到100 700位置處?
繪制文字:Hello World
在PDF語(yǔ)言中,字符串必須用圓括號(hào)括起來(lái)。
我們的PDF文檔已經(jīng)基本上組裝好了。我們需要的最后一個(gè)對(duì)象是font(字體)對(duì)象:
現(xiàn)在,閱讀這個(gè)結(jié)構(gòu)您應(yīng)該沒(méi)有問(wèn)題了。#p#
四、尾部
上面就是繪制一個(gè)頁(yè)面所需的全部對(duì)象。但是僅有這些內(nèi)容還不足以使閱讀程序(即顯示pdf文檔的程序,如Adobe的Acrobat Reader)來(lái)讀取和顯示我們的PDF文檔。繪制例程需要知道文檔描述起始于哪個(gè)對(duì)象(即root對(duì)象),以及每個(gè)對(duì)象的索引之類的技術(shù)細(xì)節(jié)。
每個(gè)對(duì)象的索引稱為交叉引用xref,它描述每個(gè)間接對(duì)象的編號(hào)、版本和絕對(duì)的文件位置。PDF文檔中的第一個(gè)索引必須從版本為65535的0號(hào)對(duì)象開(kāi)始:
標(biāo)識(shí)符xref后面的第一個(gè)數(shù)字是第一個(gè)間接對(duì)象(這里是0號(hào)對(duì)象)的編號(hào),第二個(gè)數(shù)字是xref表(7個(gè)表項(xiàng))的大小。
第一欄是間接對(duì)象的絕對(duì)位置。第二行的值12表明間接對(duì)象1的起始地址距文件開(kāi)頭為12字節(jié)。第二欄是版本,第三欄指出對(duì)象正在使用(用n表示)還是已經(jīng)釋放(用f表示)。
定義交叉引用之后,我們?cè)谖膊恐卸xroot對(duì)象:
不難看出,這是一個(gè)字典。最后,我們需要利用xref元素的絕對(duì)位置和幻數(shù)%%EOF來(lái)結(jié)束這個(gè)PDF文檔:
其中,644是在這個(gè)PDF文件內(nèi)的xref的絕對(duì)位置。
五、PDF文檔基礎(chǔ)知識(shí)的回顧
我們一旦了解了PDF語(yǔ)言的語(yǔ)法和語(yǔ)義,就能輕松構(gòu)建一個(gè)簡(jiǎn)單的PDF文檔。為了便于閱讀,我們?cè)谇鍐?中給出了完整的PDF文檔。
清單 1 完整的PDF文檔頁(yè)面內(nèi)容#p#
六、添加有效載荷
因?yàn)槲覀兿胍治鰩в蠮avaScript有效載荷的惡意PDF文檔,因此需要了解如何添加JavaScript代碼并設(shè)法使其運(yùn)行。PDF語(yǔ)言支持為事件關(guān)聯(lián)相應(yīng)的動(dòng)作。舉例來(lái)說(shuō),當(dāng)某個(gè)頁(yè)面被查看的時(shí)候,可以執(zhí)行相應(yīng)的動(dòng)作(例如 訪問(wèn)一個(gè)網(wǎng)站)。我們感興趣的是在打開(kāi)一個(gè)PDF文檔的時(shí)候執(zhí)行某個(gè)動(dòng)作。通過(guò)為catalog對(duì)象添加一個(gè)/OpenAction鍵,我們可以讓PDF文檔在打開(kāi)時(shí)無(wú)需人工介入就執(zhí)行某個(gè)動(dòng)作。
當(dāng)打開(kāi)我們的PDF文檔的時(shí)候,間接對(duì)象7所規(guī)定的動(dòng)作將被執(zhí)行。我們可以規(guī)定一個(gè)URI動(dòng)作。一個(gè)URI動(dòng)作能夠自動(dòng)地打開(kāi)一個(gè)URI,在我們這個(gè)例子中是一個(gè)URL:
七、內(nèi)嵌的 JavaScript
PDF語(yǔ)言支持內(nèi)嵌的 JavaScript。然而,這個(gè)JavaScript引擎在與底層操作系統(tǒng)的交互方面能力非常有限,所以根本沒(méi)法干壞事。 舉例來(lái)說(shuō),嵌入到一個(gè)PDF文檔的JavaScript代碼不能訪問(wèn)任何文件。所以,惡意PDF文檔必須利用某些安全漏洞才能擺脫JavaScript引擎的限制來(lái)執(zhí)行任意的代碼。我們可以使用下面的JavaScript動(dòng)作,在PDF文檔打開(kāi)時(shí)添加并執(zhí)行一些JavaScript腳本:
下面的代碼將執(zhí)行一個(gè)向JavaScript調(diào)試控制臺(tái)顯示Hello的腳本:
#p#
八、安全漏洞的利用
去年,許多惡意PDF文檔利用了PDF的util.printf方法的JavaScript安全漏洞來(lái)發(fā)動(dòng)攻擊。Core Security Technologies發(fā)表了一個(gè)通報(bào),其中含有一個(gè)PoC,如下所示:
當(dāng)這個(gè)JavaScript將被嵌入到一個(gè)PDF文檔并在(在 Windows XP SP2上使用Adobe Acrobat Reader 8.1.2)打開(kāi)的時(shí)候,它將試圖執(zhí)行地址0x30303030的代碼而造成訪問(wèn)越界。 這意味著,通過(guò)緩沖區(qū)溢出,執(zhí)行PoC將跳轉(zhuǎn)至地址0x30303030(0x30是ASCII字符0的十六進(jìn)制表示法)(即PoC一執(zhí)行,控制流程(系統(tǒng)控制權(quán))就交給0x30303030處的指令)。 因此要想利用該漏洞,我們需要編寫(xiě)我們的程序(shellcode),當(dāng)然該程序需要從0x30303030處開(kāi)始執(zhí)行。
使用內(nèi)嵌的JavaScript的問(wèn)題是,我們不能直接寫(xiě)內(nèi)存。Heap Spraying(堆噴射)是一種較易獲得任意代碼執(zhí)行Exploit的技術(shù)手段。 每當(dāng)我們?cè)贘avaScript中聲明字符串并為其賦值時(shí),這個(gè)字符串就會(huì)被寫(xiě)到一段內(nèi)存中,這段內(nèi)存是從堆中分配的,所謂堆就是專門(mén)預(yù)留給程序變量的一部分內(nèi)存。 我們沒(méi)有影響被使用的那些內(nèi)存,所以我們不能命令JavaScript使用地址0x30303030的內(nèi)存。 但是如果我們分配大量的字符串,那么很可能其中的一個(gè)字符串分配的內(nèi)存中包含了地址0x30303030。 分配許許多多的字符串稱為Heap Spraying(堆噴射)。
如果我們?cè)诙褔娚渲髨?zhí)行我們的PoC,就很有可能得到一個(gè)從地址0x30303030之前的某處開(kāi)始、從地址0x30303030之后的某處終止的字符串,這樣的話,該字符串中(起始于地址0x30303030)那些字節(jié)就會(huì)被CPU當(dāng)作機(jī)器代碼語(yǔ)句來(lái)執(zhí)行。
但是,如何讓我們指定的字符串包含用來(lái)利用起始于地址0x30303030的機(jī)器指令的正確語(yǔ)句呢? 同樣,我們也無(wú)法直接完成這個(gè)任務(wù);我們需要一種迂回戰(zhàn)術(shù)。
如果我們?cè)O(shè)法使一個(gè)字符串被CPU當(dāng)作機(jī)器代碼程序(shellcode)來(lái)解釋的話,那么CPU將開(kāi)始執(zhí)行我們從地址0x30303030開(kāi)始的程序。 不過(guò)這個(gè)方法不太理想;我們的程序必須從它的第一條指令開(kāi)始執(zhí)行,而不是從中間的某個(gè)地方開(kāi)始執(zhí)行。為了解決這個(gè)問(wèn)題,我們需要在程序前面填充大量NOP指令。 我們?cè)谟糜诙褔娚涞淖址写鎯?chǔ)這個(gè)NOP-sled,繼之以我們shellcode。 NOP-sled是一個(gè)特殊程序,它的特性是每個(gè)指令的長(zhǎng)度都是單字,而且每個(gè)指令都沒(méi)有時(shí)間的操作(NOP,即空操作 ),那就是說(shuō) CPU不斷執(zhí)行下一個(gè)NOP指令,如此下去直到它到達(dá)我們的shellcode并且執(zhí)行它(滑下NOP-sled)。
下面是一個(gè)堆噴射的范例,實(shí)際取自一個(gè)帶有NOP-sled和shellcode的惡意PDF文檔(參見(jiàn) 圖 3)。
| 圖3 JavaScript堆噴射 |
Sccs是帶有shellcode的字符串,bgbl是帶有NOP-code的字符串。
因?yàn)閟hellcode常常必須很小,所以它將通過(guò)網(wǎng)絡(luò)下載另一個(gè)程序(惡意軟件)并執(zhí)行它。對(duì)于pdf文檔來(lái)說(shuō),還有一種方法可用。第二階段的程序可以嵌入到PDF文檔,而shellcode可以從PDF文檔提取并且執(zhí)行。
九、分析惡意PDF文檔
事實(shí)上,所有的pdf文檔都包含非ASCII字符,因此我們需要使用一個(gè)十六進(jìn)制編輯器來(lái)分析它們。我們打開(kāi)一個(gè)可疑的PDF文檔,并搜索字符串JavaScript(參見(jiàn)圖 4)。
| 圖4 JavaScript 對(duì)象 |
雖然只是有一點(diǎn)用于格式化對(duì)象的空格,但是您應(yīng)該認(rèn)出PDF對(duì)象的結(jié)構(gòu):對(duì)象31是一個(gè)JavaScript動(dòng)作/S /JavaScript,腳本本身沒(méi)有包含在這個(gè)對(duì)象中,但是可以在對(duì)象32(注意引用3 0 R)中找到。 搜索字符串“31 0 R”,我們發(fā)現(xiàn)對(duì)象16引用了對(duì)象31“/AA <> ”,以及一個(gè)頁(yè)面/Type /Page ,如圖5所示。
| 圖5 頁(yè)對(duì)象 |
/AA 是一個(gè)注釋動(dòng)作,這意味著當(dāng)這個(gè)頁(yè)面被查看的時(shí)候這個(gè)動(dòng)作就會(huì)執(zhí)行。因此,我們知道:當(dāng)這個(gè)PDF文檔被打開(kāi)的時(shí)候,它將執(zhí)行一個(gè)JavaScript腳本。 讓我們看看這個(gè)腳本(對(duì)象32 )的樣子。
對(duì)象32是一個(gè)流對(duì)象,而且它是經(jīng)過(guò)壓縮的(/Filter [/FlateDecode]),見(jiàn)圖 6。
| 圖6 流對(duì)象 |
為了對(duì)它進(jìn)行解壓,我們可以提取二進(jìn)制流(1154字節(jié)長(zhǎng)),并通過(guò)一個(gè)簡(jiǎn)單的Perl或者Python程序?qū)λM(jìn)行解壓。使用Python語(yǔ)言,我們只需要導(dǎo)入zlib,然后就可以對(duì)數(shù)據(jù)進(jìn)行解壓了,假設(shè)我們已經(jīng)將我們的二進(jìn)制流存儲(chǔ)在data中了:
然而有一點(diǎn)非常清楚:那就是解壓后的腳本是惡意的,它會(huì)對(duì)函數(shù)collectEmailInfo中的一個(gè)安全漏洞加以利用,如圖7所示。
| 圖7 利用collectEmailInfo |
十、結(jié)束語(yǔ)
隨著惡意PDF文件日益增多,人們對(duì)這種文檔的惡意代碼分析技術(shù)也越來(lái)越感興趣。本文向讀者詳細(xì)介紹了如何分析一種特殊類型的惡意PDF文件:它們可以利用內(nèi)嵌JavaScript解釋器的安全漏洞。當(dāng)然,有了本文的基礎(chǔ),在分析其他類型的惡意PDF文件,如利用PDF解析器內(nèi)的安全漏洞的情形的時(shí)候,您也能觸類旁通。需要說(shuō)明的是,雖然幾乎所有的惡意PDF文檔的攻擊目標(biāo)都是Windows操作系統(tǒng),但是這里介紹的PDF語(yǔ)言是獨(dú)立于操作系統(tǒng)的,它同時(shí)適用于在Windows、Linux和OSX上的PDF文檔。
【.COM 獨(dú)家特稿,轉(zhuǎn)載請(qǐng)注明出處及作者!】
【編輯推薦】
- Adobe曝重大安全漏洞,小心打開(kāi)PDF文件
- 看PDF和Flash中毒后快速解決方法
當(dāng)前文章:深入淺出實(shí)戰(zhàn)攻防惡意PDF文檔
文章網(wǎng)址:http://m.fisionsoft.com.cn/article/ccedidi.html


咨詢
建站咨詢
