顛覆windows的信任體系——實現任意代碼簽名劫持

背景

在計算機安全領域,什麼是信任呢?現代安全解決方案——遇到惡意代碼或者惡意操作彈個窗提示下——提供的隱含的安全感?還是企業里對某個工作必需的軟體經過認真評估後的信任?實際上,並沒有唯一的正確答案。信任本質上是主觀的。重要的是,每個組織都要認真考慮在技術層面信任的意義。即便具有成熟信任定義的組織,也應該質疑下由安全解決方案和操作系統驗證過的信任是否可信。

既然你的腦子裡有了關於信任對你意味著什麼,不包括涉及人工干預的代碼審查,什麼是信任驗證的技術手段?這顯然是一個難以回答的問題,當然你也可能沒有問過自己。本白皮書的目的是展示微軟的Windows是怎樣決策信任的。通過展示如何在Windows中顛覆信任,您將有機會有更多的機會多問問自己,信任對您而言到底意味著什麼——一些在安全方面非常重要和不清楚的概念。

除了驗證簽名代碼的來源和完整性之外,代碼簽名和信任驗證也是許多安全產品(例如防病毒和EDR解決方案)的重要惡意軟體分類組件。適當的信任驗證也是大多數應用程序的執行組件白名單解決方案(AppLocker,Device

Guard等)。 在許多情況下顛覆Windows的信任架構也有可能顛覆安全產品的功效。

Windows用戶模式信任架構

使用Authenticode.aspx)數字簽名,可以驗證來自於特定供應商的可執行代碼的合法性。在用戶模式下,驗證簽名代碼的信任的API是WinVerifyTrust.aspx)和WinVerifyTrustEx.aspx)(它只是WinVerifyTrust的包裝器,具有更明確定義的函數原型)。

隨著Windows的更新迭代,同時也有必要擴展簽名和信任架構以便支持額外的文件格式和二進位Blob格式,簽名可能就需要以不同的格式存儲,信任也跟著這種技術以特有的方式進行驗證。例如,數字簽名以特定的PE文件格式存儲二進位格式。PowerShell腳本,從另一方面來看的話也是可以簽名的文本文件,因此可以理解其簽名需要不同的存儲格式。另外,當簽名代碼時,需要計算要簽名的代碼的哈希(通常稱為簽名證書哈希),並且根據文件/

blob格式執行此操作的方式是不同的。可以理解,關於數字簽名的認證,設備驅動程序的信任的驗證方法與HTTPS證書的信任方式是不同的。

考慮到需要支持獨特格式的數字簽名,並以獨特的方式執行信任驗證,微軟設計了可擴展架構來支持這一點。主題介麵包(subject interface package.aspx),SIP)架構旨在支持數字簽名的創建,檢索和哈希計算、驗證。使用信任提供者.aspx)來執行簽名代碼的信任驗證。通過使用WinVerifyTrust和wintrust.dll、crypt32.dll中的各種導出函數,

信任提供者和SIP架構幫助軟體開發人員從執行代碼簽名和信任驗證的具體步驟中完全抽象出來。在撰寫本文時,沒有證據表明該架構的文檔已被擴展到可支持第三方軟體開發人員希望支持的其特定文件格式的簽名。這可能是因為無論格式如何變化任何文件都可以在技術上通過使用目錄簽名(catalog signing,一種包含可以被認證碼簽名的文件哈希列表的文件格式)進行「簽名」。需要注意的是編錄文件的驗證只有在「CryptSvc」服務運行的情況下才能生效。

除了各種Windows SDK頭文件以及零星的關於wintrust.dll和crypt32.dll導出函數的MSDN文檔.aspx)外,信任提供者和SIP並沒有文檔化。由於第三方實施的複雜性,微軟可能故意選擇對這些架構不進行文檔化。該白皮書用於記錄信任提供者和SIP架構,同時還解釋攻擊者如何將其濫用的方式作為破壞信任的手段,並且在執行信任驗證的進程的上下文中獲取代碼執行的許可權。

本白皮書中主要介紹的是CryptoAPI.aspx#_security_cryptoapi_gly)的可擴展性,主要包括加密編碼、解碼、證書管理等。微軟不可能預見未來的加密要求,所以他們設計了一個完全可擴展的架構(大概可追溯到90年代初),以適應當前和未來的需求。不幸的是,這一非常廣泛的可擴展性,有可能允許攻擊者(具有提升的許可權)來劫持現有的功能。

什麼文件可以被簽名呢

怎麼知道一個可執行文件是否被簽名呢?一個最簡單直接的方法就是右鍵查看文件屬性,然後切換到數字簽名選項卡。

「數字簽名」選項卡顯示是否存在嵌入的認證簽名

雖然這種方法可以用來確認某些文件類型是否被簽名,如上圖所示的ise.psm1(PowerShell腳本模塊.aspx)文件)的情況,但這遠遠不是枚舉可簽名文件類型的系統方法。對文件類型的簽名支持只是SIP(負責數字簽名的創建、檢索和哈希計算、驗證的體系結構)的部分實現。

以下是ise.psm1中嵌入簽名的一部分:

# SIG # Begin signature block# MIIXXAYJKoZIhvcNAQcCoIIXTTCCF0kCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUv0M9fHFPOaghmrZBoun/tqPG# zE6gghIxMIIEYDCCA0ygAwIBAgIKLqsR3FD/XJ3LwDAJBgUrDgMCHQUAMHAxKzAp# BgNVBAsTIkNvcHlyaWdodCAoYykgMTk5NyBNaWNyb3NvZnQgQ29ycC4xHjAcBgNV# BAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEhMB8GA1UEAxMYTWljcm9zb2Z0IFJv# b3QgQXV0aG9yaXR5MB4XDTA3MDgyMjIyMzEwMloXDTEyMDgyNTA3MDAwMFoweTEL# MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v# bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEjMCEGA1UEAxMaTWlj# cm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw# ggEKAoIBAQC3eX3WXbNFOag0rDHa+SU1SXfA+x+ex0Vx79FG6NSMw2tMUmL0mQLD# TdhJbC8kPmW/ziO3C0i3f3XdRb2qjw5QxSUr8qDnDSMf0UEk+mKZzxlFpZNKH5nN# sy8iw0otfG/ZFR47jDkQOd29KfRmOy0BMv/+J0imtWwBh5z7urJjf4L5XKCBhIWO# sPK4lKPPOKZQhRcnh07dMPYAPfTG+T2BvobtbDmnLjT2tC6vCn1ikXhmnJhzDYav...# HNHPPQanI9HpDNBxWrVzcH6zIV1vBHSeB/tFtZpOI+beHjx7X3d1cyCg5lfERzyQ# 3jJyjSbMMbz8Pj/1meM0rlWQ/ZnYYiQAtJYqUN3ctT21Uu3ZVVnw46A8voTnSRMd# 5mVFLFMeFyJkWgsyqLroBTm4U/G+gZ2BB0ImzSbSfIo=# SIG # End signature block

這就是PowerShell代碼中的簽名如何存儲的(MOF文件是一個例外)。 為了使問題複雜化,可以簽名的每種文件類型都以獨特的方式存儲其簽名。 例如,PE簽名認證規範解釋了如何在PE文件(如EXE、DLL、SYS等)中存儲和驗證簽名。

