-
Notifications
You must be signed in to change notification settings - Fork 14.6k
Split Stdapi #19975
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
Split Stdapi #19975
Conversation
7145d48
to
53ce08e
Compare
I get a validation failure for AutoloadExtensions when it is clear?
|
My bad, in metasploit required strings cannot be set as 'nil' instead of |
Regarding your suggestions for the "Already Loaded Extensions", I think the first solution is the safest and avoid breaking changes. Why should it be considered as a short term solution? What are the drawbacks for this solution? Also, I'm not super familiar with the Meterpreter bootstrap process, but is there a way the payload can advertise itself which extensions are loaded in the session instead of having a routine that will test every extensions? I'm thinking about reducing the footprint and limiting the number of back-and-forth between the client and the payload. |
Thanks a lot Christophe for your review, I will consider the first solution as cheap and short-term for the following reasons:
Regarding your question to the meterpreter bootstrap process, meterpreter per-se have a different granularity compared to framework. Meterpreter think in |
I would recommend the second option if we wanted to switch this to the 6.5 branch as a breaking change. It would keep things better organized and be a better change long term. You'll still have an issue figuring out what extensions are loaded though, the grouping of the IDs will only simply the logic so far. Take the following pseudo code for consideration as an example def get_loaded_extensions
extensions = [] # populate with the others as we do now, extapi, espia, etc.
extensions.delete('stdapi') # process this as a special case
stdapi_subextensions_for_platform = get_stdapi_subextensions_for_platform
if stdapi_subextensions_for_platform.empty?
# if there are no subextensions, then we can simply assume that stdapi is loaded if there is *any* overlap
extensions << 'stdapi' unless (command_ids.to_set & STDAPI_EXTENSION_ID.upto(STDAPI_EXTENSION_ID + EXTENSION_RANGE - 1).to_set).empty?
else
stdapi_subextensions_for_platform.each do |subextension_name|
# add the subextension if the commands overlap with any of it's commands
extensions << subextension_name unless (command_ids.to_set & get_subextension_ids(subextension_name)).empty?
end
if (extensions.to_set & stdapi_subextensions_for_platform.to_set) == stdapi_subextensions_for_platform.to_set
# if *all* subextensions are loaded, remove them and declare that 'stdapi' is loaded
extensions -= stdapi_subextensions_for_platform
extensions << 'stdapi'
end
end
end
def get_subextension_ids(subextension_name)
# this abstraction allows the IDs to either be hardcoded as they are now so we can maintain backwards compatibility
return HARDCODED_SUBIDS[subextension_name]
# or use the range if they're grouped together
range_start = { 'stdapi-fs' => STDAPI_FS_EXTENSION_ID }.fetch(subextension_name)
return range_start.upto(range_start + RANGE - 1).to_a
end
def get_stdapi_subextensions_for_platform
# return the subextensions based on the platform
return [] if platform != 'windows'
return ['fs', 'registry', 'railgun', etc.] # enumerate this from the files we have on disk with the `Metasploit::Payloads` gem
end With that in place you should have all of the logic for all of the Meterpreters to identify when one of the subextensions is loaded, stdapi isn't loaded at all, all of the subextensions are loaded or the combined stdapi is loaded. This does assume however that if all of the subextensions are loaded, that it's functionally equivalent to having the main stdapi extension loaded. |
1 similar comment
I would recommend the second option if we wanted to switch this to the 6.5 branch as a breaking change. It would keep things better organized and be a better change long term. You'll still have an issue figuring out what extensions are loaded though, the grouping of the IDs will only simply the logic so far. Take the following pseudo code for consideration as an example def get_loaded_extensions
extensions = [] # populate with the others as we do now, extapi, espia, etc.
extensions.delete('stdapi') # process this as a special case
stdapi_subextensions_for_platform = get_stdapi_subextensions_for_platform
if stdapi_subextensions_for_platform.empty?
# if there are no subextensions, then we can simply assume that stdapi is loaded if there is *any* overlap
extensions << 'stdapi' unless (command_ids.to_set & STDAPI_EXTENSION_ID.upto(STDAPI_EXTENSION_ID + EXTENSION_RANGE - 1).to_set).empty?
else
stdapi_subextensions_for_platform.each do |subextension_name|
# add the subextension if the commands overlap with any of it's commands
extensions << subextension_name unless (command_ids.to_set & get_subextension_ids(subextension_name)).empty?
end
if (extensions.to_set & stdapi_subextensions_for_platform.to_set) == stdapi_subextensions_for_platform.to_set
# if *all* subextensions are loaded, remove them and declare that 'stdapi' is loaded
extensions -= stdapi_subextensions_for_platform
extensions << 'stdapi'
end
end
end
def get_subextension_ids(subextension_name)
# this abstraction allows the IDs to either be hardcoded as they are now so we can maintain backwards compatibility
return HARDCODED_SUBIDS[subextension_name]
# or use the range if they're grouped together
range_start = { 'stdapi-fs' => STDAPI_FS_EXTENSION_ID }.fetch(subextension_name)
return range_start.upto(range_start + RANGE - 1).to_a
end
def get_stdapi_subextensions_for_platform
# return the subextensions based on the platform
return [] if platform != 'windows'
return ['fs', 'registry', 'railgun', etc.] # enumerate this from the files we have on disk with the `Metasploit::Payloads` gem
end With that in place you should have all of the logic for all of the Meterpreters to identify when one of the subextensions is loaded, stdapi isn't loaded at all, all of the subextensions are loaded or the combined stdapi is loaded. This does assume however that if all of the subextensions are loaded, that it's functionally equivalent to having the main stdapi extension loaded. |
Co-authored-by: Christophe De La Fuente <[email protected]>
Co-authored-by: Christophe De La Fuente <[email protected]>
I cannot help but notice that |
The suggestions are not correct in general. probably is better to remove
|
|
Bump Payloads version again
|
Release NotesSplits the stdapi extension into subcomponents that can be loaded individually to lessen the footprint of the Windows Meterpreter Payload in memory. The original stdapi extension can still be loaded as well, and the default behavior to autoload stdapi when the Windows Meterpreter payload is loaded remains unchanged. |
Framework side PR for rapid7/metasploit-payloads#744
This PR allows to load portion of
stdapi
by using namespace-specific dlls.AutoLoadExtension
values worksAutoLoadExtension
and load differentstdapi_
extensions