SigFlip:將數據隱寫到已簽名的PE文件上
SigFlip:將數據隱寫到已簽名的PE文件上
Github地址: https://github.com/med0x2e/SigFlip
可以怎么玩呢,可以白加黑當沖鋒馬的時候,白文件寫入shellcode,黑文件加載白文件的shellcode。
也可以做維權使用,將shellcode注入到系統的白文件中,dll劫持或者loader加到啟動項里面。
使用
兩個目錄Bof和DotNet,DotNet是c#寫的用來可行性測試,包含注入代碼,loader加載功能,Bof是C寫的,也包含注入代碼和loader加載功能,主要是可以編譯成bof文件給Cobalt Strike使用。
c#代碼loader的部分直接CreateRemoteThread就運行shellcode了,而bof的loader部分使用Early Bird,啟動一個新進程 pac注入執行。
c#和Bof會寫入"\xFE\xED\xFA\xCE\xFE\xED\xFA\xCE" 當作標記,在讀取shellcode時通過這個字符就可以直接定位到shellcode了。
「注入shellcode到簽名的PE文件」
c:\> SigFlip.exe -i C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe -s C:\Temp\x86.bin -o C:\Temp\MSbuild.exe -e TestKey
「loader執行shellcode」
c:\> SigLoader.exe -f C:\Temp\MSBuild.exe -e TestKey -pid
說說原理,一句話就是將shellcode寫到了簽名時不計算的區域。
簽名的位置
https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-data-directories-image-only
image-20210809175208347
_IMAGE_DATA_DIRECTORY 第4個偏移的位置(從0開始)。
簽名信息的結構
https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-attribute-certificate-table-image-only
簽名位置
灰色背景的部分,不參與簽名的hash計算。粗體的部分,就是簽名的相關內容。
SigFlip的原理就是將數據隱寫到灰色的部分。
「數字簽名結構」
WIN_CERTIFICATE
typedef struct _WIN_CERTIFICATE {
DWORD dwLength;
WORD wRevision;
WORD wCertificateType; // WIN_CERT_TYPE_xxx
BYTE bCertificate[ANYSIZE_ARRAY];
} WIN_CERTIFICATE, *LPWIN_CERTIFICATE;
dwLength:此結構體的長度。
wRevision:在bCertificate里面保護的證書的版本號,版本號有兩種,如下表,一般為0x0200。
值信息Win32 SDK中的宏定義名0x0100Win_Certificate的老版本WIN_CERT_REVISION_1_00x0200Win_Certificate的當前版本WIN_CERT_REVISION_2_0
wCertificateType:證書類型,有如下表格中的類型:
值信息Win32 SDK中的宏定義名0x0001X.509證書WIN_CERT_TYPE_X5090x0002包含PKCS#7的SignedData的結構WIN_CERT_TYPE_PKCS_SIGNED_DATA0x0003保留WIN_CERT_TYPE_RESERVED_10x0004終端服務器協議堆棧證書簽名WIN_CERT_TYPE_TS_STACK_SIGNED
bCertificate:包含一個或多個證書,一般來說這個證書的內容一直到安全表的末尾。
具體的WIN_CERT_TYPE_PKCS_SIGNED_DATA結構參考 https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx
最值得注意的是bCertificate的字節大小要求8字節對齊。
image-20210810143903467
修改要做的步驟
根據_IMAGE_DATA_DIRECTORY 獲取 WIN_CERTIFICATE 的RVA和大小,添加數據到bCertificate后面,再注意8字節對齊即可。
Ps:為什么添加數據在bCertificate后面不影響證書的校驗呢,我原本想找找PKCS#7證書的結構看看的,搜了一圈,也沒找到比較好的。但是可以猜測,既然有8位對齊的校驗,說明后面添加幾個字符是沒有影響,再可以反推出,每個字段都有一個長度字段控制。所以后面無論我們添加多少字段,對證書的校驗都不會影響。
再 更新 dwLength 大小
更新 _IMAGE_DATA_DIRECTORY[WIN_CERTIFICATE ]的size。
更新PE頭的CheckSum (這個可選)
手動修改
有了上面的描述,我們可以手動修改試試,以“微信”為例,用它的主程序,數字簽名也都正常。
image-20210810151212409
用CFF Explore打開wechat.exe,定位到證書表的選項
image-20210810151336872
可以知道證書的位置在文件偏移的000EA800,大小是000035F8
用010 Editor跳轉到這個地方
image-20210810151722788
頭部對應上數據結構的值
typedef struct _WIN_CERTIFICATE {
DWORD dwLength;
WORD wRevision;
WORD wCertificateType; // WIN_CERT_TYPE_xxx
BYTE bCertificate[ANYSIZE_ARRAY];
} WIN_CERTIFICATE, *LPWIN_CERTIFICATE;
dwLength = 0x35f8
wRevision=0x0200
wCertificateType=0x02
后面即證書的字節了,跳轉到最后可以看到有七個字節用作了對齊
image-20210810151911438
我們可以在后面添加自己需要的字節(要是8的倍數),例如我添加16個。
image-20210810152151990
所以新的長度就是0x35f8+16 = 0x3608 ,新的長度更新到兩個地方
更新 dwLength 大小
更新 _IMAGE_DATA_DIRECTORY[WIN_CERTIFICATE ]的size。最后它的證書也是正常的。
image-20210810152502566
防御手法
檢查是否安裝了 MS13-098 KB2893294 (一般默認不安裝)
檢查注冊表
HKLM:\Software\Microsoft\Cryptography\Wintrust\ConfigHKLM:\Software\Wow6432Node\Microsoft\Cryptography\Wintrust\Config
歷史
早在2013年,就有人發現chrome的安裝包會在證書處寫自己的安裝信息。
- https://blog.didierstevens.com/2013/08/13/a-bit-more-than-a-signature/
增強對抗
loader就可以按shellcode的加載方式進行了,通常一個CreareRemoteThread就可以啟動了。在對抗中執行可以更復雜一點,對于白加黑運行,運行shellcode可以劫持返回地址,或者注入到主程序的入口來執行。