位於crypt32.dll(常通過WinVerifyTrust.aspx)間接調用)中的一個函數CryptSIPRetrieveSubjectGuid.aspx),用於發現與特定文件類型相關聯的SIP的功能。 給定文件名和可選句柄,CryptSIPRetrieveSubjectGuid返回一個GUID,表示可以處理檢索嵌入認證簽名的SIP。 功能大致如下:

  1. 根據文件魔數,嘗試確定該文件是PE,編錄文件,CTL還是cabinet文件。如果是任何這些文件類型,它將返回以下相應的SIP GUID:
  • C689AAB8-8E78-11D0-8C47-00C04FC295EE -PE
  • DE351A43-8E59-11D0-8C47-00C04FC295EE -Catalog
  • 9BA61D3F-E73A-11D0-8CD2-00C04FC295EE -CTL
  • C689AABA-8E78-11D0-8C47-00C04FC295EE -Cabinet
  1. 如果文件不匹配任何以前的文件類型,它將調用CryptEnumOIDFunction.aspx)函數,傳遞它的功能名稱為「CryptSIPDllIsMyFileType」和「CryptSIPDllIsMyFileType2」。 這些功能分別對應於以下註冊表項的查找:
  • HKLMSOFTWARE[WOW6432Node]MicrosoftCryptographyOIDEncodingType 0CryptSIPDllIsMyFileType<All sub-GUIDs>
  • HKLMSOFTWARE[WOW6432Node]MicrosoftCryptographyOIDEncodingType 0CryptSIPDllIsMyFileType2<All sub-GUIDs>

    隨著CryptEnumOIDFunction枚舉每個SIP GUID註冊表子項,它將從「FuncName」和「Dll」列出的註冊表鍵值中調用DLL導出函數。

「CryptSIPDllIsMyFileType」的功能原型文檔戳我.aspx),「CryptSIPDllIsMyFileType2」的功能原型文檔戳我.aspx)。 如果有實現,「CryptSIPDllIsMyFileType」

函數首先被調用,如果其中一個函數返回「TRUE」,則返回處理簽名的SIP

GUID。 在實踐中(至少在Windows

10上),沒有SIP實現「CryptSIPDllIsMyFileType」,所以隨後調用「CryptSIPDllIsMyFileType2」函數來嘗試解決處理SIP。

例如,PowerShell(SIP

GUID:603BCC1F-4B59-4E08-B724-D2C6297EF351)將CryptSIPDllIsMyFileType2實現為pwrshsip!PsIsMyFileType。

經過反彙編、反編譯及整理輸出,這裡是PsIsMyFileType函數的C語言版的原型:

#define CRYPT_SUBJTYPE_POWERSHELL_IMAGE { 0x603BCC1F, x4B59, x4E08, { 0xB7, 0x24, 0xD2, 0xC6, 0x29, 0x7E, 0xF3, 0x51 } }BOOL WINAPI PsIsMyFileType(IN WCHAR *pwszFileName, OUT GUID *pgSubject) {BOOL bResult;WCHAR *SupportedExtensions[7];WCHAR *Extension;GUID PowerShellSIPGUID = CRYPT_SUBJTYPE_POWERSHELL_IMAGE;SupportedExtensions[0] = L"ps1";SupportedExtensions[1] = L"ps1xml";SupportedExtensions[2] = L"psc1";SupportedExtensions[3] = L"psd1";SupportedExtensions[4] = L"psm1";SupportedExtensions[5] = L"cdxml";SupportedExtensions[6] = L"mof";bResult = FALSE;if (pwszFileName && pgSubject) {Extension = wcsrchr(pwszFileName, .);if (Extension) {Extension++;for (int i = 0; i < 7; i++) {if (!_wcsicmp(Extension, SupportedExtensions[i])) {bResult = TRUE;memcpy(pgSubject, &PowerShellSIPGUID, sizeof(GUID));break;}}}}else{SetLastError(ERROR_INVALID_PARAMETER);}returnbResult;}

從C代碼中可以看出,如果任何文件有任何上述擴展名,那麼PowerShell SIP將是用作代碼簽名的SIP。

「CryptSIPDllIsMyFileType2」不一定要檢查文件擴展名,SIP還可以選擇打開文件句柄並檢查文件中的魔數值,以確定正確的文件/blob

SIP處理順序。

其他支持的SIP文件類型處理函數如下(非詳盡列表):

  1. 000C10F1-0000-0000-C000-000000000046

    C:WindowsSystem32MSISIP.DLL

    MsiSIPIsMyTypeOfFile
  2. 06C9E010-38CE-11D4-A2A3-00104BD35090

    C:WindowsSystem32wshext.dll

    IsFileSupportedName

  3. 0AC5DF4B-CE07-4DE2-B76E-23C839A09FD1

    C:WindowsSystem32AppxSip.dll

    AppxSipIsFileSupportedName
  4. 0F5F58B3-AADE-4B9A-A434-95742D92ECEB

    C:WindowsSystem32AppxSip.dll

    AppxBundleSipIsFileSupportedName
  5. 1629F04E-2799-4DB5-8FE5-ACE10F17EBAB

    C:WindowsSystem32wshext.dll

    IsFileSupportedName
  6. 1A610570-38CE-11D4-A2A3-00104BD35090

    C:WindowsSystem32wshext.dll

    IsFileSupportedName
  7. 5598CFF1-68DB-4340-B57F-1CACF88C9A51

    C:WindowsSystem32AppxSip.dll

    P7xSipIsFileSupportedName

  8. 603BCC1F-4B59-4E08-B724-D2C6297EF351

    C:WindowsSystem32WindowsPowerShellv1.0pwrshsip.dll

    PsIsMyFileType
  9. 9F3053C5-439D-4BF7-8A77-04F0450A1D9F

    C:WindowsSystem32EsdSip.dll

    EsdSipIsMyFileType
  10. CF78C6DE-64A2-4799-B506-89ADFF5D16D6

    C:WindowsSystem32AppxSip.dll

    EappxSipIsFileSupportedName
  11. D1D04F0C-9ABA-430D-B0E4-D7E96ACCE66C

    C:WindowsSystem32AppxSip.dll

    EappxBundleSipIsFileSupportedName

對於讀者來說, 逆向上面的某些函數來查看Windows所支持代碼簽名的文件或二進位blob的類型,這將是一個很有價值的練習。

一旦需要檢索簽名的軟體獲得該 SIP 的 GUID, 那它就可以繼續提取該證書。

文件簽名檢索和哈希驗證

一旦負責處理特定文件/二進位Blob格式的簽名的SIP通過其各自的GUID標識符被識別,WinVerifyTrust

就會知道如何從該文件中獲取數字簽名並驗證其計算出的哈希對嵌入在數字中的簽名哈希簽名。為實現這一點, WinVerifyTrust

在註冊表中調用以下函數:

SIP 簽名檢索功能位置:

  • HKLMSOFTWARE[WOW6432Node]MicrosoftCryptographyOIDEncodingType 0CryptSIPDllGetSignedDataMsg{SIP Guid}
  • Dll
  • FuncName

SIP 哈希驗證函數:

  • HKLMSOFTWARE[WOW6432Node]MicrosoftCryptographyOIDEncodingType 0CryptSIPDllVerifyIndirectData{SIP Guid}
    • Dll
    • FuncName

CryptSIPDllGetSignedDataMsg.aspx)和CryptSIPDllVerifyIndirectData.aspx)的函數原型在MSDN有文檔,同樣也存在於Windows SDK中的mssip.h頭文件中。

SIP簽名檢索功能原型:

BOOL WINAPI CryptSIPGetSignedDataMsg(IN SIP_SUBJECTINFO *pSubjectInfo,OUT DWORD *pdwEncodingType,IN DWORD dwIndex,IN OUT DWORD *pcbSignedDataMsg,OUT BYTE *pbSignedDataMsg);

