SITUATION Security research & response knowledge base UTC+09 · SEOUL
INTELLIGENCE REPORT TLP:CLEAR

WordPress CVE-2026-64638: XSS2Shell Pre-Auth XSS에서 RCE까지

WordPress 로그인 화면의 reflected XSS가 관리자 상호작용을 거쳐 PHP 코드 실행으로 이어지는 원인, 영향 버전, 탐지와 대응

#cve-2026-64638#wordpress#xss2shell#reflected-xss#dom-clobbering#rce#incident-response

TL;DR

  • CVE-2026-64638, 일명 XSS2Shell은 WordPress Core 로그인 화면의 pre-auth reflected XSS 취약점이다. CVSS v4.0 점수는 8.9(High), 분류는 CWE-79다.
  • 초기 XSS 요청에는 계정이 필요하지 않지만, 공개된 RCE 체인은 공격자가 준비한 외부 페이지에 로그인된 관리자가 속아 명시적으로 상호작용하고 몇 가지 환경 조건이 맞아야 완성된다. 따라서 이를 “인터넷에서 즉시 가능한 무인증·무클릭 RCE”로 표현하면 부정확하다.
  • WordPress는 2026년 8월 6일 7.0.3에서 수정했으며 4.7까지 각 브랜치에 보안 수정 사항을 backport했다. 2026년 8월 27일 기준 최신 메이저 릴리스는 7.1이므로, 가능하면 호환성 검증 후 7.1 또는 사용 중인 브랜치의 최신 보안 릴리스로 업데이트해야 한다.
  • 패치는 로그인 오류에 포함되는 사용자 이름과 이메일을 HTML 문맥에 맞게 escape한다. 입력값을 여러 HTML parser가 서로 다르게 해석하면서 생긴 parser differential의 시작점을 차단한 것이다.
  • 공개 연구에는 동작하는 PoC와 전체 공격 체인이 포함돼 있다. 업데이트 전 노출 이력이 있다면 Application Password, 관리자 활동, REST API 요청, 새 페이지와 플러그인 파일을 함께 조사해야 한다.

취약점 개요

항목 내용
CVE CVE-2026-64638
별칭 XSS2Shell
대상 WordPress Core 로그인 화면
취약점 유형 Pre-auth reflected XSS
최종 영향 조건 충족 시 관리자 권한 악용과 PHP 코드 실행
심각도 CVSS v4.0 8.9 High
Vector CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
사용자 상호작용 필요(UI:A)
최초 수정 WordPress 7.0.3 및 4.7 이상 유지 브랜치의 backport

“Pre-auth”는 공격자가 취약한 입력을 로그인 전에 보낼 수 있다는 뜻이다. RCE까지 사용자 상호작용이 없다는 뜻은 아니다. WordPress 공식 권고도 공격자 외부 사이트를 이용한 사회공학과 피해자의 명시적 상호작용이 필요하며, 공격자가 통제할 수 없는 조건이 존재한다고 설명한다.

공개된 체인은 로그인된 관리자의 브라우저 문맥과 권한을 이용한다. 피해자가 관리자 세션을 보유하지 않았거나 Application Password 기능과 후속 권한 조건이 맞지 않으면 동일한 최종 결과에 도달하지 못할 수 있다. 반대로 XSS 자체는 관리자 세션을 노린 다른 공격으로 변형될 수 있으므로 특정 RCE 단계가 실패한다고 안전한 것은 아니다.

Application Password는 WordPress 5.6부터 Core에 포함됐다. 따라서 아래 공개 체인의 credential 발급 단계는 5.6 이상을 중심으로 읽어야 하며, 4.7–5.5에 동일한 RCE 후속 단계가 그대로 존재한다고 단정해서는 안 된다. 다만 공식 권고는 해당 구버전도 reflected XSS 영향 범위에 포함하며, 수정 릴리스로 업데이트하도록 안내한다.

영향받는 버전과 업데이트 기준

WordPress 공식 GitHub Security Advisory가 명시한 CVE-2026-64638의 최소 수정 버전은 다음과 같다.

