Merge pull request #1 from wchen-r7/pr5788
Properly support detecting target arch and OSbug/bundler_fix
commit
69ee5e3313
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue