Update UUID to match detected platform, fail exploit on invalid session
parent
0737d7ca12
commit
8b97183924
|
@ -324,6 +324,17 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
username = self.sys.config.getuid
|
||||
sysinfo = self.sys.config.sysinfo
|
||||
|
||||
# when updating session information, we need to make sure we update the platform
|
||||
# in the UUID to match what the target is actually running on, but only for a
|
||||
# subset of platforms.
|
||||
if ['java', 'python', 'php'].include?(self.platform)
|
||||
new_platform = guess_target_platform(sysinfo['OS'])
|
||||
if self.platform != new_platform
|
||||
self.payload_uuid.platform = new_platform
|
||||
self.core.set_uuid(self.payload_uuid)
|
||||
end
|
||||
end
|
||||
|
||||
safe_info = "#{username} @ #{sysinfo['Computer']}"
|
||||
safe_info.force_encoding("ASCII-8BIT") if safe_info.respond_to?(:force_encoding)
|
||||
# Should probably be using Rex::Text.ascii_safe_hex but leave
|
||||
|
@ -333,6 +344,24 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
self.info = safe_info
|
||||
end
|
||||
|
||||
def guess_target_platform(os)
|
||||
case os
|
||||
when /windows/i
|
||||
Msf::Module::Platform::Windows.realname.downcase
|
||||
when /darwin/i
|
||||
Msf::Module::Platform::OSX.realname.downcase
|
||||
when /mac os ?x/i
|
||||
# this happens with java on OSX (for real!)
|
||||
Msf::Module::Platform::OSX.realname.downcase
|
||||
when /freebsd/i
|
||||
Msf::Module::Platform::FreeBSD.realname.downcase
|
||||
when /GENERIC\.MP/i, /netbsd/i
|
||||
Msf::Module::Platform::BSD.realname.downcase
|
||||
else
|
||||
Msf::Module::Platform::Linux.realname.downcase
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Populate the session information.
|
||||
#
|
||||
|
@ -510,20 +539,31 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
# Generate a binary suffix based on arch
|
||||
#
|
||||
def binary_suffix
|
||||
# generate a file/binary suffix based on the current platform
|
||||
case self.platform
|
||||
when 'windows'
|
||||
"#{self.arch}.dll"
|
||||
when 'android', 'java'
|
||||
# generate a file/binary suffix based on the current arch and platform.
|
||||
# Platform-agnostic archs go first
|
||||
case self.arch
|
||||
when 'java'
|
||||
'jar'
|
||||
when 'linux' , 'aix' , 'hpux' , 'irix' , 'unix'
|
||||
'lso'
|
||||
when 'php'
|
||||
'php'
|
||||
when 'python'
|
||||
'py'
|
||||
else
|
||||
nil
|
||||
# otherwise we fall back to the platform
|
||||
case self.platform
|
||||
when 'windows'
|
||||
"#{self.arch}.dll"
|
||||
when 'linux' , 'aix' , 'hpux' , 'irix' , 'unix'
|
||||
'lso'
|
||||
when 'android', 'java'
|
||||
'jar'
|
||||
when 'php'
|
||||
'php'
|
||||
when 'python'
|
||||
'py'
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ module Msf::Post::Common
|
|||
when /meterpreter/
|
||||
pid_list = client.sys.process.processes.collect {|e| e['pid']}
|
||||
when /shell/
|
||||
if client.platform =~ /win/
|
||||
if client.platform == 'windows'
|
||||
o = cmd_exec('tasklist /FO LIST')
|
||||
pid_list = o.scan(/^PID:\s+(\d+)/).flatten
|
||||
else
|
||||
|
@ -49,74 +49,6 @@ 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'.
|
||||
#
|
||||
# @return [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
|
||||
#
|
||||
|
@ -258,7 +190,7 @@ module Msf::Post::Common
|
|||
when /meterpreter/
|
||||
return session.sys.config.getenv(env)
|
||||
when /shell/
|
||||
if session.platform =~ /win/
|
||||
if session.platform == 'windows'
|
||||
if env[0,1] == '%'
|
||||
unless env[-1,1] == '%'
|
||||
env << '%'
|
||||
|
@ -302,39 +234,4 @@ module Msf::Post::Common
|
|||
|
||||
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 /i[3456]86|wow64/i
|
||||
return ARCH_X86
|
||||
when /(amd|ia|x)64/i
|
||||
return ARCH_X64
|
||||
end
|
||||
|
||||
# Detect tricky variants of architecture types upfront
|
||||
|
||||
# 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 'x64', and if the ARCH_X86 kicks in first, then we will get 'x86'
|
||||
# instead of x64, 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
|
||||
|
|
|
@ -29,8 +29,12 @@ module Msf::PostMixin
|
|||
#
|
||||
# @raise [OptionValidateError] if {#session} returns nil
|
||||
def setup
|
||||
if not session
|
||||
raise Msf::OptionValidateError.new(["SESSION"])
|
||||
unless session
|
||||
raise Msf::OptionValidateError.new(["SESSION (not specified)"])
|
||||
end
|
||||
|
||||
unless session_compatible?(session)
|
||||
raise Msf::OptionValidateError.new(["SESSION (type not valid for this module)"])
|
||||
end
|
||||
|
||||
super
|
||||
|
@ -160,39 +164,36 @@ module Msf::PostMixin
|
|||
return false unless self.module_info["SessionTypes"].include?(s.type)
|
||||
end
|
||||
|
||||
# XXX: Special-case java and php for now. This sucks and Session
|
||||
# should have a method to auto-detect the underlying platform of
|
||||
# platform-independent sessions such as these.
|
||||
plat = s.platform
|
||||
if plat =~ /php|java/ and sysinfo and sysinfo["OS"]
|
||||
plat = sysinfo["OS"]
|
||||
end
|
||||
|
||||
# Types are okay, now check the platform. This is kind of a ghetto
|
||||
# workaround for session platforms being ad-hoc and Platform being
|
||||
# inflexible.
|
||||
if self.platform and self.platform.kind_of?(Msf::Module::PlatformList)
|
||||
[
|
||||
# Add as necessary
|
||||
"win", "linux", "osx"
|
||||
"windows", "linux", "osx"
|
||||
].each do |name|
|
||||
if plat =~ /#{name}/
|
||||
if self.platform =~ /#{name}/
|
||||
p = Msf::Module::PlatformList.transform(name)
|
||||
return false unless self.platform.supports? p
|
||||
end
|
||||
end
|
||||
elsif self.platform and self.platform.kind_of?(Msf::Module::Platform)
|
||||
p_klass = Msf::Module::Platform
|
||||
case plat.downcase
|
||||
when /win/
|
||||
case self.platform
|
||||
when 'windows'
|
||||
return false unless self.platform.kind_of?(p_klass::Windows)
|
||||
when /osx/
|
||||
when 'osx'
|
||||
return false unless self.platform.kind_of?(p_klass::OSX)
|
||||
when /linux/
|
||||
when 'linux'
|
||||
return false unless self.platform.kind_of?(p_klass::Linux)
|
||||
end
|
||||
end
|
||||
|
||||
# Check to make sure architectures match
|
||||
mod_arch = self.module_info['Arch']
|
||||
mod_arch = [mod_arch] unless mod_arch.kind_of?(Array)
|
||||
return false unless mod_arch.include?(self.arch)
|
||||
|
||||
# If we got here, we haven't found anything that definitely
|
||||
# disqualifies this session. Assume that means we can use it.
|
||||
return true
|
||||
|
|
|
@ -296,16 +296,13 @@ class ClientCore < Extension
|
|||
return true
|
||||
end
|
||||
|
||||
def uuid(timeout=nil)
|
||||
request = Packet.create_request('core_uuid')
|
||||
def set_uuid(uuid)
|
||||
request = Packet.create_request('core_set_uuid')
|
||||
request.add_tlv(TLV_TYPE_UUID, uuid.to_raw)
|
||||
|
||||
args = [ request ]
|
||||
args << timeout if timeout
|
||||
response = client.send_request(*args)
|
||||
client.send_request(request)
|
||||
|
||||
id = response.get_tlv_value(TLV_TYPE_UUID)
|
||||
|
||||
return Msf::Payload::UUID.new({:raw => id})
|
||||
true
|
||||
end
|
||||
|
||||
def machine_id(timeout=nil)
|
||||
|
|
|
@ -120,7 +120,9 @@ class Config
|
|||
|
||||
# make sure we map the architecture across to x64 if x86_64 is returned
|
||||
# to keep arch consistent across all session/machine types
|
||||
@sysinfo['Architecture'] = ARCH_X64 if @sysinfo['Architecture'].strip == ARCH_X86_64
|
||||
if @sysinfo['Architecture']
|
||||
@sysinfo['Architecture'] = ARCH_X64 if @sysinfo['Architecture'].strip == ARCH_X86_64
|
||||
end
|
||||
end
|
||||
@sysinfo
|
||||
end
|
||||
|
|
|
@ -77,19 +77,25 @@ class Console::CommandDispatcher::Core
|
|||
end
|
||||
|
||||
# Currently we have some windows-specific core commands`
|
||||
if client.platform =~ /win/
|
||||
if client.platform == 'windows'
|
||||
# only support the SSL switching for HTTPS
|
||||
if client.passive_service && client.sock.type? == 'tcp-ssl'
|
||||
c["ssl_verify"] = "Modify the SSL certificate verification setting"
|
||||
end
|
||||
end
|
||||
|
||||
if client.platform =~ /win/ || client.platform =~ /linux/
|
||||
if client.platform == 'windows' || client.platform == 'linux'
|
||||
# Migration only supported on windows and linux
|
||||
c["migrate"] = "Migrate the server to another process"
|
||||
end
|
||||
|
||||
if client.platform =~ /win/ || client.platform =~ /linux/ || client.platform =~ /python/ || client.platform =~ /java/
|
||||
# TODO: This code currently checks both platform and architecture for the python
|
||||
# and java types because technically the platform should be updated to indicate
|
||||
# the OS platform rather than the meterpreter arch. When we've properly implemented
|
||||
# the platform update feature we can remove some of these conditions
|
||||
if client.platform == 'windows' || client.platform == 'linux' ||
|
||||
client.platform == 'python' || client.platform == 'java' ||
|
||||
client.arch == ARCH_PYTHON || (client.arch == ARCH_JAVA && client.platform != 'android')
|
||||
# Yet to implement transport hopping for other meterpreters.
|
||||
c["transport"] = "Change the current transport mechanism"
|
||||
|
||||
|
@ -98,7 +104,7 @@ class Console::CommandDispatcher::Core
|
|||
c["sleep"] = "Force Meterpreter to go quiet, then re-establish session."
|
||||
end
|
||||
|
||||
if (msf_loaded?)
|
||||
if msf_loaded?
|
||||
c["info"] = "Displays information about a Post module"
|
||||
end
|
||||
|
||||
|
@ -462,10 +468,9 @@ class Console::CommandDispatcher::Core
|
|||
end
|
||||
|
||||
#
|
||||
# Get the machine ID of the target
|
||||
# Get the machine ID of the target (should always be up to date locally)
|
||||
#
|
||||
def cmd_uuid(*args)
|
||||
client.payload_uuid = client.core.uuid unless client.payload_uuid
|
||||
print_good("UUID: #{client.payload_uuid}")
|
||||
end
|
||||
|
||||
|
@ -850,7 +855,7 @@ class Console::CommandDispatcher::Core
|
|||
)
|
||||
|
||||
def cmd_migrate_help
|
||||
if client.platform =~ /linux/
|
||||
if client.platform == 'linux'
|
||||
print_line('Usage: migrate <<pid> | -P <pid> | -N <name>> [-p writable_path] [-t timeout]')
|
||||
else
|
||||
print_line('Usage: migrate <<pid> | -P <pid> | -N <name>> [-t timeout]')
|
||||
|
|
|
@ -40,19 +40,9 @@ class MetasploitModule < Msf::Post
|
|||
end
|
||||
|
||||
|
||||
def get_target_arch
|
||||
@target_arch ||= super
|
||||
end
|
||||
|
||||
|
||||
def get_target_os
|
||||
@target_os ||= super
|
||||
end
|
||||
|
||||
|
||||
def is_module_arch?(mod)
|
||||
mod_arch = mod.target.arch || mod.arch
|
||||
mod_arch.include?(get_target_arch)
|
||||
mod_arch.include?(session.arch)
|
||||
end
|
||||
|
||||
|
||||
|
@ -70,7 +60,7 @@ class MetasploitModule < Msf::Post
|
|||
def is_module_platform?(mod)
|
||||
platform_obj = nil
|
||||
begin
|
||||
platform_obj = Msf::Module::Platform.find_platform(get_target_os)
|
||||
platform_obj = Msf::Module::Platform.find_platform(session.platform)
|
||||
rescue ArgumentError => e
|
||||
# When not found, find_platform raises an ArgumentError
|
||||
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
|
||||
|
@ -110,7 +100,7 @@ class MetasploitModule < Msf::Post
|
|||
|
||||
|
||||
def setup
|
||||
print_status "Collecting local exploits for #{get_target_arch}/#{get_target_os}..."
|
||||
print_status "Collecting local exploits for #{session.session_type}..."
|
||||
# Initializes an array
|
||||
@local_exploits = []
|
||||
# Collects exploits into an array
|
||||
|
|
Loading…
Reference in New Issue