自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入淺出實(shí)戰(zhàn)攻防惡意PDF文檔

原創(chuàng)
安全 黑客攻防
本文將教您如何分析一種特殊類型的惡意PDF文件:它們可以利用內(nèi)嵌JavaScript解釋器的安全漏洞。

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

一、PDF中的Hello World

現(xiàn)在,我們從手工制作一個(gè)最簡單的PDF文檔開始入手,該文檔只是在一個(gè)頁面中顯示文字Hello World而已。您很可能從未見過如此簡陋的文檔,但是它很適合于本文的需要,因?yàn)槲覀冎粚?duì)一個(gè)PDF文檔的內(nèi)部構(gòu)造感興趣。我們的文檔僅僅包含顯示一個(gè)頁面所必需的最基本元素,如果您為該文件添加更多的格式的話,可讀性會(huì)更好一些。該文檔的特性之一是,只包含有一些ASCII字符,因此即使使用記事本這樣最簡單的編輯器,同樣也能閱讀它的內(nèi)容。另一個(gè)特性是,其中含有大量(多余的)空格和縮排,這使得這個(gè)PDF的結(jié)構(gòu)更加突出。最后一個(gè)特性是,其中的內(nèi)容沒有進(jìn)行壓縮處理。

二、頭部

每個(gè)PDF文檔必須以標(biāo)明其為PDF文檔的一行代碼(即幻數(shù))開頭;它還規(guī)定了用于描述這個(gè)文檔的PDF語言規(guī)范版本號(hào):%PDF-1.1。

在一個(gè)PDF文檔中,以符號(hào)%開頭的行都是注釋行,注釋行的內(nèi)容將被忽略,但是有兩個(gè)例外: 

文檔的開頭:%PDF-X.Y 

文檔的結(jié)尾:%%EOF

三、對(duì)象

在第一行之后,我們開始為我們的PDF文檔添加對(duì)象,對(duì)象是PDF語言的基本元素。這些對(duì)象在文件中的出現(xiàn)順序?qū)撁骘@示時(shí)的布局沒有任何影響。不過為簡單起見,我們將按照邏輯順序來介紹這些對(duì)象。需要注意的是,PDF語言是大小寫敏感的。

我們首先介紹的是catalog(即目錄)對(duì)象,它告訴PDF閱讀程序(例如Adobe的Acrobat Reader),為了裝配這個(gè)文檔,需要從哪里開始查找對(duì)象:

1 0 obj
/Type /Catalog
/Outlines 2 0 R
/Pages 3 0 R

這實(shí)際上是一個(gè)間接對(duì)象,因?yàn)樗哂幸粋€(gè)編號(hào),并且可以通過該編號(hào)來引用該對(duì)象。其語法很簡單:一個(gè)編號(hào)、一個(gè)版本號(hào)、單詞obj、對(duì)象本身,最后是單詞endobj,如下所示:

1 0 obj
object
endobj

通過聯(lián)合使用對(duì)象編號(hào)和版本號(hào),我們就能夠唯一地引用一個(gè)對(duì)象。

我們第一個(gè)對(duì)象catalog的類型是字典類型,字典類型在pdf文檔中非常常見。該類型以符號(hào)<<開頭,并以符合>>作為結(jié)束,如下所示:

dictionary content

字典的元素由鍵和值兩部分組成,也就是說一個(gè)元素就是一個(gè)名/值對(duì),即數(shù)據(jù)有一個(gè)名稱,還有一個(gè)與之相對(duì)應(yīng)的值;字典不僅可以存放元素,而且還能存放對(duì)象甚至其他字典。 大部分字典都是利用第一個(gè)元素來聲明自身的類型,該元素以/type為鍵,其后跟一個(gè)類型本身的名稱(對(duì)本例而言就是/Catalog)為值:

(/Type /Catalog)

對(duì)象catalog必須給出在這個(gè)PDF中能找到的頁面(對(duì)應(yīng)于pages對(duì)象)和大綱(對(duì)應(yīng)于outline對(duì)象),如下:

/Outlines 2 0 R
/Pages 3 0 R

2 0 R和3 0 R 分別表示引用間接對(duì)象2和間接對(duì)象3。間接對(duì)象2描述大綱,間接對(duì)象3描述頁面。

下面開始為我們的PDF文檔添加第二個(gè)間接對(duì)象:

2 0 obj
/Type /Outlines
/Count 0
endobj