SIP 哈希驗證函數原型:

BOOL WINAPI CryptSIPVerifyIndirectData(IN SIP_SUBJECTINFO *pSubjectInfo,IN SIP_INDIRECT_DATA *pIndirectData);

SIP_SUBJECTINFO.aspx) SIP_INDIRECT_DATA.aspx)

1387/5000提供給這些函數的參數由調用信任提供者負責填充(有關信任提供者架構的更多細節,請參見以下部分)。當CryptSIPGetSignedDataMsg被調用時,SIP將提取編碼的數字簽名(最常用的是CERT_SIGNED_CONTENT_INFO.aspx)結構體,ASN.1 PKCS_7_ASN_ENCODING和X509_ASN_ENCODING編碼),並通過「pbSignedDataMsg」參數返回。CERT_SIGNED_CONTENT_INFO內容由簽名證書(包括其發行鏈)、用於對文件進行哈希和簽名的演算法以及文件的簽名散列組成。調用信任提供者然後對數字簽名進行解碼,提取散列演算法和簽名哈希值,然後將它們傳遞給CryptSIPVerifyIndirectData。在校驗認證碼哈希計算並與已簽名哈希進行比較後,如果匹配,則CryptSIPVerifyIndirectData返回TRUE,否則返回FALSE,然後WinVerifyTrust將返回一個錯誤,表明哈希不匹配。

CryptSIPVerifyIndirectData是最重要的數字簽名驗證功能之一,但這將會犯錯:因為攻擊者可以將現有的合法數字簽名應用於其惡意軟體——這是一種在野的攻擊技術。

以下是一個適用於合法認證碼簽名的惡意軟體示例的哈希失真的示例:

在使用微軟認證碼簽名的未簽名文件上顯示哈希不匹配錯誤的示例(注意相同的SignerCertificate指紋值)

未簽名的文件在應用於簽名文件的認證碼簽名時無法驗證。微軟就是這麼設計的。

信任提供者架構

到目前為止,已經討論了SIP的基本架構。如現在應該理解的,SIP僅負責數字簽名應用、檢索和散列計算、驗證。應用於文件的數字簽名的存在是無意義的,除非某些標準被實際驗證。這就是信任提供者發揮作用的地方——除了內置到所需的信任提供者中的標準之外,還可以根據調用者指定的參數組合對WinVerifyTrust進行驗證。

像SIP一樣,信任提供者也由GUID唯一標識。 截至到Windows 10,有以下信任提供者存在:

GUID 描述 A7F4C378-21BE-494e-BA0F-BB12C5D208C5 UNKNOWN .NET VERIFIER 7801EBD0-CF4B-11D0-851F-0060979387EA CERT_CERTIFICATE_ACTION_VERIFY 6078065B-8F22-4B13-BD9B-5B762776F386 CONFIG_CI_ACTION_VERIFY D41E4F1F-A407-11D1-8BC9-00C04FA30A41 COR_POLICY_LOCKDOWN_CHECK D41E4F1D-A407-11D1-8BC9-00C04FA30A41 COR_POLICY_PROVIDER_DOWNLOAD 31D1ADC1-D329-11D1-8ED8-0080C76516C6 COREE_POLICY_PROVIDER F750E6C3-38EE-11D1-85E5-00C04FC295EE DRIVER_ACTION_VERIFY 573E31F8-AABA-11D0-8CCB-00C04FC295EE HTTPSPROV_ACTION 5555C2CD-17FB-11d1-85C4-00C04FC295EE OFFICESIGN_ACTION_VERIFY 64B9D180-8DA2-11CF-8736-00AA00A485EB WIN_SPUB_ACTION_PUBLISHED_SOFTWARE C6B2E8D0-E005-11CF-A134-00C04FD7BF43 WIN_SPUB_ACTION_PUBLISHED_SOFTWARE_NOB 189A3842-3041-11D1-85E1-00C04FC295EE WINTRUST_ACTION_GENERIC_CERT_VERIFY FC451C16-AC75-11D1-B4B8-00C04FB66EA0 WINTRUST_ACTION_GENERIC_CHAIN_VERIFY 00AAC56B-CD44-11D0-8CC2-00C04FC295EE WINTRUST_ACTION_GENERIC_VERIFY_V2 573E31F8-DDBA-11D0-8CCB-00C04FC295EE WINTRUST_ACTION_TRUSTPROVIDER_TEST

信任提供者的部分組件的聲明在MSDN和windowsSDk的SoftPub.h的文檔中能找到,但是它們的實現並沒有文檔化。對開發人員而言,這就需要從信任證書、簽名、信任鏈、吊銷和時間戳正確執行驗證。開發人員調用WinVerifyTrust使用的更常見的信任提供程序之一是WINTRUST_ACTION_GENERIC_VERIFY_V2以用來確認通用校驗碼簽名。如果需要在用戶模式下驗證驅動程序的可信性任,

則應使用 DRIVER_ACTION_VERIFY。

與 sip 一樣, 信任提供程序也在註冊表中註冊了以下項:

- HKLM\SOFTWARE\[WOW6432Node\]Microsoft\Cryptography\Providers\Trust

在"信任"鍵中,是一個子項列表,對應於可能發生的每個信任提供程序驗證步驟:初始化(Initialization)、消息(Message)、簽名(Signature)、證書(Certificate)、認證檢查(CertCheck)、最終策略(FinalPolicy)、診斷策略(DiagnosticPolicy)和清理(Cleanup)。其中的每個密鑰都是實現每個步驟的信任提供程序

guid (不是所有的都是必需的. 例如, 證書檢查、診斷策略和清理)。在每個各自的 GUID 子項中, 都是由註冊表裡的 dll

和導出函數來實現信任提供程序步驟的$DLL$Function

在註冊表中註冊的信任提供者的示例

每個信任提供程序步驟的用途可以大致細分如下:

  1. 初始化:

    a. 初始化 CRYPT_PROVIDER_DATA.aspx) 結構體(該結構體基於WINTRUST_DATA.aspx)

    結構體),然後傳遞給WinVerifyTrust。CRYPT_PROVIDER_DATA是在所有信任提供程序函數之間傳遞的結構體,用於在所有調用中維護狀態,包括可能在執行過程中的每個步驟的錯誤代碼

    (請參見 wintrust 中的 TRUSTERROR_STEP 值)。

    b. 打開要驗證的文件的只讀句柄。
  2. 消息:

    a. 從主題介麵包中獲取簽名者信息。這是驗證過程中的唯一步驟,它調用各自的SIP以獲取正確的簽名。請注意,在嘗試從嵌入的驗證碼簽名獲取簽名之前,某些信任校驗實用程序將首先檢查簽名的目錄存儲。

    b. "初始化" 和 "消息" 步驟都被稱為 "對象提供程序"。
  3. 簽名:

    a. 在此步驟中, 將生成數字簽名, 並驗證 counter-signers 和時間戳。

    b. 這一步驟被稱為「簽名提供者」。
  4. 證書:

    a. 這一步中,整個證書鏈將被生成。

    b. 這一步被稱為「證書提供者」。
  5. 認證檢查:

    a. 如果實現此可選步驟, 則為證書鏈中的每個索引調用此函數, 並用於向信任提供者指示證書鏈應繼續構建。
  6. 最終策略:

    a. 這是大多數信任決策的作用。此時, 簽名和證書鏈已被解碼、解析並提供給這個實現函數。

    b. 驗證簽名、證書鏈和證書存儲的哪些組件因信任提供程序而異。下面是使用 WINTRUST_ACTION_GENERIC_VERIFY_V2 信任提供程序時發生的一些檢查的小列表 (實現 WINTRUST!SoftPubAuthenticode):

