1. The Box — Garfield at a glance
Garfield is a Hard-rated HackTheBox Active Directory box that chains seven distinct AD primitives end-to-end. The user flag is reached via a Logon Script Hijack (writable SYSVOL + ScriptPath ACL chain). The root flag requires pivoting to a separate network segment to compromise a Read-Only Domain Controller, then forging a Golden Ticket against the RODC krbtgt account and using a KeyList Request to extract real KRBTGT-equivalent keys for the writable DC. No public exploits are involved — every step is a Microsoft-documented AD feature being abused exactly as designed.
The technical interest of this box is concentrated in the second half: the RODC Golden Ticket + KeyList Request technique is a relatively recent (2022-2024) addition to the AD attacker toolkit and is poorly documented outside specialised writeups. The first half (writable SYSVOL → ScriptPath hijack) is the classic 2017-era Will Schroeder / Sean Metcalf research that still pays out in real engagements when a domain admin team has loose SYSVOL ACLs.
Kill chain at a glance
| # | Stage | Technique |
|---|---|---|
| 1. | Recon + BloodHound | Nmap, smbmap, bloodyAD, BloodHound graph queries |
| 2. | Logon Script Hijack on l.wilson | Write malicious .bat to SYSVOL, set scriptPath via writable ACL, l.wilson logs in → shell |
| 3. | ForceChangePassword l.wilson → l.wilson_adm | BloodHound-identified ACL edge; bloodyAD changes the password without knowing the old one |
| 4. | AddSelf to RODC Administrators (TIER 1) | l.wilson_adm joins itself to a group that grants admin on RODC01 |
| 5. | RBCD fake computer + S4U2Self/Proxy | Create attacker-controlled machine account, configure RBCD on RODC01, S4U abuse to impersonate Administrator on CIFS |
| 6. | Ligolo-ng tunnel to 192.168.100.0/24 | RODC01 lives on a private segment; pivot via the compromised foothold |
| 7. | Shell on RODC01 + Mimikatz dump krbtgt_8245 | LSA dump of the per-RODC krbtgt account's AES256 key |
| 8. | Forge RODC Golden Ticket + KeyList Request | Rubeus golden ticket signed with krbtgt_8245; KeyList TGS returns real Administrator AES256/NTLM derived keys |
| 9. | Pass-the-Hash to DC01 | Evil-WinRM with Administrator NTLM → root flag |
j.arbuckle / Th1sD4mnC4t!@1978 for SMB/LDAP enumeration, and BloodHound API credentials admin:ti7K7nEvSJ9o7z50bEWS_JufEOWiB14I. This isn't a "find the foothold" box — the difficulty lives entirely in the chained AD primitives.2. Reconnaissance
Standard Active Directory recon. The Nmap output is the only piece worth more than a glance: it confirms a Windows Domain Controller, gives us the domain name, and the exposed ports tell us what protocols are available for attack.
Nmap — confirming a Windows DC
The combination of 53 (DNS), 88 (Kerberos), 389 (LDAP), 445 (SMB), 464 (Kerberos password change), and 3268 (Global Catalog LDAP) is the unambiguous fingerprint of a Windows Domain Controller. Domain is garfield.htb, hostname is DC01. Port 5985 (WinRM) open means we can use Evil-WinRM for interactive shell access once we have valid credentials.
SMB enumeration — readable shares
NETLOGON and SYSVOL are readable to any domain user — that is the default and not yet interesting. What matters is whether they are writable. smbmap reports READ ONLY for our user, but SMB share permissions in AD environments are layered: the share permission can be one thing, the underlying NTFS DACLs another. The actual question is "can our account write a file into \\garfield.htb\SYSVOL\garfield.htb\scripts\?" That has to be tested with smbclient directly. Spoiler: we can, eventually.
Writable ACLs via bloodyAD
bloodyAD (Cravaterouge / GitHub) is the modern Python replacement for the BloodHound-discovery + custom-script workflow. It enumerates exactly the writes our principal can perform over LDAP and S4U2Self. The critical finding here is that we have WriteProperty on the scriptPath attribute of l.wilson. That single ACL is what makes this box solvable from this account.
BloodHound — the attack graph
• "Shortest paths to Domain Admins" — shows the multi-step graph below
• "Find all writable objects" for J.ARBUCKLE — confirms the scriptPath write
| Finding | |
|---|---|
| Users | Administrator, j.arbuckle, l.wilson, l.wilson_adm, RODC01\$, DC01\$ |
| Critical edges | J.ARBUCKLE → WriteProperty(scriptPath) → L.WILSONL.WILSON → ForceChangePassword → L.WILSON_ADML.WILSON_ADM → ForceChangePassword → RODC01\$ (computer account)TIER 1 → AddSelf → RODC ADMINISTRATORS |
| Significance | Three chained ACL primitives end at "Administrator on RODC01". The RODC is on a different subnet — pivot required. The chain stops at RODC, NOT at DC01 — that final step needs the Golden Ticket + KeyList technique. |
3. Initial Access — Logon Script Hijack
Every domain user has an attribute called scriptPath (LDAP) / "Logon script" (GUI). When the user authenticates interactively (RDP, console, certain remote-execution paths), the DC tells the user's client to execute the script at \\<domain>\NETLOGON\<scriptPath value>. NETLOGON is itself a virtual mount over \\<domain>\SYSVOL\<domain>\scripts\. So a script located at SYSVOL\garfield.htb\scripts\printerDetect.bat appears as \\garfield.htb\NETLOGON\printerDetect.bat and runs in the logged-on user's context.
Why this is exploitable
Two independent ACLs combine to give code execution:
- Write access to SYSVOL scripts directory — the box has been misconfigured so any domain user can drop files here. Default SYSVOL replication should restrict this to Domain Admins.
- WriteProperty on
scriptPathof the target user — our principalj.arbucklehas this onl.wilson. We don't need to know l.wilson's password; we just set their logon script.
When l.wilson next logs in (the box auto-simulates this with a scheduled service), the DC pushes our script. Our script can be a reverse shell. Game over for that user.
A minimal PowerShell reverse-shell delivered as a .bat that calls powershell:
If this put fails with NT_STATUS_ACCESS_DENIED, the SYSVOL write isn't available and the chain is broken. On Garfield the write succeeds — that's a deliberate misconfiguration that mirrors a class of real-world finding.
LDAP write. The DC accepts because j.arbuckle has WriteProperty on this attribute (BloodHound confirmed). The change is immediate and replicates instantly within the single-DC environment.
bloodyAD ... set object 'CN=l.wilson,...' scriptPath -v '' and remove the .bat after rooting, otherwise you're leaving an obvious persistence artifact in SYSVOL that the next player will trip over.4. User Pivot — l.wilson → l.wilson_adm
We have l.wilson, but the user flag is on l.wilson_adm. BloodHound told us l.wilson has ForceChangePassword on l.wilson_adm. This is the User-Force-Change-Password extended right in AD (GUID 00299570-246d-11d0-a768-00aa006e0529) — it lets the principal reset another user's password without knowing the current one. It's typically granted to helpdesk OUs; here it spans privilege tiers, which is the configuration mistake.
Check the target is reachable from our shell
Reset the password via PowerShell SDS
Same effect achievable from Kali with bloodyAD --host garfield.htb -u l.wilson -p '' set password l.wilson_adm 'Password456!' — the ACL is on the LDAP object, not specific to the in-domain shell. Using the existing PowerShell session avoids needing a separate Kerberos ticket cache for l.wilson.
Login as l.wilson_adm via Evil-WinRM
5. Privilege Escalation Setup — RODC Administrators
Now the chain gets interesting. BloodHound showed two more edges:
- L.WILSON_ADM → ForceChangePassword → RODC01\$ — we can reset the RODC computer account password
- TIER 1 → AddSelf → RODC ADMINISTRATORS — l.wilson_adm is in the TIER 1 group, which has AddSelf on the RODC Administrators group
The end goal is administrative access to RODC01.garfield.htb so we can run Mimikatz against it and steal the per-RODC krbtgt key. We need two things first: (1) admin rights on RODC01, (2) network reachability to RODC01.
Add ourselves to RODC Administrators
On RODCs, the "RODC Administrators" group is granted local-admin privileges via the standard BUILTIN\Administrators nested membership. After this add, l.wilson_adm can RDP, WinRM, or PowerShell-Remoting to RODC01 as a local admin — IF the network reaches it.
The network problem — RODC01 on isolated subnet
RODC01 lives on 192.168.100.0/24, which our Kali box cannot route to. DC01 (10.129.23.120) is dual-homed: it has an interface in our network AND an interface in the 192.168.100.0/24 segment. We need a pivot through DC01.
Why we can't just RBCD straight to DC01
RBCD on DC01 would give us code execution as Administrator on DC01 directly — sounds easier. But DC01 has Protected Users, RBCD-aware monitoring, and likely RBCD-locked accounts. The chain favoured by this box deliberately routes through RODC: easier targets, plus the RODC compromise gives us a per-RODC krbtgt that can be used to forge tickets, including the KeyList variant that ends up at the real KRBTGT-equivalent keys.
6. RBCD Attack — Fake Computer + S4U2Self/Proxy
Resource-Based Constrained Delegation (RBCD) is the modern Kerberos delegation primitive. A target account (typically a computer account) has an attribute msDS-AllowedToActOnBehalfOfOtherIdentity — a list of principals that are permitted to use S4U2Proxy to obtain service tickets for that target on behalf of arbitrary users. If we can write to that attribute on a target machine account, we can impersonate any user (including Administrator) to that machine's services.
We have ForceChangePassword on RODC01\$ — that effectively gives us full control of the RODC computer account, including writing its msDS-AllowedToActOnBehalfOfOtherIdentity attribute. We then need an attacker-controlled principal in the list. By default any authenticated user can create up to 10 machine accounts (the ms-DS-MachineAccountQuota default), so we create a fake one.
The attack flow
- Create attacker-owned machine account — e.g.
FAKE\$with a known password. - Force-change RODC01\$ password — gives us its NTLM hash for the next step.
- Set RODC01\$ msDS-AllowedToActOnBehalfOfOtherIdentity = {FAKE\$}
- S4U2Self as FAKE\$ → request a service ticket for FAKE\$ acting as Administrator. Because FAKE\$ has TrustedForDelegation implicit (machine accounts), this succeeds.
- S4U2Proxy using the S4U2Self ticket as evidence → request a CIFS service ticket for RODC01 in the name of Administrator. The RBCD attribute on RODC01 trusts FAKE\$, so this succeeds.
- We now have
CIFS/RODC01.garfield.htbas Administrator — write access to RODC01's C\$, ADMIN\$, etc.
The combined impacket flow
We now have a Kerberos ticket cache file with a CIFS service ticket valid for RODC01 as Administrator. Set the env var to use it:
7. Pivot — Ligolo-ng tunnel to RODC subnet
We have a valid Kerberos ticket for RODC01, but RODC01 is on 192.168.100.0/24 — unreachable from Kali. The pivot point is DC01 (10.129.23.120) which has a leg on both networks. We use Ligolo-ng to tunnel arbitrary TCP through DC01 to the RODC subnet.
Setup — proxy on Kali, agent on DC01
8. Shell on RODC01 as SYSTEM
With the route in place, we use our S4U2Proxy CIFS ticket against RODC01 to drop tooling onto C\$ and then a shell.
We are SYSTEM on RODC01. The RODC is a Domain Controller (read-only) — that means it has an LSA secrets store containing the per-RODC krbtgt account key. That key is what we need next.
9. krbtgt_8245 AES256 — Mimikatz LSA dump
Every RODC has its own krbtgt-style account named krbtgt_<RID> — here, krbtgt_8245. This account exists because RODCs cannot use the real KRBTGT (writable DCs only) but still need to issue TGTs locally for users in their allowed-replication scope. The krbtgt_
Mimikatz LSA dump
AES256 key extracted: d6c93cbe006372adb8403630f9e86594f52c8105a52f9b21fef62e9c7a75e240. This is the signing key for any TGT issued by RODC01's krbtgt account. Save it — it goes into Rubeus next.
10. RODC Golden Ticket + KeyList Request
Here is the new technique that makes Garfield interesting beyond a generic AD compromise. A standard Golden Ticket (Mimikatz, Sean Metcalf 2014) is signed with the writable DC's krbtgt key and is accepted by every DC in the forest. A RODC Golden Ticket, by contrast, is signed with the krbtgt_
The answer is the KeyList Request (MS-KILE §3.3.5.7.5, added to AD in newer Windows Server versions and exposed by Rubeus 2.1+). When a service ticket request includes a "key list" extension, the KDC responds with the existing long-term keys (NTLM, AES) for the requested principal — but only if the requesting RODC is configured to be allowed to read that principal's secrets. We control the RODC. We get to configure that. So we:
- Allow Administrator's credentials to be replicated to RODC01 (modify the RODC's
msDS-RevealOnDemandGroupattribute via l.wilson_adm's domain admin-equivalent rights through the chain). - Forge a RODC Golden Ticket as "Administrator" signed with krbtgt_8245.
- Use that ticket to request a service ticket for
krbtgt/garfield.htbwith the/keyListflag. - The DC processing the request sees a ticket signed by an RODC krbtgt, sees that the principal is in the allowed-replication group, and returns Administrator's long-term AES256 + NTLM hashes inside the KeyList response.
- We now have Administrator's NTLM hash → Pass-the-Hash to DC01.
Step 1 — Allow Administrator replication to RODC01
Step 2 — Forge RODC Golden Ticket with Rubeus
Step 3 — KeyList TGS Request
msDS-RevealOnDemandGroup on RODC01. If you skip that step, the DC refuses to return keys and just returns a normal TGS. Order matters.11. DC01 Root Flag — Pass-the-Hash
Administrator NTLM hash extracted: EE238F6DEBC752010428F20875B092D5. Pass-the-Hash to DC01 over WinRM:
secretsdump.py -hashes :EE238F6DEBC752010428F20875B092D5 [email protected] gives the full krbtgt + every account hash. Use that for persistence (real KRBTGT golden ticket) on a real engagement.12. Mitigation — what defenders should fix
Every step of this chain is a real AD primitive being abused — there is no exploit code, no patched CVE. The fix is configuration hygiene at multiple layers. A defender team that gets even three of the following right blocks Garfield-class compromises entirely.
Per-stage mitigations
| Stage | Mitigation |
|---|---|
| Logon Script Hijack | (1) Audit SYSVOL share + NTFS DACLs — only Domain Admins should write to \SYSVOL\<domain>\scripts\. (2) Run a BloodHound query for "non-DA principals with WriteProperty on scriptPath of user objects" — there should be zero. (3) Subscribe to 4663 Object Access events on SYSVOL with explicit alerts for non-DA writes. |
| ForceChangePassword sprawl | BloodHound's "Find all ACL paths to high-value targets" should not show ForceChangePassword edges from low-tier accounts to higher-tier accounts. Tighten with: helpdesk OUs scoped to a specific Tier-2 user OU, never to admin accounts. |
| AddSelf on privilege groups | RODC Administrators (and any other DC-admin-equivalent group) should NEVER have AddSelf granted to a wider group. This is what made the "Tier 1 → AddSelf → RODC Admins" edge possible. Audit with Get-ADGroup -Filter "name -like '*Admin*'" | Get-Acl and look for AddSelf ACEs. |
| RBCD | Disable msDS-MachineAccountQuota (set to 0). Audit msDS-AllowedToActOnBehalfOfOtherIdentity writes via Event ID 5136. Enforce Authentication Policies that restrict which accounts can be delegation targets. |
| RODC compromise | Disable Print Spooler service on every DC (RODC included) — common privilege escalation path. Patch RODCs as fast as writable DCs. |
| RODC Golden Ticket + KeyList | Most critical: review the msDS-RevealOnDemandGroup of every RODC. Default should be ONLY "Allowed RODC Password Replication Group" (which by default is empty). Adding privileged users to RevealOnDemand is the configuration mistake that enables the KeyList attack. Monitor for changes to this attribute with Event ID 5136. |
| Pass-the-Hash to DC | Add Administrator to Protected Users group. Restrict WinRM to a specific admin workstation. Require smartcard logon for Domain Admins. |
Detection rules worth deploying
- Event ID 4663 on SYSVOL — write by non-DA = alert.
- Event ID 4738 with scriptPath modification — alert if non-helpdesk user is the editor.
- Event ID 5136 on directory object modify — specifically msDS-AllowedToActOnBehalfOfOtherIdentity and msDS-RevealOnDemandGroup.
- Event ID 4624 logon type 3 from RODC subnet → DC subnet — rare and worth flagging.
- Suspicious Kerberos TGS — KeyList requests appear as TGS-REQ with KERB-KEY-LIST padata. Some SIEMs decode this; if yours does, alert on it.
13. Closing thoughts
Garfield is a textbook chain of AD primitives. The technical interest is twofold: (1) the multi-stage ACL graph that requires three pivots before reaching admin on RODC, and (2) the RODC Golden Ticket + KeyList Request technique that turns RODC compromise into writable-DC compromise without ever directly attacking the writable DC.
Three things to internalise:
An RODC is not a security boundary against domain compromise. The traditional thinking — "an RODC is read-only, so even if it's compromised the writable DC is safe" — assumed an attacker would have to do live-replication or extract per-account secrets from the RODC, both of which need the principal to be in the RODC's allowed replication group. The KeyList Request technique short-circuits all of that: once you control the RODC, you can just ask for a KeyList for any principal allowed to replicate to it. Audit your RODCs' replication policy aggressively.
BloodHound finds every ACL primitive in this box. Run it proactively on your own AD — every chain shown here would surface as a "shortest path to high-value target" result. The defender posture is simple: there should be no ACL paths from non-Tier-0 to Tier-0 accounts. None.
Logon Script Hijack is a 10-year-old technique that still works. Will Schroeder ("harmj0y") and Sean Metcalf documented this in 2016. The reason it keeps producing user flags on hard boxes (and real engagements) is that the prerequisite — writable SYSVOL by a non-DA user — looks innocuous in a permissions review. Audit SYSVOL ACLs as a top priority. The blast radius is "code execution as every interactive user".
Tools used: bloodyAD, BloodHound, impacket (addcomputer, rbcd, getST, smbclient, psexec, secretsdump), Evil-WinRM, Ligolo-ng, Mimikatz, Rubeus. Every one is open-source and current as of 2025. Build your AD attack lab around these, in this order, and you can replicate Garfield in a couple of hours.