Added new metasploit extension. Needs more work but the majority of the extension is there

git-svn-id: https://beef.googlecode.com/svn/trunk@1259 b87d56ec-f9c0-11de-8c8a-61c5e9addfc9
This commit is contained in:
passbe
2011-09-03 00:44:26 +00:00
parent 97b244d61a
commit a2acadb4eb
6 changed files with 16594 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
#
# Copyright 2011 Wade Alcorn wade@bindshell.net
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
module BeEF
module Extension
module Metasploit
module API
module MetasploitHooks
BeEF::API::Registra.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Modules, 'post_soft_load')
# Load modules from metasploit just after all other module config is loaded
def self.post_soft_load
msf = BeEF::Extension::Metasploit::RpcClient.instance
if msf.login
msf_module_config = {}
path = BeEF::Core::Configuration.instance.get('beef.extension.metasploit.path')
if not BeEF::Extension::Console.resetdb? and File.exists?("#{path}msf-exploits.cache")
print_debug "Attempting to use Metasploit exploits cache file"
raw = File.read("#{path}msf-exploits.cache")
begin
msf_module_config = YAML.load(raw)
rescue => e
puts e
end
count = 1
msf_module_config.each{|k,v|
BeEF::API::Registra.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_options', [k])
BeEF::API::Registra.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'override_execute', [k, 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|
m_details = msf.call('module.info', 'exploits', 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)
#}
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'
}
BeEF::API::Registra.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_options', [key])
BeEF::API::Registra.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'override_execute', [key, nil])
print_over "Loaded #{count} Metasploit exploits."
count += 1
end
}
print "\r\n"
File.open("#{path}msf-exploits.cache", "w") do |f|
f.write(msf_module_config.to_yaml)
print_debug "Wrote Metasploit exploits to cache file"
end
end
BeEF::Core::Configuration.instance.set('beef.module', msf_module_config)
end
end
# Get module options + payloads when the beef framework requests this information
def self.get_options(mod)
msf_key = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.msf_key")
msf = BeEF::Extension::Metasploit::RpcClient.instance
if msf_key != nil and msf.login
msf_module_options = msf.call('module.options', 'exploit', msf_key)
if msf_module_options
options = BeEF::Extension::Metasploit.translate_options(msf_module_options)
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
# Execute function for all metasploit exploits
def self.override_execute(mod, opts)
msf = BeEF::Extension::Metasploit::RpcClient.instance
msf_key = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.msf_key")
if msf_key != nil and msf.login
# Are the options correctly formatted for msf?
# This call has not been tested
msf.call('module.execute', 'exploit', msf_key, opts)
end
# 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
return true
end
end
end
end
end
end

View File

@@ -0,0 +1,33 @@
#
# Copyright 2011 Wade Alcorn wade@bindshell.net
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Enable MSF by changing extension:metasploit:enable to true
# Then set msf_callback_host to be the public IP of your MSF server
#
# Ensure you load the xmlrpc interface in Metasploit
# msf > load xmlrpc ServerHost=10.211.55.2 Pass=abc123 ServerType=Web
# Please note that the ServerHost parameter must have the same value of host and callback_host variables here below.
beef:
extension:
metasploit:
name: 'Metasploit'
enable: true
host: "127.0.0.1"
url-path: "/RPC2"
port: 55553
user: "msf"
pass: "abc123"
callback_host: "192.168.84.1"
autopwn_url: "autopwn"

View File

@@ -0,0 +1,85 @@
#
# Copyright 2011 Wade Alcorn wade@bindshell.net
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
module BeEF
module Extension
module Metasploit
extend BeEF::API::Extension
# Translates msf exploit options to beef options array
def self.translate_options(msf_options)
options = []
msf_options.each{|k,v|
case v['type']
when "string", "address", "port", "integer"
v['type'] = 'text'
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['valueField'] = 'enum',
v['displayField'] = 'enum',
v['autoWidth'] = true,
v['mode'] = 'local'
end
v['name'] = k
v['label'] = k
options << v
}
return 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'])
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
}
end
end
return nil
end
# Translates metasploit enums to ExtJS combobox store_data
def self.translate_enums(enums)
values = []
enums.each{|e|
values << [e]
}
return values
end
end
end
end
require 'extensions/metasploit/rpcclient'
require 'extensions/metasploit/api'

