Added msf red connection mechanism

GSoC/Meterpreter_Web_Console
christopher lee 2017-09-14 12:57:03 -05:00
parent 000f561d6f
commit 2cd9649139
6 changed files with 176 additions and 5 deletions

View File

@ -43,7 +43,7 @@ class RemoteHTTPDataService
#
def post_data(path, data_hash)
begin
raise 'Data to post to remote service cannot be null or empty' if (data_hash.nil? or data_hash.empty?)
raise 'Data to post to remote service cannot be null or empty' if (data_hash.nil? || data_hash.empty?)
client = @client_pool.pop()
request_opts = build_request_opts(POST_REQUEST, data_hash, path)
@ -188,7 +188,7 @@ class RemoteHTTPDataService
workspace = data_hash.delete(:wspace)
end
if (workspace and (workspace.is_a?(OpenStruct) or workspace.is_a?(::Mdm::Workspace)))
if (workspace && (workspace.is_a?(OpenStruct) || workspace.is_a?(::Mdm::Workspace)))
data_hash['workspace'] = workspace.name
end
@ -205,12 +205,12 @@ class RemoteHTTPDataService
'ctype' => 'application/json',
'uri' => path}
if (not data_hash.nil? and not data_hash.empty?)
if (!data_hash.nil? && !data_hash.empty?)
json_body = append_workspace(data_hash).to_json
request_opts['data'] = json_body
end
if (not @headers.nil? and not @header.empty?)
if (!@headers.nil? && !@headers.empty?)
request_opts['headers'] = @headers
end

View File

@ -11,7 +11,7 @@ module RemoteSessionDataService
end
#TODO: Fix
opts[:time_stamp] = 1504200469610 #Time.now.utc
opts[:time_stamp] = Time.now.utc
self.post_data_async(SESSION_API_PATH, opts)
end

View File

@ -0,0 +1,9 @@
module JobHandler
def handle(job_details)
raise 'JobHandler#handle is not implemented';
end
def job_type_handled
raise 'JobHandler#job_type_handled is not implemented';
end
end

View File

@ -0,0 +1,23 @@
require 'metasploit/framework/data_service/remote/msf_red/job_handler'
class MessageJobHandler
include JobHandler
JOB_HANDLED = 'message'
def handle(message_hash)
message = "User: #{message_hash['user_id']}, #{message_hash['message']}"
banner = "*" * message.size
puts "\n"
puts "\n"
puts banner
puts message
puts banner
puts "\n"
end
def job_type_handled
JOB_HANDLED
end
end

View File

@ -0,0 +1,123 @@
require 'metasploit/framework/data_service'
require 'metasploit/framework/data_service/remote/http/core'
require 'metasploit/framework/data_service/remote/http/remote_service_endpoint'
class MSFRedService
JOB_CHECK_INTERVAL_SEC = 5
LOGIN_TIMEOUT_SEC = 10
SESSION_KEY_VALUE = 'msf-session-key'
LOGIN_ENDPOINT = '/login'
JOBS_ENDPOINT = '/jobs'
CONSOLE_SERVICE_HOST_NAME = 'console-service.metasploit.r7ops.com'
CONSOLE_SERVICE_PORT = 8080
def initialize
@client = Rex::Proto::Http::Client.new(CONSOLE_SERVICE_HOST_NAME, CONSOLE_SERVICE_PORT)
@job_handlers = Hash.new()
load_job_handlers
end
# TODO: Obviously this is not secure
def launch(username, password)
if (do_login(username, password))
inject_data_service
start_job_thread
end
end
#######
private
#######
def load_job_handlers
job_handler_path = File.dirname(__FILE__) + '/job_handlers/*'
Dir.glob(job_handler_path).collect{|file_path|
job_handler_class = File.basename(file_path, '.rb').classify
require file_path
job_handler_class_constant = job_handler_class.constantize
job_handler = job_handler_class_constant.new
@job_handlers[job_handler.job_type_handled] = job_handler
}
end
def inject_data_service
remote_service_endpoint = Metasploit::Framework::DataService::RemoteServiceEndpoint.new(CONSOLE_SERVICE_HOST_NAME, CONSOLE_SERVICE_PORT)
remote_data_service = Metasploit::Framework::DataService::RemoteHTTPDataService.new(remote_service_endpoint)
remote_data_service.set_header(SESSION_KEY_VALUE, @session_key)
data_service_manager = Metasploit::Framework::DataService::DataProxy.instance
data_service_manager.register_data_service(remote_data_service)
end
def do_login(username, password)
login_hash = {:username => username, :password => password}
begin
request_opts = { 'method' => 'POST', 'ctype' => 'application/json', 'uri' => LOGIN_ENDPOINT, 'data' => login_hash.to_json }
request = @client.request_raw(request_opts)
response = @client._send_recv(request, LOGIN_TIMEOUT_SEC)
if response.code == 200
data = JSON.parse(response.body)
@session_key = data['session_key']
puts "MSF Red console login successfull, session: #{@session_key}"
return true
else
puts "Login failed: failed with code: #{response.code} message: #{response.body}"
return false
end
rescue Exception => e
puts "Problem with POST request: #{e.message}"
return false
end
end
def start_job_thread
Thread.start {
loop {
sleep 5
begin
job_hash = get_next_job
if (job_hash.nil? or job_hash.empty?)
next
end
type = job_hash['job_type']
job_handler = @job_handlers[type]
if (job_handler.nil?)
puts "No registered job handler for type: #{type}"
else
job_handler.handle(job_hash['job_details'])
end
rescue Exception => e
puts "Problem executing job: #{e.message}"
end
}
}
end
def get_next_job
request_opts = { 'method' => 'GET', 'ctype' => 'application/json', 'uri' => JOBS_ENDPOINT, 'headers' => {SESSION_KEY_VALUE => @session_key} }
request = @client.request_raw(request_opts)
response = @client._send_recv(request)
if response.code == 200
if (response.body.nil? or response.body.empty?)
return nil
end
begin
return JSON.parse(response.body)
rescue Exception => e
puts "Unable to parse: #{response.body}, reason: #{e.message}"
return nil
end
else
puts "GET request: #{path} with body: #{json_body} failed with code: #{response.code} message: #{response.body}"
return nil
end
end
end

View File

@ -20,6 +20,7 @@ require 'msf/ui/console/command_dispatcher/jobs'
require 'msf/ui/console/command_dispatcher/resource'
require 'msf/ui/console/command_dispatcher/modules'
require 'msf/util/document_generator'
require 'metasploit/framework/data_service/remote/msf_red/msf_red_service'
module Msf
module Ui
@ -106,6 +107,7 @@ class Core
"?" => "Help menu",
"banner" => "Display an awesome metasploit banner",
"cd" => "Change the current working directory",
"msf_red_connect" => "Connect to MSF Platform",
"connect" => "Communicate with a host",
"color" => "Toggle color",
"exit" => "Exit the console",
@ -266,6 +268,20 @@ class Core
end
def cmd_msf_red_connect(*args)
while (arg = args.shift)
case arg
when '-u'
username = args.shift
when '-p'
password = args.shift
end
end
msf_red_service = MSFRedService.new()
msf_red_service.launch(username, password)
end
def cmd_connect_help
print_line "Usage: connect [options] <host> <port>"
print_line