i. 驗證文件是否已使用指定的代碼簽名證書(由 "1.3. 6.1. 5.5. 7.3. 3" 的增強密鑰用法 (EKU) 表示)進行簽名。

ii. 檢查證書是否已過期,是否有時間戳。

iii. 檢查證書是否被吊銷。

iv. 驗證文件是否使用「弱」哈希演算法進行了簽名。

v. 如果文件是指定為 "Windows 系統證書籤名的組件驗證 "(EKU-1.3. 6.1. 4.1. 311.10.3. 6), 則驗證簽名證書鏈到一組固定的受信任的 Microsoft 根證書。

  1. 診斷策略:

    a. 此可選步驟旨在幫助信任提供程序開發人員進行調試。它的目的是讓微軟的開發者在返回到 WinVerifyTrust 之前可以把結構體內容dump出來。

    b. WINTRUST_ACTION_TRUSTPROVIDER_TEST是實現此步驟的唯一信任提供程序。WINTRUST_ACTION_TRUSTPROVIDER_TESTWINTRUST_ACTION_GENERIC_VERIFY_V2是相同的,不過它是實現wintrust!SoftpubDumpStructure的一個額外步驟。SoftpubDumpStructure將填充的 CRYPT_DATA_PROVIDER 結構轉儲到 C:TRUSTPOL.txt。從命令提示符(需要有寫入c盤的許可權)使用 signtool.exe (在 Windows SDK 中) 可以輕鬆地測試此步驟。指定WINTRUST_ACTION_TRUSTPROVIDER_TEST (認證碼測試) 信任提供程序的GUID:

    i. signtool verify /pg {573E31F8-DDBA-11D0-8CCB-00C04FC295EE} filename.exe
  2. 清理:

    a. 在此可選步驟中, 信任提供程序可以清除所有已填充的 CRYPT_PROVIDER_PRIVDATA結構體, 以便跨信任提供程序步驟傳遞特定策略的數據。信任提供者和SIP註冊

了解信任提供者和 sip 在註冊表中註冊的合法方法, 以便了解攻擊者如何利用註冊過程 (或完全顛覆它),這非常重要。

SIP 註冊

SIP通過調用DllRegisterServer.aspx)的導出函數「wintrust!

CryptSIPAddProvider.aspx)」來完成註冊。這使得SIP可以通過調用 「regsvr32.exe SIPfilename.dll」 來完成註冊。CryptSIPAddProvider 需要 SIP_ADD_NEWPROVIDER.aspx) 結構體, 它由在實現簽名功能的SIP DLL中的導出函數組成。需要以下SIP_ADD_NEWPROVIDER欄位:

  1. pwszDLLFileName:

    SIP DLL 的名稱。這可能只是文件名, 但它應該是完整的路徑。
  2. pwszGetFuncName:

    實現CryptSIPGetSignedDataMsg.aspx)的導出函數名
  3. pwszPutFuncName:

    實現CryptSIPPutSignedDataMsg.aspx)的導出函數名
  4. pwszCreateFuncName:

    實現CryptSIPCreateIndirectData.aspx)的導出函數名
  5. pwszVerifyFuncName:

    實現CryptSIPVerifyIndirectData.aspx)的導出函數名
  6. pwszRemoveFuncName:

    實現CryptSIPRemoveSignedDataMsg.aspx)的導出函數名

下列 SIP_ADD_NEWPROVIDER 欄位是可選的:

  1. pwszIsFunctionNameFmt2:

    實現pfnIsFileSupportedName.aspx)
  2. pwszGetCapFuncName:

    實現pCryptSIPGetCaps.aspx)
  3. pwszIsFunctionName:

    實現pfnIsFileSupported.aspx)

在調用 CryptSIPAddProvider 時, wintrust.dll 將各自的導出函數名和實現 dll 添加到

HKLMSOFTWARE[WOW6432Node]MicrosoftCryptographyOIDEncodingType 0

註冊表子鍵中。

SIP dll 還應實現 DllUnregisterServer.aspx) 註銷功能, 該函數調用 CryptSIPRemoveProvider.aspx) 刪除所有相關的 SIP 註冊表項。

信任提供者註冊

信任提供者通過調用 DllRegisterServer的導出函數wintrustWintrustAddActionID.aspx)實現。這使得信任提供者可以通過調用 "regsvr32.exe TrustProviderfilename.dll" 來正式註冊。 WintrustAddActionID 需要一個

CRYPT_REGISTER_ACTIONID.aspx)——由在執行所有信任驗證步驟的信任提供程序 DLL 中的導出函數組成的結構體,。信任提供程序註冊功能可以與 SIP 註冊的函數共享, 也可以在專用 DLL 中獨立。

在調用 WintrustAddActionID 時, wintrust.dll 將各自的導出函數名和實現 dll 添加到

HKLMSOFTWARE[WOW6432Node]MicrosoftCryptographyProvidersTrust

註冊表子鍵中。

信任提供者通過調用DllUnregisterServer的導出函數 wintrust! WintrustRemoveActionID.aspx) 來取消註冊。

信任提供者和 SIP 註冊示例

最重要的信任提供者註冊位於wintrust!DllRegisterServer中,執行以下註冊步驟:

  1. 調用 WintrustDllRegisterServer

    a. 調用

    wintrust!CryptRegisterOIDFunction函數,使用CryptEncodeObject 和

    CryptDecodeObject註冊 ASN.1編碼/解碼常式。這類的許多函數在創建數字簽名時被調用。在分析數字簽名以進行驗證時,

    通常會調用它們的解碼對應函數。與 SIP 和信任提供程序註冊一樣, 這些實現函數也存儲在註冊表中:
    • HKLMSOFTWARE[WOW6432Node]MicrosoftCryptographyOIDEncodingType1[CryptDllDecodeObject|CryptDllEncodeObject]

所有這些編碼函數都接受以下函數簽名:

    • BOOL WINAPI EncoderDecoderFunction(DWORD

      dwCertEncodingType, LPCSTR lpszStructType,

      PSPC_PE_IMAGE_DATA pInfo, BYTE pbEncoded, DWORD

      pcbEncoded);

WintrustDllRegisterServer 註冊以下編碼/解碼常式:

i. 1.3.6.1.4.1.311.2.1.15 (SPC_PE_IMAGE_DATA_OBJID)

函數: wintrust!WVTAsn1SpcPeImageDataEncode

ii. 1.3.6.1.4.1.311.2.1.25 (SPC_CAB_DATA_OBJID)

函數: wintrust!WVTAsn1SpcLinkEncode

iii. 1.3.6.1.4.1.311.2.1.20 (SPC_JAVA_CLASS_DATA_OBJID)

函數: wintrust!WVTAsn1SpcLinkEncode

iv. 1.3.6.1.4.1.311.2.1.28 (SPC_LINK_OBJID)

函數: wintrust!WVTAsn1SpcLinkEncode

v. 1.3.6.1.4.1.311.2.1.30 (SPC_SIGINFO_OBJID)

函數: wintrust!WVTAsn1SpcSigInfoEncode

vi. 1.3.6.1.4.1.311.2.1.4 (SPC_INDIRECT_DATA_OBJID)

函數: wintrust!WVTAsn1SpcIndirectDataContentEncode