View File

@@ -0,0 +1,20 @@
#
# Copyright 2011 Wade Alcorn wade@bindshell.net
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This is a dummy module to fool BeEF's loading system
class Msf_module < BeEF::Core::Command
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,209 @@
#
# Copyright 2011 Wade Alcorn wade@bindshell.net
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
module BeEF
module Extension
module Metasploit
class RpcClient < ::XMLRPC::Client
include Singleton
def initialize
@config = BeEF::Core::Configuration.instance.get('beef.extension.metasploit')
if not (@config.key?('host') or @config.key?('url-path') 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
@token = nil
@lastauth = nil
super(@config['host'],@config['url-path'],@config['port'])
end
def get_lock()
sleep 0.2 while @lock
@lock = true
end
def release_lock()
@lock = false
end
# login into metasploit
def login
get_lock()
res = self.call("auth.login", @config['user'] , @config['pass'])
if(not (res and res['result'] == "success"))
release_lock()
print_error 'Could not authenticate to Metasploit xmlrpc.'
return false
end
print_info 'Successful connection with Metasploit.' if not @lastauth
@token = res['token']
@lastauth = Time.now
release_lock()
true
end
# sends commands to the metasploit xml rpc server
def call(meth, *args)
if(meth != "auth.login")
self.login() if not @token
args.unshift(@token)
end
begin
super(meth, *args)
rescue Errno::ECONNREFUSED
print_error "Connection to Metasploit backend failed."
return false
rescue XMLRPC::FaultException => e
if e.faultCode == 401 and meth == "auth.login"
print_error "Your username and password combination was rejected by the Metasploit backend server"
elsif e.faultCode == 401
res = self.login()
else
print_error "An unknown exception has occured while talking to the Metasploit backend."
print_error "The Exception text is (#{e.faultCode} : #{e.faultString}."
print_error "Please check the Metasploit logs for more details."
end
return false
rescue Exception => e
print_error "An unknown exception (#{e}) has occured while talking to the Metasploit backend."
print_error "Please check the Metasploit logs for more details."
return false
end
end
def browser_exploits()
get_lock()
res = self.call('module.exploits')
return [] if not res or not res['modules']
mods = res['modules']
ret = []
mods.each do |m|
ret << m if(m.include? '/browser/')
end
release_lock()
ret.sort
end
def get_exploit_info(name)
return if not @enabled
get_lock()
res = self.call('module.info','exploit',name)
release_lock()
res || {}
end
def get_payloads(name)
return if not @enabled
get_lock()
res = self.call('module.compatible_payloads',name)
release_lock()
res || {}
end
def get_options(name)
return if not @enabled
get_lock()
res = self.call('module.options','exploit',name)
release_lock()
res || {}
end
def payloads()
return if not @enabled
get_lock()
res = self.call('module.payloads')
release_lock()
return {} if not res or not res['modules']
res['modules']
end
def payload_options(name)
return if not @enabled
get_lock()
res = self.call('module.options','payload',name)
release_lock
return {} if not res
res
end
def launch_exploit(exploit,opts)
return if not @enabled
get_lock()
begin
res = self.call('module.execute','exploit',exploit,opts)
rescue Exception => e
print_error "Exploit failed for #{exploit} \n"
release_lock()
return false
end
release_lock()
uri = ""
if opts['SSL']
uri += "https://"
else
uri += "http://"
end
uri += @config.get('beef.extension.metasploit.callback_host') + ":" + opts['SRVPORT'] + "/" + opts['URIPATH']
res['uri'] = uri
res
end
def launch_autopwn
return if not @enabled
opts = {
'LHOST' => @config.get('beef.extension.metasploit.callback_host') ,
'URIPATH' => @apurl
}
get_lock()
begin
res = self.call('module.execute','auxiliary','server/browser_autopwn',opts)
rescue Exception => e
print_error "Failed to launch autopwn\n"
release_lock()
return false
end
release_lock()
end
end
end
end
end