Merge pull request #1 from wchen-r7/pr5788

Properly support detecting target arch and OS
bug/bundler_fix
Mo Sadek 2015-07-31 11:18:06 -05:00
commit 69ee5e3313
2 changed files with 170 additions and 59 deletions

View File

@ -49,6 +49,74 @@ module Msf::Post::Common
pid_list.include?(pid)
end
# Returns the target architecture.
# You should use this instead of session.platform, because of the following reasons:
# 1. session.platform doesn't always give you an arch. For example: a shell session.
# 2. session.platform doesn't mean the target platform/arch, it means whatever the session is.
# For example: you can use a python meterpreter on a Windows platform, and you will
# get 'python/python' as your arch/platform, and not 'x86/win32'.
#
# @returns [String] The archtecture recognizable by framework's ARCH_TYPES.
def get_target_arch
arch = nil
case session.type
when 'meterpreter'
arch = get_recognizable_arch(client.sys.config.sysinfo['Architecture'])
when 'shell'
if session.platform =~ /win/
arch = get_recognizable_arch(get_env('PROCESSOR_ARCHITECTURE').strip)
else
arch = get_recognizable_arch(get_env('MACHTYPE').strip)
end
end
arch
end
# Returns the target OS.
# You should use this instead of session.platform, because of the following reasons:
# 1. session.platform doesn't always provide a consistent OS name. For example: for a Windows
# target, session.platform might return 'win32', which isn't recognized by Msf::Module::Platform.
# 2. session.platform doesn't mean the target platform/arch, it means whatever the session is.
# For example: You can use a python meterpreter on a Windows platform, and you will get
# 'python/python', as your arch/platform, and not 'windows'.
#
# @return [String] The OS name recognizable by Msf::Module::Platform.
def get_target_os
os = nil
info = ''
case session.type
when 'meterpreter'
info = client.sys.config.sysinfo['OS']
when 'shell'
if session.platform =~ /win/
info = get_env('OS').strip
else
info = cmd_exec('uname -s').strip
end
end
case info
when /windows/i
os = Msf::Module::Platform::Windows.realname.downcase
when /darwin/i
os = Msf::Module::Platform::OSX.realname.downcase
when /freebsd/i
os = Msf::Module::Platform::FreeBSD.realname.downcase
when /GENERIC\.MP/i, /netbsd/i
os = Msf::Module::Platform::BSD.realname.downcase
else
os = Msf::Module::Platform::Linux.realname.downcase
end
os
end
#
# Executes +cmd+ on the remote system
#
@ -216,5 +284,40 @@ module Msf::Post::Common
nil
end
private
# Returns an architecture recognizable by ARCH_TYPES.
#
# @param [String] target_arch The arch. Example: x86
# @return [String] One of the archs from ARCH_TYPES.
def get_recognizable_arch(target_arch)
arch = nil
# Special handle some cases that ARCH_TYPES won't recognize.
# https://msdn.microsoft.com/en-us/library/aa384274.aspx
case target_arch
when /i386/, /i686/
return ARCH_X86
when /amd64/i, /ia64/i
return ARCH_X86_64
end
# Rely on ARCH_TYPES to tell us a framework-recognizable ARCH.
# Notice we're sorting ARCH_TYPES first, so that the longest string
# goes first. This step is used because sometimes let's say if the target
# is 'x86_64', and if the ARCH_X86 kicks in first, then we will get 'x86'
# instead of x86_64, which is inaccurate.
recognizable_archs = ARCH_TYPES
recognizable_archs = recognizable_archs.sort_by {|a| a.length}.reverse
recognizable_archs.each do |a|
if target_arch =~ /#{a}/
arch = a
break
end
end
arch
end
end

View File

