揭秘Chimera勒索軟件如何解密文件
概述
最近,我們曾發(fā)表過一篇關于Chimera勒索軟件密鑰泄漏的文章(文章鏈接)。但是在這篇文章中,我們將會披露更多相關的技術細節(jié),我們將會給大家介紹如何利用這些泄漏出來的密鑰來解密文件。除此之外,我們還會對這些泄漏密鑰的有效性進行測試。
實驗數(shù)據(jù)和分析方法
一般而言,編寫一款勒索軟件的解密程序往往需要開發(fā)人員擁有較強的能力,他們不僅需要對加密算法有較深層次的理解,而且還得從勒索軟件中尋找漏洞。不同的漏洞則意味著開發(fā)人員需要用不同的思維理念來開發(fā)破解工具。
某些時候,我們需要對有漏洞的加密算法進行一定的改造,并且開發(fā)出一款能夠猜測密鑰的工具(例如Petya勒索軟件的破解過程)。某些時候,我們的工作重點應該放在勒索軟件的對稱密鑰生成器上(例如DMALocker 2.0的破解過程),或者將注意力集中在勒索軟件的加密算法身上(可以參考7ev3n勒索軟件所采用的自定義加密算法)。
但是這一次,我們已經(jīng)為大家準備好了一些現(xiàn)成的工具:
1. 泄漏的密鑰集;
2. 由Chimera的開發(fā)者提供給該勒索軟件受害者的原始解密程序;
對解密程序進行逆向分析
正如我們此前在對Chimera進行分析時所描述的,勒索軟件的攻擊者通常會在目標主機中留下勒索信息,而Chimera的作者向受害者提供了一個鏈接,他們可以自行下載一個外部解密工具。為了能夠讓解密工具運行,用戶需要購買一個私鑰,只有當私鑰與公鑰成功配對時,用戶被加密的文件才能夠成功恢復。
這個解密工具采用了.NET語言進行編寫,該工具中所有的文件解密操作全部由一個外部組件來控制-一個名為“PolarisSSLWrapper.dll”的DLL文件。經(jīng)過了分析之后,我們發(fā)現(xiàn)該組件能夠提供以下兩個函數(shù):
所以我們就沒有必要自己親自去設計解密函數(shù)了,我們可以直接利用這個現(xiàn)成的API。
首先,我們需要先對該工具中主要的組件進行逆向分析。因為我們在進行下一步操作之前,需要弄清楚這兩個函數(shù)是如何被調用的,以及該函數(shù)需要傳入哪些參數(shù)。
從下面這張代碼截圖中,我們可以看到用于解密文件的外部函數(shù)是如何被調用的:
如上圖所示,我們所關心函數(shù)是“DecryptFileWrapper”。該函數(shù)需要傳入三個參數(shù):(1)待解密文件的存儲路徑(以一個ASCII字符串表示);(2)購買的私鑰(字節(jié)數(shù)組);(3)私鑰長度。該函數(shù)的返回值是一個布爾類型的值,用來通知系統(tǒng)文件的解密操作是否成功。我們可以對該函數(shù)進行重構,具體如下所示:
bool _cdecl DecryptFileWrapper(char filePath, BYTE*privateKey, size_t privateKeySize);
函數(shù)會從收到的bitmessage中讀取出私鑰信息,并將其解碼(Base64編碼)成字節(jié)數(shù)組的形式:
由于Chimera的服務器在幾個月前就已經(jīng)下線了,所以我們無法捕獲到該勒索軟件的網(wǎng)絡通信數(shù)據(jù)。但是多虧了BleepingComputer此前所發(fā)表的研究報告,我們現(xiàn)在可以獲取到該勒索軟件網(wǎng)絡通信信息的結構。示例:
56209A92A96E9F96B0D9E6F962D0D9EF:5Zn9azBBDQQznI9znnHZBDs6+nQz6nB9/6DBa0nXbDz0aghs6fg62Rn9ZzxnDGEzRQ9tFdIZDfa05Lz+nlb6IGnzSDQz0tznrdUzGgq9Nibzx0Zusl2aHn6nzZZE6tbQQe/vzbASDuanTBL5SazSARe52QSq6BEzD5rGqzZhnaLaZrfbI6bN6A6nnnH5lgbeSAzXdz+6eNxqQt9ITziIxF+eDFBBBVZ+zHf6esQzzH2uBnQnaHzzi6tDna9Xngfh6bzQQZBfq+vFbZ9ZfvnTL6D2arAnBzb6A06Qzfn2zRD5hz5eLZzDIDR00/anblbU2bvRTH6ZGaXDeBQQ5NHGhQEAAdZBtx/VaVQsrrDZdasadBHi0RDeZz0Da6glNRz9/U59zXaaeAN0Di5eb2zQtvr5h6Fvb6tzB9THtRUGS6Qzt6BxAz/zTg6gs56h5xXzSnslBQRzngandHzFTaBHix692DLxDaziQnZBQDQRB/Zz5HXQfNzz5aad90+uHAsDBDDVzZsngtbgSHDTzA2X5zQs2tHba5z99qF66IQHqZaZD2erzuDQzzx9NlXaTZEiH2IrVGSZizxEFQzLBl6+BDDn5zuG6x6zBhfaNB56nDUXt6BnzzuvNVq2xzDTn2lSu/QrHzNbFdGSLazTh29z5Fx9D5Zt6QBBrQ+aFuNDhASgDDH20UDnQB00gBa2t6/i+Lq6eV9ZHzzDdEn2T6HXfg+BEnvr5tXB5zZL2zbtvBVxFX2QsBZ9ZrzzG6fIvnvnz6NZ5endiz0IzAQ2Dbqa6gnnsSnznsVIizznibdZIFvF/nsqbVQZB9Zn2nBQUDTQzzDT65NxHzLRvz6VzZsQV5bih+S+shaD6ASaDFzHNQD9ZVIi+ZrafBxes6zqQaBfEs6z+Igd6nZhEzDLZZN/9QbhQzlzfBf5IFL0nqt2qqnSeqgz0bzQgZ9Dq6r50SB6xHhn9DfnNa6hR0DUiubDH5z0+n60UD0Uzz6ti6faD5Sz99f6dtQN6LUfZn/RagfiqnzTXZrvBZv95a9aT9u9tE6qLH0BSNArn0I9rF2eBDQH92zFUBBBVs9e/ZrXZ2Qaz/zn6BzxQ05qtqNQTZ6AS22z6nBf/200L66zasDHrzZ9agHAx2qBNUlRaUDFszInzzaLD5IzGQeQaAU60zz6nZQvVe906uDTXGlaZDDfBQUzD/nRDrZUaa2h59Hf5gbeezTHNiHBaBDzzQBx0BX5Zz92Z2zanfSZZ/2BRnzzzQBzxa/iIxiDNb6Qdd9Bh6/FQnfeznSv5rZ6DZitTGZZUAdzgD5azVAn2G/G+EssFuhV5aBb0N/N2q+2656zgxBBDzn2+0NIZLudxTXRsDNDza0V/9gzzEaqBdZax6QDlfnQhAVIn9XZu/D+gr9+ZRqz5266IBST5E5LBZed/s0zS2QHeBrIHnznZtez+02+Q+50g+ZUD6nrbhR2f+NzB6NgZ6ID9e5hnEEQ99xlnSDZT2aQN6QBRueDRZzNaTz6bvQrGhaBaeFl96hZDZLUDIu6rAzB
其結構為:[感染者ID]:[base64編碼密鑰]
在對密鑰進行了解碼之后,我們得到了一個長度為1155字節(jié)的字節(jié)數(shù)組。
這個數(shù)組中存儲的原始字節(jié)數(shù)據(jù)即為我們所需要的密鑰。
解析密鑰
此前泄漏出來的密鑰是一堆十六進制的字符串。如果我們將這些數(shù)據(jù)轉換為原始的二進制數(shù)據(jù),就會發(fā)現(xiàn)這些密鑰的長度均為0×483字節(jié)。這是一個非常重要的發(fā)現(xiàn),因為這些密鑰的格式與上文中描述的密鑰是一樣的,所以我們不需要對這些數(shù)據(jù)進行額外的處理了。我們所要做的,就是將這些十六進制數(shù)據(jù)轉換為原始的二進制數(shù)據(jù)即可。
泄漏文件的格式還算比較整齊,每一個密鑰的結尾都會另起一行。我們可以直接移除開頭的一些無用數(shù)據(jù),然后將這份文件作為輸入:
更確切地來說,我們此前將這些數(shù)據(jù)描述為密鑰集合,但實際上它們應該是密鑰對的集合。每一對密鑰的長度均為0×483字節(jié)。其中,前0×103字節(jié)的數(shù)據(jù)中包含的是公鑰信息,接下來的0×380字節(jié)即為私鑰信息。我們所使用的API需要這一串完整的數(shù)據(jù)作為輸入,解密工具的DLL組件會將這些數(shù)據(jù)當作“私鑰”來進行處理。由于公鑰和私鑰的信息全部包含在這些數(shù)據(jù)里面了,所以解密工具就可以自動驗證密鑰的匹配結果。
尋找出合適的解密密鑰
正如你所見,我們已經(jīng)完成了大部分的工作。剩下的最后一件事情就是確定泄漏的密鑰集中是否真的存在可以解密我們文件的密鑰。
在這一步操作中,我們不得不使用算法來解決我們的問題。我們的實現(xiàn)方式看起來與字典攻擊有些類似,我們的“字典”是一套泄漏密鑰的集合。為了進行驗證,我們將會嘗試解密其中的一份被加密的文件。我們大致的思路用下面這段偽代碼來表示:
- while ((privateKey = getNextFromSet()) != NULL) {
- if(DecryptFileWrapper(encryptedFile, privateKey, privateKeyLen) == true) {
- printf("Hurray, key found!");
- storeTheFounKey(privateKey);
- return true;
- }
- }
- printf ("Sorry, your key is not in the leakedset!");
- return false;
如果你對此感興趣的話,可以點擊下方的地址下載完整的代碼:
https://github.com/hasherezade/chimera_decrypt
找出了能夠成功匹配的密鑰之后,我們就可以解密剩下的所有文件了。
測試
測試一:
Chimera在每次運行的時候會生成一個唯一的隨機密鑰對。然后,它會利用bitmessage來將密鑰對發(fā)送至C&C服務器上。值得注意的是,發(fā)送的數(shù)據(jù)還包括與目標用戶有關的其他數(shù)據(jù)集合。
為了完成測試,我使用了一個由原始Chimera勒索軟件樣本生成的密鑰,并將其從內存中導出。在將密鑰傳遞給用于發(fā)送數(shù)據(jù)的函數(shù)之前,密鑰的信息是可以清楚地看到的。如下面這張截圖所示:
我將這些數(shù)據(jù)轉換成了與泄漏密鑰相同的格式(連續(xù)的十六進制字符串)。
我們事先準備好的工具可以正常運行,測試文件已經(jīng)被成功解密了:
測試二:
因為在泄漏數(shù)據(jù)中我們已經(jīng)得到了完整的密鑰對,所以我們也可以用它們來進行測試。在實驗過程中,我從其中一個泄漏密鑰中截取出了公鑰數(shù)據(jù),然后將其提供給了Chimera樣本。我之所以這樣做,是為了模擬出一份受害者(密鑰已經(jīng)泄漏)被加密的文件。
接下來,我們需要用提取出的公鑰替換掉Chimera自動生成的原始公鑰:
現(xiàn)在,我們就可以嘗試使用泄漏密鑰和事先準備好的工具來解密受攻擊的文件了:
解密成功了!我們的測試也成功證實了泄漏的數(shù)據(jù)中的確包含有真實的密鑰對,這些數(shù)據(jù)并不是無效的垃圾數(shù)據(jù)。
除了上述兩個測試之外,我們還進行了很多其他的測試,而且我們還對這些工具進行了編譯。如果你感興趣的話,可以訪問我們的Github代碼庫來了解詳細的信息(Github主頁鏈接)。
總結
通過查看密鑰的格式,我們就可以推測泄漏的數(shù)據(jù)中應該包含有合法的密鑰數(shù)據(jù)。除此之外,我們也從其他安全研究專家那里得到了證實,泄漏密鑰中的部分數(shù)據(jù)確實能夠匹配他們捕獲的通信樣本。但是,我們已經(jīng)沒有辦法從受害者那里得到分析樣本了。Chimera在幾個月前就已經(jīng)徹底掛掉了,而且大多數(shù)受感染的用戶可能早就已經(jīng)將被加密的文件刪除了。