vii. 1.3.6.1.4.1.311.2.1.10 (SPC_SP_AGENCY_INFO_OBJID)

函數: wintrust!WVTAsn1SpcSpAgencyInfoEncode

viii. 1.3.6.1.4.1.311.2.1.26 (SPC_MINIMAL_CRITERIA_OBJID)

函數: wintrust!WVTAsn1SpcMinimalCriteriaInfoEncode

ix. 1.3.6.1.4.1.311.2.1.27 (SPC_FINANCIAL_CRITERIA_OBJID)

函數: wintrust!WVTAsn1SpcFinancialCriteriaInfoEncode

x. 1.3.6.1.4.1.311.2.1.11 (SPC_STATEMENT_TYPE_OBJID)

函數: wintrust!WVTAsn1SpcStatementTypeEncode

xi. 1.3.6.1.4.1.311.12.2.1 (CAT_NAMEVALUE_OBJID)

函數: wintrust!WVTAsn1CatNameValueEncode

xii. 1.3.6.1.4.1.311.12.2.2 (CAT_MEMBERINFO_OBJID)

函數: wintrust!WVTAsn1CatMemberInfoEncode

xiii. 1.3.6.1.4.1.311.12.2.3 (CAT_MEMBERINFO2_OBJID)

函數: wintrust!WVTAsn1CatMemberInfo2Encode

xiv. 1.3.6.1.4.1.311.2.1.12 (SPC_SP_OPUS_INFO_OBJID)

函數: wintrust!WVTAsn1SpcSpOpusInfoEncode

xv. 1.3.6.1.4.1.311.2.4.2 (szOID_INTENT_TO_SEAL)

函數: wintrust!WVTAsn1IntentToSealAttributeEncode

xvi. 1.3.6.1.4.1.311.2.4.3 (szOID_SEALING_SIGNATURE)

函數: wintrust!WVTAsn1SealingSignatureAttributeEncode

xvii. 1.3.6.1.4.1.311.2.4.4 (szOID_SEALING_TIMESTAMP)

函數: wintrust!WVTAsn1SealingTimestampAttributeEncode

  1. 接下來, SoftpubDllRegisterServer 調用 WintrustAddActionID 來註冊下列信任提供者:

    a. WINTRUST_ACTION_GENERIC_VERIFY_V2

    b. WIN_SPUB_ACTION_PUBLISHED_SOFTWARE

    c. WIN_SPUB_ACTION_PUBLISHED_SOFTWARE_NOBADUI

    d. WINTRUST_ACTION_GENERIC_CERT_VERIFY

    e. WINTRUST_ACTION_TRUSTPROVIDER_TEST

    f. HTTPSPROV_ACTION. 下面的相關默認 "用法".aspx) 也註冊 (全部存儲在註冊表HKLMSOFTWARE[WOW6432Node]MicrosoftCryptographyProvidersTrustUsages中):

    i. 1.3.6.1.4.1.311.10.3.3 (szOID_SERVER_GATED_CRYPTO)

    Alloc/dealloc 函數: wintrust!SoftpubLoadDefUsageCallData

    ii. 1.3.6.1.5.5.7.3.1 (szOID_PKIX_KP_SERVER_AUTH)

    Alloc/dealloc 函數: wintrust!SoftpubLoadDefUsageCallData

    iii. 1.3.6.1.5.5.7.3.2 (szOID_PKIX_KP_CLIENT_AUTH)

    Alloc/dealloc 函數: wintrust!SoftpubLoadDefUsageCallData

    iv. 2.16.840.1.113730.4.1 (szOID_SGC_NETSCAPE)

    Alloc/dealloc 函數: wintrust!SoftpubLoadDefUsageCallData

    g. DRIVER_ACTION_VERIFY

    h. WINTRUST_ACTION_GENERIC_CHAIN_VERIFY
  1. 最後, mssip32DllRegisterServer 被調用來註冊SIP。具體來說, 調用 CryptSIPAddProvider 來註冊以下SIP:

    a. DE351A42-8E59-11D0-8C47-00C04FC295EE

    CRYPT_SUBJTYPE_FLAT_IMAGE

    b. C689AABA-8E78-11d0-8C47-00C04FC295EE

    CRYPT_SUBJTYPE_CABINET_IMAGE

    c. C689AAB8-8E78-11D0-8C47-00C04FC295EE

    CRYPT_SUBJTYPE_PE_IMAGE

    d. DE351A43-8E59-11D0-8C47-00C04FC295EE

    CRYPT_SUBJTYPE_CATALOG_IMAGE

    e. 9BA61D3F-E73A-11D0-8CD2-00C04FC295EE

    CRYPT_SUBJTYPE_CTL_IMAGE
  1. mssip32DllRegisterServer 還顯式註銷了以下 sip (實際上, Java SIP 組件保留在windows默認的註冊表中):

a. C689AAB9-8E78-11D0-8C47-00C04FC295EE

CRYPT_SUBJTYPE_JAVACLASS_IMAGE

b. 941C2937-1292-11D1-85BE-00C04FC295EE

CRYPT_SUBJTYPE_SS_IMAGE.aspx)

雖然不建議這樣做, 但所有 wintrust 的信任提供程序和 SIP 註冊都可以使用以下命令 (從提升許可權的命令提示符中) 正式註銷:

regsvr32.exe /u C:WindowsSystem32wintrust.dll

運行上述命令將剝離 Windows 在用戶模式下的 執行大多數數字簽名檢索和信任驗證的用戶模式的能力。

信任提供者和 SIP 交互

雖然在前面的 "消息" 信任提供者步驟中提到了 SIP 和信任提供者之間的交互, 不過按順序說明所有步驟的圖表應該更有用吧。

WinVerifyTrust、信任提供者和SIP之間的交互說明

希望到目前為止, 對信任提供者和SIP的角色有一個基本的了解, 以及它們的體系架構在很大程度上是通過註冊註冊表來實現模塊化的。在下一節中, 將討論對 Windows 信任體系結構的模塊化的攻擊。

Windows 信任體系架構攻擊

通過對 Windows 用戶模式信任體系結構的基本了解以及較高的許可權級別, 攻擊者擁有了他需要破壞信任體系的武器。那麼攻擊者通過顛覆信任可以來實現什麼呢?

  1. 讓操作系統相信攻擊者提供的代碼是以 "受信任的" 代碼簽名證書 (例如, 用於簽名 Microsoft 代碼的) 簽名和驗證的。這種攻擊背後的動機是:

    a. 使安全產品將攻擊者提供的代碼分類為良性。

    b. 從執行簽名驗證的安全/診斷工具中隱藏。

    c. 一般情況下,在實時檢測工具之下,安全人員可能更容易忽略 "使用合法證書籤名" 的代碼。

    d. 在執行用戶模式信任驗證的任何進程的上下文中載入惡意代碼。
  2. 顛覆應用程序強制基於可信簽名許可權策略的白名單發布規則。發布者強校驗是最常見的名單規則方案之一,因為它甚至允許受信任發布者簽名的代碼可以繞過不允許軟體更新的哈希規則而更新、執行,這種情況下更難維護和審核。SIP 劫持 #1: CryptSIPDllGetSignedDataMsg

如前所述,SIP的CryptSIPDllGetSignedDataMsg組件是允許從已簽名的文件中檢索編碼的數字證書的。再次提醒下,SIP的CryptSIPDllGetSignedDataMsg組件的已實現導出功能存在於以下註冊表項中:

  1. HKLMSOFTWARE[WOW6432Node]MicrosoftCryptographyOIDEncodingType 0CryptSIPDllGetSignedDataMsg{SIP Guid}
  • Dll -實現數字簽名檢索函數的 DLL 的路徑
  • FuncName -實現數字簽名檢索功能的導出函數的名稱