@ -17,54 +17,35 @@ class Metasploit3 < Msf::Post
meterpreter. Additionally, the ShowDescription option can be set
to 'true' to a detailed description on the suggested exploits.
It's important to note that not all local exploits will be fired. For
example, if a module doesn't have a default datastore option that is
required for it to run, then it will not come up in the suggester's
results.
It's important to note that not all local exploits will be fired.
They are chosen based on these conditions: session type,
platform, architecture, and required default options.
},
'License' => MSF_LICENSE,
'Author' => [ 'sinn3r',
'Mo'
],
'Author' => [ 'sinn3r', 'Mo' ],
'Platform' => all_platforms,
'SessionTypes' => [ 'meterpreter', 'shell' ]
))
register_options([
Msf::OptInt.new('SESSION', [ true, "The session to run this module on." ]),
Msf::OptBool.new('ShowDescription', [true, "Displays a detailed description for the available exploits", false])
Msf::OptBool.new('SHOWDESCRIPTION', [true, "Displays a detailed description for the available exploits", false])
],Msf::Post)
end
def all_platforms
Msf::Module::Platform.subclasses.collect {|c| c.realname.downcase }
end
def get_target_arch
@target_arch ||= lambda {
return '' unless session.present?
arch = ''
arch = session.platform.split('/').first if session.platform.include?('/')
return '' if ARCH_TYPES.include?(arch)
return arch
}.call
@target_arch ||= super
end
def get_target_platform
@target_platform ||= lambda {
return '' unless session.present?
platform = session.platform.include?('/') ? session.platform.split('/').second : session.platform
if platform =~ /^win/
platform = 'win'
end
return platform
}.call
def get_target_os
@target_os ||= super
end
@ -88,9 +69,10 @@ class Metasploit3 < Msf::Post
def is_module_platform?(mod)
platform_obj = nil
begin
platform_obj = Msf::Module::Platform.find_platform(get_target_platform)
rescue ArgumentError
platform_obj = Msf::Module::Platform.find_platform(get_target_os)
rescue ArgumentError => e
# When not found, find_platform raises an ArgumentError
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
return false
end
@ -99,6 +81,11 @@ class Metasploit3 < Msf::Post
end
def is_session_type_compat?(mod)
mod.session_compatible?(session.sid)
end
def set_module_options(mod)
mod.datastore.merge!(self.datastore)
if !mod.datastore['SESSION'] && session.present?
@ -107,58 +94,75 @@ class Metasploit3 < Msf::Post
end
def is_module_wanted?(mod)
(
mod.kind_of?(Msf::Exploit::Local) &&
mod.respond_to?(:check) &&
is_session_type_compat?(mod) &&
is_module_platform?(mod) &&
is_module_arch?(mod) &&
is_module_options_ready?(mod)
)
end
def setup
print_status "Collecting local exploits..."
#Initializes an array
print_status "Collecting local exploits for #{get_target_arch}/#{get_target_os}..."
# Initializes an array
@local_exploits = []
# Collects exploits into an array
framework.exploits.each do |name, obj|
mod = framework.exploits.create(name)
next unless mod
set_module_options(mod)
if mod.kind_of?(Msf::Exploit::Local) &&
mod.respond_to?(:check) &&
is_module_platform?(mod) &&
is_module_options_ready?(mod)
if !get_target_arch.empty? && is_module_arch?(mod)
@local_exploits << mod
else
@local_exploits << mod
end
end
end
@local_exploits << mod if is_module_wanted?(mod)
end
end
def show_found_exploits
if datastore['VERBOSE']
print_status("The following #{@local_exploits.length} exploit checks are being tried:")
else
print_status("#{@local_exploits.length} exploit checks are being tried...")
end
@local_exploits.each do |x|
vprint_status(x.fullname)
end
end
def run
print_status("Number of exploits being tried: #{@local_exploits.length}")
if @local_exploits.length < 1
print_error "No suggestions available."
return
end
show_found_exploits
@local_exploits.each do |m|
begin
checkcode = m.check
begin
checkcode = m.check
# See def is_check_interesting?
if is_check_interesting?(checkcode)
# Prints the full name and the checkcode message for the exploit
print_good("#{m.fullname}: #{checkcode.second}")
#If the datastore option is true, a detailed description will show
if datastore['ShowDescription']
# If the datastore option is true, a detailed description will show
if datastore['SHOWDESCRIPTION']
# Formatting for the description text
print_line Rex::Text.wordwrap(Rex::Text.compress(m.description), 2, 70)
end
else
# Prints the full name and the checkcode message for the exploit
vprint_status("#{m.fullname}: #{checkcode.second}")
end
# Creates a log record in framework.log
rescue Rex::Post::Meterpreter::RequestError => e
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
vprint_error("#{e.class} #{m.shortname} failled to run: #{e.message}")
end
if @local_exploits.length < 1
print_error "No suggestions available. "
end
else
vprint_status("#{m.fullname}: #{checkcode.second}")
end
rescue Rex::Post::Meterpreter::RequestError => e
# Creates a log record in framework.log
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
vprint_error("#{e.class} #{m.shortname} failled to run: #{e.message}")
end
end
end
def is_check_interesting?(checkcode)
[
Msf::Exploit::CheckCode::Vulnerable,
@ -167,15 +171,19 @@ class Metasploit3 < Msf::Post
].include?(checkcode)
end
def print_status(msg='')
super("#{session.session_host} - #{msg}")
end
def print_good(msg='')
super("#{session.session_host} - #{msg}")
end
def print_error(msg='')
super("#{session.session_host} - #{msg}")
end
end