通過前面對(duì)間接對(duì)象1的說明,您現(xiàn)在應(yīng)該對(duì)這個(gè)對(duì)象的語法并不陌生了。這個(gè)對(duì)象是一個(gè)/Outlines類型的字典。它具有一個(gè)鍵為/Count、值為0的元素,這意味著這個(gè)PDF文檔沒有大綱。我們可以通過編號(hào)2和版本0來引用這個(gè)對(duì)象。

讓我們總結(jié)一下我們的PDF文檔已有的內(nèi)容: 

PDF標(biāo)識(shí)行 

間接對(duì)象1:catalog 

間接對(duì)象2:outline

在添加文字頁面之前,讓我們演示PDF語言的另一個(gè)特性。我們的1號(hào)對(duì)象catalog引用了我們的2號(hào)對(duì)象outline,如圖1所示。

 
圖1   引用間接對(duì)象

PDF語言還允許我們把2號(hào)對(duì)象直接嵌入到1號(hào)對(duì)象中,如圖2所示。

 
圖2   被嵌入到對(duì)象中的間接對(duì)象

事實(shí)上,outline對(duì)象的長度只有一行,并且對(duì)語義也沒有什么影響,現(xiàn)在只是為了可讀性才加上。先不管它,我們繼續(xù)組裝我們的PDF文檔。我們前面定義了catalog(目錄)和outlines(大綱)對(duì)象,接下來還得定義我們的頁面。

除/Kids元素之外,下面的代碼應(yīng)該很容易理解。Kids 元素是一個(gè)頁面列表;一個(gè)列表必須用方括弧括住。因此依據(jù)這個(gè)Pages對(duì)象來看,我們的文檔中只有一個(gè)頁面;這個(gè)頁面的具體規(guī)定,見間接對(duì)象4(注意引用4 0 R ):

3 0 obj
/Type /Pages
/Kids [4 0 R]
/Count 1
endobj

要描述頁面,我們必須規(guī)定頁面的內(nèi)容、用于顯示這個(gè)頁面的資源以及頁面的大小。這些任務(wù)可由下面的代碼來完成:

4 0 obj
/Type /Page
/Parent 3 0 R
/MediaBox [0 0 612 792]
/Contents 5 0 R
/Resources <<
/ProcSet [/PDF /Text]
/Font << /F1 6 0 R >>
endobj

頁面內(nèi)容是由間接對(duì)象5來規(guī)定的。/MediaBox 是頁面的尺寸。這個(gè)頁面所用的資源是字體和PDF文字繪制例程。我們在間接對(duì)象6中將字體規(guī)定為[F1]。

間接對(duì)象5中存放的是頁面內(nèi)容,它是一種特殊的對(duì)象,即流對(duì)象。流對(duì)象可以用來保存由單詞stream和endstream包圍的對(duì)象內(nèi)容。流對(duì)象的好處是允許使用多種類型的編碼技術(shù)(在PDF語言中稱為過濾器),例如壓縮(例如zlib FlateDecode編碼)。考慮到易讀性,我們沒有在這個(gè)流中實(shí)施壓縮處理:

5 0 obj
 
/Length 43 >>

stream

BT /F1 24 Tf 100 700 Td (Hello World) Tj ET

endstream

endobj

這個(gè)流的內(nèi)容是一組PDF文字繪制指令。這些指令是由BT和ET括起來的,實(shí)際上就是命令繪制例程做下面的事情: 

使用大小為24的F1字體 

轉(zhuǎn)到100 700位置處 

繪制文字:Hello World

在PDF語言中,字符串必須用圓括號(hào)括起來。

我們的PDF文檔已經(jīng)基本上組裝好了。我們需要的最后一個(gè)對(duì)象是font(字體)對(duì)象:

6 0 obj
/Type /Font
Subtype /Type1
/Name /F1
/BaseFont /Helvetica
/Encoding /MacRomanEncoding
endobj

現(xiàn)在,閱讀這個(gè)結(jié)構(gòu)您應(yīng)該沒有問題了。#p#

四、尾部

上面就是繪制一個(gè)頁面所需的全部對(duì)象。但是僅有這些內(nèi)容還不足以使閱讀程序(即顯示pdf文檔的程序,如Adobe的Acrobat Reader)來讀取和顯示我們的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ì)象開始:

