
CVE-2026-42647(JoomSport WordPressプラグインのsortfパラメータを介した認証なしの時間ベースのブラインドSQLインジェクション)を再現するためのDockerベースのラボです。比較用に脆弱なターゲットと修正済みターゲットを含みます。
sortf経由)このリポジトリには、CVE-2026-42647を再現および検証するためのローカルDockerラボが含まれています。この脆弱性は、WordPressプラグインJoomSport(スポーツ向け:チーム&リーグ、フットボール、ホッケーなど)に影響を与える認証不要のSQLインジェクションです。
脆弱な動作は、選手リストの並べ替え機能で発生します。一般の訪問者は、sortfクエリパラメータを制御でき、これはSQLのORDER BY句を構築するために使用されます。脆弱なバージョンでは、値はテキストとしてサニタイズされ、バッククォートで囲まれますが、SQLクエリに追加される前に厳格な許可リストに対して検証されません。
このラボでは、2つのJoomSportバージョンを比較します:
| サービス | JoomSportバージョン | 目的 | URL |
|---|---|---|---|
vuln | 5.7.6 | 脆弱な比較対象 | http://localhost:8081 |
patched | 5.7.8 | 修正済み比較対象 | http://localhost:8082 |
公開されているアドバイザリでは、5.7.8より前のバージョンが影響を受け、5.7.8が修正されたバージョンとされています。このラボでは、準備時にWordPress.orgのプラグインSVNタグリストで5.7.7のソースタグが入手できなかったため、脆弱なターゲットとして5.7.6を使用しています。
実証される脆弱性の連鎖は次のとおりです:```text Unauthenticated visitor → JoomSport season player list route → attacker-controlled sortf parameter → unsafe dynamic ORDER BY construction → SQL expression execution → measurable database delay in vulnerable version → patched version rejects the injected sort field and falls back to a safe allowlisted field
このラボは、時間ベースのブラインドSQLインジェクションとして脆弱性を検証します。データベースのダンプ、資格情報の抽出、データの変更、または破壊的なSQL操作は行いません。
このラボは、管理されたローカル研究、ソースレベルの理解、およびポートフォリオのデモンストレーションのみを目的として設計されています。
## Verified Facts
| 主張 | 証拠 | このラボで確認する方法 |
| ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| JoomSport 5.7.8未満は、認証されていないSQLインジェクションに対して脆弱であると報告されています。 | 公開されたアドバイザリは、JoomSport `< 5.7.8` / `<= 5.7.7` が影響を受けると特定しています。 | 参考文献セクションを確認し、脆弱なサービスとパッチ適用済みのサービスを比較してください。 |
| JoomSport 5.7.8は修正バージョンです。 | 公開されたアドバイザリとソース比較により、5.7.8では順序式を構築する前に`sortf`値を検証することが示されています。 | 両方のバージョンの`class-jsport-playerlist.php`を検査してください。 |
| 影響を受けるパラメータは`sortf`です。 | 脆弱なプレイヤーリストコードは`classJsportRequest::get('sortf')`を読み取ります。 | PoCを実行し、注入された`sortf`リクエストを観察してください。 |
| 脆弱なコードは、ユーザー入力から動的なSQL順序付け値を構築します。 | 脆弱なバージョンでは、`sortf`を使用して`$options['ordering']`を構築します。 | `sportleague/classes/objects/class-jsport-playerlist.php`を検査してください。 |
| SQLシンクは`ORDER BY`句です。 | 生成された`$ordering`値は、後で`ORDER BY`を使ってSQLクエリに追加されます。 | `sportleague/base/wordpress/classes/class-jsport-getplayers.php`を検査してください。 |
| パッチは許可リストスタイルの修正を使用しています。 | パッチ適用バージョンでは、ソートフィールドを使用する前に、許可された静的カラムと期待される動的フィールドパターンを導入しています。 | JoomSport 5.7.6と5.7.8のソースを比較してください。 |
| このラボは時間ベースのブラインドSQLインジェクションを示しています。 | 脆弱なターゲットは、注入された`SLEEP()`式が使用されると遅延しますが、パッチ適用済みのターゲットは遅延しません。 | `python3 poc/poc.py http://localhost:8081 http://localhost:8082`を実行してください。 |
## Assumptions and Unknowns
このラボでは、JoomSport 5.7.6を脆弱な比較対象として使用しています。これは、公開された修正バージョンが5.7.8であり、ラボの準備時にWordPress.orgのプラグインSVNタグリストで5.7.7のソースタグが利用できなかったためです。
このラボは、5.7.6が唯一の脆弱なバージョンであると主張するものではありません。これは、脆弱な動作を修正済みの5.7.8の動作と比較するための再現可能な脆弱なベースラインとして使用されています。
このラボは、プレイヤーリストのソートフローにおける`sortf`パラメータに焦点を当てています。
実証された影響は時間ベースのブラインドSQLインジェクションです。このラボでは以下を実証しません:
* 直接的なデータベースダンプ,
* 資格情報の抽出,
* 認証バイパス,
* 特権昇格,
* 任意のデータ変更,
* リモートコード実行,
* 永続化,
* 外部コールバック,
* またはラボ外のシステムに対する攻撃。
エラーベースまたはブーリアンベースの動作は、データベースの動作、アプリケーション構成、および応答の違いによって可能かもしれませんが、このラボはそれらの手法に依存していません。主要な証明はタイミングベースです。
## Root Cause Summary
根本原因は、`sortf`リクエストパラメータからの動的SQL `ORDER BY`句の安全でない構築です。
脆弱なコードパスは次の場所から始まります:```text
sportleague/classes/objects/class-jsport-playerlist.php
選手リスト読み込みロジック内で、JoomSportはリクエストパラメータを読み取ります:```text sortf
そして、それを使用して構築します:```text
$options['ordering']
該当する脆弱なソースパターンは次のとおりです。```php
if (classJsportRequest::get('sortf')) {
$typeAD = in_array(classJsportRequest::get('sortd'), array("ASC","DESC")) ? classJsportRequest::get('sortd') : "ASC";
$options['ordering'] = str_replace(" ","",sanitize_text_field("".classJsportRequest::get('sortf')."")).' '.$typeAD;
}
問題は主に `sortd` パラメータではありません。`sortd` の値は次のように制限されています:```text
ASC
DESC
問題は sortf パラメータです。これはソートに使用されるSQL識別子/式の位置を制御するためです。
危険な式は次のとおりです:```php
"".classJsportRequest::get('sortf').""
コードは、攻撃者制御の入力をMySQL識別子コンテキスト内に配置し、それをSQL順序付けフラグメントとして前方に渡します。
コードは以下を適用する:```php
sanitize_text_field()
しかし、sanitize_text_field() はSQL識別子のバリデーションではありません。テキストをクリーニングするために設計されており、SQL構文を安全に構築するためのものではありません。
脆弱なコードはまた、ユーザーが制御するソートフィールドをバッククォートで囲んでいます。しかし、攻撃者が識別子の内容に影響を与えられる場合、バッククォートはセキュリティ境界にはなりません。攻撃者が値にバッククォートを注入できれば、意図された識別子コンテキストから脱出できます。
生成された順序値は、後でプレイヤー取得クエリに渡され、SQLの ORDER BY 句に追加されます。```text
sportleague/base/wordpress/classes/class-jsport-getplayers.php
シンクパターンは:```php
$query .= ' ORDER BY '.($ordering);
これにより、脆弱なデータフローが作成されます:```text sortf request parameter → classJsportRequest::get('sortf') → $options['ordering'] → $ordering → ORDER BY
セキュリティ上の問題は、アプリケーションがユーザー制御のリクエストパラメータを、厳格な許可リストに対して事前に検証することなく、SQL識別子/式として扱っていることです。
## ソースパッチの概要
該当するパッチは次の場所にあります:```text
sportleague/classes/objects/class-jsport-playerlist.php
脆弱なバージョンでは、プレイヤーリストコードはリクエスト値から直接 $options['ordering'] を構築します:```php
if (classJsportRequest::get('sortf')) {
$typeAD = in_array(classJsportRequest::get('sortd'), array("ASC","DESC")) ? classJsportRequest::get('sortd') : "ASC";
$options['ordering'] = str_replace(" ","",sanitize_text_field("".classJsportRequest::get('sortf')."")).' '.$typeAD;
}
脆弱な部分は、`classJsportRequest::get('sortf')` がSQLの並び替え式の中で使用されていることです。
JoomSport 5.7.8では、`$options['ordering']` を構築する前に検証済みのソートフィールド変数を導入することで、この動作を変更しています。
パッチ版では、安全なデフォルト値を初期化します:```php
$sortFieldEsc = 'post_title';
次に、許可された静的ソート列を定義します。```php $sortCols = array("played", "career_minutes", "post_title");
`sortf` が存在する場合、パッチコードはそれが期待される静的値のいずれかに一致する場合のみ受け入れます:```php
if (in_array(classJsportRequest::get('sortf'), $sortCols)) {
$sortFieldEsc = classJsportRequest::get('sortf');
}
このパッチは、期待される動的なイベント/統計フィールドフォーマットも許可します:```php if (preg_match('/^eventid_\d+$/', classJsportRequest::get('sortf'))) { $sortFieldEsc = classJsportRequest::get('sortf'); }
if (preg_match('/^ef_\d+$/', classJsportRequest::get('sortf'))) { $sortFieldEsc = classJsportRequest::get('sortf'); }
最後のセキュリティ関連の変更は、`$options['ordering']` が未加工の `sortf` リクエスト値の代わりに `$sortFieldEsc` から構築されることです:```diff
- $options['ordering'] = str_replace(" ","",sanitize_text_field("`".classJsportRequest::get('sortf')."`")).' '.$typeAD;
+ $options['ordering'] = str_replace(" ","",sanitize_text_field("`".$sortFieldEsc."`")).' '.$typeAD;
これは動的ソートを除去するものではありません。信頼境界を変更します。パッチ前:```text request sortf value directly controlled the ORDER BY identifier
パッチ適用後:```text
request sortf value can only influence ORDER BY if it matches an allowed column name or an expected dynamic field pattern
攻撃者が次のような予期しない値を送信した場合:```text post_title`DESC,(SLEEP(2))#
パッチ適用後のコードでは、その値は `$sortFieldEsc` に代入されません。
代わりに、ソートフィールドは以下にフォールバックします:```text
post_title
これは、脆弱なサービスが遅延し、パッチ適用済みのサービスがベースラインのタイミングに近いままである理由です。
パッチからのセキュリティ教訓は:```text Dynamic SQL identifiers such as ORDER BY columns must be validated with strict allowlists. Text sanitization and backtick wrapping are not sufficient for SQL identifier safety.
## ラボアーキテクチャ