Stageless PHP/Python/Java/Windows with Malleable C2 profile support#801
Conversation
|
@smcintyre-r7 thanks for having a look at this monster mate. I've clearly left a bit of debug logging stuff in Java and still need to tidy a few things up. Thanks for getting on this. |
|
Thanks @smcintyre-r7 ! I've addressed those points. Let me know what you think. Cheers. |
JavaNo ProfileTest Profile 1@OJ the profile that is causing problems is the same i am using in mettle |
|
@dledda-r7 Thanks for testing again mate. I've fixed the java payload. It was working for my profile as I wasn't setting restricted headers like your profile was. So you should be ok now. This should be working in Mettle as well! |
|
I added to the framework side as well, so grab that too please. |
|
Hey @OJ, super thanks for quickly addressing that. gonna start mass-testing mettle now with all the arches and picking up like ~20 profiles just to be sure we are all set and then move to Java and friends. Thank you very much for this 🎉 |
Test PlanJava ✅reverse_tcp (staged, stageless)staged ✅stageless ✅reverse_http(staged,stageless)staged ✅stageless ✅test 15 profilesamazon ✅bing_maps ✅bingsearch_getonly ✅microsoft_update ✅mscrl ✅msnbcvideo_getonly ✅office365_calendar ✅oscp ✅reddit ✅rtmp ✅slack ✅stackoverflow ✅trevor ✅youtube_video ✅zoom ✅ |
|
@dledda-r7 did the Microsoft Update profile start working after the most recent changes that included the ability to set the Host header? |
|
There was a problem hiding this comment.
Hello OJ! I am trying the Windows meterpreter but with stageless (both tcp and http) i am getting access violation on windows 22h2 compiled with mingw, staged tcp works good.
can you check on your side? from what i saw, the ReflectiveLoader is getting executed and the crash is happening between the DllMain and the first communication with msf, so probably is a problem with the TLV block maybe(?), still investigating
EDIT: here is some more Debug output. Still investigating
DebugString: "[1d0c] [METSRV] Initializing from configuration: 0x000000014004BA00"
DebugString: "[1d0c] [XOR] XORing 28 bytes with key 6a1fa167"
DebugString: "[1d0c] [METSRV] Config length is 4 0x00000004"
DebugString: "[1d0c] [METSRV] Config block size is 36 0x00000024"
DebugString: "[1d0c] [METSRV] decrypting config packet"
DebugString: "[1d0c] [DEC] Packet header: [0x6A 0x1F 0xA1 0x67] [0x6A 0x1F 0xA1 0x67 0x6A 0x1F 0xA1 0x67 0x6A 0x1F 0xA1 0x67 0x6A 0x1F 0xA1 0xD8] [0x6A 0x1F 0xA1 0x65] [0x6A 0x1F 0xA1 0x6B] [0x6A 0x1D 0xA3 0xDA]"
DebugString: "[1d0c] [DEC] Packet buffer size is: 36"
DebugString: "[1d0c] [XOR] XORing 32 bytes with key 6a1fa167"
DebugString: "[1d0c] [DEC] Packet header: [0x6A 0x1F 0xA1 0x67] [0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xBF] [0x00 0x00 0x00 0x02] [0x00 0x00 0x00 0x0C] [0x00 0x02 0x02 0xBD]"
DebugString: "[1d0c] [DEC] Encryption flags set to 2"
DebugString: "[1d0c] [DEC] Actual payload Length: 4"
DebugString: "[1d0c] [DEC] Header Type: 131773"
DebugString: "[1d0c] [DEC] Local packet payload successfully allocated, copying data"
DebugString: "[1d0c] [DEC] TLV 1 length / type: [0x56 0xA2 0xB5 0xF0] [0xAB 0xAB 0xAB 0xAB]"
DebugString: "[1d0c] [DEC] Skipping 1453503984 bytes"
EXCEPTION_DEBUG_INFO:
dwFirstChance: 1
ExceptionCode: C0000005 (EXCEPTION_ACCESS_VIOLATION)
ExceptionFlags: 00000000
ExceptionAddress: 0000000000468903
NumberParameters: 2
ExceptionInformation[00]: 0000000000000000 Read
ExceptionInformation[01]: 0000000056F06DD6 Inaccessible Address
First chance exception on 0000000000468903 (C0000005, EXCEPTION_ACCESS_VIOLATION)!
There was a problem hiding this comment.
Hey OJ!
I can't suggest you one small thing because it is not part of this PR, probably more a problem on the previous PR we landed. mingw complains about one small thing. here is the diff to make it shut up.
index 90aa7c12..74bd10cb 100644
--- a/c/meterpreter/source/metsrv/server_transport_winhttp.c
+++ b/c/meterpreter/source/metsrv/server_transport_winhttp.c
@@ -1035,9 +1035,9 @@ BOOL get_http_options_from_tlv(Packet* packet, Tlv* optionsTlv, HttpRequestOptio
targetOptions->uuid_prefix = packet_get_tlv_group_entry_value_wstring(packet, optionsTlv, TLV_TYPE_C2_UUID_PREFIX, NULL);
targetOptions->uuid_suffix = packet_get_tlv_group_entry_value_wstring(packet, optionsTlv, TLV_TYPE_C2_UUID_SUFFIX, NULL);
targetOptions->headers = packet_get_tlv_group_entry_value_wstring(packet, optionsTlv, TLV_TYPE_C2_HEADERS, NULL);
- targetOptions->payload_prefix = packet_get_tlv_group_entry_value_raw_copy(packet, optionsTlv, TLV_TYPE_C2_PREFIX, &targetOptions->payload_prefix_size);
+ targetOptions->payload_prefix = packet_get_tlv_group_entry_value_raw_copy(packet, optionsTlv, TLV_TYPE_C2_PREFIX, (DWORD *) &targetOptions->payload_prefix_size);
targetOptions->payload_prefix_skip = packet_get_tlv_group_entry_value_uint(packet, optionsTlv, TLV_TYPE_C2_PREFIX_SKIP);
- targetOptions->payload_suffix = packet_get_tlv_group_entry_value_raw_copy(packet, optionsTlv, TLV_TYPE_C2_SUFFIX, &targetOptions->payload_suffix_size);
+ targetOptions->payload_suffix = packet_get_tlv_group_entry_value_raw_copy(packet, optionsTlv, TLV_TYPE_C2_SUFFIX, (DWORD *) &targetOptions->payload_suffix_size);
targetOptions->payload_suffix_skip = packet_get_tlv_group_entry_value_uint(packet, optionsTlv, TLV_TYPE_C2_SUFFIX_SKIP);
targetOptions->ua = packet_get_tlv_group_entry_value_wstring(packet, optionsTlv, TLV_TYPE_C2_UA, NULL);
// A profile's `set uri` may list several candidate URIs, emitted as|
Hello @OJ, OJ/metasploit-framework#26 this is fixing the issue i have encountered. |
|
Sorry I've been away for a while and haven't been near a PC. |
|
OK so payloads and framework I think are all good at this point. Are you guys seeing any different? |
4325462 to
327ff97
Compare
Add support for stageless java via jar file.
And fix a prefix/suffix type issue in UUIDs.
Without this, the MC2 host headers can't be modified, so any profile that uses something like the 'Host' header (like Diego's profile) would fail. This allows it to be set, making it work as expected.
A profile's `set uri` may list several space-separated candidate URIs (Cobalt Strike picks one at random per request). Read every TLV_TYPE_C2_URI from the GET/POST group into opts['uris'] instead of a single value, and have _build_request_url pick one at random per request. This avoids pasting the raw "uri-a uri-b" string into the request URL, which produced a space-corrupted HTTP request line. Also add DEBUGGING-gated instrumentation to trace the C2 HTTP exchange: a debug_hexdump helper plus logging of the outgoing GET request (uuid/url/headers, or a non-c2 marker), the raw response body, the bytes after prefix/suffix strip and inbound decode, packet validation outcome, the incoming command id/TLVs in create_response, and the old->new UUID in _core_patch_uuid.
A profile's `set uri` may list several space-separated candidate URIs (Cobalt Strike picks one at random per request), emitted as repeated TLV_TYPE_C2_URI values. parse_c2_verb_config now collects every TLV_TYPE_C2_URI into $config['uris'] instead of reading a single value, and http_build_profile_url picks one at random per request via array_rand. This avoids pasting the raw "uri-a uri-b" string into the request URL, which produced a space-corrupted HTTP request line. Both the config-block and runtime transport-switch paths are covered, and GET and POST both route through the random selection.
A profile's `set uri` may list several space-separated candidate URIs (Cobalt Strike picks one at random per request), emitted as repeated TLV_TYPE_C2_URI values. C2VerbConfig now carries a String[] uris instead of a single uri; ConfigParser and core_transport_add collect every TLV_TYPE_C2_URI via getValues(); and HttpTransport.buildProfileUrl picks one at random per request via Math.random. This avoids pasting the raw "uri-a uri-b" string into the request URL, which produced a space-corrupted HTTP request line. Both the config-block and runtime transport-add paths are covered, and GET and POST both route through the random selection. Also add a `docker` target to java/Makefile that builds the payload inside the rapid7/msf-ubuntu-x64-meterpreter image (no local JDK/Maven needed), mounting only the metasploit-payloads checkout and chowning the build artifacts back to the invoking user.
A profile's `set uri` may list several space-separated candidate URIs (Cobalt Strike picks one at random per request), emitted as repeated TLV_TYPE_C2_URI values. HttpRequestOptions now carries a STRTYPE* uris / uri_count instead of a single uri (the base/default URL is just a one-element array), and generate_uri picks one at random per request via rand(). The change lives entirely in the shared HTTP code paths, so both the winhttp and wininet transports are covered without duplication: - get_http_options_from_tlv collects every TLV_TYPE_C2_URI into uris[] using a new packet_get_tlv_group_entry_n indexed group accessor (core.c/core.h). - generate_uri (shared by both transports) picks a random candidate, and falls back to the default base URI when a verb config has none. - http_options_set_single_uri / http_options_free_uris manage the base URI and cleanup; both winhttp and wininet configure paths and destroy_options use them. - set_http_options_to_tlv emits one TLV_TYPE_C2_URI per candidate so transport-list reporting round-trips all of them.
327ff97 to
b632aef
Compare
Stageless PHP/Python/Java/Windows with Malleable C2 profile support
This PR modifies the Meterpreter implementations in various ways. All payloads now support:
Some work was already done on the Windows side, but that has been tweaked/fixed in this PR and hence needs to be tested again.
This code relies on the changes that are part of the Metasploit Framework PR. Discussion and more details can be found over there.
NOTE: Merge is targeting
6.5branch.