
Drupal 11.4.8 — высокий — удалённый — XSS — перемещение блока: метки соседних элементов пропускают экранирование @label
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · drupal-move-block-markup
Разбор: https://abraxaslabs.tech/research/drupal-move-block-markup
Класс: Stored XSS Доступ: Удалённый
Drupal core 11.4.8 (61044508) - Drupal
SA-CORE-2026-012 переключил текущую строку Move Block на t('@label (current)'), которая проходит через Html::escape(). Соседние строки в том же регионе по-прежнему присваивают BlockPluginTrait::label() напрямую в #markup в MoveBlockForm. Эта метка — это configuration['label'], необработанное текстовое поле. Затем Renderer::ensureMarkupIsSafe применяет XSS-фильтрацию к строке со списком администраторских тегов, поэтому <b> (и другие администраторские теги) выживает.
Редактор Layout Builder, который может задать заголовку блока HTML, достигает другого редактора или администратора, открывающего Move на другом блоке в том же регионе. Stored XSS в диалоге Move. Не RCE и не LPE.
| ID | CVE пока нет |
| Класс | Stored XSS |
| Доступ | Удалённый (настройка блока в Layout Builder; жертва открывает Move Block) |
| CWE | CWE-79 |
| CVSS | Средний: 5.4 CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
| Продукт | Drupal core |
| Затронуто | 11.4.8 (61044508071749629aaf3380aa85971e94df9e84) |
| Аутентификация | Настройка блока в Layout Builder. Жертва открывает Move Block. |
| Лицензия | GNU Affero GPL v3.0 |
| Лаборатория | только 127.0.0.1 |
Автор: пользователь, который может размещать или настраивать блоки Layout Builder (не конфигурацию сайта). Жертва: другой редактор LB или администратор, открывающий Move на другом блоке в том же регионе.
| Привилегия | Метод / сток | Тип | Доказано в лаборатории или выведено |
|---|---|---|---|
| Вывод HTML атакующего в соседней строке диалога Move | $label['#markup'] = $plugin->label(); затем ensureMarkupIsSafe | Целостность HTML | Доказано в лаборатории. HTML соседней строки — <b class="lb-sib">DRUPAL-MOVE-BLOCK-MARKUP-WITNESS</b> |
Сохранение разметки администраторских тегов (<b> и остальных из Xss::getAdminTagList) | строковый #markup проходит XSS-фильтрацию по администраторскому списку, а не экранируется | Целостность HTML | Доказано в лаборатории для <b> |
| Сессия / действия от имени редактора-жертвы в origin Layout Builder | Stored XSS в этом диалоге | Целостность сессии жертвы | Выведено. Лаборатория останавливается на сыром HTML в соседней ячейке |
| Отрицательный: текущая строка | t('@label (current)', ...) | Закрыто | Доказано в лаборатории. <em class="lb-cur">... |
Отрицательный: соседняя строка через @label | исправленный путь гаджета | Закрыто | Доказано в лаборатории. <b class="lb-sib">... |
Закрыто по этому остатку: установка на живой сайт Drupal (эта лаборатория — гаджет); кража сессии через UI Layout Builder как измеряемый HTTP-оракул; RCE; LPE. Неаутентифицированные посетители не могут открыть Move Block.
Тот же остаток от пина: AttributeXss HTMX attrs.
Я зафиксировал Drupal 11.4.8 после SA-CORE-2026-012. Рекомендация закрыла заголовок текущего блока. MoveBlockForm.php 210-218:
if ($is_current_block) {
$label['#markup'] = $this->t('@label (current)', ['@label' => $plugin->label()]);
// ...
}
else {
$label['#markup'] = $plugin->label();
}
BlockPluginTrait::label() возвращает configuration['label'], если он задан. Renderer::ensureMarkupIsSafe не выполняет XSS-фильтрацию MarkupInterface (@label уже экранирован). Сырая строка фильтруется с использованием списка тегов администратора.
Уже зафиксированные неверные пути: считать текущую строку всё ещё сырой (это не так); утверждать, что это RCE; использовать живой сайт Drupal как единственный оракул (остаток — это данные функции); обратная оболочка. Театр.
python3 drupal-move-block-markup-Abraxas-Labs.py
или
cd lab
./run.sh
Нацелено только на http://127.0.0.1:19490. Точная копия функций 11.4.8 (остаток копии MoveBlockForm, FormattableMarkup, ensureMarkupIsSafe, Xss::filter). Не живой сайт drupal:11.4.8. Последняя строка использует how=gadget.
SUCCESS drupal-move-block-markup how=gadget sibling-raw-tag=yes current-escaped=yes patched-sibling-escaped=yes DRUPAL-MOVE-BLOCK-MARKUP-WITNESS
Используйте @label (или Html::escape) для каждой строки, а не только для текущего блока.
61044508071749629aaf3380aa85971e94df9e84)MoveBlockForm.php · BlockPluginTrait.phpGNU Affero GPL v3.0. См. LICENSE. Только для лаборатории с loopback. Без гарантий.