
phpMyAdmin 5.2.3 - 高 - リモート - CSRF - /sql におけるトークン除去
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-csrf-sql
解説記事: https://abraxaslabs.tech/research/phpmyadmin-csrf-sql
クラス: CSRF 到達範囲: リモート
phpMyAdmin 5.2.3(タグ RELEASE_5_2_3、コミット 962857e)。Common.php は checkTokenRequestParam より前にグローバル変数から PSR-7 リクエストを構築する。不一致時、Sanitize::removeRequestVars は $_POST と $_GET をクリアするが、そのスナップショットはクリアしない。その後 $sql_query は $request->getParsedBodyParam('sql_query') からコピーされる。AJAX POST はトークン不一致で中断される。非 AJAX POST は継続する。SqlController はクリアされた $_POST['sql_query'] を優先し、そうでなければグローバル変数を保持する。
phpMyAdmin のセッション Cookie を持つ被害者がいれば十分である。sql_query を付けて、有効なトークンなし、かつ ajax_request なしで index.php?route=/sql に POST する。SELECT はその MySQL ユーザーとして実行される。5.2.3 のデフォルト CookieSameSite=Strict は多くのクロスサイトブラウザをブロックする。同一サイト、Lax、None、または HTTP 認証では依然として成立する。いずれにせよ、これは壊れた CSRF 制御である。
| ID | CVE 未割当 |
| クラス | CSRF |
| 到達範囲 | リモート。デフォルトの CookieSameSite=Strict は多くのクロスサイトブラウザをブロックする。同一サイト / Lax / None / HTTP 認証では依然として成立する。 |
| CWE | CWE-352 |
| CVSS | High: 8.1 CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N |
| 製品 | phpMyAdmin |
| 影響を受けるバージョン | 5.2.3 タグ RELEASE_5_2_3(962857e) |
| 認証 | 被害者の phpMyAdmin セッション Cookie(または HTTP 認証)。有効な CSRF トークンは不要。 |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1:19240 のみ |
被害者のブラウザに ajax_request なしで phpMyAdmin へ POST させることができる者は誰でも、その MySQL ユーザーとして SQL を実行できる。
| 権限 | メソッド / パス | ラボで実証済みか推測か |
|---|---|---|
| 被害者の MySQL アカウントとして攻撃者の SQL を実行する(その SQL ボックスの整合性 + 偵察) | POST index.php?route=/sql sql_query=... db=... token なし、ajax_request なし | ラボで実証済み。レスポンス本文に PMA-CSRF-SQL-WITNESS が含まれていた。一般ログに appuser としての SELECT が記録された |
| AJAX では同じハンドラを中断させる | 同じ POST に ajax_request=1 を付ける | ラボで実証済み。Token mismatch。INSERT のマーカー行は存在しない。一般ログにその INSERT は記録されなかった |
クリアされた $_POST のみを読むハンドラを回避する | トークンなしで POST /database/structure/drop-table | ラボで実証済み。keepme は依然として存在する |
エクスポート(SaveDir)、パーティションの DROP/TRUNCATE、アカウントロック、/config/set、pmadb 作成における同じギャップ | クリア後に PSR-7 ボディを読む任意のハンドラ | 推測。検証は未実施 |
このラボで除外されたもの: 未認証の PMA(先に Cookie ログインが必要)、AJAX ルート(不一致で終了する)、トークンなしの drop-table、OS シェル。デフォルトの Strict SameSite により、古典的なクロスサイトフォームは多くの場合 Cookie を送信しない。それでも残るのは、同一サイトおよび Lax/None のデプロイにおける失敗した CSRF チェックである。
RELEASE_5_2_3 を対象とした 8 つの並列ソース調査。Common.php は checkTokenRequestParam() の前に $request = createFromGlobals() を生成する。不一致時、Sanitize::removeRequestVars() は $_POST/$_GET のみをクリアする。非 AJAX は継続する。SqlController は $_POST が空の場合にグローバルの $sql_query を使用する。ルートは GET|POST /sql。
誤った方向性:AJAX の /sql を残存物とみなす(これは Token mismatch で中断される);drop-table を残存物とみなす(そのハンドラは strip された $_POST を読むだけである);デフォルトの Strict SameSite を「CSRF は閉じている」とみなす(制御は依然として破綻しており、same-site / Lax / None が残る)。
python3 phpmyadmin-csrf-sql-Abraxas-Labs.py
または
cd lab
./run.sh
ループバックのみ: http://127.0.0.1:19240。イメージ phpmyadmin:5.2.3 と mysql:8.0。Compose プロジェクト phpmyadmin-csrf-sql。PoC は同一サイトのループバック POST です(Strict SameSite でもクッキーは送信されます)。ウィットネス PMA-CSRF-SQL-WITNESS。
SUCCESS phpmyadmin-csrf-sql sql-ran=yes ajax-abort=yes drop-held=yes PMA-CSRF-SQL-WITNESS
不一致が発生した場合、リクエストを空のボディに置き換えるか、AJAX だけでなくすべての POST を拒否してください。古いリクエストから sql_query をコピーしないでください。ログアウトと同様にフェイルクローズしてください。
962857e)libraries/classes/Common.php トークン削除前のリクエストスナップショットSanitize::removeRequestVars は $_POST/$_GET のみをクリアするSqlController のグローバル $sql_queryGNU Affero GPL v3.0。LICENSE を参照してください。ループバックラボ専用です。保証はありません。