* 本文原創作者:維一零,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載
在今年的黑帽大會上,國外的一個安全研究員展示了如何通過Windows的數字簽名bypass對惡意程序代碼的檢測。下載大會的該演講的ppt大概看了一下,報告分為兩部分,第一部分展示數字簽名的的校驗“漏洞”,第二部分展示該作者自己研究實現的一個pe程序加載器,用來配合第一部分的“漏洞“bypass殺毒軟件對惡意程序的檢測。本文重點在于第一部分的這個數字簽名校驗”漏洞“,通過回顧分析數字簽名的校驗來闡述這個”漏洞“的原理。
數字簽名與數字證書
講這個”漏洞“之前先講一下數字簽名的原理,理解一般的數字簽名驗證過程。下面是數字簽名的相關概念和驗證過程:
數字簽名:對一段數據摘要使用私鑰進行加密,公鑰進行解密校驗
數字證書:對數字簽名的解密公鑰和身份信息使用CA的私鑰進行加密,系統信任的CA公鑰進行解密
如上圖所示,數字簽名用來保護所有者的數據,所以從這些數據出發,所有者簽發數據的數字簽名過程是要先計算這些數據的摘要(也就是對這些數據做個hash運算,目前由于SHA-1開始不安全,正在逐漸換成SHA-2算法),然后使用所有者的私鑰進行加密(目前主流還是RSA,也有一些ECC或其他算法),加密后的數據帶上所有者的信息按照一定的標準格式組織好其實就是所謂的數字簽名。
而接收方(使用者)要驗證這個數字簽名,一般通過數字證書,因為其中包含兩個重要的信息,一個就是用于解密數字簽名的公鑰(通過這個公鑰才能正確解密出數據所有者事先加密好的數據摘要值,用于驗證比對數據的一致性),另一個就是指明了這個公鑰的所有者的信息(當然要和數字簽名所有者的信息一致)。
而數字證書其實是由第三方的可信機構頒發給數字簽名所有者的一份數據文件,生成算法和數字簽名類似,只不過它是把所有者的公鑰和身份這些固定信息數據進行了加密返回給了所有者,此時所有者的身份正常是得到了可信機構的認證了。最后一個環節,數字簽名、數字證書通常都是附加到所有者的數據后面一起傳送給了使用者,但是如何解密數字證書來進行驗證呢?我的理解是,這個要依托于系統,比如windows,他們會維護一批可信機構的列表,在驗證證書的時候,就會先從這個列表里校驗和獲取證書簽發機構的身份和公鑰,并返回到用戶系統進行存儲和使用。
正是通過這樣一整套的相對完善的機制,最終比較靠譜的保證了接收數據的有效性。而本文所指的Windows程序的數字簽名,其實就是指所有者要保護的數據是一些Windows下的可執行程序這樣一種情況。
可被利用的“漏洞”
從上面的簽名校驗流程看,由于整個過程涉及環節比較多,相應的每個環節都存在有被攻破的可能性,比如hash碰撞、根證書偽造等,但是本文不涉及此類問題。實際上,數字簽名仍然是保護數據有效的一種可靠的途徑,只要操作得當,算法強度足夠,被攻破的可能性還是比較低。而本文所說的“漏洞”,也不是上面整個驗證過程的漏洞,下面就來看一看這個“漏洞”是什么意思吧。
找一個帶有數字簽名的程序來實驗,就以微軟官方的庫文件msvcr100.dll為例。右鍵點擊文件屬性,可以看到有一個數字簽名的標簽,依次點擊可以查看到下面的簽名有效狀態,表示這個程序的數字簽名驗證成功,“程序數據沒有被篡改”(這里加引號說明理解需要謹慎,詳看下文)。
然后修改這個文件,比如在尾部隨便添加幾個字節的數據,再次查看數字簽名的狀態后如下圖所示,說明系統檢測到文件被篡改,數字簽名驗證為無效。
這就給我們造成一種感覺,數字簽名真的可以保證數據不被篡改,只要數據受到篡改,就會被系統的驗證機制檢測到并提示簽名無效。然而,這種感覺其實并不靠譜,因為我們實際上只是對簽名文件添加了一些數據,并沒有修改到程序的原始數據區域的部分,理論上只要系統能夠找到程序的數字簽名并通過上述的驗證流程,那么數字簽名就仍是有效的,受保護數據沒有遭到篡改。那么,有沒有辦法讓這個添加了數據的文件去正確識別數字簽名并顯示簽名有效呢,答案是肯定的,而這也正是本文所指的“漏洞”。
這里直接給出這個“漏洞”的信息:對于一個Windows的可執行程序,簽發數字簽名的時候需要計算的數據摘要并不會是程序文件的全部數據,而是要排除一些特定區域的數據。而這些區域當然和PE文件結構有關,具體地,不管是簽發時還是校驗時計算的hash都會排除一個checksum字段、一個Security數據目錄字段以及數字簽名證書部分的數據。至于原因,當然是為了合理地組織pe程序的數字簽名,符合pe文件格式的標準了。下面是三個字段的相關信息:
struct IMAGE_NT_HEADERS
…
struct IMAGE_OPTIONAL_HEADER32
…
DWORD CheckSum //pe映像校驗和,dll常用
…
struct DATA_DIR Security
DWORD VirtualAddress //指向數字簽名證書數據結構_WIN_CERTIFICATE
DWORD Size //_WIN_CERTIFICATE結構大小
struct _WIN_CERTIFICATE
DWORD dwLength //本結構數據的大小,一般和Security.Size相等
WORD wRevision
WORD wCertificateType
BYTE bCertificate[ANYSIZE_ARRAY] //數字簽名證書數據
由于計算hash時排除以上3個相關的數據,故這三個字段本身就是Windows系統留給用戶可以操作修改的區域。而實際上,要讓上述在尾部添加數據的文件顯示數字簽名有效,即Windows系統對數字簽名可正確識別,只需要更新Security.Size這個字段一致,且滿足添加的數據長度為8的整數倍即可:
由此可見,數字簽名狀態正常,并不意味著帶簽名的程序就是完整未被篡改過的,通過修改程序的字段數據可以實現在帶簽名的程序后面添加任意的數據且簽名狀態驗證正常。上面的三個字段如果同時修改,即checksum、Security.Size和dwLength都正常,除非很嚴格的去對數字簽名的數據部分進行檢查,否則比較難以檢測出帶簽名的程序文件是否被惡意篡改添加了非法數據。而這一點,就構成所謂的“漏洞”,能夠成為很多惡意程序的良好的藏身之處,借此bypass很多防火墻、反病毒等軟件的檢測。比如黑客可以將惡意代碼嵌入帶有正常簽名的程序后面來繞過一些防護系統的檢測,從而為后續的一些攻擊行動起到一個很好的掩護作用。
另一種Windows程序的簽名“漏洞”
經過以上的分析,所謂的簽名“漏洞”,其實是數字簽名文件組織上的概念誤區,導致將簽名的正常狀態和簽名文件的完整性混淆在一起。這里介紹一種更為方便的Windows程序,能夠以更簡單的方式實現以上同樣的效果。
打開Windows系統文件夾“C:/Windows/Installer”,在這個目錄下可以找到一些具有微軟數字簽名的msi/msp格式的文件。我們知道msi是微軟格式的安裝包,點擊運行后系統會自動調用Msiexec.exe來啟動程序,而這種程序相比于PE程序這個文件格式來說,對數字簽名的識別好像更為簡單,也沒有PE程序結構的特殊限制。于是,隨便往帶有簽名的msi文件尾部添加一些數據,而無需再修改文件的其他數據,msi的數字簽名狀態仍然校驗正常。比如我系統找到的下面一個文件:
可以看到,對于msi簽名文件,隨意添加數據簽名狀態不變,說明即使被添加了非法數據,系統也能順利找到msi程序的數字簽名進行校驗,而由于msi程序的原始保護部分沒有受到篡改,所以數字簽名狀態驗證正常。
總結
通過本文的分析,實際上這個程序簽名的“漏洞”并算不上通常意義上的漏洞,但是卻因為本身比較容易被概念混淆,使用可能沒有充分得當,導致可能存在一些比較嚴重的可利用環節。所以本文的結論就是:程序的數字簽名只能用于驗證程序的代碼和數據是否被篡改,而無法用于驗證程序文件本身是否被篡改。
* 本文原創作者:維一零,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載