作者:360威脅情報中心
2017年9月18日,Piriform 官方發布安全公告,公告稱該公司開發的 CCleaner version 5.33.6162 和 CCleaner Cloud version 1.07.3191 中的 32 位應用程序被植入了惡意代碼。被植入后門代碼的軟件版本被公開下載了一個月左右,導致百萬級別的用戶受到影響,泄露機器相關的敏感信息甚至極少數被執行了更多的惡意代碼。
CCleaner 是獨立的軟件工作室 Piriform 開發的系統優化和隱私保護工具,目前已經被防病毒廠商 Avast 收購,主要用來清除 Windows 系統不再使用的垃圾文件,以騰出更多硬盤空間,它的另一大功能是清除使用者的上網記錄。自從2004年2月發布以來,CCleaner 的用戶數目迅速增長而且很快成為使用量第一的系統垃圾清理及隱私保護軟件。而正是這樣一款隱私保護軟件卻被爆出在官方發布的版本中被植入惡意代碼,且該惡意代碼具備執行任意代碼的功能。
這是繼 Xshell 被植入后門代碼事件后,又一起嚴重的軟件供應鏈攻擊活動。360威脅情報中心通過對相關的技術細節的進一步分析,推測這是一個少見的基于編譯環境污染的軟件供應鏈攻擊,值得分享出來給安全社區討論。
被植入了惡意代碼的 CCleaner 版本主要具備如下惡意功能:
__scrt_get_dyn_tls_init_callback()
中插入了一個函數調用,并將此函數調用指向執行另一段惡意代碼。speccy.piriform.com
,并下載執行第二階段的惡意代碼。根據360威脅情報中心的分析,此次事件極有可能是攻擊者入侵開發人員機器后污染開發環境中的 CRT 靜態庫函數造成的,導致的后果為在該開發環境中開發的程序都有可能被自動植入惡意代碼,相應的證據和推論如下:
1、被植入的代碼位于用戶代碼 main 函數之前
main 函數之前的綠色代碼塊為編譯器引入的 CRT 代碼,這部分代碼非用戶編寫的代碼。
2、植入的惡意代碼調用過程
可以看到 CRT 代碼 sub_4010CD
內部被插入了一個惡意 call 調用。
3、被植入惡意代碼的 CRT 代碼源碼調用過程
通過分析,我們發現使用VS2015編譯的Release版本程序的CRT反匯編代碼與本次分析的代碼一致,調用過程為:
_mainCRTStartup --> __scrt_common_main_seh --> __scrt_get_dyn_tls_dtor_callback --> Malicious call
4、CCleaner中被修改的 __scrt_get_dyn_tls_init_callback()
和源碼對比
基于以上的證據,可以確定的是攻擊者是向 __scrt_get_dyn_tls_init_callback()
中植入惡意源代碼并重新編譯成 OBJ 文件再替換了開發環境中的靜態鏈接庫中對應的 OBJ 文件,促使每次編譯 EXE 的過程中,都會被編譯器通過被污染的惡意的 LIB/OBJ 文件自動鏈接進惡意代碼,最終感染編譯生成的可執行文件。
__scrt_get_dyn_tls_init_callback()
函數位于源代碼文件dyn_tls_init.c
中。
通過分析發現,如果要向程序CRT代碼中植入惡意代碼,最好的方式就是攻擊編譯過程中引入的CRT靜態鏈接庫文件,方法有如下三種:
C運行時庫函數的主要功能為進行程序初始化,對全局變量進行賦初值,加載用戶程序的入口函數等。
我們以 VS2008 為例,編寫一個功能簡單的 main 函數如下:
#include "stdafx.h"
int main(int argc, _TCHAR* argv[])
{
printf("%d\n", 1);
return 0;
}
在 main 函數結尾處設置斷點,使用 /MD 編譯選項編譯調試運行
切換到反匯編代碼并執行到 main 函數返回:
返回后查閱源碼可以看到對應的 CRT 源代碼為:crtexe.c
源代碼路徑:
D:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src\crtexe.c
參考 MSDN 我們知道,在 VS2008 中,使用 /MD 編譯選項編譯 Release 版本的程序引用的 CRT 靜態庫為 msvcrt.lib,文件路徑為:
D:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\lib\msvcrt.lib
以 VS2008 中的 msvcrt.lib 為例
這里介紹靜態庫 LIB 文件,是指編譯器鏈接生成后供第三方程序靜態鏈接調用的庫文件,其實是單個或多個 OBJ 通過 AR 壓縮打包后的文件,內部包含 OBJ 文件以及打包路徑信息,比如 msvcrt.lib
文件解壓后得到的部分OBJ文件路徑如下:
可以看到,msvcrt.lib
解壓后確實也有 CRT 對應的 OBJ 文件:crtexe.obj
等。
源代碼編譯后的 COFF 格式的二進制文件,包含匯編代碼信息、符號信息等等,編譯器最終會將需要使用的 OBJ 鏈接生成 PE 文件,crtexe.obj
文件格式如下:
了解了 CRT 運行時庫的編譯鏈接原理,我們可以知道,使用/MD編譯選項編譯的 main 函數前的C運行時庫函數在靜態鏈接過程中是使用的 msvcrt.ib
中的 crcexe.obj
等進行編譯鏈接的,并且源代碼中定義不同的 main 函數名稱,編譯器會鏈接 msvcrt.lib
中不同的 OBJ 文件,列舉部分如下表所示:
我們以 VS2008 中編譯 main()
函數為例,如果修改 msvcrt.lib
中的 crcexe.obj
的二進制代碼,比如修改源碼并重編譯crcexe.c
或者直接修改 crcexe.obj
,再將編譯/修改后的 crcexe.obj
替換 msvcrt.lib
中對應的 OBJ,最后將VS2008 中的 msvcrt.lib
替換,那么使用/MD編譯選項編譯的所有帶有 main()
函數的 EXE 程序都會使用攻擊者的crcexe.obj
編譯鏈接,最終植入任意代碼。
為展示試驗效果,我們通過修改 crcexe.obj
中 main 函數調用前的兩個字節為 0xCC,試驗效果將展示編譯的所有 EXE 程序 main 調用前都會有兩條 int3 指令:
crcexe.obj
在 msvcrt.lib
中的路徑:
f:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\dll_obj\crcexe.obj
替換 msvcrt.lib
中的 OBJ 文件需要兩步,這里直接給出方法:
lib /REMOVE: f:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\dll_obj\crcexe.obj msvcrt.lib
lib msvcrt.lib f:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\dll_obj\crcexe.obj
將替換了 crcexe.obj
的 msvcrt.lib
覆蓋 VS 編譯器中的 msvcrt.lib
:
D:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\lib\msvcrt.lib
重新編譯執行我們的測試程序,可以看到在 main 函數執行前的兩條插入的 int3 指令:
2017年9月初360威脅情報中心發布了《供應鏈來源攻擊分析報告》,總結了近幾年來的多起知名的供應鏈攻擊案例,發現大多數的供應鏈攻擊渠道為軟件捆綁。通過污染軟件的編譯環境的案例不多,最出名的就是2015年影響面巨大的Xcode開發工具惡意代碼植入事件,從當前的分析來看,CCleaner也極有可能是定向性的編譯環境污染供應鏈攻擊。以下是一些相關的技術結論:
由于這類定向的開發環境污染攻擊的隱蔽性及影響目標的廣泛性,攻擊者有可能影響 CCleaner 以外的其他軟件,我們有可能看到攻擊者造成的其他供應鏈污染事件。
https://msdn.microsoft.com/en-us/library/abx4dbyh(v=vs.90).aspx