標(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的起始地址距文件開頭為12字節(jié)。第二欄是版本,第三欄指出對(duì)象正在使用(用n表示)還是已經(jīng)釋放(用f表示)。

定義交叉引用之后,我們在尾部中定義root對(duì)象:

trailer
/Size 7
/Root 1 0 R

不難看出,這是一個(gè)字典。最后,我們需要利用xref元素的絕對(duì)位置和幻數(shù)%%EOF來結(jié)束這個(gè)PDF文檔:

startxref
644
%%EOF

其中,644是在這個(gè)PDF文件內(nèi)的xref的絕對(duì)位置。

五、PDF文檔基礎(chǔ)知識(shí)的回顧

我們一旦了解了PDF語言的語法和語義,就能輕松構(gòu)建一個(gè)簡單的PDF文檔。為了便于閱讀,我們在清單1中給出了完整的PDF文檔。

%PDF-1.1
1 0 obj
/Type /Catalog /Outlines 2 0 R /Pages 3 0 R

endobj

2 0 obj

/Type /Outlines /Count 0

endobj

3 0 obj

/Type /Pages /Kids [4 0 R] /Count 1

endobj

4 0 obj

 /Type /Page /Parent 3 0 R /MediaBox [0 0 612 792] /Contents 5 0 R

/Resources <<            

/ProcSet [/PDF /Text]            

/Font << /F1 6 0 R >>

endobj

5 0 obj

/Length 43 >>

stream

BT /F1 24 Tf 100 700 Td (Hello World) Tj ET

endstream

endobj

6 0 obj

/Type /Font /

Subtype /Type1 

/Name /F1 

/BaseFont /Helvetica 

/Encoding /MacRomanEncoding

endobj

xref

0 7

0000000000 65535 f

0000000012 00000 n

0000000089 00000 n

0000000145 00000 n

0000000214 00000 n

0000000419 00000 n

0000000520 00000 n

trailer

/Size 7 /Root 1 0 R

startxref

644

%%EOF

清單 1  完整的PDF文檔頁面內(nèi)容#p#

六、添加有效載荷

因?yàn)槲覀兿胍治鰩в蠮avaScript有效載荷的惡意PDF文檔,因此需要了解如何添加JavaScript代碼并設(shè)法使其運(yùn)行。PDF語言支持為事件關(guān)聯(lián)相應(yīng)的動(dòng)作。舉例來說,當(dāng)某個(gè)頁面被查看的時(shí)候,可以執(zhí)行相應(yīng)的動(dòng)作(例如 訪問一個(gè)網(wǎng)站)。我們感興趣的是在打開一個(gè)PDF文檔的時(shí)候執(zhí)行某個(gè)動(dòng)作。通過為catalog對(duì)象添加一個(gè)/OpenAction鍵,我們可以讓PDF文檔在打開時(shí)無需人工介入就執(zhí)行某個(gè)動(dòng)作。

1 0 obj
/Type /Catalog
/Outlines 2 0 R
/Pages 3 0 R
/OpenAction 7 0 R
endobj

當(dāng)打開我們的PDF文檔的時(shí)候,間接對(duì)象7所規(guī)定的動(dòng)作將被執(zhí)行。我們可以規(guī)定一個(gè)URI動(dòng)作。一個(gè)URI動(dòng)作能夠自動(dòng)地打開一個(gè)URI,在我們這個(gè)例子中是一個(gè)URL:

7 0 obj
/Type /Action
/S /URI
/URI (https://DidierStevens.com)
endobj
ss 

七、內(nèi)嵌的 JavaScript

PDF語言支持內(nèi)嵌的 JavaScript。然而,這個(gè)JavaScript引擎在與底層操作系統(tǒng)的交互方面能力非常有限,所以根本沒法干壞事。 舉例來說,嵌入到一個(gè)PDF文檔的JavaScript代碼不能訪問任何文件。所以,惡意PDF文檔必須利用某些安全漏洞才能擺脫JavaScript引擎的限制來執(zhí)行任意的代碼。我們可以使用下面的JavaScript動(dòng)作,在PDF文檔打開時(shí)添加并執(zhí)行一些JavaScript腳本:

7 0 obj
/Type /Action
/S /JavaScript
/JS (console.println("Hello"))
endobj

下面的代碼將執(zhí)行一個(gè)向JavaScript調(diào)試控制臺(tái)顯示Hello的腳本:

console.println("Hello")
#p#

八、安全漏洞的利用

去年,許多惡意PDF文檔利用了PDF的util.printf方法的JavaScript安全漏洞來發(fā)動(dòng)攻擊。Core Security Technologies發(fā)表了一個(gè)通報(bào),其中含有一個(gè)PoC,如下所示:

var num = 12999999999999999999888888.....
util.printf(„%45000f”,num)

當(dāng)這個(gè)JavaScript將被嵌入到一個(gè)PDF文檔并在(在 Windows XP SP2上使用Adobe Acrobat Reader 8.1.2)打開的時(shí)候,它將試圖執(zhí)行地址0x30303030的代碼而造成訪問越界。 這意味著,通過緩沖區(qū)溢出,執(zhí)行PoC將跳轉(zhuǎn)至地址0x30303030(0x30是ASCII字符0的十六進(jìn)制表示法)(即PoC一執(zhí)行,控制流程(系統(tǒng)控制權(quán))就交給0x30303030處的指令)。 因此要想利用該漏洞,我們需要編寫我們的程序(shellcode),當(dāng)然該程序需要從0x30303030處開始執(zhí)行。

使用內(nèi)嵌的JavaScript的問題是,我們不能直接寫內(nèi)存。Heap Spraying(堆噴射)是一種較易獲得任意代碼執(zhí)行Exploit的技術(shù)手段。 每當(dāng)我們在JavaScript中聲明字符串并為其賦值時(shí),這個(gè)字符串就會(huì)被寫到一段內(nèi)存中,這段內(nèi)存是從堆中分配的,所謂堆就是專門預(yù)留給程序變量的一部分內(nèi)存。 我們沒有影響被使用的那些內(nèi)存,所以我們不能命令JavaScript使用地址0x30303030的內(nèi)存。 但是如果我們分配大量的字符串,那么很可能其中的一個(gè)字符串分配的內(nèi)存中包含了地址0x30303030。 分配許許多多的字符串稱為Heap Spraying(堆噴射)。

如果我們在堆噴射之后執(zhí)行我們的PoC,就很有可能得到一個(gè)從地址0x30303030之前的某處開始、從地址0x30303030之后的某處終止的字符串,這樣的話,該字符串中(起始于地址0x30303030)那些字節(jié)就會(huì)被CPU當(dāng)作機(jī)器代碼語句來執(zhí)行。

但是,如何讓我們指定的字符串包含用來利用起始于地址0x30303030的機(jī)器指令的正確語句呢? 同樣,我們也無法直接完成這個(gè)任務(wù);我們需要一種迂回戰(zhàn)術(shù)。

如果我們設(shè)法使一個(gè)字符串被CPU當(dāng)作機(jī)器代碼程序(shellcode)來解釋的話,那么CPU將開始執(zhí)行我們從地址0x30303030開始的程序。 不過這個(gè)方法不太理想;我們的程序必須從它的第一條指令開始執(zhí)行,而不是從中間的某個(gè)地方開始執(zhí)行。為了解決這個(gè)問題,我們需要在程序前面填充大量NOP指令。 我們在用于堆噴射的字符串中存儲(chǔ)這個(gè)NOP-sled,繼之以我們shellcode。 NOP-sled是一個(gè)特殊程序,它的特性是每個(gè)指令的長度都是單字,而且每個(gè)指令都沒有時(shí)間的操作(NOP,即空操作 ),那就是說 CPU不斷執(zhí)行下一個(gè)NOP指令,如此下去直到它到達(dá)我們的shellcode并且執(zhí)行它(滑下NOP-sled)。

下面是一個(gè)堆噴射的范例,實(shí)際取自一個(gè)帶有NOP-sled和shellcode的惡意PDF文檔(參見 圖 3)。

 
圖3 JavaScript堆噴射

Sccs是帶有shellcode的字符串,bgbl是帶有NOP-code的字符串。

因?yàn)閟hellcode常常必須很小,所以它將通過網(wǎng)絡(luò)下載另一個(gè)程序(惡意軟件)并執(zhí)行它。對(duì)于pdf文檔來說,還有一種方法可用。第二階段的程序可以嵌入到PDF文檔,而shellcode可以從PDF文檔提取并且執(zhí)行。

九、分析惡意PDF文檔

事實(shí)上,所有的pdf文檔都包含非ASCII字符,因此我們需要使用一個(gè)十六進(jìn)制編輯器來分析它們。我們打開一個(gè)可疑的PDF文檔,并搜索字符串JavaScript(參見圖 4)。

 
圖4    JavaScript 對(duì)象

