Authenticode簽名在未簽名代碼中的應用詳解
一、前言
我們都知道,攻擊者會將合法的數(shù)字簽名證書應用于他們的惡意軟件中,想來應該是為了逃避簽名校驗。其中有個例子就是勒索軟件Petya。作為一個逆向工程師或者是紅隊開發(fā)人員,了解如何將合法簽名應用于未簽名、攻擊者提供的代碼中是很重要的。本文將介紹代碼簽名機制,數(shù)字簽名二進制格式,和在未簽名的PE文件中應用數(shù)字證書的技術(shù)。很快你就能看到我下個月發(fā)布的一些研究與這些技術(shù)有關(guān)。
二、背景
對PE文件(exe,dll,sys等)簽名了意味著什么?簡單來說就是如果打開PE文件的文件屬性,有個標簽頁是“數(shù)字簽名”,那么意味著它是簽名過的。當你看到標簽“數(shù)字簽名”,意味著PE文件是Authenticode簽名,在其文件內(nèi)部有個二進制數(shù)據(jù)塊,它包含了證書和文件哈希(特別說明的是,在計算Authenticode哈希時不考慮PE頭)。Authenticode簽名的存儲格式可以在PE Authenticode規(guī)范中找到。
有很多文件有簽名,但是卻不包含“數(shù)字簽名”標簽頁(例如notepad.exe)。這是否意味著文件沒有簽名或者微軟發(fā)布了未簽名的代碼?當然不是。盡管notepad沒有內(nèi)嵌的Authenticode簽名,但是它有另一種簽名(catalog簽名)。Windows包含了一個由很多catalog文件組成的catalog存儲,它基本上是個Authenticode哈希列表。每個catalog文件都被簽名,以表明任何匹配哈希的文件都來自catalog文件的簽名者(大部分微軟文件是這樣的)。因此盡管Explorer UI沒有試圖查找catalog簽名,但是可以使用其他簽名校驗工具來查詢catalog簽名,如powershell中的Get-AuthenticodeSignature和Sysinternals中的Sigcheck工具。
注意:catalog文件位于%windir%\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}
在上面的截圖中,SignatureType屬性表明notepad.exe是catalog簽名。還值得注意的是IsOSBinary屬性。盡管其實現(xiàn)是未文檔化的,如果簽名是已知的微軟根證書,那么這將顯示True??梢酝ㄟ^逆向CertVerifyCertificateChainPolicy函數(shù)來了解其中內(nèi)部原理。
使用“-i”選項調(diào)用Sigcheck來驗證catalog證書,它也會顯示包含匹配到Authenticode哈希的catalog文件路徑。“-h”選項也會計算并顯示PE文件的SHA1和SHA256 Authenticode哈希(PESHA1和PE256)。
知道了Authenticode哈希,你就可以查看catalog文件中的各種條目。你可以雙擊一個catalog文件以查看它的信息。我寫了一個CatalogTools的PowerShell模塊來解析catalog文件。“hint”元數(shù)據(jù)字段表明了確實是notepad.exe的信息。

