Update style

This commit is contained in:
Brendan Coles
2019-02-16 10:29:52 +00:00
parent 214e5b977f
commit 5a7fe2be0e
2 changed files with 290 additions and 276 deletions

View File

@@ -6,85 +6,84 @@
module BeEF
module Extension
module Metasploit
extend BeEF::API::Extension
@short_name = 'msf'
@full_name = 'Metasploit'
@description = 'Metasploit integration'
@short_name = 'msf'
@full_name = 'Metasploit'
@description = 'Metasploit integration'
# Translates msf exploit options to beef options array
def self.translate_options(msf_options)
callback_host = BeEF::Core::Configuration.instance.get('beef.extension.metasploit.callback_host')
options = []
msf_options.each{|k,v|
next if v['advanced'] == true || v['evasion'] == true
v['allowBlank'] = 'true' if v['required'] == false
case v['type']
when "string", "address", "port", "integer"
v['type'] = 'text'
v['value'] = rand(3**20).to_s(16) if k == 'URIPATH'
v['value'] = v['default'] if k != "URIPATH"
v['value'] = BeEF::Core::Configuration.instance.get('beef.extension.metasploit.callback_host') if k == "LHOST"
msf_options.each do |k, v|
next if v['advanced'] == true
next if v['evasion'] == true
v['allowBlank'] = 'true' if v['required'] == false
when "bool"
v['type'] = 'checkbox'
when "enum"
v['type'] = 'combobox'
v['store_type'] = 'arraystore',
v['store_fields'] = ['enum'],
v['store_data'] = self.translate_enums(v['enums']),
v['value'] = v['default']
v['valueField'] = 'enum',
v['displayField'] = 'enum',
v['autoWidth'] = true,
v['mode'] = 'local'
case v['type']
when 'string', 'address', 'port', 'integer'
v['type'] = 'text'
if k == 'URIPATH'
v['value'] = rand(3**20).to_s(16)
elsif k == 'LHOST'
v['value'] = callback_host
else
v['value'] = v['default']
end
v['name'] = k
v['label'] = k
options << v
}
return options
when 'bool'
v['type'] = 'checkbox'
when 'enum'
v['type'] = 'combobox'
v['store_type'] = 'arraystore',
v['store_fields'] = ['enum'],
v['store_data'] = translate_enums(v['enums']),
v['value'] = v['default']
v['valueField'] = 'enum',
v['displayField'] = 'enum',
v['autoWidth'] = true,
v['mode'] = 'local'
end
v['name'] = k
v['label'] = k
options << v
end
options
end
# Translates msf payloads to a beef compatible drop down
def self.translate_payload(payloads)
if payloads.has_key?('payloads')
values = self.translate_enums(payloads['payloads'])
return unless payloads.key?('payloads')
defaultPayload = values[0]
defaultPayload = 'generic/shell_bind_tcp' if values.include? 'generic/shell_bind_tcp'
values = translate_enums(payloads['payloads'])
if values.length > 0
return {
'name' => 'PAYLOAD',
'type' => 'combobox',
'ui_label' => 'Payload',
'store_type' => 'arraystore',
'store_fields' => ['payload'],
'store_data' => values,
'valueField' => 'payload',
'displayField' => 'payload',
'mode' => 'local',
'autoWidth' => true,
'defaultPayload' => defaultPayload,
'reloadOnChange' => true
}
end
end
return nil
default_payload = values.include?('generic/shell_bind_tcp') ? 'generic/shell_bind_tcp' : values.first
return unless values.length.positive?
{
'name' => 'PAYLOAD',
'type' => 'combobox',
'ui_label' => 'Payload',
'store_type' => 'arraystore',
'store_fields' => ['payload'],
'store_data' => values,
'valueField' => 'payload',
'displayField' => 'payload',
'mode' => 'local',
'autoWidth' => true,
'defaultPayload' => default_payload,
'reloadOnChange' => true
}
end
# Translates metasploit enums to ExtJS combobox store_data
def self.translate_enums(enums)
values = []
enums.each{|e|
values << [e]
}
return values
enums.map{|e| [e]}
end
end
end
end

View File

