diff --git a/plugins/aggregator.rb b/plugins/aggregator.rb index 4b0348a726..7790a0835f 100644 --- a/plugins/aggregator.rb +++ b/plugins/aggregator.rb @@ -1,4 +1,3 @@ -#!/usr/bin/env ruby # # $Id$ # @@ -9,139 +8,141 @@ require "metasploit/aggregator" module Msf - Aggregator_yaml = "#{Msf::Config.get_config_root}/aggregator.yaml" #location of the aggregator.yml containing saved aggregator creds + Aggregator_yaml = "#{Msf::Config.get_config_root}/aggregator.yaml" # location of the aggregator.yml containing saved aggregator creds -class Plugin::Aggregator < Msf::Plugin - class AggregatorCommandDispatcher - include Msf::Ui::Console::CommandDispatcher + class Plugin::Aggregator < Msf::Plugin + class AggregatorCommandDispatcher + include Msf::Ui::Console::CommandDispatcher - @response_queue = [] + @response_queue = [] - def name - "Aggregator" - end - - def commands - { - 'aggregator_connect' => "Connect to a running Aggregator instance ( host[:port] )", - 'aggregator_save' => "Save connection details to an Aggregator instance", - 'aggregator_disconnect' => "Disconnect from an active Aggregator instance", - 'aggregator_addresses' => "List all remote ip addresses available for ingress", - 'aggregator_cables' => "List all remote listeners for sessions", - 'aggregator_cable_add' => "Setup remote https listener for sessions", - 'aggregator_cable_remove' => "Stop remote listener for sessions", - 'aggregator_default_forward' => "forward a unlisted/unhandled sessions to a specified listener", - 'aggregator_sessions' => "List all remote sessions currently available from the Aggregator instance", - 'aggregator_session_forward' => "forward a session to a specified listener", - 'aggregator_session_park' => "Park an existing session on the Aggregator instance" - } - end - - def aggregator_verify - if ! @aggregator - print_error("No active Aggregator instance has been configured, please use 'aggregator_connect'") - return false + def name + "Aggregator" end - true - end - - def usage(*lines) - print_status("Usage: ") - lines.each do |line| - print_status(" #{line}") - end - end - - def usage_save - usage("aggregator_save") - end - - def usage_connect - usage("aggregator_connect host[:port]", - " -OR- ", - "aggregator_connect host port") - end - - def usage_cable_add - usage('aggregator_cable_add host:port [certificate]', - ' -OR- ', - 'aggregator_cable_add host port [certificate]') - end - - def usage_cable_remove - usage('aggregator_cable_remove host:port', - ' -OR- ', - 'aggregator_cable_remove host port') - end - - def usage_session_forward - usage("aggregator_session_forward remote_id") - end - - def usage_default_forward - usage("aggregator_session_forward") - end - - def cmd_aggregator_save(*args) - #if we are logged in, save session details to aggregator.yaml - if args[0] == "-h" - usage_save - return + def commands + { + 'aggregator_connect' => "Connect to a running Aggregator instance ( host[:port] )", + 'aggregator_save' => "Save connection details to an Aggregator instance", + 'aggregator_disconnect' => "Disconnect from an active Aggregator instance", + 'aggregator_addresses' => "List all remote ip addresses available for ingress", + 'aggregator_cables' => "List all remote listeners for sessions", + 'aggregator_cable_add' => "Setup remote https listener for sessions", + 'aggregator_cable_remove' => "Stop remote listener for sessions", + 'aggregator_default_forward' => "forward a unlisted/unhandled sessions to a specified listener", + 'aggregator_sessions' => "List all remote sessions currently available from the Aggregator instance", + 'aggregator_session_forward' => "forward a session to a specified listener", + 'aggregator_session_park' => "Park an existing session on the Aggregator instance" + } end - if args[0] - usage_save - return + def aggregator_verify + if !@aggregator + print_error("No active Aggregator instance has been configured, please use 'aggregator_connect'") + return false + end + + true end - group = "default" - - if ((@host and @host.length > 0) and (@port and @port.length > 0 and @port.to_i > 0)) - config = {"#{group}" => {'server' => @host, 'port' => @port}} - ::File.open("#{Aggregator_yaml}", "wb") { |f| f.puts YAML.dump(config) } - print_good("#{Aggregator_yaml} created.") - else - print_error("Missing server/port - reconnect and then try again.") - return + def usage(*lines) + print_status("Usage: ") + lines.each do |line| + print_status(" #{line}") + end end - end - def cmd_aggregator_connect(*args) - if ! args[0] - if ::File.readable?("#{Aggregator_yaml}") - lconfig = YAML.load_file("#{Aggregator_yaml}") - @host = lconfig['default']['server'] - @port = lconfig['default']['port'] - aggregator_login + def usage_save + usage("aggregator_save") + end + + def usage_connect + usage("aggregator_connect host[:port]", + " -OR- ", + "aggregator_connect host port") + end + + def usage_cable_add + usage('aggregator_cable_add host:port [certificate]', + ' -OR- ', + 'aggregator_cable_add host port [certificate]') + end + + def usage_cable_remove + usage('aggregator_cable_remove host:port', + ' -OR- ', + 'aggregator_cable_remove host port') + end + + def usage_session_forward + usage("aggregator_session_forward remote_id") + end + + def usage_default_forward + usage("aggregator_session_forward") + end + + def cmd_aggregator_save(*args) + # if we are logged in, save session details to aggregator.yaml + if args[0] == "-h" + usage_save + return + end + + if args[0] + usage_save + return + end + + group = "default" + + if (@host && @host.length.positive?) && (@port && @port.length.positive? && @port.to_i > 0) + config = { "#{group}" => { 'server' => @host, 'port' => @port } } + ::File.open("#{Aggregator_yaml}", "wb") { |f| f.puts YAML.dump(config) } + print_good("#{Aggregator_yaml} created.") + else + print_error("Missing server/port - reconnect and then try again.") return end end - if(args.length == 0 or args[0].empty? or args[0] == "-h") - usage_connect - return + def cmd_aggregator_connect(*args) + if !args[0] + if ::File.readable?("#{Aggregator_yaml}") + lconfig = YAML.load_file("#{Aggregator_yaml}") + @host = lconfig['default']['server'] + @port = lconfig['default']['port'] + aggregator_login + return + end + end + + if args.length == 0 || args[0].empty? || args[0] == "-h" + usage_connect + return + end + + @host = @port = @sslv = nil + + case args.length + when 1 + @host, @port = args[0].split(':', 2) + @port ||= '2447' + when 2 + @host, @port = args + else + usage_connect + return + end + aggregator_login end - @host = @port = @sslv = nil + def cmd_aggregator_sessions(*_args) + return unless aggregator_verify - case args.length - when 1 - @host,@port = args[0].split(':', 2) - @port ||= '2447' - when 2 - @host,@port = args - else - usage_connect - return - end - aggregator_login - end + sessions_list = @aggregator.sessions + return if sessions_list.nil? - def cmd_aggregator_sessions(*args) - return if not aggregator_verify - sessions_list = @aggregator.sessions - unless sessions_list.nil? # get details for each session and print in format of sessions -v print_status("Sessions found:") sessions_list.each do |session| @@ -152,307 +153,304 @@ class Plugin::Aggregator < Msf::Plugin next unless value.conn_id == session_id local_id = key end - #filter session that do not have details as forwarding options (this may change later) - if details && details['ID'] - print_status "\t Remote ID: #{details['ID']}" - print_status "\t Type: meterpreter #{guess_target_platform(details['OS'])}" - print_status "\t Info: #{details['USER']} @ #{details['HOSTNAME']}" - print_status "\t Tunnel: #{details['LOCAL_SOCKET']} -> #{details['REMOTE_SOCKET']}" - print_status "\t Via: exploit/multi/handler" - print_status "\t UUID: #{details['UUID']}" - print_status "\t MachineID: #{details['MachineID']}" - unless details['LAST_SEEN'].nil? - print_status"\t CheckIn: #{details['LAST_SEEN'].to_i}s ago" - end - print_status "\tRegistered: Not Yet Implemented" - print_status "\t Forward: #{target}" - unless local_id.nil? - print_status"\tSession ID: #{local_id}" - end - print_status "" - end + # filter session that do not have details as forwarding options (this may change later) + next unless details && details['ID'] + + print_status "\t Remote ID: #{details['ID']}" + print_status "\t Type: meterpreter #{guess_target_platform(details['OS'])}" + print_status "\t Info: #{details['USER']} @ #{details['HOSTNAME']}" + print_status "\t Tunnel: #{details['LOCAL_SOCKET']} -> #{details['REMOTE_SOCKET']}" + print_status "\t Via: exploit/multi/handler" + print_status "\t UUID: #{details['UUID']}" + print_status "\t MachineID: #{details['MachineID']}" + print_status "\t CheckIn: #{details['LAST_SEEN'].to_i}s ago" unless details['LAST_SEEN'].nil? + print_status "\tRegistered: Not Yet Implemented" + print_status "\t Forward: #{target}" + print_status "\tSession ID: #{local_id}" unless local_id.nil? + print_status "" end end - end - def cmd_aggregator_addresses(*args) - return if not aggregator_verify - address_list = @aggregator.available_addresses - unless address_list.nil? + def cmd_aggregator_addresses(*_args) + return if !aggregator_verify + + address_list = @aggregator.available_addresses + return unless address_list.nil? + print_status("Remote addresses found:") address_list.each do |addr| print_status(" #{addr}") end end - end - def cmd_aggregator_cable_add(*args) - return if not aggregator_verify - host, port, certificate = nil - case args.length - when 1 - host, port = args[0].split(':', 2) - when 2 - host, port = args[0].split(':', 2) - if port.nil? - port = args[1] - else - certificate = args[1] - end - when 3 - host, port, certificate = args - else - usage_cable_add - return - end - if port.nil? || port.to_i <= 0 - usage_cable_add - end - if certificate && File.exists?(certificate) - certificate = File.new(certificate).read - end - @aggregator.add_cable(Metasploit::Aggregator::Cable::HTTPS, host, port, certificate) - end - - def cmd_aggregator_cables - return if not aggregator_verify - res = @aggregator.cables - print_status("Remote Cables:") - res.each do |k| - print_status(" #{k}") - end - - end - - def cmd_aggregator_cable_remove(*args) - return if not aggregator_verify - case args.length - when 1 - host, port = args[0].split(':', 2) - when 2 - host, port = args - end - if host.nil? - usage_cable_remove - return - end - @aggregator.remove_cable(host, port) - end - - def cmd_aggregator_session_park(*args) - return if not aggregator_verify - case args.length - when 1 - session_id = args[0] - s = framework.sessions.get(session_id) - unless s.nil? - if @aggregator.sessions.keys.include? s.conn_id - @aggregator.release_session(s.conn_id) - framework.sessions.deregister(s) + def cmd_aggregator_cable_add(*args) + return if !aggregator_verify + host, port, certificate = nil + case args.length + when 1 + host, port = args[0].split(':', 2) + when 2 + host, port = args[0].split(':', 2) + if port.nil? + port = args[1] else - # TODO: determine if we can add a transport and route with the aggregator - # for now just report action not taken - print_status("#{session_id} does not originate from the aggregator connection.") + certificate = args[1] + end + when 3 + host, port, certificate = args + else + usage_cable_add + return + end + usage_cable_add if port.nil? || port.to_i <= 0 + + certificate = File.new(certificate).read if certificate && File.exists?(certificate) + + @aggregator.add_cable(Metasploit::Aggregator::Cable::HTTPS, host, port, certificate) + end + + def cmd_aggregator_cables + return if !aggregator_verify + res = @aggregator.cables + print_status("Remote Cables:") + res.each do |k| + print_status(" #{k}") + end + + end + + def cmd_aggregator_cable_remove(*args) + return if !aggregator_verify + + case args.length + when 1 + host, port = args[0].split(':', 2) + when 2 + host, port = args + end + if host.nil? + usage_cable_remove + return + end + @aggregator.remove_cable(host, port) + end + + def cmd_aggregator_session_park(*args) + return if !aggregator_verify + + case args.length + when 1 + session_id = args[0] + s = framework.sessions.get(session_id) + unless s.nil? + if @aggregator.sessions.keys.include? s.conn_id + @aggregator.release_session(s.conn_id) + framework.sessions.deregister(s) + else + # TODO: determine if we can add a transport and route with the aggregator + # for now just report action not taken + print_status("#{session_id} does not originate from the aggregator connection.") + end + else + print_status("#{session_id} is not a valid session.") end else - print_status("#{session_id} is not a valid session.") - end - else - usage('aggregator_session_park session_id') - return + usage('aggregator_session_park session_id') + return + end end - end - def cmd_aggregator_default_forward(*args) - return if not aggregator_verify - @aggregator.register_default(@aggregator.uuid, nil) - end + def cmd_aggregator_default_forward(*_args) + return if !aggregator_verify - def cmd_aggregator_session_forward(*args) - return if not aggregator_verify - remote_id = nil - case args.length - when 1 - remote_id = args[0] - else - usage_session_forward - return + @aggregator.register_default(@aggregator.uuid, nil) end - # find session with ID matching request - @aggregator.sessions.each do |session| - session_uri, target = session - details = @aggregator.session_details(session_uri) - if details['ID'] == remote_id - return @aggregator.obtain_session(session_uri, @aggregator.uuid) + + def cmd_aggregator_session_forward(*args) + return if !aggregator_verify + + remote_id = nil + case args.length + when 1 + remote_id = args[0] + else + usage_session_forward + return + end + # find session with ID matching request + @aggregator.sessions.each do |session| + session_uri, _target = session + details = @aggregator.session_details(session_uri) + next unless details['ID'] == remote_id + return @aggregator.obtain_session(session_uri, @aggregator.uuid) end print_error("#{remote_id} was not found.") end - end - def cmd_aggregator_disconnect(*args) - if @aggregator && @aggregator.available? - # check if this connection is the default forward - @aggregator.register_default(nil, nil) if @aggregator.default == @aggregator.uuid + def cmd_aggregator_disconnect(*_args) + if @aggregator && @aggregator.available? + # check if this connection is the default forward + @aggregator.register_default(nil, nil) if @aggregator.default == @aggregator.uuid - # now check for any specifically forwarded sessions - local_sessions_by_id = {} - framework.sessions.each_pair do |id, s| - local_sessions_by_id[s.conn_id] = s - end + # now check for any specifically forwarded sessions + local_sessions_by_id = {} + framework.sessions.each_pair do |_id, s| + local_sessions_by_id[s.conn_id] = s + end - sessions = @aggregator.sessions - unless sessions.nil? - sessions.each_pair do |session, console| - next unless local_sessions_by_id.keys.include?(session) - if console == @aggregator.uuid - # park each session locally addressed - cmd_aggregator_session_park(framework.sessions.key(local_sessions_by_id[session])) - else - # simple disconnect session that were from the default forward - framework.sessions.deregister(local_sessions_by_id[session]) + sessions = @aggregator.sessions + unless sessions.nil? + sessions.each_pair do |session, console| + next unless local_sessions_by_id.keys.include?(session) + if console == @aggregator.uuid + # park each session locally addressed + cmd_aggregator_session_park(framework.sessions.key(local_sessions_by_id[session])) + else + # simple disconnect session that were from the default forward + framework.sessions.deregister(local_sessions_by_id[session]) + end end end end - end - @aggregator.stop if @aggregator - if @payload_job_ids - @payload_job_ids.each do |id| - framework.jobs.stop_job(id) + @aggregator.stop if @aggregator + if @payload_job_ids + @payload_job_ids.each do |id| + framework.jobs.stop_job(id) + end + @payload_job_ids = nil end - @payload_job_ids = nil - end - @aggregator = nil - end - - def aggregator_login - - if ! ((@host and @host.length > 0) and (@port and @port.length > 0 and @port.to_i > 0)) - usage_connect - return + @aggregator = nil end - if(@host != "localhost" and @host != "127.0.0.1") - print_error("Warning: SSL connections are not verified in this release, it is possible for an attacker") - print_error(" with the ability to man-in-the-middle the Aggregator traffic to capture the Aggregator") - print_error(" traffic, if you are running this on an untrusted network.") - return + def aggregator_login + + if !((@host && @host.length.positive?) && (@port && @port.length.positive? && @port.to_i > 0)) + usage_connect + return + end + + if @host != "localhost" and @host != "127.0.0.1" + print_error("Warning: SSL connections are not verified in this release, it is possible for an attacker") + print_error(" with the ability to man-in-the-middle the Aggregator traffic to capture the Aggregator") + print_error(" traffic, if you are running this on an untrusted network.") + return + end + + # Wrap this so a duplicate session does not prevent access + begin + cmd_aggregator_disconnect + rescue ::Interrupt => i + raise i + rescue ::Exception + end + + begin + print_status("Connecting to Aggregator instance at #{@host}:#{@port}...") + @aggregator = Metasploit::Aggregator::ServerProxy.new(@host, @port) + end + + aggregator_compatibility_check + + unless @payload_job_ids + @payload_job_ids = [] + @my_io = local_handler + end + + @aggregator.register_response_channel(@my_io) + @aggregator end - # Wrap this so a duplicate session does not prevent access - begin - cmd_aggregator_disconnect - rescue ::Interrupt - raise $! - rescue ::Exception - end - - begin - print_status("Connecting to Aggregator instance at #{@host}:#{@port}...") - @aggregator = Metasploit::Aggregator::ServerProxy.new(@host, @port) - end - - aggregator_compatibility_check - - unless @payload_job_ids - @payload_job_ids = [] - @my_io = get_local_handler - end - - @aggregator.register_response_channel(@my_io) - @aggregator - end - - def aggregator_compatibility_check - unless @aggregator.nil? + def aggregator_compatibility_check + false if @aggregator.nil? unless @aggregator.available? print_error("Connection to aggregator @ #{@host}:#{@port} is unavailable.") cmd_aggregator_disconnect end end - end - def get_local_handler - server = TCPServer.new('127.0.0.1', 0) - port = server.addr[1] - server.close + def local_handler + # get a random ephemeral port + server = TCPServer.new('127.0.0.1', 0) + port = server.addr[1] + server.close - multi_handler = framework.exploits.create('multi/handler') + multi_handler = framework.exploits.create('multi/handler') - multi_handler.datastore['LHOST'] = "127.0.0.1" - # multi_handler.datastore['PAYLOAD'] = "multi/meterpreter/reverse_https" - multi_handler.datastore['PAYLOAD'] = "multi/meterpreter/reverse_http" - multi_handler.datastore['LPORT'] = "#{port}" + multi_handler.datastore['LHOST'] = "127.0.0.1" + # multi_handler.datastore['PAYLOAD'] = "multi/meterpreter/reverse_https" + multi_handler.datastore['PAYLOAD'] = "multi/meterpreter/reverse_http" + multi_handler.datastore['LPORT'] = "#{port}" - # %w(DebugOptions PrependMigrate PrependMigrateProc - # InitialAutoRunScript AutoRunScript CAMPAIGN_ID HandlerSSLCert - # StagerVerifySSLCert PayloadUUIDTracking PayloadUUIDName - # IgnoreUnknownPayloads SessionRetryTotal SessionRetryWait - # SessionExpirationTimeout SessionCommunicationTimeout).each do |opt| - # multi_handler.datastore[opt] = datastore[opt] if datastore[opt] - # end + # %w(DebugOptions PrependMigrate PrependMigrateProc + # InitialAutoRunScript AutoRunScript CAMPAIGN_ID HandlerSSLCert + # StagerVerifySSLCert PayloadUUIDTracking PayloadUUIDName + # IgnoreUnknownPayloads SessionRetryTotal SessionRetryWait + # SessionExpirationTimeout SessionCommunicationTimeout).each do |opt| + # multi_handler.datastore[opt] = datastore[opt] if datastore[opt] + # end - multi_handler.datastore['ExitOnSession'] = false - multi_handler.datastore['EXITFUNC'] = 'thread' + multi_handler.datastore['ExitOnSession'] = false + multi_handler.datastore['EXITFUNC'] = 'thread' - multi_handler.exploit_simple( - 'LocalInput' => nil, - 'LocalOutput' => nil, - 'Payload' => multi_handler.datastore['PAYLOAD'], - 'RunAsJob' => true - ) - @payload_job_ids << multi_handler.job_id - # requester = Metasploit::Aggregator::Http::SslRequester.new(multi_handler.datastore['LHOST'], multi_handler.datastore['LPORT']) - requester = Metasploit::Aggregator::Http::Requester.new(multi_handler.datastore['LHOST'], multi_handler.datastore['LPORT']) - requester - end - - # borrowed from Msf::Sessions::Meterpreter for now - def guess_target_platform(os) - case os - when /windows/i - Msf::Module::Platform::Windows.realname.downcase - when /darwin/i - Msf::Module::Platform::OSX.realname.downcase - when /mac os ?x/i - # this happens with java on OSX (for real!) - Msf::Module::Platform::OSX.realname.downcase - when /freebsd/i - Msf::Module::Platform::FreeBSD.realname.downcase - when /openbsd/i, /netbsd/i - Msf::Module::Platform::BSD.realname.downcase - else - Msf::Module::Platform::Linux.realname.downcase + multi_handler.exploit_simple( + 'LocalInput' => nil, + 'LocalOutput' => nil, + 'Payload' => multi_handler.datastore['PAYLOAD'], + 'RunAsJob' => true + ) + @payload_job_ids << multi_handler.job_id + # requester = Metasploit::Aggregator::Http::SslRequester.new(multi_handler.datastore['LHOST'], multi_handler.datastore['LPORT']) + requester = Metasploit::Aggregator::Http::Requester.new(multi_handler.datastore['LHOST'], multi_handler.datastore['LPORT']) + requester end + + # borrowed from Msf::Sessions::Meterpreter for now + def guess_target_platform(os) + case os + when /windows/i + Msf::Module::Platform::Windows.realname.downcase + when /darwin/i + Msf::Module::Platform::OSX.realname.downcase + when /mac os ?x/i + # this happens with java on OSX (for real!) + Msf::Module::Platform::OSX.realname.downcase + when /freebsd/i + Msf::Module::Platform::FreeBSD.realname.downcase + when /openbsd/i, /netbsd/i + Msf::Module::Platform::BSD.realname.downcase + else + Msf::Module::Platform::Linux.realname.downcase + end + end + + private :guess_target_platform + private :aggregator_login + private :aggregator_compatibility_check + private :aggregator_verify + private :local_handler end - private :guess_target_platform - private :aggregator_login - private :aggregator_compatibility_check - private :aggregator_verify - private :get_local_handler - end + # + # Plugin initialization + # - # - # Plugin initialization - # + def initialize(framework, opts) + super - def initialize(framework, opts) - super + add_console_dispatcher(AggregatorCommandDispatcher) + print_status("Aggregator interaction has been enabled") + end - add_console_dispatcher(AggregatorCommandDispatcher) - print_status("Aggregator interaction has been enabled") - end + def cleanup + remove_console_dispatcher('Aggregator') + end - def cleanup - remove_console_dispatcher('Aggregator') - end + def name + "aggregator" + end - def name - "aggregator" - end - - def desc - "Interacts with the external Session Aggregator" + def desc + "Interacts with the external Session Aggregator" + end end end -end diff --git a/plugins/msfd.rb b/plugins/msfd.rb index 7d964d10ff..653ec6f672 100644 --- a/plugins/msfd.rb +++ b/plugins/msfd.rb @@ -1,4 +1,3 @@ -#!/usr/bin/env ruby # # $Id$ # diff --git a/plugins/msgrpc.rb b/plugins/msgrpc.rb index 30c1bee857..cc49d292b7 100644 --- a/plugins/msgrpc.rb +++ b/plugins/msgrpc.rb @@ -1,4 +1,3 @@ -#!/usr/bin/env ruby # # This plugin provides an msf daemon interface that spawns a listener on a # defined port (default 55552) and gives each connecting client its own diff --git a/plugins/nexpose.rb b/plugins/nexpose.rb index 00c1173bc1..570c01a602 100644 --- a/plugins/nexpose.rb +++ b/plugins/nexpose.rb @@ -1,4 +1,3 @@ -#!/usr/bin/env ruby # # $Id$ # diff --git a/plugins/openvas.rb b/plugins/openvas.rb index 4b9c02cd08..2a3b294a0d 100644 --- a/plugins/openvas.rb +++ b/plugins/openvas.rb @@ -1,4 +1,3 @@ -#!/usr/bin/env ruby # # This plugin provides integration with OpenVAS. Written by kost and # averagesecurityguy.