三、數(shù)字簽名二進制格式
現(xiàn)在,你已經(jīng)了解了PE文件的簽名(Authenticode和catalog),了解一些簽名的二進制格式是有用的。Authenticode和catalog簽名都以PKCS #7 signed data格式存儲,它是ASN.1格式的二進制數(shù)據(jù)。ASN.1只是一個標準,是用來表明不同數(shù)據(jù)類型的二進制數(shù)據(jù)是如何存儲的。在解析數(shù)字簽名之前,你必須首先知道它在文件中是如何存儲的。Catalog文件是直接包含了原始的PKCS #7數(shù)據(jù)。有個在線的ASN.1解碼器可以解析ASN.1數(shù)據(jù),并直觀的顯示出來。例如,嘗試加載notepad.exe的catalog簽名,你將直觀的看到數(shù)據(jù)的布局。下面是解析結(jié)果的片段:
ASN.1編碼數(shù)據(jù)中的每個屬性都開始于一個對象ID(OID),這是一種表示數(shù)據(jù)類型的唯一數(shù)字序列。上面片段中值得看的OID如下:
- 1.2.840.113549.1.7.2:這表明了以下是PKCS #7簽名數(shù)據(jù),它是Authenticode和catalog簽名的格式。
- 1.3.6.1.4.1.311.12.1.1:這表明下面是catalog文件哈希數(shù)據(jù)
花時間瀏覽數(shù)字簽名中所有的字段是值得的。本文無法包含所有的字段,然而另外的加密/簽名相關(guān)的OID能在這里找到。
嵌入的PE Authenticode簽名
內(nèi)嵌在PE文件中Authenticode簽名被追加到文件的末尾(這是格式良好的PE文件)。很明顯,操作系統(tǒng)需要一些信息以便提取出內(nèi)嵌的簽名偏移和大小。使用CFF Explorer看查看下kernel32.dll:
內(nèi)嵌的數(shù)字簽名的偏移和大小存儲在可選頭中的數(shù)據(jù)目錄的安全目錄中。數(shù)據(jù)目錄包含了PE文件中各種結(jié)構(gòu)的偏移和大小,如導出表,導入表,重定位等。在數(shù)據(jù)目錄中的所有的偏移都是相對虛擬地址(RVA),意味著它們是PE文件加載到內(nèi)存中相對基址的偏移。只有一個例外,那就是安全目錄,其存儲的偏移是文件偏移。原因是Windows加載其不會將安全目錄的內(nèi)容加載到內(nèi)存中。
安全目錄中文件偏移指向的二進制數(shù)據(jù)是一個WIN_CERTIFICATE結(jié)構(gòu)體。下面是這個結(jié)構(gòu)在010Editor中的顯示(文件偏移是0x000A9600):
PE Authenticode簽名應該總是包含WIN_CERT_TYPE_PKCS_SIGNED_DATA的wRevision。PKCS #7,ASN.1編碼簽名的數(shù)據(jù)的字節(jié)數(shù)組和catalog文件中看到的是一樣的。唯一的不同是你找不到OID 1.3.6.1.4.1.311.12.1.1(其表明是catalog哈希)。
使用在線ASN.1解碼器解析原始的bCertificate數(shù)據(jù),我們能確認我們處理的是正確的PKCS #7數(shù)據(jù):
四、將數(shù)字簽名應用于未簽名的代碼
現(xiàn)在你已經(jīng)對數(shù)字簽名的二進制格式和存儲位置有了大概的了解,你能開始將存在的簽名應用于未簽名的代碼中了。
內(nèi)嵌的Authenticode簽名的應用
將簽名文件中內(nèi)嵌的Authenticode簽名應用到未簽名的PE文件中是很簡單的。盡管過程可以自動化,但是我還是解釋一下如何通過一個二進制編輯器和CFF Explorer來手動實現(xiàn)。
第1步:確定你想要盜取的Authenticode簽名。在這個例子中,我使用kernel32.dll
第2步:確定安全目錄中的WIN_CERTIFICATE結(jié)構(gòu)體的偏移和位置
上面截圖中的文件偏移是0x000A9600,大小是0x00003A68。
第3步:使用二進制編輯器打開kernel32.dll,選擇開始于偏移0xA9600的0x3A68字節(jié),并復制這些字節(jié)。
第4步:使用二進制編輯器打開未簽名的PE文件(本例中是HelloWorld.exe),滾動到文件末尾,粘帖從kernel32.dll拷貝的數(shù)據(jù)。保存文件。
第5步:使用CFF Explorer打開HelloWorld.exe,并更新安全目錄指向數(shù)字簽名的偏移(0x00000E00)和大小(0x00003A68)。修改后保存文件。忽略“不可靠”的警告。CFF Explorer不會將安全目錄作為文件偏移,當它試圖引用數(shù)據(jù)所在節(jié)時就產(chǎn)生了“困境”。
完成了!現(xiàn)在,簽名校驗工具將解析并顯示適當?shù)暮灻Nㄒ坏木媸呛灻遣豢煽康?,因為計算文件的Authenticode不能匹配存儲在證書中的哈希。
現(xiàn)在,如果你想知道SignerCertificate thumbprint值為什么不匹配,那么你是個有追求的讀者啊??紤]到我們使用了相同的簽名,為什么不能匹配證書thumbprint呢?這是因為Get-AuthenticodeSignature首先會試圖查詢kernel32.dll的catalog文件。這個例子中,它找到了kernel32的條目,并顯示了catalog文件中的簽名者的簽名信息。Kernel32.dll也是使用Authenticode簽名的。為了校驗Authenticode哈希的thumprint值是相同的,臨時關(guān)閉了負責查詢catalog哈希的CryptSvc服務(wù)?,F(xiàn)在你將看到thumprint值已經(jīng)匹配了,這表明catalog哈希是使用不同于kernel32.dll使用的簽名證書來簽名的。
將catalog簽名應用于PE文件
實際上,CryptSvc一直會運行并執(zhí)行catalog查詢操作。假設(shè)你想注意OPSEC并想匹配用于簽名你目標二進制的相同的證書。事實上,你確實能通過交換WIN_CERTIFICATE結(jié)構(gòu)中的bCertificate并更新dwLength來將catalog文件的內(nèi)容應用于內(nèi)嵌的PE簽名。注意我們的目標是將Authenticode簽名應用于我們的未簽名的二進制中,這和用于簽名catalog文件是相同的:證書thumprint 是AFDD80C4EBF2F61D3943F18BB566D6AA6F6E5033。
第1步:確定包含你的目標二進制的Authenticode哈希的catalog文件,本例是kernel32.dll。如果一個文件使用Authenticode簽名,Sigcheck解析catalog文件將失敗。但是Signtool(windows SDK中包含)還是可以用。
第2步:在16進制編輯器中打開catalog文件,文件大小是0x000137C7
第3步:在16進制編輯器中手動構(gòu)造WIN_CERTIFICATE結(jié)構(gòu)。讓我們?yōu)g覽下我們使用的每個字段:
- dwLength:這是WIN_CERTIFICATE結(jié)構(gòu)的全部長度,如bCertificate字節(jié)加上其他字段的大小=4(DWORD的大小)+2(WORD的大小)+0x000137C7(bCertificate,.cat文件的大小)=0x000137CF.
- wRevision: 0x0200表示W(wǎng)IN_CERT_REVISION_2_0
- wCertificateType: 0x0002表示W(wǎng)IN_CERT_TYPE_PKCS_SIGNED_DATA
- bCertificate:這包含了catalog文件的原始數(shù)據(jù)
當在16進制編輯器中構(gòu)造完,注意按小端存儲字段。
第4步:從構(gòu)造的WIN_CERTIFICATE中復制所有的內(nèi)容,將他們附加到未簽名的PE文件中,并更新安全目錄的偏移和大小。
現(xiàn)在,假設(shè)你的計算和對齊是正確的,thumbprint將匹配catalog文件。
五、異常檢測
希望本文描述的技術(shù)能使人思考到如何檢測數(shù)字簽名的濫用。盡管我沒有徹底調(diào)查過簽名檢測,但是讓我們拋出一系列問題來激勵其他人開始研究并寫出簽名異常的檢測:
1. 對于合法簽名的微軟PE,PE時間戳和證書有效期是否有相關(guān)性呢?攻擊者提供的代碼的時間戳偏離上述的相關(guān)性嗎?
2. 在閱讀本文后,哈希不匹配的簽名文件的信任等級是多少?
3. 如何檢測內(nèi)嵌Authenticode簽名包含catalog文件的PE文件?Hint:上述提到的特定的OID可能是有用的。
4. 停止/禁用CryptSvc服務(wù)對本地簽名驗證有什么影響?如果這中情況發(fā)生了,那么大部分系統(tǒng)文件,其所有的意圖和目的都將不會簽名
5. 每個合法的PE中我都能看到有0x10字節(jié)的填充。我演示的例子中沒有0對齊的x10。
6. 合法的微軟數(shù)字簽名和應用到自簽名證書中的所有證書屬性有什么不同?
7. 數(shù)字簽名之外有數(shù)據(jù)追加會怎么樣?參考這篇文章。
8. 專業(yè)人員在調(diào)查不同證書使用相同的代碼時,應該找到Authenticode哈希。VirusTotal提供了Authentihash值,該值也能通過Sigcheck –h計算。如果我調(diào)查一個例子的不同變種對應單獨的一個Authentihash,我發(fā)現(xiàn)那將非常有趣。