
독립적인 근본 원인 분석 및 WordPress의 인증되지 않은 SQL 인젝션에서 RCE로 이어지는 개념 증명(CVE-2026-63030 + CVE-2026-60137)으로, Docker 랩과 상세한 익스플로잇 체인 문서를 포함합니다.
WordPress 코어는 2026-07-17에 wp2shell을 기본 설치(WordPress 6.9.0-6.9.4, 7.0.0-7.0.1, 플러그인 불필요)에 영향을 주는 치명적이고 인증되지 않은 RCE로 공개했습니다. 원래 발견자(Searchlight Cyber)는 공개 시점에 기술적 세부 사항을 공개하지 않았습니다. 이 저장소는 취약한 버전(6.9.4)과 패치된 버전(6.9.5) 사이의 WordPress 코어 소스 diff와 로컬 랩에서의 실시간 검증만을 기반으로 도출된 독립적 근본 원인 분석을 문서화합니다.
크레딧: 여기의 재현은 sergiointel/wp2shell-poc의 요청 형태를 따르며, 바이트 단위로 확인되고 실제 패치 diff와 교차 검증되었습니다.
root_cause_analysis.md - 전체 분석 문서: 연결된 두 버그, 정확한 취약 코드, 패치 diff, 익스플로잇 체인, 실제 WP 6.9.4 인스턴스에 대한 실시간 전후 검증.poc_upstream.py - sergiointel의 원본 PoC(SQLi 전용)의 수정되지 않은 사본.poc_upstream_rce.py - 공개 약 22시간 후 업데이트된 sergiointel의 PoC로, 어떤 자격 증명도 크래킹하지 않고 인증되지 않은 권한 상승 및 RCE를 추가합니다. root_cause_analysis.md의 섹션 7을 참조하십시오.poc_extract.py / poc_extract2.py - Docker/프록시 환경에서 업스트림 스크립트의 기본 SLEEP(0.15)가 네트워크 지터로 손실되어 신뢰할 수 있는 신호를 얻는 데 필요한 튜닝된 변형(더 큰 SLEEP(), 더 높은 타이밍 임계값, 더 긴 문자 검색 상한).docker-compose.yml - 검증에 사용된 것과 동일한 WordPress 6.9.4 + MariaDB 랩을 실행합니다.payload.json, response.json, response_patched.json - PoC의 구조를 복제하는 수동 제작 요청과 6.9.5 패치 파일을 적용하기 전후의 원시 서버 응답.두 번째로 독립적으로 작성된 PoC(github.com/Icex0/wp2shell-poc)가 전체적으로 검토되었으며 동일한 근본 원인 메커니즘을 독립적으로 설명하여 아래 분석을 뒷받침합니다. 내용 기반(부울, 타이밍 기반 아님) 블라인드 SQLi 추출을 사용하여 이 랩의 관리자 자격 증명 해시가 100% 정확도로 복구되었고, 알려진 자격 증명을 사용하여 SQLi-to-RCE 전체 체인이 실시간으로 시연되었습니다: SQL 주입에서 자격 증명 추출, 인증된 플러그인 업로드 웹셸, www-data로 코드 실행. root_cause_analysis.md의 섹션 6을 참조하십시오.
그 자격 증명 크래킹 경로는 실제이지만 유일한 경로는 아닙니다. sergiointel의 PoC는 이후 UNION SELECT를 사용하여 WordPress 자체 Customizer/nav-menu/oEmbed-cache 코드가 인증되지 않은 사용자 생성 요청이 성공하도록 신뢰하는 가짜 데이터베이스 행을 위조함으로써 자격 증명 크래킹 없이 인증되지 않은 RCE를 달성하도록 업데이트되었습니다. root_cause_analysis.md의 섹션 7을 참조하십시오. 인증되지 않은 SQL 주입만으로도 기본 설치에서 전체 RCE에 충분합니다.
CVE-2026-63030 (REST 배치 경로 혼동, CWE-436):
WP_REST_Server::serve_batch_request_v1()은 단순 push로 $matches[] 배열에 추가하지만, 하위 요청의 경로가 구문 분석에 실패하면(예: 의도적으로 잘못된 "http://:" 항목) 추가를 건너뜁니다. 이 한 번의 건너뜀으로 인해 이후의 모든 항목에 대해 $matches[]가 $requests[]와 한 인덱스씩 동기화되지 않습니다. 디스패치 시점에 $matches[$i]는 더 이상 $requests[$i]에 해당하지 않으므로 코드는 실제로 검증된 경로가 아닌 다른 경로의 일치하는 핸들러 아래에서 요청의 데이터를 실행하게 됩니다.
CVE-2026-60137 (SQL 주입): WP_Query::get_posts()는 is_array() 분기 내부에서만 author__not_in에 대해 absint() 정리를 실행했습니다. 스칼라 문자열 값은 정리를 완전히 건너뛰고 ... post_author NOT IN ($value)에 직접 연결되었습니다.
연쇄: 경로 혼동 버그를 통해 공격자는 /wp/v2/categories에 대해 선언된 요청(author_exclude를 인식하지 않으므로 정리되지 않음)이 실제로 posts 컨트롤러(author_exclude를 읽고 WP_Query로 전달함)를 통해 디스패치되도록 할 수 있습니다. 인증이 필요하지 않습니다.
RCE 주장에 대해: 인증되지 않은 블라인드 SQL 주입이 작동하며 wp_users.user_pass를 포함한 임의의 DB 콘텐츠를 유출할 수 있음을 실시간으로 확인했습니다. 가상화된 랩에서 단일 타이밍 기반 추출 패스는 상당한 비트 오류 노이즈(여기 테스트에서 문자당 약 94% 정확도)가 있었습니다. 콘텐츠 기반(부울) 오라클은 그러한 실패 모드를 공유하지 않았으며 동일한 필드를 100% 정확도로 복구했습니다. RCE는 두 가지 경로로 확인되었습니다: 복구된 비밀번호 해시 크래킹(비밀번호 강도에 따라 다름)과 WordPress 자체 Customizer/nav-menu/oEmbed-cache 코드가 신뢰하는 UNION-위조 데이터베이스 행을 사용하는 인증되지 않은 권한 상승 가젯 체인(무조건적, 자격 증명 손상 불필요). root_cause_analysis.md의 섹션 7을 참조하십시오.
docker compose up -d
# WordPress 설치 마법사가 :8890에서 접근 가능해질 때까지 기다린 후 설정을 완료하십시오
HTTP_PROXY=http://127.0.0.1:8080 HTTPS_PROXY=http://127.0.0.1:8080 \
python3 poc_extract2.py http://localhost:8890 "SELECT DATABASE()"
전체 기술 문서는 root_cause_analysis.md를 참조하십시오.
WordPress는 공식 수정 사항을 게시했습니다: 6.9.5 및 7.0.2(베타 브랜치용 7.1 Beta 2), 2026-07-17 출시. 영향을 받는 버전을 실행 중이라면 즉시 업데이트하십시오. 이 저장소는 패치가 이미 공개된 후 방어 및 교육 목적으로 게시되었습니다. 여기의 코드는 소유한 시스템이나 명시적으로 테스트가 승인된 시스템에서만 실행하십시오.