create aggregator connection as plugin

bug/bundler_fix
Jeffrey Martin 2016-11-11 16:24:27 -06:00
parent 23c2787d57
commit 5bf54fef0f
No known key found for this signature in database
GPG Key ID: 0CD9BBC2AF15F171
2 changed files with 378 additions and 0 deletions

View File

@ -21,6 +21,7 @@ group :development do
# module documentation
gem 'octokit', '~> 4.0'
# rails-upgrade staging gems
gem 'metasploit-aggregator', git: 'git@github.com:rapid7/metasploit-aggregator', branch: "master"
end
group :development, :test do

377
plugins/aggregator.rb Normal file
View File

@ -0,0 +1,377 @@
#!/usr/bin/env ruby
#
# $Id$
#
# This plugin provides management and interaction with an external session aggregator.
#
# $Revision$
#
require "msf/aggregator"
module Msf
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
@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_cable_list' => "List all remote listeners for sessions",
'aggregator_cable_add' => "Setup remote listener for sessions",
'aggregator_cable_remove' => "Stop remote listener for sessions",
'aggregator_default_forward' => "forward a unlisted/unhandled sessions to a specified listener",
'aggregator_session_forward' => "forward a session to a specified listener",
'aggregator_session_list' => "List all remote sessions currently available from the Aggregator instance",
'aggregator_session_park' => "Park an existing session on the Aggregator instance",
'aggregator_sysinfo' => "Display detailed system information about the Aggregator instance",
}
end
def aggregator_verify_db
if ! (framework.db and framework.db.usable and framework.db.active)
print_error("No database has been configured, please use db_create/db_connect first")
return false
end
true
end
def aggregator_verify
# return false if not aggregator_verify_db
if ! @aggregator
print_error("No active Aggregator instance has been configured, please use 'aggregator_connect'")
return false
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 uri host:port",
" -OR- ",
"aggregator_session_forward uri host port")
end
def usage_default_forward
usage("aggregator_session_forward host:port",
" -OR- ",
"aggregator_session_forward host port")
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 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
end
end
def cmd_aggregator_connect(*args)
# return if not aggregator_verify_db
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 or args[0].empty? or 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
def cmd_aggregator_session_list(*args)
return if not aggregator_verify
sessions_list = @aggregator.sessions
unless sessions_list.nil?
print_status("Sessions found:")
sessions_list.each do |session|
print_status(" #{session}")
end
end
end
def cmd_aggregator_addresses(*args)
return if not aggregator_verify
address_list = @aggregator.available_addresses
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 host.nil?
port = args[1]
else
certificate = args[1]
end
when 3
host, port, certificate = args
else
usage_cable_add
return
end
if host.nil?
usage_cable_add
end
if certificate && File.exists?(certificate)
certificate = File.new(certificate).read
end
@aggregator.add_cable(Msf::Aggregator::Cable::HTTPS, host, port, certificate)
end
def cmd_aggregator_cable_list
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)
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
usage('aggregator_session_park session_id')
return
end
end
def cmd_aggregator_sysinfo(*args)
return if not aggregator_verify
res = { "wip" => "not implemented"}
print_status("System Information")
res.each_pair do |k,v|
print_status(" #{k}: #{v}")
end
end
def cmd_aggregator_default_forward(*args)
return if not aggregator_verify
host, port = nil
case args.length
when 1
host, port = args[0].split(':', 2)
when 2
host, port = args
end
if port.nil?
usage_default_forward
return
end
@aggregator.register_default(host, port, nil)
end
def cmd_aggregator_session_forward(*args)
return if not aggregator_verify
session_uri, host, port = nil
case args.length
when 2
session_uri, handler = args
host, port = handler.split(':', 2)
when 3
session_uri, host, port = args
else
usage_session_forward
return
end
# TODO: call @aggregator.session and make sure session_uri is listed
# TODO: ensure listener at host:port is open local if not start multi/handler universal
@aggregator.obtain_session(session_uri, host, port)
end
def cmd_aggregator_disconnect(*args)
@aggregator.stop if @aggregator
@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
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
raise $!
rescue ::Exception
end
begin
print_status("Connecting to Aggregator instance at #{@host}:#{@port}...")
@aggregator = Msf::Aggregator::ServerProxy.new(@host, @port)
end
aggregator_compatibility_check
@aggregator
end
def aggregator_compatibility_check
unless @aggregator.nil?
unless @aggregator.available?
print_error("Connection to aggregator @ #{@host}:#{@port} is unavailable.")
cmd_aggregator_disconnect
end
end
end
private :aggregator_login
private :aggregator_compatibility_check
private :aggregator_verify
private :aggregator_verify_db
end
#
# Plugin initialization
#
def initialize(framework, opts)
super
add_console_dispatcher(AggregatorCommandDispatcher)
print_status("Aggregator interaction has been enabled")
end
def cleanup
remove_console_dispatcher('Aggregator')
end
def name
"aggregator"
end
def desc
"Interacts with the external Session Aggregator"
end
end
end