브랜치 취약 버전 최소 수정 버전
7.0 7.0.0–7.0.2 7.0.3
6.9 6.9.0–6.9.5 6.9.6
6.8 6.8.0–6.8.6 6.8.7
6.7 6.7.0–6.7.5 6.7.6
6.6 6.6.0–6.6.5 6.6.6
6.5 6.5.0–6.5.8 6.5.9
6.4 6.4.0–6.4.8 6.4.9
6.3 6.3.0–6.3.8 6.3.9
6.2 6.2.0–6.2.9 6.2.10
6.1 6.1.0–6.1.10 6.1.11
6.0 6.0.0–6.0.12 6.0.13
5.9 5.9.0–5.9.13 5.9.14
5.8 5.8.0–5.8.13 5.8.14
5.7 5.7.0–5.7.15 5.7.16
5.6 5.6.0–5.6.17 5.6.18
5.5 5.5.0–5.5.18 5.5.19
5.4 5.4.0–5.4.19 5.4.20
5.3 5.3.0–5.3.21 5.3.22
5.2 5.2.0–5.2.24 5.2.25
5.1 5.1.0–5.1.22 5.1.23
5.0 5.0.0–5.0.25 5.0.26
4.9 4.9.0–4.9.29 4.9.30
4.8 4.8.0–4.8.28 4.8.29
4.7 4.7.0–4.7.33 4.7.34

이 표는 이 CVE만을 기준으로 한 최소선이다. 이후 8월 12일 별도의 보안 수정이 7.0.4와 각 유지 브랜치에 추가됐고, 8월 19일 WordPress 7.1이 정식 공개됐다. 운영 환경에서는 표의 최소 버전에 머물지 말고 현재 브랜치의 최신 보안 릴리스 또는 최신 WordPress 7.1을 사용한다.

WordPress 4.6 이하는 현재 보안 업데이트를 받지 않는다. 해당 버전에 backport가 없다는 사실을 “영향 없음”으로 해석해서는 안 되며, 지원되는 최신 버전으로 마이그레이션해야 한다.

근본 원인: 두 HTML parser의 해석 차이

시작점은 로그인 실패 메시지다. 존재하지 않는 사용자 이름으로 로그인을 시도하면 wp_authenticate_username_password()가 입력값을 오류 문장에 삽입했다.

sprintf(
    __( '<strong>Error:</strong> The username <strong>%s</strong> is not registered on this site.' ),
    $username
)

사용자 이름은 앞단에서 sanitize_user()를 거치며, 이 함수의 처리 과정에는 wp_strip_all_tags()와 PHP의 strip_tags()가 사용된다. 그러나 PHP parser가 태그로 보지 않는 비정상적인 공백 형태를 WordPress의 KSES parser와 브라우저는 유효한 요소로 다시 해석할 수 있었다.

attacker-controlled username
  └─ sanitize_user() / wp_strip_all_tags()
      └─ PHP strip_tags()는 일부 비정상 형식을 일반 문자열로 판단
          └─ 로그인 오류 메시지에 escape 없이 삽입
              └─ wp_kses_post()와 브라우저는 허용된 HTML 요소로 재해석

각 필터를 따로 보면 “태그 제거”와 “허용된 HTML만 통과”라는 방어가 존재한다. 문제는 동일한 문자열을 parser마다 다르게 이해했다는 점이다. 불신 입력을 HTML에 넣기 직전 문맥에 맞게 escape하지 않고, 서로 다른 sanitizer의 조합에 의존한 것이 취약점의 핵심이다.

XSS가 PHP 코드 실행으로 확장되는 과정

