
深刻度: 高 (CVSS 7.2)
CWE: CWE-918 (SSRF) + CWE-306 (認証の欠如)
影響を受けるバージョン: chamilo/chamilo-lms 2.0-RC.2
修正バージョン: 2.0-RC.3
アドバイザリ: GHSA-mxc9-9335-45mc
NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-33715
クレジット: Romain Deperne
Chamilo LMS 2.0 の install.ajax.php は、完全にインストール済みのインスタンスにおいて認証なしでアクセス可能です。その test_mailer アクションは POST データから任意の Symfony Mailer DSN と送信先を受け付けるため、未認証の攻撃者がサーバーに対して任意の内部ホストへの SMTP 接続を開始させ (SSRF)、Chamilo サーバーを経由してオープンリレーとしてメールを送信させることができます。
Chamilo LMS が複数の CVE を蓄積しているものの、AJAX エンドポイントについては深く監査されていないことに気づいたため、私はこれを監査しました。私のアプローチは、public/main/inc/ajax/ 内のすべてのファイルを列挙し、それぞれが require_once __DIR__.'/../global.inc.php' で始まっているかどうか — コードベース全体で認証を強制するインクルード — を確認するというものでした。
install.ajax.php は例外でした。これには Composer のオートローダーしかインクルードされていません。ファイル名からすでにインストール用の残骸コードであることが示唆されており、その中で test_mailer を grep したところ、POST データから生の Symfony Mailer DSN 文字列を受け取り、それを直接 Transport::fromDsn() に渡していることが確認できました。
これは完全な SSRF プリミティブです。未認証の攻撃者が、サーバーが接続するプロトコル、ホスト、ポートを制御できます。設定した任意のトランスポートを介して実際のメールが送信されるという事実により、これはオープンリレーにもなります。私はシンプルな curl を用いて、完全にインストール済みのインスタンス上で、セッション Cookie なしにこのエンドポイントへ到達可能であることを確認しました。
根本原因はアーキテクチャにあります。Apache の RewriteCond %{REQUEST_FILENAME} !-f が既存の PHP ファイルを直接 PHP に渡し、フロントコントローラに到達させないため、このファイルは Symfony のセキュリティファイアウォールをバイパスします。
ファイル: public/main/inc/ajax/install.ajax.php
このファイルはインストールウィザード用に設計されましたが、インストール後もアクセス可能なままです。同じディレクトリ内の他のすべての AJAX エンドポイントとは異なり、global.inc.php をインクルードしていません — つまり認証ゼロ、認可チェックゼロです:
// Line 18 — only loads Composer autoloader, no auth
require_once __DIR__.'/../../../../vendor/autoload.php';
test_mailer アクション(約138行目)は、攻撃者が制御可能な POST パラメータを受け付けます:
case 'test_mailer':
$mailerDsn = (string) $request->request->get('mailerDsn'); // arbitrary SMTP DSN
$mailerTestDestination = (string) $request->request->get('mailerTestDestination'); // arbitrary email
// ...
$transport = Transport::fromDsn($mailerDsn); // connects to attacker's SMTP server
$mailer = new Mailer($transport);
$mailer->send($email); // sends email through it
適切に保護されたエンドポイントと比較してください:
// chat.ajax.php line 9 — correct pattern
require_once __DIR__.'/../global.inc.php'; // enforces authentication
api_block_anonymous_users();
このファイルは Apache によって直接配信されます(RewriteCond %{REQUEST_FILENAME} !-f は既存の PHP ファイルをそのまま通過させ、Symfony のセキュリティファイアウォールをバイパスします)。global.inc.php がインクルードされていないため、セッションも認証もインストール完了チェックも存在しません。
完全なデモンストレーションについては poc.py を参照してください。
# SSRF — force Chamilo to connect to internal SMTP server
curl -X POST "http://<target>/main/inc/ajax/install.ajax.php?a=test_mailer" \
-d "mailerDsn=smtp://10.0.0.1:25" \
-d "[email protected]" \
-d "mailerFromName=Test" \
-d "[email protected]"
# Open relay — send phishing email through the Chamilo server
curl -X POST "http://<target>/main/inc/ajax/install.ajax.php?a=test_mailer" \
-d "mailerDsn=smtp://mail.chamilo.org:587" \
-d "[email protected]" \
-d "mailerFromName=Chamilo Security" \
-d "[email protected]"