此外, 如前所述, CryptSIPDllGetSignedDataMsg 函數具有以下原型:

BOOL WINAPI CryptSIPGetSignedDataMsg(IN SIP_SUBJECTINFO *pSubjectInfo,OUT DWORD *pdwEncodingType,IN DWORD dwIndex,IN OUT DWORD *pcbSignedDataMsg,OUT BYTE *pbSignedDataMsg);

任何熟悉 c/c++ 的攻擊者都能夠輕鬆地實現此類功能, 並將現有的 SIP 條目替換為其惡意功能。首先, 了解每個參數的含義是很重要的:

  1. pSubjectInfo:從調用信任提供者傳入的結構體指針, 包含有關提取簽名的文件的所有相關信息。這裡是一個例子:傳遞給

    pwrshsip!PsGetSignature (PowerShell SIP的

    CryptSIPDllGetSignedDataMsg組件)結構體的轉儲(dump):

  1. pdwEncodingType:在從pSubjectInfo中指定的文件檢索數字簽名時,此參數指示調用函數(信任提供者"消息"組件)如何正確解碼返回數字簽名。最常見是的PKCS_7_ASN_ENCODING

    和 X509_ASN_ENCODING 一起進行二進位或運算 。
  2. dwIndex: 此參數應為零, 但理論上 SIP 可以包含多個嵌入的簽名, dwIndex 表示從指定文件中提取哪一個數字簽名。
  3. pcbSignedDataMsg: 通過 pbSignedDataMsg 返回的數字簽名的長度 (以位元組為單位)。
  4. pbSignedDataMsg: 返回到調用信任提供程者的已編碼的數字簽名。

因此,如果攻擊者要實現此功能並使用它作為示例,來覆蓋可執行文件的SIP(C689AAB8-8E78-11D0-8C47-00C04FC295EE)的CryptSIPDllGetSignedDataMsg組件,則任何

PE 文件都可能返回攻擊者選擇的任意數字簽名。

想像一下下面虛構的攻擊場景:

  1. 攻擊者在註冊表中實現了可執行文件SIP的CryptSIPDllGetSignedDataMsg組件。
  1. 簡單地說, 無論是否有嵌入的驗證碼簽名, 為任何可執行文件返回相同的 Microsoft 證書。
  1. 為了確保返回適當格式的數字簽名,最好在對其進行劫持之前在調試器中的合法CryptSIPDllGetSignedDataMsg上設置斷點。這樣做可以確保PKCS#7認證簽名數據始終可以正確地返回。

