PE内嵌Authenticode证书及内核态驱动程序检查方式分析
2020-04-28 10:44:00 Author: www.4hou.com(查看原文) 阅读量:209 收藏

导语:Windows中,要从内核驱动程序进行数字签名检查并不简单。原因在于,所有已记录且易于使用的wintrust.h API都位于用户模式下,这为我们增加了不少的困难。

概述

在Windows系统中,从内核驱动程序进行数字签名检查并不是一项容易的工作。原因在于,所有已记录且易于使用的wintrust.h API都位于用户模式下,这为我们增加了不少的困难。

第一种选择是使用OpenSSL,但是如果我们构建针对Windows 1903版本或以上的驱动程序,WHQL进程似乎需要提交其他日志,例如SDV等。OpenSSL项目中存在着较多的问题,我们会因为内存未对齐而收到很多警告,可能达到1000+ Warining。更重要的是,使用这种方式所生成的加密摘要并不是我们所期望的,很可能由于在实现过程中出现错误而导致最终的结果出错。另外,如果我们完整阅读代码,并搜索“hack”、“todo”关键词,得到的结果会让我们感到不安。最后,使用OpenSSL编译的驱动程序通常为250KB,而使用本地方法仅为30KB,如果我们的空间非常有限,那么就需要谨慎考虑是否选择这种方法。

