From 94eeba35219997f4b09920b941da541184f545c8 Mon Sep 17 00:00:00 2001 From: adfoster-r7 Date: Fri, 26 Jan 2024 11:25:50 +0000 Subject: [PATCH] Update payload to_handler command to support option overrides --- .../ui/console/command_dispatcher/payload.rb | 46 ++++++++++++++++++- spec/acceptance/meterpreter_spec.rb | 2 +- spec/support/acceptance/child_process.rb | 18 ++++++-- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/payload.rb b/lib/msf/ui/console/command_dispatcher/payload.rb index 7f47e2517f59..4c5b0707f4cb 100644 --- a/lib/msf/ui/console/command_dispatcher/payload.rb +++ b/lib/msf/ui/console/command_dispatcher/payload.rb @@ -16,6 +16,10 @@ class Payload Msf::Simple::Buffer.transform_formats + \ Msf::Util::EXE.to_executable_fmt_formats + @@to_handler_opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Show this message' ] + ) + @@generate_opts = Rex::Parser::Arguments.new( '-p' => [ true, 'The platform of the payload' ], '-n' => [ true, 'Prepend a nopsled of [length] size on to the payload' ], @@ -45,12 +49,40 @@ def commands ) end + def cmd_to_handler_help + print_line 'Usage: to_handler [options]' + print_line + print_line 'Creates a handler a payload. Datastore options may be supplied after normal options.' + print_line 'This is convenient way of using multi/handler, setting the payload, and then setting datastore options.' + print_line + print_line 'Example: to_handler' + print_line 'Example: to_handler LHOST=192.168.123.1' + print @@to_handler_opts.usage + end + def cmd_to_handler(*args) if args.include?('-r') || args.include?('--reload-libs') driver.run_single('reload_lib -a') end + mod_with_opts = mod.replicant handler = framework.modules.create('exploit/multi/handler') + handler.share_datastore(mod_with_opts.datastore) + + @@to_handler_opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + cmd_to_handler_help + return false + else + unless val.include?('=') + cmd_to_handler_help + return false + end + + handler.datastore.import_options_from_s(val) + end + end handler_opts = { 'Payload' => mod.refname, @@ -62,8 +94,6 @@ def cmd_to_handler(*args) } } - handler.share_datastore(mod.datastore) - replicant_handler = nil handler.exploit_simple(handler_opts) do |yielded_replicant_handler| replicant_handler = yielded_replicant_handler @@ -83,6 +113,18 @@ def cmd_to_handler(*args) alias cmd_exploit cmd_to_handler + # + # Tab completion for the generate command + # + def cmd_to_handler_tabs(str, words) + fmt = { + '-h' => [ nil ], + } + flags = tab_complete_generic(fmt, str, words) + options = tab_complete_option(active_module, str, words) + flags + options + end + # # Returns the command dispatcher name. # diff --git a/spec/acceptance/meterpreter_spec.rb b/spec/acceptance/meterpreter_spec.rb index ea4fc557930c..0353804af578 100644 --- a/spec/acceptance/meterpreter_spec.rb +++ b/spec/acceptance/meterpreter_spec.rb @@ -134,7 +134,7 @@ def initialize(path) expect(payload.size).to be > 0 end - console.sendline 'to_handler' + console.sendline payload.handler_command(default_module_datastore: default_module_datastore) console.recvuntil(/Started reverse TCP handler[^\n]*\n/) payload_process = executed_payload session_id = nil diff --git a/spec/support/acceptance/child_process.rb b/spec/support/acceptance/child_process.rb index 786b28aed4bf..49fc3aaea543 100644 --- a/spec/support/acceptance/child_process.rb +++ b/spec/support/acceptance/child_process.rb @@ -368,15 +368,27 @@ def setg_commands(default_global_datastore: {}) # @param [Hash] default_module_datastore # @return [String] The command which can be used on msfconsole to generate the payload def generate_command(default_module_datastore: {}) - module_datastore = default_module_datastore.merge(@datastore[:module]) generate_options = @generate_options.map do |key, value| "#{key} #{value}" end + "generate -o #{path} #{generate_options.join(' ')} #{datastore_options(default_module_datastore: default_module_datastore)}" + end + + # @param [Hash] default_module_datastore + # @return [String] The command which can be used on msfconsole to create the listener + def handler_command(default_module_datastore: {}) + "to_handler #{datastore_options(default_module_datastore: default_module_datastore)}" + end + + # @param [Hash] default_module_datastore + # @return [String] The datastore options string + def datastore_options(default_module_datastore: {}) + module_datastore = default_module_datastore.merge(@datastore[:module]) module_options = module_datastore.map do |key, value| "#{key}=#{value}" end - "generate -o #{path} #{generate_options.join(' ')} #{module_options.join(' ')}" + module_options.join(' ') end # @param [Hash] default_global_datastore @@ -394,7 +406,7 @@ def as_readable_text(default_global_datastore: {}, default_module_datastore: {}) #{generate_command(default_module_datastore: default_module_datastore)} ## Create listener - to_handler + #{handler_command(default_module_datastore: default_module_datastore)} ## Execute command #{Shellwords.join(execute_command)}