a. 在 PowerShell 腳本中, 這涉及 base64 解碼 "SIG # 開始簽名塊"(SIG # Begin signature block)。

b. 在帶有嵌入驗證碼簽名的PE文件中, PKCS #7 校驗簽名的數據存在於PE校驗碼規範(PE Authenticode specification)中所記錄的嵌入式WIN_CERTIFICATE.aspx)結構體的bCertificate 欄位中。

c. 編錄文件本身就是 PKCS #7 校驗碼簽名的數據 (實際上可以在嵌入的 PE 校驗碼簽名中使用)。

  1. 現在, 攻擊者的實現只需要返回正確的編碼簽名數據長度和簽名數據。

在這種攻擊場景中,被劫持的CryptSIPDllGetSignedDataMsg可以返回用於簽署許多系統組件(如notepad.exe)的目錄文件的位元組。為了方便地確定與已簽名文件關聯的編錄文件,可以使用 sigcheck.exe:

sigcheck -i C:WindowsSystem32
otepad.exe

在當前的例子中,返回下面的編錄文件路徑:

C:WINDOWSsystem32CatRoot{F750E6C3-38EE-11D1-85E5-00C04FC295EE}Microsoft-Windows-Client-Features-Package-AutoMerged-shell~31bf3856ad364e35~amd64~~10.0.15063.0.cat

現在,攻擊者實現只需要從該編錄文件返回位元組,使任何PE文件看起來都使用了與notepad.exe相同的證書進行簽名。模塊化設計方法是將所需的簽名內容嵌入到攻擊者提供的SIP DLL中的資源中。

下面的示例說明了 PowerShell SIP CryptSIPDllGetSignedDataMsg 組件是如何使用自定義的惡意 SIP來劫持的, 它將始終返回與 PowerShell 文件相同的合法 Microsoft 證書:

PowerShell CryptSIPDllGetSignedDataMsg 劫持的演示

可以看出, 在劫持之前, 不出所料,test.ps1 顯示為未簽名。然而, 在劫持發生後,test.ps1 似乎是用 Microsoft 證書籤名的:

一個未經簽名的 PowerShell 腳本, 似乎突然間就被微軟給簽

雖然未簽名的 PowerShell 腳本看起來由 Microsoft 簽名了, 但它的哈希驗證並沒有通過。

雖然看起來劫持是成功的, 但有一個缺陷-簽名無法驗證, 因為計算的哈希與數字簽名中的已簽名哈希不匹配。此劫持的另一個不良影響是,任何PowerShell代碼都將使用相同的數字簽名, 這將在大多數情況下導致哈希不匹配。

為了防止信任驗證因哈希不匹配而失敗, 還需要劫持CryptSIPDllVerifyIndirectData 。

SIP 劫持 #2: CryptSIPDllVerifyIndirectData

正如前面的劫持場景中所解釋的,劫持已註冊SIP的CryptSIPDllGetSignedDataMsg組件允許未經簽名的代碼看起來像是被簽名了。但是,考慮到哈希值不匹配,數字簽名將無法在攻擊者提供的代碼上進行驗證。然而,

再劫持 CryptSIPDllVerifyIndirectData 下函數就不存在這個問題了。

再次提醒下, CryptSIPDllVerifyIndirectData 實現存儲在以下註冊表值中:

  • HKLMSOFTWARE[WOW6432Node]MicrosoftCryptographyOIDEncodingType 0CryptSIPDllVerifyIndirectData{SIP Guid}
    • Dll
    • FuncName

函數原型:

BOOL WINAPI CryptSIPVerifyIndirectData(IN SIP_SUBJECTINFO *pSubjectInfo,IN SIP_INDIRECT_DATA *pIndirectData);

調試CryptSIPVerifyIndirectData的合法實現,可以確認當計算出的驗證碼哈希與簽名的哈希值匹配時,CryptSIPVerifyIndirectData返回TRUE。因此,所有惡意SIP需要做的就是為被劫持的相應SIP匹配生成,返回TRUE,從而使之看起來可以通過哈希驗證。繼續執行PowerShell劫持示例,惡意SIP僅為哈希驗證常式返回true,將解決攻擊者提供的代碼無法正確驗證的問題。

BOOL WINAPI AutoApproveHash(SIP_SUBJECTINFO *pSubjectInfo,SIP_INDIRECT_DATA *pIndirectData) {UNREFERENCED_PARAMETER(pSubjectInfo);UNREFERENCED_PARAMETER(pIndirectData);return TRUE;}

接下來, 劫持哈希驗證處理程序 (連同以前的劫持簽名檢索功能) 將通過所有的檢查, 將未經簽名的 PowerShell 代碼偽裝為已簽署Microsoft的代碼:

劫持 PowerShell SIP 的 CryptSIPVerifyIndirectData 組件

現在, 未簽名的 PowerShell 文件出現簽名並經過正確驗證

"數字簽名" UI 選項卡顯示一個未簽名的 PowerShell 文件, 它顯示簽名並經過正確驗證。

Sysinternals sigcheck 顯示一個未簽名的 PowerShell 文件, 它顯示簽名並經過正確驗證。

一個更理想的劫持場景是甚至懶得劫持

CryptSIPDllGetSignedDataMsg 的目標 SIP。 相反, 只需應用合法的驗證碼簽名 (例如 從

C:WindowsSystem32WindowsPowerShellv1.0ModulesISEise.psm1)

到攻擊者提供的代碼, 並只劫持 CryptSIPVerifyIndirectData。這樣做為攻擊者提供了以下好處:

  1. 有更少的劫持和清理工作;
  2. 良性、合法簽名的代碼將正確應用其各自的簽名;
  3. 攻擊者提供的帶有 "合法" 的嵌入式校驗碼證書的代碼很可能會受到安全產品的嚴格審查。

test.ps1 具有和ise.psm1相同的嵌入式校驗碼簽名, 並且證書指紋值相匹配

雖然目前為止示例集中在

PowerShell SIP 上, 但這些劫持原則適用於所有SIP。下面是一個被劫持的可執行文件的SIP

(C689AAB8-8E78-11D0-8C47-00C04FC295EE) 的示例, 它將合法的 Microsoft

數字簽名應用於攻擊者提供的二進位文件上:

notepad_backdoored.exe擁有應用於本屬於notepad.exe (目錄簽名) 的數字簽名

"數字簽名" UI 選項卡還確認攻擊者-suppled notepad_backdoored. exe 驗證為已簽名的 Microsoft 文件。

此劫持將騙過任何執行用戶模式信任/簽名驗證的程序, 包括 Sysinternals 的Process Explorer:

notepad_backdoored.exe 在 Sysinternals 的Process Explorer中顯示為「已驗證簽名"。

繞過 UMCI 設備保護 執行

在應用程序白名單方案中, 使用未經簽名的/未經批准的二進位文件來驗證信任的機制,構成了一個

"雞和蛋" 問題,即需要根據部署的惡意 SIP DLL 的信任來驗證白名單政策。結果是, 至少使用設備保護,系統將無法載入惡意的 SIP

DLL, 不過這將導致信任驗證在許多情況下失敗。這可以理解地有可能導致系統穩定性問題。理想情況下 (對於攻擊者) 將有一個可以為

CryptSIPVerifyIndirectData 角色提供服務的簽名

DLL。幸運的是,回想一下,CryptSIPVerifyIndirectData 函數接受以下函數簽名:

BOOL WINAPI CryptSIPVerifyIndirectData(IN SIP_SUBJECTINFO *pSubjectInfo,IN SIP_INDIRECT_DATA *pIndirectData);

此外, 為了通過驗證檢查, 函數必須返回 TRUE。因此, 我們面臨以下要求, 以產生一個簽名的CryptSIPVerifyIndirectData 函數:

  1. Dll文件必須有簽名;
  2. 函數必須接受兩個參數;
  3. 函數必須使用WINAPI/stdcall 調用規範;
  4. 函數必須返回TRUE(通常為非零數或者奇數);
  5. 函數不能改變傳入的參數, 因為這可能導致內存損壞;
  6. 除了返回 "TRUE" 之外, 該函數最好沒有其他意料之外的影響;
  7. 函數必須導出。

毫無疑問, 這樣一個查找候選函數的過程可以通過將函數轉換為中間語言來進行自動分析, 而不需要很長時間就能找到候選輸出函數-ntdll!DbgUiContinue:

ntdll!DbgUiContinue的反彙編及注釋

只需將目標 SIP 的 CryptSIPVerifyIndirectData 註冊表項設置為 C:WindowsSystem32
tdll.dll
DbgUiContinue,就足以通過對任何應用了合法的嵌入校驗碼簽名的代碼進行哈希校驗檢查。實際上,在對強制啟用設備保護的系統上的可執行文件

SIP 進行測試時, 攻擊者提供的代碼被阻止執行。但是, 劫持 PowerShell SIP 啟用了受約束的語言模式繞過,

從而實現了任意的、無簽名的代碼執行。不過,對於使用可執行文件與 PowerShell 代碼進行的其他 (可能是內核支持的) 信任斷言,

還不清楚。也有可能存在比DbgUiContinue更好用的劫持函數 , 但這足以證明攻擊者提供的無簽名的 SIP DLL足夠可以用來劫持。

下面的示例演示了PowerShell在啟用了設備保護的約束語言模式下,防止在發生劫持事件之前執行添加類型,並防止 CryptSIPVerifyIndirectData 在被劫持之後進行後續旁路操作:

在劫持之前,由於受限的語言模式,test.psm1中的代碼將被阻止執行

在 "簽名代碼重用" 攻擊發生之後,將繞過受約束的語言模式。

儘管這種形式的劫持並不代表完全接管強制設備保護用戶模式完整性 (UMCI),但它確實從隱形角度提出了一種良好的劫持方法,因為它不需要攻擊者將任何惡意代碼丟棄到磁碟-即攻擊者提供 SIP。

信任提供者「最終策略」(FinalPolicy )劫持

正如在 "信任提供者體系架構" 部分中所描述的那樣, 最終的信任決策由信任提供程序的 最終策略組件進行。這是 FinalPolicy 的函數簽名:

HRESULT WINAPI FinalPolicyFunction(_Inout_ struct _CRYPT_PROVIDER_DATA *pProvData);

FinalPolicy 為各自的信任提供者實現功能,其位於這裡:

HKLMSOFTWARE[WOW6432Node]MicrosoftCryptographyProvidersTrustFinalPolicy{trust provider GUID}

雖然攻擊者可以選擇實現自己的信任提供程序

DLL 來顛覆 FinalPolicy,但這需要攻擊者將惡意代碼在硬碟落地。此外, 與 SIP 相比,

完全實現信任提供者的介面比較複雜。不過,如前所述,可以用已簽名代碼來劫持

FinalPolicy,以此來模擬傳遞其所有檢查。備選的已簽名的劫持函數需要滿足以下要求:

  1. DLL 必須有簽名;
  2. 函數必須只接受一個參數;
  3. 函數必須使用WINAPI/stdcall 調用規範;
  4. 函數的返回結果必須是 0 (S_OK) ,以表示HRESULT成功;
  5. 函數不能改變傳入的參數, 因為這可能導致內存損壞;
  6. 除了返回 0之外, 該函數最好沒有別的影響;
  7. 函數必須被導出。

未實現的導出函數 wintrust!SoftpubCleanup 滿足了執行劫持的所有要求。

SoftpubCleanup函數的反彙編

轉化為C語言的話,等效於下面的內容:

HRESULT WINAPI SoftpubCleanup(CRYPT_PROVIDER_DATA *data){return S_OK;}

例如, 設置 WINTRUST_ACTION_GENERIC_VERIFY_V2 (00AAC56B-CD44-11D0-8CC2-00C04FC295EE)

的 FinalPolicy 組件將導致許多簽名驗證工具 (如AuthenticodeSignature、sigcheck、signtool

等)認為未簽名的代碼或應用合法簽名的代碼作為受信任的。在實踐中, 使用 SoftpubCleanup 執行此劫持會導致進程資源管理器

(procexp)必現崩潰。

躲避Autoruns的檢測

將合法的 microsoft 校驗碼數字簽名應用於攻擊者提供的代碼劫持目標 SIP 的 CryptSIPVerifyIndirectData 組件的額外影響是, 默認情況下, 它將從啟動中隱藏, 而不顯示 "microsoft" 或 "Windows"項。

隨著可執行程序 SIP 劫持完成,默認情況下,一個持久的攻擊者提供的 EXE 不會出現:

在Autoruns的默認視圖中看不到notepad_backdoored.exe

但是, 當 取消選擇"隱藏 Microsoft 條目" 和 "隱藏 Windows 條目" 時, Run 鍵中的惡意條目將變為可見:

確認只有在取消選擇 "隱藏 Windows 條目" 時才會出現 notepad_backdoored.exe

持久化和代碼執行

了解了如何劫持 SIP和信任提供者,應該清楚的是,除了顛覆信任之外,這些劫持攻擊還允許在執行代碼簽名或簽名驗證的任何應用程序的上下文中執行代碼。通過實現 SIP 或信任提供程序,代碼可能在下列列表的程序中執行:

  1. DllHost.exe——當在文件屬性中顯示「數字簽名」標籤時
  2. Process Explorer——當顯示「簽名校驗」標籤時
  3. Autoruns
  4. Sigcheck
  5. consent.exe——任何時候顯示UAC彈窗時
  6. signtool.exe
  7. smartscreen.exe
  8. Get-AuthenticodeSignature
  9. Set-AuthenticodeSignature
  10. 基於對 WinVerifyTrust 的調用執行證書驗證的安全供應商軟體

可以通過在進程監視器(Process Monitor)中篩選下列註冊表項路徑來發現其他的代碼執行和持久化:

  • HKLMSOFTWAREMicrosoftCryptographyProviders
  • HKLMSOFTWAREWOW6432NodeMicrosoftCryptographyProviders
  • HKLMSOFTWAREMicrosoftCryptographyOID
  • HKLMSOFTWAREWOW6432NodeMicrosoftCryptographyOID

在使用攻擊者提供的代碼劫持信任提供程序時,出於穩定性考慮,一種可能的是將惡意邏輯作為 "診斷策略(DiagnosticPolicy)" 組件的一部分來實現, 以不影響合法的信任功能。

當試圖在

SIP 的上下文中獲取代碼執行時, 一種獲取代碼執行考慮可能是在 "CryptSIPDllIsMyFileType" 組件中實現惡意邏輯,

並返回 "FALSE",表示其他 "CryptSIPDllIsMyFileType" 和 "CryptSIPDllIsMyFileType2

"組件應該被調用,以確定哪個 SIP 代表了有問題的文件。然而, 要注意的是,

任何武器化方案都有它自己獨特的一套指標或折中方案來確保惡意代碼可以被簽名。

最後一個考慮是,

SIP 和信任提供者 dll 不需要在註冊表中指定它們的完整路徑。如果只指定了 SIP 或信任提供程序文件名, 則通過標準的 DLL

載入順序來載入它。這使攻擊者能夠在不需要修改註冊表的情況下劫持現有的 SIP/信任提供程序 dll。例如, 在 Windows 10 中,

Microsoft Office SIP VBA 宏 sip (9FA65764-C36F-4319-9737-658A34585BB7)

只使用其文件名註冊 (僅限 WoW64): mso.dll。此外, 僅在指定了 "mso.dll" 的文件名的情況下,

在執行用戶模式信任驗證的任何代碼中都有可能出現泛型 dll 載入順序劫持漏洞。

顛覆 CryptoAPI v2 (CAPI) 事件日誌

雖然默認情況下未啟用,但是啟用

Microsoft-Windows-CAPI2/Operational 事件日誌可能是獲取失敗的信任驗證相關的上下文信息的寶貴來源。每當調用

WinVerifyTrust 時,都會生成 EID 81,如果簽名或信任驗證失敗, 則事件將被填充為錯誤。例如, 以下是與

"notepad_backdoored" 的失敗的信任驗證相關的事件詳細信息,它具有合法的 Microsoft 認證數字簽名 (相關部分加粗):

上面的事件是一個 "錯誤" 事件。在本例中, 如果可執行程序 SIP 的 CryptSIPVerifyIndirectData 組件被劫持, 則 WinVerifyTrust 事件仍將被記錄, 但作為 "信息" 事件表示信任驗證成功:

因此, 雖然 Microsoft-Windows-CAPI2/Operational 事件日誌可以提供有價值的攻擊上下文 (主要是文件路徑和驗證過程的名稱)信息,但它的預期行為可以被信任驗證攻擊來破壞掉。

攻擊操作注意事項

以下建議旨在幫助在實現惡意 SIP 時緩解檢被檢測到的可能性:

  • 如果 SIP被用來劫持現有的 SIP功能,請實現與您劫持的函數相同的函數名,這樣就沒必要再更改 "FuncName" 註冊表值了。
  • 雖然建議不要將合法的 SIP 二進位文件替換為你自己的 (例如 wintrust.dll),但最好讓你的SIP dll

    與被劫持的dll 同名。除了具有相對路徑 (例如 WoW64 mso.dll) 的 SIP 註冊之外,還需要更改 "dll" 註冊表值。更改

    "dll" 值的最不可疑的方法是更改從 "dll" 中剝離文件路徑,並把自己的 SIP Dll 放在目標應用程序的當前目錄中。 例如, 將

    "C:WindowsSystem32WINTRUST.dll" 更改為 "WINTRUST.dll"。請注意, wintrust.dll

    不存在於 KnownDlls 中。
  • 如果實現完整的 SIP (如具有適當的註冊/註銷功能), 請注意與 SIP 操作相關的函數相對容易生成Yara簽名。考慮直接通過註冊表執行 SIP 註冊/劫持。例如, 以下導入將為一個良好的Yara 規則:
    • CryptSIPAddProvider
    • CryptSIPRemoveProvider
    • CryptSIPLoad
    • CryptSetOIDFunctionValue
    • CryptRegisterOIDFunction
  • 如果你的SIP DLL直接操作註冊表的MicrosoftCryptographyOID鍵值,則需要混淆下子鍵的路徑。
  • 對於計劃使用 SIP dll 劫持的合法 dll,請將其校驗碼簽名應用於二進位文件。儘管存在哈希不匹配,理想情況下,仍可以劫持

    CryptSIPVerifyIndirectData SIP

    組件來緩解此問題。需要注意的是,許多系統二進位文件都是編錄簽名的。不過你也可以將編錄簽名應用於內嵌的校驗碼簽名。

    應用同一證書將產生相同的指紋計算,並繞過安全產品可能執行的一些簡單檢查。
  • 如果要註冊一個新的 SIP GUID,請使用以前定義過的一個但是當前未註冊的文件,並應用與所使用的SIP GUID

    相同的文件名和導出函數名稱。例如, Silverlight 具有以下 GUID 的 SIP:

    BA08A66F-113B-4D58-9329-A1B37AF30F0E
    • 文件名:xapauthenticodesip.dll
    • 導出函數:XAP_CryptSIPCreateIndirectData, XAP_CryptSIPGetSignedDataMsg, XAP_CryptSIPPutSign

      edDataMsg,XAP_CryptSIPRemoveSignedDataMsg,XAP_CryptSIPVerifyIndirectData,XAP_IsFileSupportedName

本文由看雪論壇 龍幽 翻譯 轉載請註明來自看雪社區


推薦閱讀:

歷史上有哪些解救人質行動失敗的案例?

TAG:MicrosoftWindows | 数字签名 | 劫持 |