第二种选择是使用从代码完整性DLL加载到System进程中的未记录导出。尽管这并非是在客户端计算机上发布驱动程序地最为安全的方法,但这种方式实现起来相对较为简单。Ido Moshe和Liron Zuarets在这篇文章中(https://medium.com/cybereason/code-integrity-in-the-kernel-66b3f5cce5f)进行了非常好的解释。

最后,第三个选项是使用Bcrypt,我们可以从C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\shared\bcrypt.h中的内核驱动程序链接到这个头部文件,同时也可以链接到内核库ksecdd.lib。我们可以找到各种有趣的导出方式,例如BCryptOpenAlgorithmProvider、BCryptImportKeyPair、BCryptGenerateSymmetricKey、BCryptCreateHash、BCryptHashData、BCryptDecrypt、BCryptEncrypt、BCryptExportKey、BCryptVerifySignature等等,但是其中的很多都是由其他函数创建并作为HANDLE传递的结构,现在必须由我们来人工制作并传递。可以通过以下方式来查看导出:

dumpbin.exe /exports "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\km\x64\ksecdd.lib"

Authenticode认证码

Authenticode是一种Microsoft的代码签名技术,它使用具有公钥和私钥的非对称加密。在驱动程序的不可执行部分,包含一个嵌入式DER编码的X509证书,或者也可以使用目录文件(分离的签名)来验证驱动程序的完整性。2008年,Microsoft曾在Authenticode_PE.docx文档中对Authenticode进行了完整的说明,但并非所有部分都做了及时更新,例如,文档中指出证书的指纹是MD5哈希值,但现在实际上指纹(DER编码后证书的哈希值)已经变为SHA-1哈希值。

添加单个证书或添加同一个链上的多个证书都不会影响二进制签名,因为证书表自身、证书表指针和文件校验都不属于证书签名的一部分,如下图所示。

PE文件和Authenticode签名格式的概述:

1.png

在这里,我们不难发现一个安全问题。如果将任意数据添加到具有签名的二进制文件的Certificate条目中,该哈希值将仍然有效。幸运的是,.cat文件解决了这一问题,但并非所有的驱动程序都经过目录签名。因此,如果我们是红队成员,我们可以不再使用Mimikatz这类工具,只需要添加一个新的第三方根CA,就可以不会再引起人们的关注。

我们列举出这一过程中的一些关键术语。

1、摘要/消息摘要:哈希函数的输出。

2、加密摘要:签名者的私钥用于加密摘要信息,以生成签名。

3、签名消息:计算摘要和加密的整个过程。

4、公钥:仅包含一个模数和指数。

5、PKCS #7:加密数据的标准格式,包括签名数据、证书和证书吊销列表(CRL)。

签名过程的基本步骤包括:

1、生成PE映像的哈希值,特别是上图白色背景部分所展示的内容。

2、使用签名者的私钥对上述摘要进行加密(例如使用RSA 2048),从而生成加密摘要。

3、将加密摘要、证书和哈希算法结合在一起,创建签名块。

4、将签名块插入到PE文件中。

当用户验证嵌入的Authenticode签名时,基本步骤包括:

1、从嵌入式证书提取公钥。

2、使用公钥解密嵌入的加密摘要。

3、在PE代码/数据等部分,再次运行用于创建原始摘要的相同哈希算法(例如SHA-256)以创建摘要。

4、比较步骤2和步骤3得到的摘要,如果相同,则公钥与用于对原始代码进行签名的私钥相匹配,证明该代码未被篡改。

证书链

RDN是以0个或多个逗号分隔的组件,称为“相对专有名称”(Relative Distinguished Name,RDN),会形成一个专有名称(DN)。我们以本地上传的Adobe Reader为例,查看二进制文件的专有名称。如下图所示,我们可以看到AcroRd32.exe标题字段的10个相对专有名称。

Adobe Reader的证书标题:

2.png

证书路径:

3.png

检查证书链返回其根的过程,仅仅是将子颁发者与父标题进行比较。在上图的上方展示了路径信息,下表说明了子级(颁发者字段)和父级(标题字段)之间的对应联系。几乎可以肯定,我们的计算机上已经安装了指纹为[5fb7ee..]的DigiCert根CA,如下图所示。

AcroRd32.exe

颁发者:

CN = DigiCert EV Code Signing CA (SHA2)

OU = www.digicert.com

O = DigiCert Inc

C = US

标题:

CN = Adobe Inc.

OU = Acrobat DC

O = Adobe Inc.

L = San Jose

S = ca

C = US

SERIALNUMBER = 2748129

2.5.4.15 = Private Organization

1.3.6.1.4.1.311.60.2.1.2 = Delaware

1.3.6.1.4.1.311.60.2.1.3 = US

指纹:

1bfc555fd6489422bc2baba036b31aa75dc0aa17

序列号:

0ee3f1c8f451cbf21203341a53f23e71

签名算法:

sha256RSA

DigiCert EV Code Signing CA (SHA2)

颁发者:

CN = DigiCert High Assurance EV Root CA

OU = www.digicert.com

O = DigiCert Inc

C = US

标题:

CN = DigiCert EV Code Signing CA (SHA2)

OU = www.digicert.com

O = DigiCert Inc

C = US

指纹:

60ee3fc53d4bdfd1697ae5beae1cab1c0f3ad4e3

序列号:

03f1b4e15f3a82f1149678b3d7d8475c

签名算法:

sha256RSA

DigiCert High Assurance EV Root CA

颁发者:

CN = DigiCert High Assurance EV Root CA

OU = www.digicert.com

O = DigiCert Inc

C = US

标题:

CN = DigiCert High Assurance EV Root CA

OU = www.digicert.com

O = DigiCert Inc

C = US

指纹:

5fb7ee0633e259dbad0c4c9ae6d38f1a61c7dc25

序列号:

02ac5c266a0b409b8f0b79f2ae462577

签名算法:

sha1RSA

证书位置

根证书可以在注册表的HKLM键下找到。一开始,我们认为这里存在着安全问题,管理员用户可以对主机进行内核调试,或者将其附加到lsass.exe并窃取缓存的凭据,或者将psexec以SYSTEM权限覆盖到受保护的文件夹。同时,管理员也通过上述位置添加或删除系统证书。下表列举了所有类型证书在Windows证书管理器中的存储位置。

证书存储的注册表路径:

[用户上下文]

HKCU:\SOFTWARE\Microsoft\SystemCertificates\   存储用户专用公钥的物理位置

HKCU:\SOFTWARE\Policies\Microsoft\SystemCertificates\     存储活动目录(AD)组策略对象(GPO)安装的用户专用公钥的物理位置

[计算机上下文]

HKLM:\SOFTWARE\Microsoft\SystemCertificates\   存储计算机所需公钥的物理位置

HKLM:\SOFTWARE\Microsoft\Cryptography\Services\   存储与特定服务相关的密钥的物理位置

HKLM:\SOFTWARE\Policies\Microsoft\SystemCertificates\    存储组策略对象(GPO)安装的计算机所需公钥的物理位置

HKLM:\SOFTWARE\Microsoft\EnterpriseCertificates\      存储由AD域中Enterprise PKI容器安装的计算机所需公钥的物理位置

证书存储的文件夹:

[用户上下文]

C:\user\abc\APPDATA\Microsoft\SystemCertificates\      用户专用公钥和私钥指针的物理存储位置

C:\user\abc\APPDATA\Microsoft\Crypto\  用户专用私钥容器的物理存储位置

[计算机上下文]

C:\ProgramData\Microsoft\Crypto\    计算机专用私钥容器的物理存储位置

证书存储的类型包括:

1、AddressBook:其他用户和资源的证书存储;

2、AuthRoot:第三方证书颁发机构(CA)的证书存储;

3、CertificationAuthority:中间证书颁发机构(CA)的证书存储;

4、Disallowed:证书存储区中已经被撤销的证书;

5、My:用户使用的个人证书存储,这是大多数自定义证书的存储位置;

6、Root:信任的证书颁发机构(CA)的证书存储;

7、TrustedPeople:信任的用户和资源的证书存储;

8、TrustedPublisher:信任的应用程序发布者的证书存储。

我们的“DigiCert High Assurance EV Root CA”是第三方CA,因此我们可以在以下的注册表键中,找到计算机所需的系统证书:

HKLM\SOFTWARE\Microsoft\SystemCertificates\AuthRoot\Certificates

DigiCert根证书的指纹是5fb7ee0633e259dbad0c4c9ae6d38f1a61c7dc25。在下图中,我们可以在注册表中找到该证书。在Windows中,我们可以通过指纹来有效地搜索所需证书。

计算机上全部非Microsoft颁发的根证书:

4.png

要查看单个证书的详细信息,另一种方式是从签名的二进制文件中手动提取证书,我们可以在链中将任何证书“Copy to file”。随后,我们就可以使用certutil工具转储大量数据,或者使用certutil查看有关完整二进制文件的详细信息。

OID

OID表示法是指以点分隔的数字字符串,例如1.2.840.113549.1.9.4,以十六进制表示为06 09 2A 86 48 86 F7 0D 01 09 04。我编写了一个Python3脚本,来对其进行转换:https://github.com/AstralVX/oidhex_to_dot 。messageDigest的OID可以拆分为:

1.2.840.113549.1.9.4 – messageDigest

1.2.840.113549.1.9 – PKCS-9签名

1.2.840.113549.1 – PKCS

1.2.840.113549 – RSADSI

1.2.840 – USA

1.2 – ISO成员

1 – ISO分配的OID

TLV

每个ASN.1数据都被编码为标签长度值(TLV)三元组。标签定义了对象类型,例如整型、布尔型、字符串或序列等。TLV也可以包含子TLV。

示例ASN.1数据:30 0D 0C 05 48 45 4C 4C 4F 02 01 1E 01 01 00

我们对TLV进行解释,下面是ASN.1序列和C样式结构:

标签:30

长度:0D

说明:序列长度为13。

标签:OC

长度:05

值:48 45 4C 4C 4F

说明:UTF8字符串长度为6,其值为HELLO。

标签:02

长度:01

值:1E

说明:整型长度为1,且值为0x1E(十进制30)。

标签:01

长度:01

值:00

说明:布尔型长度为1,值为0(FALSE)。

//ASN.1 sequence
Sequence {
    Name::= UTF8 String
    Age::= Integer
    isSmoker::= [0] Boolean OPTIONAL
}
 
//C struct
struct person { CHAR[5] Name, INT age, BOOL isSmoker}

ASN.1

ASN.1是描述结构的通用方法。Authenticode数字签名中包含Authenticated属性(包含有用的部分)和Unauthenticated属性(时间戳签名,MS签署)。在下图中,只展示了一些具有可读名称的OID,并没有完成所有转换,并且漏掉了一些重要的OID。我们在身份验证属性中看到的是:

1.2.840.113549.1.9.3 = contentType,包含messageDigest OID。(1.3.6.1.4.1.311.2.1.4) 

1.3.6.1.4.1.311.2.1.11 = SPC_STATEMENT_TYPE_OBJID

1.3.6.1.4.1.311.2.1.12 = SpcSpOpusInfo,包含:programName [可选]描述,字段 [可选]和一个URL。

1.2.840.113549.1.9.4 = messageDigest

其中, 1.3.6.1.4.1.311.2.1.4 == SPC_INDIRECT_DATA_OBJID (06 0a 2b 06 01 04 01 82 37 02 01 04)是一个SpcIndirectDataContent结构:

SpcIndirectDataContent (struct)
{
  Data - SpcAttributeTypeAndOptionalValue (struct)
  {
    Type - OID: SPC_PE_IMAGE_DATAOBJ [1.3.6.1.4.1.311.2.1.15] (06 0a 2b 06 01
           04 01 82 37 02 01 0f)
    Value - SpcPeImageData (struct)
    {
      Flags -
      File - SPCLink (struct)
      {
        URL [0]:
        Moniker [1]: SpcSerializedObject (struct)
        {
          SpcUuid - 10 byte const GUID (a6 b5 86 d5 b4 a1 24 66 ae 05 a2 17 da
                    8e 60 d6)
          SerializedData - struct of page hashes if present
        }
      }
      File [2]: SpcString (struct) containing Unicode string "<<>>"
    }
  }
  MessageDigest - DigestInfo (struct)
  {
    DigestAlgorithim - must be same as SignerInfo.DigestAlgorithim
    Digest - message digest value
  }
}

Adobe Reader的数字签名标签:

5.png

实现

考虑到版权问题,我们无法发布包含数千行代码的完整加密代码。但从较高的层次上来看,可以执行以下操作:

1、读取目标二进制文件的PE头,以进行数字签名检查,解析其中的DOS/NT部分,并提取嵌入式Authenticode证书。

2、解析TLV:解析SignedData序列,随后对另一个摘要算法TLV进行解析,从而获得ContentInfo结构和SignerInfo结构。

3、在证书之间循环,检查中间证书的序列号、有效日期范围、哈希算法、EKU代码签名等。

4、验证最高父级根证书,可以使用Bcrypt生成最高级别证书的指纹,然后在根证书存储中检查该指纹。

5、随后,通过使用适当的摘要算法,对实际二进制文件进行哈希处理,然后将其与嵌入式AuthenticodeInfo签名者消息摘要进行比较,以验证消息摘要。

6、接下来,验证加密的摘要,确认是否属于签名原始消息摘要的签名者。这一过程是通过生成已签名属性结构的摘要,并将其公钥应用于嵌入式加密摘要以获得未签名摘要来实现的。如果二者匹配,则表明签名者是使用其私钥进行了签名。在这里,需要大量的Bcrypt,这也是最棘手的部分,使用人工构造的pRsaKeyBlob,它由[BCRYPT_RSAKEY_BLOB, pbPublicExponent(大端字节序), pbRawPublicKey(大端字节序)]组成。然后,我们可以在BCryptImportKeyPair(BCRYPT_RSAPUBLIC_BLOB)和BCryptEncrypt(BCRYPT_PAD_NONE)中使用精心构造的结构,该结构使用公钥对未签名的摘要进行验证。

7、最后是对映像摘要进行验证,并将生成的哈希值与存储在authenticode的映像摘要进行比较。

遗憾的是,在上述所有过程中,都包含大量的TLV解析、Bcrypt、缓冲区溢出检查、黑名单证书检查、证书固定检查。要实现上述过程,不仅仅需要几次Bcrypt调用和一些解析,而是有数千行需要开展的工作。但是,至少目前我们已经有了实现方式的思路。下图展示了一些我们需要创建的标头。

与Authenticode处理有关的结构:

6.png

样本值

以下是我们文章中提到的Adobe二进制文件的示例值,如果大家需要进行比较,可以以此作为参考。

公钥:

30 82 01 0a 02 82 01 01  00 b3 cc 04 ee e8 24 99
23 43 3b 6b 34 ce e6 ee  80 c5 8b ab 38 a4 28 f4
55 8f ab 8b e5 ab cb 44  62 25 c8 71 24 1f f6 15
03 35 76 a9 b0 9b a5 db  28 8a 24 45 fc e6 e4 fd
22 fe b7 17 8b d6 d3 77  11 42 bb 1a e3 6f f9 42
d2 b5 9b 41 d6 b1 5d 8f  f9 87 18 fb 55 fd 5e 1a
51 3d bc 44 ac 96 ba d5  97 9d 88 e4 59 cf e7 21
f1 07 28 d7 a5 ef 17 00  2c 5e 1e 1d 67 c5 b4 a9
83 8f 2e 2c 08 51 64 e4  14 89 91 2e 6e e4 30 f5
24 e9 b3 0e c3 08 98 a0  9c f1 c9 68 7a 3d dd d6
f9 9c 3b db 2c 96 a2 7f  17 97 87 f8 16 5f ed 64
fb 1d 72 43 ff 1a 95 3d  91 28 90 68 56 76 2b 66
4e ff a8 ee 36 9f 49 cb  a6 ee 87 9c 76 22 1d fb
98 48 9e 72 2e d1 1b b1  d8 2d 52 6b eb fa 62 00
9a c8 83 04 b6 64 ed 45  4c 21 34 f4 8d 36 3b 8b
b4 52 47 b3 a9 4e 2b 54  94 0f b2 b7 06 54 25 23
1f 36 fb 07 ba d4 a3 ea  b7 02 03 01 00 01

图片摘要 - 原始:

ef 64 7e 10 ca 06 df 3d 22 d1 10 fb 78 17 92 b4
f2 2c 0e f7 1e c1 95 cf 0c 33 59 a4 b8 b2 ff cb

内容信息(Bcrypt标头+图片摘要):

30 5c 06 0a 2b 06 01 04 01 82 37 02 01 04 a0 4e
30 4c 30 17 06 0a 2b 06 01 04 01 82 37 02 01 0f
30 09 03 01 00 a0 04 a2 02 80 00 30 31 30 0d 06
09 60 86 48 01 65 03 04 02 01 05 00 04 20 ef 64
7e 10 ca 06 df 3d 22 d1 10 fb 78 17 92 b4 f2 2c
0e f7 1e c1 95 cf 0c 33 59 a4 b8 b2 ff cb

摘要算法(_DIGEST_ALGO_IDENTIFIER_SHA256):

60 86 48 01 65 03 04 02 01

签名者信息 - 签名摘要(ALGO_IDENTIFIER_RSA):

2a 86 48 86 f7 0d 01 01 01

消息摘要,例如SHA-256(内容信息):

a7 ee 55 49 55 11 15 df f5 ea 6a b4 10 44 9f de
24 66 c5 f4 3f 8e 5c e4 de 01 20 4c 55 ab ca 6e

加密摘要:

33 d9 b3 76 1d a7 37 70 a1 b1 5b 3a 11 e8 12 34
03 43 b2 18 b4 b1 af 60 ad 2f cb 41 33 f5 6d 13
f5 6c 3f 84 d6 ef a1 77 07 b1 55 2c 9e 12 d5 1b
1f 3c 0e 6b 5e 9a d9 2f 5f d7 8b b2 a0 a1 62 c1
80 60 4f 8f ad 2c 0d 90 0e 1a 96 aa 13 24 8f ca
d8 05 c1 aa 98 1d df df 93 85 ea eb 7e 0c 7f 94
df d0 36 e5 ca df fc 64 d1 a0 7b 30 5a 87 a0 38
7b cb ea e1 6c d1 53 ad ab 48 3f 7f 73 90 66 39
bc b1 6a 8a b2 42 1c 7b bb 63 9f 3c 03 e6 82 f5
3a 0e fc 22 d1 9c eb a5 da 2b be 93 b3 9d 88 a3
43 d0 0c 70 90 06 84 0d 33 ff 3a 8e 3a b6 8f a6
7d 54 4a ea 59 f6 b4 7f 95 51 49 dc 96 0a ba 29
8e a1 71 36 d5 a9 d2 72 39 0d 54 15 b8 62 5c f1
aa 3a 2b f4 18 16 5b 8b 8b 62 49 02 89 c6 7d ea
29 15 0e c3 a9 15 ee 7f bd da 96 6d 35 6f 4d 2b
7e e1 04 f0 de be 7b 01 15 a4 07 a8 09 df 69 d9

签名者信息 - 签名属性:

31 81 9a 30 19 06 09 2a 86 48 86 f7 0d 01 09 03
31 0c 06 0a 2b 06 01 04 01 82 37 02 01 04 30 1c
06 0a 2b 06 01 04 01 82 37 02 01 0b 31 0e 30 0c
06 0a 2b 06 01 04 01 82 37 02 01 15 30 2e 06 0a
2b 06 01 04 01 82 37 02 01 0c 31 20 30 1e a0 1c
80 1a 00 41 00 64 00 6f 00 62 00 65 00 20 00 41
00 63 00 72 00 6f 00 62 00 61 00 74 30 2f 06 09
2a 86 48 86 f7 0d 01 09 04 31 22 04 20 a7 ee 55
49 55 11 15 df f5 ea 6a b4 10 44 9f de 24 66 c5
f4 3f 8e 5c e4 de 01 20 4c 55 ab ca 6e

本文翻译自:https://astralvx.com/index.php/2020/03/20/authenticode-certificates-and-checks-from-a-km-driver/如若转载,请注明原文地址:


文章来源: https://www.4hou.com/posts/p7w6
如有侵权请联系:admin#unsafe.sh