로그인 오류에 HTML 요소가 만들어지는 것만으로는 아직 JavaScript가 실행되지 않는다. 공개 연구는 WordPress Core의 여러 정상 기능을 연결해 이 primitive를 확장했다.

  1. 공격자가 준비한 외부 웹 페이지로 로그인된 관리자를 유도한다.
  2. 로그인 실패 메시지에 삽입된 요소가 로그인 화면에서 실제 DOM으로 생성된다.
  3. 로그인 화면에도 로드되는 user-profile.js가 공격자가 만든 DOM 구조와 자동으로 상호작용한다.
  4. DOM clobbering으로 정상 JavaScript가 참조하는 URL 값이 공격자 의도대로 바뀌고, WordPress origin으로 요청이 발생한다.
  5. WordPress REST API의 JSONP 응답과 jQuery의 script 처리 동작이 결합돼 WordPress origin에서 JavaScript 실행 primitive가 만들어진다.
  6. Same Origin Method Execution(SOME) 방식으로 관리자 브라우저의 Application Password 승인 동작을 유발한다.
  7. 발급된 관리자 Application Password로 REST API를 호출해 공격자 JavaScript가 포함된 콘텐츠를 게시한다.
  8. 관리자 origin에서 실행된 JavaScript가 유효한 nonce와 권한을 이용해 악성 플러그인을 업로드하고, 웹에서 접근 가능한 PHP 파일을 실행한다.
pre-auth login input
  └─ reflected HTML elements
      └─ DOM clobbering + WordPress JavaScript gadget
          └─ REST JSONP / same-origin JavaScript execution
              └─ logged-in admin interaction and Application Password
                  └─ authenticated content creation
                      └─ plugin upload
                          └─ PHP code execution

이 체인은 “취약한 서버가 요청 하나를 받으면 곧바로 셸을 실행한다”는 형태가 아니다. 공격자의 최초 요청에는 인증이 필요 없지만, 최종 RCE에는 로그인된 관리자, 사회공학, 브라우저 창 관계, Application Password와 관리자 권한 등 여러 단계가 필요하다. 이것이 CVSS에서 Attack Complexity가 High이고 User Interaction이 Active인 이유다.

패치는 무엇을 바꿨나

7.0 브랜치의 공개 수정 커밋은 오류 메시지에 포함되는 사용자 이름과 이메일에 esc_html()을 적용했다.

sprintf(
    __( '<strong>Error:</strong> The username <strong>%s</strong> is not registered on this site.' ),
    esc_html( $username )
)

이제 attacker-controlled value가 HTML 문법으로 재해석되지 않고 텍스트로 출력된다. 같은 커밋은 비밀번호 오류에 표시되는 사용자 이름·이메일과 URL·attribute 문맥도 각각 esc_html(), esc_url(), esc_attr()로 처리했다.

핵심은 입력 정제만 믿지 않고, 실제 HTML 출력 지점에서 contextual escaping을 적용한 것이다. 공격자가 만든 문자열이 KSES와 브라우저에서 DOM 요소로 재해석되기 전에 텍스트로 고정되므로 이후 user-profile.js, DOM clobbering과 REST JSONP를 연결할 시작점이 사라진다.

공개 PoC와 실제 악용을 구분해서 보기

pwn.ai는 8월 6일 기술 분석과 동작하는 PoC를 공개했다. 따라서 공격자가 차이를 분석해야만 했던 패치 직후와 달리, 현재는 취약점 재현과 자동화에 필요한 정보가 공개된 상태다.

캐나다 Cyber Centre는 8월 10일 공지에서 open-source reporting을 근거로 실제 악용이 보고됐다고 적었다. 다만 WordPress 공식 권고와 공개 CVE record에는 특정 공격 campaign, 피해 조직 또는 성공한 대규모 침해를 입증하는 세부 정보가 없다. 그러므로 현재 근거는 다음처럼 구분하는 것이 안전하다.

  • 공개 PoC와 전체 공격 체인: 확인됨
  • 인터넷에서의 악용 주장: 정부 공지에 인용됨
  • 특정 조직의 성공적인 RCE 또는 대규모 campaign: 공개 근거만으로 확인되지 않음

실제 악용 규모가 불명확하더라도 Core 로그인 화면이라는 넓은 공격 표면과 공개 PoC 때문에 패치 우선순위는 높다. “확인된 침해가 없다”는 이유로 업데이트를 미뤄서는 안 된다.

