
CVE-2026-64638 (XSS2Shell)용 비파괴적 탐지기 — WordPress 사전 인증 XSS 반사 프리미티브
WordPress wp-login.php의 CVE-2026-64638 ("XSS2Shell") 반사(reflection) 프리미티브를 탐지하는 비파괴적이고 의존성 없는 도구입니다.
CVE-2026-64638은 WordPress 코어의 인증 전(pre-authentication) 반사형 XSS로, PWN.AI가 2026-08-07에 공개했으며(CVSS 8.9, CWE-79) 7.0.3에서 패치되었고 모든 유지 관리 브랜치(6.9.6, 6.8.7, 6.7.6, 6.6.6, 6.5.9, …)로 백포트되었습니다.
근본 원인은 PHP의 strip_tags()와 WordPress의 KSES 새니타이저 사이의 **파서 차이(parser differential)**입니다:
strip_tags()는 < 뒤에 공백이 오면 태그로 인식하지 않으므로 < area id=x>와 같은 사용자 이름이 일반 텍스트로 남습니다.<area id="x"> 요소로 다시 파싱합니다.이로 인해 공격자가 선택한 id/class/href 속성을 가진 DOM 주입이 발생합니다. 이는 공개된 다단계 체인(DOM clobbering → REST JSONP → 애플리케이션 비밀번호 탈취 → 플러그인 업로드 → 로그인한 관리자 피해자에 대한 RCE)의 기반이 되는 프리미티브입니다.
두 가지 비파괴적 프로브(임의의 마커 사용자 이름으로 로그인 실패):
<b>marker</b>가 이스케이프되지 않은 채 나타납니다.< area id=marker>가 strip_tags()를 통과하여 응답에 실제/정규화된 요소(예: area id="marker")로 다시 나타납니다.어떤 페이로드도 실행되지 않습니다. 이 도구는 공격자 HTML이 실제 DOM으로 렌더링되는지만 측정합니다. 선택적 추가 기능:
--version — 피드 <generator> 태그를 통해 코어 버전 식별.--jsonp — 공개된 체인에서 사용하는 REST JSONP 봉투(_jsonp/_envelope)에 연결할 수 있는지 확인.python3 xss2shell_check.py https://example.com
python3 xss2shell_check.py --jsonp --verbose https://example.com
python3 xss2shell_check.py --version https://example.com
python3 xss2shell_check.py --json https://example.com
Python 3.6+, 표준 라이브러리만 사용. 의존성 없음.
| 코드 | 의미 |
|---|---|
| 0 | 취약함(반사 프리미티브 존재) |
| 1 | 패치됨 / 취약하지 않음 |
| 2 | 오류(연결 불가, WAF 챌린지, 예상치 못한 응답) |
<area id="…">)입니다. 속성 따옴표는 KSES 세대에 따라 다르며(기존 사용자 정의 파서: <area id=x>; DOMDocument: <area id="x"> / <area id="x" />), 따라서 모든 형식이 매칭됩니다. 다시 파싱되지 않는 원시 < area …> 통과는 브라우저에서 비활성 텍스트일 뿐 프리미티브가 아니므로 RAW_TEXT_ONLY로 보고되며 오탐(false positive)을 유발하지 않습니다.login_errors 필터나 CDN/WAF가 응답을 다시 쓰거나 로그인 오류가 사용자 이름을 에코하지 않는 경우 오탐(false negative)이 발생할 수 있습니다.승인된 보안 테스트 전용입니다. 이 도구는 소유하거나 명시적인 서면 허가를 받은 시스템만 테스트하기 위한 것입니다. 승인되지 않은 테스트는 대부분의 관할권에서 불법입니다.
| 플래그 | 용도 |
|---|
--version | 코어 버전 식별(피드 생성기 태그, 홈페이지 메타 대체) |
--jsonp | REST JSONP 봉투(_jsonp/_envelope)에 연결할 수 있는지도 확인 |
-v, --verbose | 프로브 응답 스니펫 출력(보고서용 증거) |
--json | 기계 판독 가능한 JSON 결과(CI / 자동화) |
| 관찰된 동작 | 판정 | 종료 코드 |
|---|
<b>marker</b>가 이스케이프되지 않은 채 에코됨 | RAW_HTML — 취약함 | 0 |
< area id=marker>가 실제 <area id="marker">로 다시 파싱됨(모든 따옴표/void 형식) | AREA_BYPASS — 취약함 | 0 |
| 사용자 이름이 HTML 이스케이프됨 | ESCAPED — 취약하지 않음 | 1 |
| 태그가 제거되고 텍스트만 남음 | STRIPPED — 취약하지 않음 | 1 |
원시 < area …>가 통과하지만 다시 파싱되지 않음 | RAW_TEXT_ONLY — 비활성 텍스트, 취약하지 않음 | 1 |
| 에코가 전혀 없음 | NOT_REFLECTED — 취약하지 않음 | 1 |
| 프로브 차단(HTTP ≥ 400 / 챌린지 페이지) 또는 대상 연결 불가 | 오류 | 2 |