雖然只是有一點(diǎn)用于格式化對(duì)象的空格,但是您應(yīng)該認(rèn)出PDF對(duì)象的結(jié)構(gòu):對(duì)象31是一個(gè)JavaScript動(dòng)作/S /JavaScript,腳本本身沒有包含在這個(gè)對(duì)象中,但是可以在對(duì)象32(注意引用3 0 R)中找到。 搜索字符串“31 0 R”,我們發(fā)現(xiàn)對(duì)象16引用了對(duì)象31“/AA <> ”,以及一個(gè)頁面/Type /Page ,如圖5所示。

 
圖5 頁對(duì)象

/AA 是一個(gè)注釋動(dòng)作,這意味著當(dāng)這個(gè)頁面被查看的時(shí)候這個(gè)動(dòng)作就會(huì)執(zhí)行。因此,我們知道:當(dāng)這個(gè)PDF文檔被打開的時(shí)候,它將執(zhí)行一個(gè)JavaScript腳本。 讓我們看看這個(gè)腳本(對(duì)象32 )的樣子。

對(duì)象32是一個(gè)流對(duì)象,而且它是經(jīng)過壓縮的(/Filter [/FlateDecode]),見圖 6。

 
圖6  流對(duì)象

為了對(duì)它進(jìn)行解壓,我們可以提取二進(jìn)制流(1154字節(jié)長),并通過一個(gè)簡單的Perl或者Python程序?qū)λM(jìn)行解壓。使用Python語言,我們只需要導(dǎo)入zlib,然后就可以對(duì)數(shù)據(jù)進(jìn)行解壓了,假設(shè)我們已經(jīng)將我們的二進(jìn)制流存儲(chǔ)在data中了:

import zlib
decompressed = zlib.decompress(data)

然而有一點(diǎn)非常清楚:那就是解壓后的腳本是惡意的,它會(huì)對(duì)函數(shù)collectEmailInfo中的一個(gè)安全漏洞加以利用,如圖7所示。

 
圖7   利用collectEmailInfo

十、結(jié)束語

隨著惡意PDF文件日益增多,人們對(duì)這種文檔的惡意代碼分析技術(shù)也越來越感興趣。本文向讀者詳細(xì)介紹了如何分析一種特殊類型的惡意PDF文件:它們可以利用內(nèi)嵌JavaScript解釋器的安全漏洞。當(dāng)然,有了本文的基礎(chǔ),在分析其他類型的惡意PDF文件,如利用PDF解析器內(nèi)的安全漏洞的情形的時(shí)候,您也能觸類旁通。需要說明的是,雖然幾乎所有的惡意PDF文檔的攻擊目標(biāo)都是Windows操作系統(tǒng),但是這里介紹的PDF語言是獨(dú)立于操作系統(tǒng)的,它同時(shí)適用于在Windows、Linux和OSX上的PDF文檔。

【51CTO.COM 獨(dú)家特稿,轉(zhuǎn)載請注明出處及作者!】

【編輯推薦】

  1. Adobe曝重大安全漏洞,小心打開PDF文件
  2. 看PDF和Flash中毒后快速解決方法
責(zé)任編輯:許鳳麗 來源: 51CTO.com
相關(guān)推薦

2011-07-04 10:39:57

Web

2021-03-16 08:54:35

AQSAbstractQueJava

2022-09-26 09:01:15

語言數(shù)據(jù)JavaScript

2017-07-02 18:04:53

塊加密算法AES算法

2019-01-07 15:29:07

HadoopYarn架構(gòu)調(diào)度器

2021-07-20 15:20:02

FlatBuffers阿里云Java

2012-05-21 10:06:26

FrameworkCocoa

2020-12-09 09:59:40

Redis原理實(shí)戰(zhàn)

2009-11-17 17:31:58

Oracle COMM

2021-07-19 11:54:15

MySQL優(yōu)先隊(duì)列

2023-12-04 13:22:00

JavaScript異步編程

2010-07-26 12:57:12

OPhone游戲開發(fā)

2016-10-14 13:53:05

JavascriptDOMWeb

2016-10-14 14:32:58

JavascriptDOMWeb

2010-07-16 09:11:40

JavaScript內(nèi)存泄漏

2024-01-09 12:05:24

SSH協(xié)議端口

2022-01-11 07:52:22

CSS 技巧代碼重構(gòu)

2019-12-04 10:13:58

Kubernetes存儲(chǔ)Docker

2022-11-09 08:06:15

GreatSQLMGR模式

2021-04-27 08:54:43

ConcurrentH數(shù)據(jù)結(jié)構(gòu)JDK8
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)