flawopen.com/Teardowns/cve-2026-87902-wordpress-page-template-path-traversal
CVE-2026-87902: WordPress 페이지 템플릿 경로 순회
검증되지 않은 디코딩 페이지 이름이 템플릿 해석에 사용되어 인증 없이 로컬 PHP를 포함할 수 있었습니다. RCE에는 특정 테마 및 PHP 조건이 필요합니다.[1]
책을 꺼내기 전에 요청을 확인하는 사서를 떠올려 보세요. WordPress는 템플릿으로 가는 한 경로를 확인했지만 디코딩된 이름 경로는 놓쳤습니다. 특수 경로 표시는 테마 디렉터리 밖으로 이어질 수 있었습니다. 수정은 이름을 검증하고 허용된 디렉터리 안에 제한합니다.[1], [2], [3]
핵심 개념 및 용어
경로 순회- 입력을 검증하지 않으면
..같은 요소가 의도한 디렉터리 밖으로 이동할 수 있습니다.[1] 로컬 PHP 포함- 서버에 이미 있는 PHP 파일을 로드합니다. RCE에는 추가 조건이 필요합니다.[1]
`validate_file()`- 사용 전에 허용되지 않는 경로 요소를 거부하는 WordPress 함수입니다.[3]
프레임워크 매핑
- 이 가이드에서 설명하는 약점의 CWE 참조: CWE-98
- CISA KEV — 추가일 2026-09-25 — CVE-2026-87902
근본 원인 분석 (Root Cause)
get_page_template()에서 WordPress는 pagename을 디코딩해 page-{name}.php를 추가했지만 취약 버전은 validate_file()을 적용하지 않았습니다. 인접 분기에는 검사가 있었습니다. 따라서 경로가 테마 밖으로 나갈 수 있었습니다. page-* 최상위 디렉터리와 읽을 수 있는 로컬 PHP가 필요하며 RCE에는 추가 PHP/서버 조건이 필요합니다. 7.1.2는 디코딩 값을 검증하고 locate_template()의 경로를 제한합니다. WordPress 권고문은 이 취약점을 CWE-98(PHP include/require에 사용되는 파일 이름의 부적절한 제어)로 분류하며, 발견과 책임 있는 공개의 공로를 Robert Ressl에게 돌립니다.[1], [2], [3], [7]
CVE-2026-87902 도달 조건: 노출 범위와 조건부 RCE
| 배포 조건 | 1차 출처가 확인한 내용 | 운영자 조치 |
|---|---|---|
| 영향받는 WordPress Core 브랜치 | GHSA는 영향을 받는 버전을 브랜치별로 나열하며, 범위는 4.7.0–4.7.36부터 7.1.0–7.1.1까지입니다. 해당 수정 버전은 4.7.37(가장 오래된 백포트)부터 7.1.2(현재 브랜치)까지이며, 나열된 각 브랜치마다 별도의 수정 버전이 있습니다. | 설치된 Core 버전을 확인하고 해당 브랜치의 수정 버전을 적용하세요. 4.7 이전 버전은 지원되는 릴리스로 업그레이드하세요. |
| 활성 테마 구조 | 활성 부모 또는 자식 테마에 이름이 page-로 시작하는 최상위 디렉터리(예: page-templates)가 있어야 합니다. | 활성 부모 테마와 자식 테마 디렉터리를 모두 확인하세요. 활성 테마를 바꾸면 이 조건을 다시 확인하세요. |
| 읽을 수 있는 로컬 PHP 파일 | 선택된 .php 파일이 활성 테마 디렉터리 밖에 존재하고 웹 서버 계정에서 읽을 수 있어야 합니다. | 웹 서버가 읽을 수 있는 로컬 PHP 파일을 확인하세요. CVE의 버전 범위만으로 파일 포함이 발생했다고 판단하지 마세요. |
| 조건부 RCE 환경 | 권고문은 추가 PHP/서버 조건이 충족될 때만 RCE를 설명합니다. 예로 register_argc_argv=On일 때의 pearcmd.php, 공식 PHP Docker 이미지, PHP 8.5 이전 버전을 사용하는 기본 cPanel 구성을 듭니다. | 실제 PHP 런타임과 설정을 평가하세요. 영향받는 WordPress 버전만으로 RCE나 침해가 입증되지는 않습니다. |
단계별 공격 실행 흐름
소스 코드 비교: 취약한 구현 vs 보안 패치
이 발췌문은 공식 7.1.1과 7.1.2 태그를 비교합니다. 패치는 디코딩 후 값을 검증하며 같은 릴리스는 locate_template()에서 해석 경로도 제한합니다. 이는 upstream 소스 변경이지 완전한 독립 패치나 익스플로잇 시연이 아닙니다.[2], [3]
소스 코드 발췌: wp-includes/template.php — get_page_template()
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename ) {
$templates[] = "page-{$pagename_decoded}.php";
}
}
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename && 0 === validate_file( $pagename_decoded ) ) {
$templates[] = "page-{$pagename_decoded}.php";
}
}
엔지니어링 및 시스템 보안 강화 체크리스트
- ✓사용 중인 브랜치의 수정 버전으로 업그레이드하고 실제 실행 코드를 확인하세요.[1], [4]
- ✓인터넷에 노출된 WordPress를 목록화하고 지원 종료된 4.7 미만 버전을 찾으세요.[1], [4]
- ✓패치 전 노출된 사이트는 로그와 예상치 못한 PHP 파일 및 계정을 확인하세요. 신호만으로 침해를 증명할 수는 없습니다.
- ✓사용자 지정 해석기에서 디코딩 후 경로 요소를 검증하고 실제 경로를 허용 디렉터리로 제한하세요.[1], [3]
- ✓Core와 테마를 지원 릴리스로 유지하세요. 테마 변경은 조건을 바꿀 수 있습니다.[1], [4]