즉시 대응

1. Core 업데이트

먼저 WordPress document root에서 버전과 업데이트 가능 여부를 확인한다.

wp core version
wp core check-update
wp core update
wp core verify-checksums --include-root

2026년 8월 27일 기준 가능하면 WordPress 7.1로 이동한다. 호환성 문제로 기존 브랜치에 남아야 한다면 해당 브랜치의 최신 보안 릴리스를 사용하고, 위 표의 CVE별 최소 수정 버전보다 낮지 않은지 확인한다. 관리 화면을 사용할 경우 Dashboard → Updates에서 업데이트 결과와 자동 background update 성공 여부를 검증한다.

2. 긴급 완화

업데이트 전 짧은 시간 동안에는 다음 조치를 검토할 수 있다.

  • 관리용 wp-login.php/wp-admin/ 접근을 VPN, identity-aware proxy 또는 승인된 IP로 제한
  • 사용하지 않는 Application Password 기능을 임시 비활성화하거나 관리자별 허용 정책 적용
  • 운영상 가능한 경우 DISALLOW_FILE_MODS로 플러그인·테마 설치 및 파일 변경 경로 제한
  • WAF에서 비정상 로그인 POST, REST JSONP parameter, Application Password 승인 경로를 집중 로깅·차단

이 조치는 공개된 체인의 일부 단계를 어렵게 만들 뿐 XSS를 제거하지 않는다. 특히 DISALLOW_FILE_MODS는 Core 업데이트도 방해할 수 있으므로 업데이트 절차와 충돌하지 않게 적용해야 한다. WAF signature 역시 parser 차이와 encoding 변형을 모두 다룬다는 보장이 없으므로 패치를 대체하지 못한다.

침해 점검

Application Password와 관리자 계정

공개된 RCE 체인의 핵심 전환점은 관리자 Application Password다. 먼저 관리자 ID를 확인하고 각 계정의 credential 생성 시각, 최근 사용 시각과 source IP를 검토한다.

wp user list --role=administrator --fields=ID,user_login,user_email,user_registered --format=table
wp user application-password list <USER_ID> --fields=uuid,name,created,last_used,last_ip --format=table

조사 결과를 보존한 뒤 출처를 설명할 수 없는 credential은 폐기한다. 침해 가능성이 높고 정상 연동 영향을 파악했다면 해당 관리자의 Application Password를 모두 폐기하는 방법도 있다.

wp user application-password delete <USER_ID> <UUID>
wp user application-password delete <USER_ID> --all

다음 항목도 함께 확인한다.

  • 취약 기간에 생성됐거나 권한이 상승한 관리자·편집자 계정
  • 알 수 없는 Application Password 이름, 생성 시각, last_ip
  • 관리자 이메일, 비밀번호, role과 capability 변경
  • 관리자 세션의 비정상 source IP·User-Agent·접속 시간
  • 승인되지 않은 REST API integration과 외부 callback domain

웹·WAF 로그

공개 체인의 시간 순서와 맞는 이벤트를 서로 연관 지어 본다.

  • POST /wp-login.php 직후 비정상 REST API 요청
  • _jsonp, _method=GET, _envelope=1, rest_route가 함께 나타나는 요청
  • /wp-admin/authorize-application.php 접근과 Application Password 생성
  • /wp-json/wp/v2/pages를 통한 새 페이지 생성 또는 수정
  • /wp-admin/update.php?action=upload-plugin 접근과 plugin ZIP 업로드
  • 직후 새 /wp-content/plugins/<unknown>/...php 파일에 대한 직접 요청
  • 관리자 브라우저가 평소 접속하지 않던 외부 domain으로 이동한 정황

기본 Apache·NGINX access log에는 POST body가 기록되지 않는 경우가 많다. 이 경우 wp-login.php 요청만 보이고 취약한 사용자 이름 값은 남지 않을 수 있다. 반대로 _jsonpauthorize-application.php가 있었다는 사실만으로 공격 성공을 단정해서도 안 된다. 같은 시간대의 관리자 세션, Application Password 생성, 콘텐츠와 파일 변경까지 이어졌는지 확인한다.