@@ -6,243 +6,258 @@
module BeEF
module Extension
module Metasploit
class RpcClient < ::Msf::RPC::Client
require 'net/http'
include Singleton
class RpcClient < ::Msf::RPC::Client
include Singleton
def initialize
@config = BeEF::Core::Configuration.instance.get('beef.extension.metasploit')
def initialize
@config = BeEF::Core::Configuration.instance.get('beef.extension.metasploit')
if not (@config.key?('host') or @config.key?('uri') or @config.key?('port') or @config.key?('user') or @config.key?('pass'))
print_error 'There is not enough information to initalize Metasploit connectivity at this time'
print_error 'Please check your options in config.yaml to verify that all information is present'
BeEF::Core::Configuration.instance.set('beef.extension.metasploit.enabled', false)
BeEF::Core::Configuration.instance.set('beef.extension.metasploit.loaded', false)
return nil
end
@lock = false
@lastauth = nil
@unit_test = false
opts = {
:host => @config['host'] || '127.0.0.1',
:port => @config['port'] || 55552,
:uri => @config['uri'] || '/api/',
:ssl => @config['ssl'] ,
:ssl_version => @config['ssl_version'] ,
:context => {}
}
if opts[:ssl_version] =~ /SSLv3/i
print_warning("Warning: Connections to Metasploit RPC over SSLv3 are insecure. Use TLSv1 instead.")
end
#auto start msfrpcd
if (@config['auto_msfrpcd'])
launch_msf = ''
@config['msf_path'].each do |path|
if File.exist?(path['path'] + 'msfrpcd')
launch_msf = path['path'] + 'msfrpcd'
print_info '[Metasploit] Found msfrpcd: ' + launch_msf
end
end
unless @config.key?('host') || @config.key?('uri') || @config.key?('port') ||
@config.key?('user') || @config.key?('pass')
print_error 'There is not enough information to initalize Metasploit connectivity at this time'
print_error 'Please check your options in config.yaml to verify that all information is present'
BeEF::Core::Configuration.instance.set('beef.extension.metasploit.enabled', false)
BeEF::Core::Configuration.instance.set('beef.extension.metasploit.loaded', false)
return
end
if (launch_msf.length > 0)
msf_url = 'https://'
argssl = ''
unless opts[:ssl]
argssl = '-S'
msf_url = 'http://'
end
@lock = false
@lastauth = nil
@unit_test = false
@msf_path = nil
msf_url += opts[:host] + ':' + opts[:port].to_s() + opts[:uri]
child = IO.popen([launch_msf, "-f", argssl, "-P" , @config['pass'], "-U" , @config['user'], "-u" , opts[:uri], "-a" , opts[:host], "-p" , opts[:port].to_s()], 'r+')
print_info '[Metasploit] Attempt to start msfrpcd, this may take a while. PID: ' + child.pid.to_s
opts = {
:host => @config['host'] || '127.0.0.1',
:port => @config['port'] || 55552,
:uri => @config['uri'] || '/api/',
:ssl => @config['ssl'],
:ssl_version => @config['ssl_version'],
:context => {}
}
# Give daemon time to launch
# poll and giveup after timeout
retries = @config['auto_msfrpcd_timeout']
uri = URI(msf_url)
http = Net::HTTP.new(uri.host, uri.port)
if opts[:ssl_version].match?(/SSLv3/i)
print_warning '[Metasploit] Warning: Connections to Metasploit RPC over SSLv3 are insecure. Use TLSv1 instead.'
end
if opts[:ssl]
http.use_ssl = true
http.ssl_version = opts[:ssl_version]
end
if not @config['ssl_verify']
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
headers = { 'Content-Type' => "binary/message-pack" }
path = uri.path.empty? ? "/" : uri.path
begin
sleep 1
code = http.head(path, headers).code.to_i
rescue => e
retry if (retries -= 1) > 0
end
else
print_error '[Metasploit] Please add a custom path for msfrpcd to the config-file.'
end
end
super(opts)
end
def get_lock()
sleep 0.2 while @lock
@lock = true
if @config['auto_msfrpcd']
@config['msf_path'].each do |path|
if File.exist? "#{path['path']}/msfrpcd"
@msf_path = "#{path['path']}/msfrpcd"
end
end
def release_lock()
@lock = false
if @msf_path.nil?
print_error '[Metasploit] Please add a custom path for msfrpcd to the config file.'
return
end
def call(meth, *args)
ret = nil
begin
ret = super(meth,*args)
rescue => e
print_error "Metasploit: #{e}"
return nil
end
ret
end
print_info "[Metasploit] Found msfrpcd: #{@msf_path}"
return unless launch_msfrpcd(opts)
end
super(opts)
end
#
# @note auto start msfrpcd
#
def launch_msfrpcd(opts)
if opts[:ssl]
argssl = '-S'
proto = 'http'
else
argssl = ''
proto = 'https'
end
msf_url = "#{proto}://#{opts[:host]}:#{opts[:port]}#{opts[:uri]}"
child = IO.popen([
@msf_path,
'-f',
argssl,
'-P' , @config['pass'],
'-U' , @config['user'],
'-u' , opts[:uri],
'-a' , opts[:host],
'-p' , opts[:port].to_s
], 'r+')
print_info "[Metasploit] Attempt to start msfrpcd, this may take a while. PID: #{child.pid}"
# Give daemon time to launch
# poll and giveup after timeout
retries = @config['auto_msfrpcd_timeout']
uri = URI(msf_url)
http = Net::HTTP.new(uri.host, uri.port)
if opts[:ssl]
http.use_ssl = true
http.ssl_version = opts[:ssl_version]
end
unless @config['ssl_verify']
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
headers = { 'Content-Type' => 'binary/message-pack' }
path = uri.path.empty? ? '/' : uri.path
begin
sleep 1
code = http.head(path, headers).code.to_i
print_debug "[Metasploit] Success - HTTP response: #{code}"
rescue => e
retry if (retries -= 1).positive?
end
true
end
def get_lock
sleep 0.2 while @lock
@lock = true
end
def unit_test_init
@unit_test = true
end
# login to metasploit
def login
get_lock()
def release_lock
@lock = false
end
res = super(@config['user'] , @config['pass'])
if not res
release_lock()
print_error 'Could not authenticate to Metasploit MSGRPC.'
return false
end
if (!@lastauth)
print_info 'Successful connection with Metasploit.' if (!@unit_test)
print_debug "Metasploit: Received temporary token: #{self.token}"
# Generate permanent token
new_token = token_generate
if new_token.nil?
print_warning "Metasploit: Could not retrieve permanent Metasploit token. Connection to Metasploit will time out in 5 minutes."
else
self.token = new_token
print_debug "Metasploit: Received permanent token: #{self.token}"
end
end
@lastauth = Time.now
def call(meth, *args)
super(meth, *args)
rescue => e
print_error "[Metasploit] RPC call to '#{meth}' failed: #{e}"
puts e.backtrace
return
end
def unit_test_init
@unit_test = true
end
# login to metasploit
def login
get_lock
res = super(@config['user'], @config['pass'])
unless res
print_error '[Metasploit] Could not authenticate to Metasploit RPC sevrice.'
return false
end
unless @lastauth
print_info '[Metasploit] Successful connection with Metasploit.' unless @unit_test
print_debug "[Metasploit] Received temporary token: #{token}"
# Generate permanent token
new_token = token_generate
if new_token.nil?
print_warning "[Metasploit] Could not retrieve permanent Metasploit token. Connection to Metasploit will time out in 5 minutes."
else
self.token = new_token
print_debug "[Metasploit] Received permanent token: #{token}"
end
end
@lastauth = Time.now
release_lock()
true
end
true
ensure
release_lock
end
# generate a permanent auth token
def token_generate
res = self.call('auth.token_generate')
return if not res or not res['token']
res['token']
end
# generate a permanent auth token
def token_generate
res = call('auth.token_generate')
def browser_exploits()
get_lock()
res = self.call('module.exploits')
return [] if not res or not res['modules']
return unless res || res['token']
mods = res['modules']
ret = []
mods.each do |m|
ret << m if(m.include? '/browser/')
end
release_lock()
ret.sort
end
res['token']
end
def get_exploit_info(name)
get_lock()
res = self.call('module.info','exploit',name)
release_lock()
res || {}
end
def get_payloads(name)
get_lock()
res = self.call('module.compatible_payloads',name)
release_lock()
res || {}
end
def get_options(name)
get_lock()
res = self.call('module.options','exploit',name)
release_lock()
res || {}
end
def payloads()
get_lock()
res = self.call('module.payloads')
release_lock()
return {} if not res or not res['modules']
res['modules']
end
def payload_options(name)
get_lock()
res = self.call('module.options','payload',name)
release_lock
return {} if not res
res
end
def launch_exploit(exploit,opts)
get_lock()
begin
res = self.call('module.execute','exploit',exploit,opts)
rescue => e
print_error "Exploit failed for #{exploit} \n"
release_lock()
return false
end
release_lock()
def browser_exploits
get_lock
res = call('module.exploits')
uri = ""
if opts['SSL']
uri += "https://"
else
uri += "http://"
end
return [] unless res || res['modules']
uri += @config['callback_host'] + ":#{opts['SRVPORT']}/" + opts['URIPATH']
res['modules'].select{|m| m.include?('/browser/') }.sort
ensure
release_lock
end
res['uri'] = uri
res
end
def get_exploit_info(name)
get_lock
res = call('module.info', 'exploit', name)
res || {}
ensure
release_lock
end
def launch_autopwn
opts = {
'LHOST' => @config['callback_host'] ,
'URIPATH' => @apurl
}
get_lock()
begin
res = self.call('module.execute','auxiliary','server/browser_autopwn',opts)
rescue => e
print_error "Failed to launch autopwn\n"
release_lock()
return false
end
release_lock()
return res
def get_payloads(name)
get_lock
res = call('module.compatible_payloads', name)
res || {}
ensure
release_lock
end
end
end
def get_options(name)
get_lock
res = call('module.options', 'exploit', name)
res || {}
ensure
release_lock
end
def payloads
get_lock
res = call('module.payloads')
return {} unless res || res['modules']
res['modules']
ensure
release_lock
end
def payload_options(name)
get_lock
res = call('module.options', 'payload', name)
return {} unless res
res
rescue => e
return {}
ensure
release_lock
end
def launch_exploit(exploit, opts)
get_lock
res = call('module.execute', 'exploit', exploit, opts)
proto = opts['SSL'] ? 'https' : 'http'
res['uri'] = "#{proto}://#{@config['callback_host']}:#{opts['SRVPORT']}/#{opts['URIPATH']}"
res
rescue => e
print_error "Exploit failed for #{exploit} \n"
return false
ensure
release_lock
end
def launch_autopwn
opts = {
'LHOST' => @config['callback_host'],
'URIPATH' => @apurl
}
get_lock
call('module.execute', 'auxiliary', 'server/browser_autopwn', opts)
rescue => e
print_error "Failed to launch autopwn"
return false
ensure
release_lock
end
end
end
end
end