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
Multi transport support, connection resiliency changes, payload ports, and more #5300
Conversation
This is pretty basic stuff, but at least it's reusable.
RDI is now back to what it was before, as this leaves all the other RDI style payloads alone. Instead we have a new Meterpreter loader which does the stuff that is required to make meterpreter work well with the new configuration options. This is just the case for reverse_tcp and bind_tcp so far, need to do the other payloads too, along with all the x64 versions.
Getting closer to a normalised view of what this stuff will look like. There URL patching is slowly being removed. Reverse HTTPS works fine, and by default HTTP should too. Next up, x64 for the same main ones.
Meterpreter handles the exitfunk internally as part of the config now
Correctly check the URL against the non-widechar version. Get the SSL verification stuff working again.
Migration now uses the new meterpreter loader. Migration configuration is loaded and created by meterpreter on the fly, and supports the multiple transport stuff that's just been wired in.
The 'next' and 'prev' commands were added so that the session can jump transports without having to add new ones at the same time. There's also a command which gives the UUID now so that this can be reused across sessions.
Includes a verbose flag for the extra HTTP/S properties
Ported the stager and wired in the new work to make the configuration function.
Adjust a few other things along the way, including tidying of code, removing of dead stuff.
Stageless payloads need to have the socket FD left along (ie. 0) otherwise each of them will think that the socket is already open. Instead we need to make sure it's left as 0 as per the configuration and from there the stageless code will fire up a new socket based on the transport in question.
Conflicts: lib/msf/core/payload/windows/stageless_meterpreter.rb lib/msf/core/payload/windows/x64/stageless_meterpreter.rb lib/rex/post/meterpreter/client_core.rb modules/payloads/stages/linux/x86/meterpreter.rb modules/payloads/stages/windows/meterpreter.rb modules/payloads/stages/windows/x64/meterpreter.rb
@hmoore-r7 staticness added. Thanks for picking that up. I had also missed the |
@bcook-r7 I was super concerned about breaking the existing payloads and that's why we went with the new |
This allows for checking against exit types to be super easy instead of having to have extra checks in place. Also changed the order of scope_id and uri in the transport URI generation. The net effect of this is NOP because these things only appear separately.
As per Egypt's suggestions.
The payload changes in this PR will be fixed up/removed in the update-x64-stagers PR.
The payload_uuid rework looks good, thanks! |
This time it's against the currently "installed" version of Meterpeter binaries. When Meterpreter is landed down the track we'll need to make sure that the payload sizes are updated again.
Come on travis, Y U NO BUILD?! |
metasploit-payloads 0.0.5 should be testable with this now. I'll spin another tomorrow with machine_id improvements for windows. |
Quick note, migration on Linux does indeed get broken here. Though after testing master with a few different distros, it really works in a limited range of circumstances - Ubuntu 12.04 and 10.04 i386 work fine, but Debian did not. |
It looks like all we need to do is update the migration payload generator for linux to append a proper configuration block like the stager does. My work-in-progress patch to add the config block is here: I'm not quite sure how to get a properly formatted transport block for regenerating the payload for migration. |
Do we also need the delete transport command implemented before this can land? Adding that would need new bins it seems. For the sake of unblocking, I'm willing to live temporarily with Linux migration failing, since it is of fairly limited utility, and this fixes some higher-priority bugs. |
Thanks Brent. I was never able to get Linux migration functioning locally so I had no scenario to test it. Thank you again for looking at it. Unblocking might be a good idea, and I'll put a bug together that describes what needs to be fixed. I think that I can do the transport deletion in another PR, this is already big enough. What do you think? Also, it seems that this PR needs remerging. Shall I sort that out prior to you landing? Thanks again! |
Yep, yep and yep |
Conflicts: Gemfile.lock modules/payloads/singles/cmd/windows/powershell_bind_tcp.rb
Well, that was an interesting experience! Hopefully we'll be able to manage smaller chunks moving forward. Cheers. |
Thank you very much @bcook-r7 for wading through that. I expect some teething issues, but I'm here to react accordingly. Cheers, I owe you some beverages. |
And yes, I would expect all future PRs to be substantially smaller. This just had an impact on so many parts of the system. |
Overview
This PR provides the basis for support of multiple transport mechanisms within the one Meterpreter session. The goal ultimately is to be able to utilise multiple transports at the same time and having MSF handle things gracefully behind the scenes regardless of which communication channel is successful. This PR doesn't quite get that far, but does provide the ability to:
While we still only have the ability to talk to one transport at a time, the resiliency of the shells should go up as the code now automatically tries each of the specified transports (using timeouts configured individually) until the session expires.
Timeouts that are transport-specific can be modified on the fly, and the session time (for the entire Meterpeter session) can be modified separately as well.
This PR relies on the Meterpreter binaries being updated as well. The PR for those updates can be found in the Meterpreter repo over here: rapid7/meterpreter#156
Configuration changes
This code comes with a stack of changes around how Meterpreter sessions are configured. Originally we had global variables stored in the Meterpreter binaries that had known values in them prior to being run. These values were modified via a search-and-replace feature. Meterpreter was loaded from disk, patched with these values, and then uploaded to the target.
This is no longer the case. The contents of Meterpreter itself are no long patched directly. Instead a new "configuration block" has been created that contains all of the session, transport and stageless extension information. A pointer to this block of memory is given to Meterpreter on start up.
The configuration is made up of 3 different possible sections
Session
, containing:comms_fd
: Any existing socket handle for communications, or0
(32-bit unsigned integer)exit_func
: One of the pre-determined exit function constants, or0
(32-bit unsigned integer)expiry
: The number of whole seconds until the Meterpreter session should end (32-bit signed integer)uuid
: The UUID of the session (64 chars)Transport
(1 or more), containing:Common
: a block that contains data common to any transport type, containing:url
: The URL of the transport (512 chars)comms_timeout
: Timeout in whole seconds for when communicatiosn failsretry_total
: Time in whole seconds that Meterpreter should continue to retry on this transport.retry_wait
: Time in whole seconds between each reconnection attempt.proxy
, which contains all the proxy information:hostname
: Proxy host name (128 chars)username
: Proxy user name (64 chars)password
: Proxy password (64 chars)ua
: User agent to use when making requests (256 chars)cert_hash
: The SHA1 hash of the certificate to validate against (20 bytes)Extensions
(0 or more), containing:size
: Size of the extension in bytes (32-bit unsigned integer)dll
: The binary data of the extension itself (array of bytes,size
long)Meterpreter knows that it has reached the end of each individual transport configuration block when a single
NULL
character is found at the start of the block'surl
. It is then assumed that immediately after this character that the extensions information is present.Meterpreter will continue to loop through stageless extensions until it finds an extension size of
0
.When the Meterpreter payload is generated a block of configuration is created that looks like this:
This configuration block is written to memory immediately after the
metsrv
payload. Originally we used thereflectivedllinject
payload type when creating these payloads, but this doesn't happen any more. Thereflectivedllinject
payload invokes the underlying DLL and passes in the socket handle that is found inedi
. Rather than mess we this and damaging other payload types, there's now a new custom one calledmeterpreter_loader
, which effectively does the same thing, but with the following differences:metsrv
passing in a pointer to the configuration blockTherefore, when the payload gets uploaded, this is what it looks like:
From there, the code in the payload and
metsrv
does the rest.Notes
next
andprev
commands to cycle through existing transports, which requires knowledge of the relationships between the transports in the list. We will need to come up with a way of saying "jump to this one".Sample Run
Here are some of the jobs we'll be using
All of this stuff should be reproducable with any transport combinations so long as you don't mix up the platform.
View the existing list of transports, the
*
shows the 'active' transport:We can add using the
add
subcommand of thetransport
commandWith a http/s payload in place, the
-v
flag becomes useful to see the extra parameters:And from here we can move to the next transport:
It's trivial to move back to the original transport, but given that the original listener is a staged listener it will attempt to send the stage down the wire. This stage is ignored by a stageless payload:
With the previous work done on the connection resiliency, we should be able to completely restart MSF, and have our connection come back, this time on the second transport that we've added because the first one has technically "failed" (ie. it's round-robin):
And to show it still works, let's add a new tcp transport that points to the stageless endpoint and jump straight to it:
We can also query and modify the timeouts for the current session and transport directly:
If the session does actually expire, then the session will die:
Firing up a new x64 session, we can demonstrate that transports do in fact move along when the session is migrated:
We also have the new
uuid
command for informational purposes:This is used behind the scenes in various ways.
Verification
I apologise to the poor folks to have to go through this, because it's going to be epic (I think). Given that this stuff mucks with almost everything, almost everything has to be validated.
prev
andnext
).uuid
works.exit -y
, shells should reconnect when MSF is restarted and listeners set up again.reverse_http/s
payloads now exit cleanly (ie. this fixes Meterpreter - Reverse HTTP/HTTPS - process not quitting #4097).Things to do before this can be landed
delete
command for transports.Thanks
Thanks to everyone to helps get this in. I appreciate the support.