콘텐츠와 파일 시스템

wp post list --post_type=page --fields=ID,post_title,post_status,post_date,post_author --format=table
wp plugin list --fields=name,status,version,update --format=table
find wp-content/plugins wp-content/mu-plugins wp-content/themes -type f -mtime -30 -print
find wp-content/uploads -type f -name '*.php' -print

점검 시 확인할 항목은 다음과 같다.

  • 짧은 시간만 공개됐다가 삭제·비공개 처리된 페이지와 게시물 revision
  • 설명할 수 없는 plugin directory, PHP 파일, must-use plugin과 theme 변경
  • 업로드 디렉터리의 PHP·phar·phtml 등 실행 가능 파일
  • wp-config.php, .htaccess, 웹 서버 virtual host와 scheduled task 변경
  • 웹 프로세스가 실행한 shell, downloader, archive utility와 비정상 외부 통신
  • Core checksum 결과와 공식 배포본의 차이

wp core verify-checksums는 WordPress Core 파일을 확인할 뿐 플러그인, 테마, 업로드, 데이터베이스 변조까지 증명하지 않는다. 깨끗한 결과만으로 침해가 없었다고 결론 내리면 안 된다.

침해가 의심될 때

  1. 서버와 관련 로그, 데이터베이스, 파일 시스템 snapshot을 보존한다.
  2. 의심 Application Password를 폐기하고 관리자 세션을 종료한 뒤 관리자·호스팅·배포 자격 증명을 교체한다.
  3. WordPress salts를 교체하고 외부 API key, DB password, SFTP·SSH credential의 유출 가능성을 평가한다.
  4. 신뢰할 수 있는 새 환경 또는 clean backup에서 Core를 재배포하고 플러그인·테마를 공식 출처로 다시 설치한다.
  5. 데이터베이스에서 계정, capability, 페이지, 옵션, cron과 plugin activation 변경을 조사한다.
  6. WAF·CDN·origin·EDR 로그를 하나의 시간축으로 결합해 최초 접근, 관리자 상호작용, credential 생성, 파일 업로드와 후속 명령 실행을 확인한다.
  7. 복구 후 관리자 MFA, Application Password 최소화, 관리 경로 접근 제어, 파일 무결성 감시와 로그 중앙 수집을 적용한다.

웹셸 하나만 삭제하고 운영을 재개하면 공격자가 만든 계정, Application Password, 예약 작업 또는 변조된 플러그인이 남을 수 있다. PHP 코드 실행이 확인됐다면 해당 서버와 그 서버가 접근할 수 있던 secret을 신뢰하지 않는 것이 원칙이다.

결론

CVE-2026-64638의 핵심은 작은 parser 해석 차이가 WordPress 로그인 화면의 정상 JavaScript, REST JSONP, Application Password와 관리자 기능을 거치며 서버 코드 실행까지 확장됐다는 점이다.

대응 우선순위는 명확하다.

  1. WordPress 7.1 또는 현재 브랜치의 최신 보안 릴리스로 업데이트
  2. 취약 기간의 로그인·REST·Application Password·plugin upload 활동 조사
  3. 관리자 계정, 새 콘텐츠와 파일 시스템 무결성 확인
  4. 의심 credential과 세션 폐기, 침해 확인 시 clean rebuild 수행

초기 primitive가 pre-auth라는 사실과 최종 RCE에 관리자 상호작용이 필요하다는 사실은 동시에 참이다. 어느 한쪽만 강조해 과장하거나 위험을 축소하지 않는 것이 이 취약점을 정확하게 다루는 출발점이다.

References


본 문서는 승인된 환경의 방어와 사고 대응을 위한 자료다. 취약점 검증은 반드시 소유하거나 명시적으로 허가받은 시스템에서만 수행해야 한다.