Update UUID to match detected platform, fail exploit on invalid session

bug/bundler_fix
OJ 2016-10-29 13:45:28 +10:00
parent 0737d7ca12
commit 8b97183924
No known key found for this signature in database
GPG Key ID: D5DC61FB93260597
7 changed files with 90 additions and 158 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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]')

View File

@ -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