Stageless PHP/Python/Java/Windows/Mettle with Malleable C2 profile support#21483
Stageless PHP/Python/Java/Windows/Mettle with Malleable C2 profile support#21483OJ wants to merge 27 commits into
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
|
Hello @OJ, I think the fetch-payloads are not working anymore. I am trying to triage the issue: I am not sure if this was related to the previous PR i have landed. |
PythonTCPStaggedStagelessHTTPstagelessamazon.profilebing_mapsbingsearch_getonlymicrosoft_update_getonlymscrlmsnbc_videooffice365_calendaroscprmtpSlackStackoverflowTrevorYoutubeZoombroken Staggedhttpsstagelessamazon.profilebing_maps.profilebingsearch_getonly.profilemicrosoft_update.profilemscrl.profilemsnbcvideo_getonly.profileoffice365_calendar.profileoscp.profilereddit.profilertmp.profileslack.profilestackoverflow.profiletrevor.profileyoutube_video.profilezoom.profilebroken |
PHP TestingTCPStagedstagelesshttpstagelessamazon.profilebing_maps.profilebingsearch_getonly.profilemicrosof_update.profilemscrlmsnbcvideo_getonly.profileoffice365.profileoscp.profilereddit.profilertmp.profileslackstackoverflowtrevoryoutube.profilezoom.profilestagedhttpsstagelessamazon.profilebing_maps.profilebingsearch_getonly.profilemicrosoft_update.profilemscrlmsnbcvideo_getonly.profileoffice365.profileoscp.profilereddit.profilertmp.profileslackstackoverflowtrevor.profileyoutube.profilezoom.profilestaged |
|
hey @dledda-r7 @msutovsky-r7 @smcintyre-r7 food for thought: The This is telling MSF to put the responses to commands as a Currently I haven't built support for this, so it just falls back to being in the body of the response. Do you want me to make it so that we just handle this like CS does and no worry about having servers with limitations in front? Should we throw a warning to the user? Keen to hear your thoughts, thanks. |
|
I have pushed up the latest round of changes to payloads/framework/mettle, which includes changes to all the payloads. The primary change is supporting multiple space-delimited URIs in the get/post sections (this is what was causing things to go bad in the Thanks to all for the help so far! |
Let's throw a warning for now if we can reliably detect the conditions in which this would be an issue. We can document the limitation in a ticket, optionally pointing users to it where they can comment on it +1 it or whatever in the warning. That'll let us get back around to it in the future without throwing things too far off track today. Does that sound reasonable? |
What do you mean by that? Do you mean we indicate when certain commands won't work? We'd have to detect that on the fly based on the encoding, the size of the output of the command, etc. Would it not be better to just not support it to start with? Most commands would likely be well under the 8kb limit (assuming the user doesn't pre/append too much data to it), but I'm still concerned that there's a good chance packets will result in being too big. Up to you though :) If you want some kind of support, can you define what you would mean by 'detecting' in this case? Thanks! |
|
Yeah that makes sense, we can disregard my original comment. If it's feasible to support it, let's try to do that and not worry about servers with limitations like an Nginx reverse proxy. We can just try to document that somewhere. |
Comms handle is a windows concern, so that's removed from the generation of the config TLV now.
This is a biggie!
They aren't valid any more.
Stagless android was busted when meterp switched to TLV config. This moves the flags to a TLV instead of the first byte of the config block.
Primary fix here is to make sure we put the UUID in the configuration in the right format. It was being ignored by Windows, but not by python.
Properly supports stageless now.
With MC2 support!
PHP, java, python, and php. Adjusting windows to support. Mettle yet to come.
Make the malleable C2 parser robust to real Cobalt Strike profiles and
honour space-separated URI lists.
Parser tolerance: detect blocks by lookahead (`name { ... }`) instead of
a fixed keyword whitelist, and allow identifier-named blocks/directives.
Unsupported blocks (dns-beacon, http-config, process-inject, post-ex,
code-signer, ...) are now parsed for structure and ignored by to_tlv
rather than aborting the whole profile. A stray top-level directive is
consumed instead of raising.
Multi-URI support: a `set uri` value may list several space-separated
candidate URIs (CS picks one at random per request). ParsedProfile#uris
now splits and flattens them so the handler registers a mount per
candidate, and add_uri emits a separate TLV_TYPE_C2_URI per candidate
(each with the query string) instead of one TLV holding the raw
space-joined string, which the client could not turn into a valid URL.
45b3012 to
69a5e60
Compare
This updates the config block accounts for the 8 byte handle like the staged variants do.
|
@smcintyre-r7 what's left on this side to wort out mate? |
Malleable C2 for all meterpreter runtimes (PHP/Python/Java/Mettle/Windows)
Builds on this previous PR to bring full MC2 + stageless feature parity to every meterpreter, plus a few fixes the wider work uncovered.
What's in here
MC2 wiring for non-Windows meterpreters
Mettle, PHP, Python, and Java now honour a Malleable C2 profile end-to-end:
set uri "/foo"overrides LURI for that verb's requests; the framework registers each profile URI alongside LURI inall_urisso requests land on the right handler.client.metadata/client.idplacement (parameter,header,cookie, default path-append) emitTLV_TYPE_C2_UUID_GET/HEADER/COOKIEso payloads place the UUID where the profile says.prepend,base64/base64url, andappenddirectives on those placements work — the framework emitsTLV_TYPE_C2_ENC_UUID+TLV_TYPE_C2_UUID_PREFIX+TLV_TYPE_C2_UUID_SUFFIX; each payload wraps the UUID accordingly; the handler reverses it.Inbound vs outbound encoding split
TLV_TYPE_C2_ENCsplit into three independent settings — all carried in bothTLV_TYPE_C2_GETandTLV_TYPE_C2_POSTgroups:TLV_TYPE_C2_ENC_INBOUNDserver { output { base64|base64url } }TLV_TYPE_C2_ENC_OUTBOUNDclient { output { base64|base64url } }(POST only)TLV_TYPE_C2_ENC_UUIDclient { metadata|id { base64|base64url } }Plus
TLV_TYPE_C2_UUID_PREFIX/SUFFIXfor theprepend/appenddirectives on those placement sections.Old
TLV_TYPE_C2_ENCis gone; staged C-meterpreter, mettle, java, php, python, framework all use the split.TLV_TYPE_TRANS_*were unused and removed — the python extension'stransport.pyis stubbed withNotImplementedErrorpending a rewrite onto the C2 TLVs, this might be removed entirely as it's probably not a feature that anyone uses anyway.UUID handling consistency
All four runtimes now follow the same pattern (matching
metsrv generate_uri):TLV_TYPE_C2_UUIDcarries the current connection's UUID (set initially viagenerate_uri_uuid(URI_CHECKSUM_INIT_CONN, uuid)inconfig.rb).COMMAND_ID_CORE_PATCH_UUID(renamed from_PATCH_URL) updates the in-memory UUID without mutating the base URL.scheme://host:port+ profile uri + current rendered UUID.Java stageless overhaul
Main-Class: StagelessMain, full meterpreter +JarFileClassLoader+ config-block resource embedded).msfvenom -f jarnow routes through the modules'generate_jaroverride rather than the inherited stager-jar path.loadExtensionworks under either bootstrap mode — lazily creates aJarFileClassLoader(and reuses it across loads) when the JVM-supplied AppClassLoader is in play.Stageless
EXTENSIONS=supportEvery stageless single (Python/PHP/Java/Mettle, plus the existing Windows path) now bakes the listed extensions into the config block and hot-loads them before the C2 dispatch loop starts. The framework picks the right on-disk format via a new
:ext_formatopt ('x86.dll'/'x64.dll'/'jar'/'py'/'php'/'bin') so non-Windows extensions skip the RDI prep and are shipped as-is (with the gem's encrypted-payload short-circuit honoured for everything that has one).Mettle's 8 KB config-block reservation can't hold real extensions; that's now caught at generation time with a clear error pointing the user at runtime
load <ext>instead.EXTENSIONS=stdapiis a no-op for mettle (stdapi is already linked intomettle.bin).Misc fixes / refactors found along the way
reverse_http.rb#request_summarynow logsreq.resource(full request URI) instead ofluri— much more useful when MC2 routes hit/<profile-uri>/<uuid>mount points.reverse_http.rb#find_resource_idrewritten to derive the candidate UUID from either query parameter, header, or path segment, then reverse profile-sideprepend/append+ base64 before handing it toprocess_uri_resource. Conservative: returns the candidate untouched if a declared wrapper isn't present (instead of mangling and feeding garbage downstream).Validated end-to-end
EXTENSIONS=stdapi):ext_format)Notes for review
metasploit-payloadsandmettlerepos both have matching pull requests.Testing
In short, for PHP, Python, Windows, Mettle and Java:
MALLEABLEC2to use a C2 profile file (like this).Build and run the payloads with the correct associated handlers. Good luck. Goodspeed. The testing matrix here is huge.
NOTE: I have not been able to test Android Meterpreter, so I will need help with this one.
NOTE: Merge is targeting
6.5branch.