
Drupal 11.4.8 - Alta - Remoto - XSS - Move Block: rótulos irmãos ignoram o escape de @label
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · drupal-move-block-markup
Classe: XSS Armazenado Alcance: Remoto
Drupal core 11.4.8 (61044508) - Drupal
SA-CORE-2026-012 alterou a linha atual do Move Block para t('@label (current)'), que aplica Html::escape(). Linhas irmãs na mesma região ainda atribuem BlockPluginTrait::label() diretamente a #markup em MoveBlockForm. Esse label é configuration['label'], um campo de texto bruto. Renderer::ensureMarkupIsSafe então aplica filtro XSS a uma string com a lista de tags de admin, então um <b> (e outras tags de admin) sobrevive.
Um editor do Layout Builder que pode definir o título de um bloco como HTML alcança outro editor ou admin que abre Move em um bloco diferente naquela região. XSS Armazenado no diálogo Move. Não é RCE e não é LPE.
| ID | ainda sem CVE |
| Classe | XSS Armazenado |
| Alcance | Remoto (configuração de bloco do Layout Builder; vítima abre Move Block) |
| CWE | CWE-79 |
| CVSS | Médio: 5.4 CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
| Produto | Drupal core |
| Afetado | 11.4.8 (61044508071749629aaf3380aa85971e94df9e84) |
| Autenticação | Configuração de bloco do Layout Builder. Vítima abre Move Block. |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1 |
Autor: usuário que pode posicionar ou configurar blocos do Layout Builder (não configuração do site). Vítima: outro editor de LB ou admin que abre Move em um bloco diferente na mesma região.
| Privilégio | Método / sink | Tipo | Comprovado em lab ou inferido |
|---|---|---|---|
| Imprimir HTML do atacante na linha irmã do diálogo Move | $label['#markup'] = $plugin->label(); então ensureMarkupIsSafe | Integridade do HTML | Comprovado em lab. HTML irmão é <b class="lb-sib">DRUPAL-MOVE-BLOCK-MARKUP-WITNESS</b> |
Manter markup de tag de admin (<b>, e o resto de Xss::getAdminTagList) | string #markup é filtrada por XSS com a lista de admin, não escapada | Integridade do HTML | Comprovado em lab para <b> |
| Sessão / ações como o editor vítima na origem do Layout Builder | XSS Armazenado naquele diálogo | Integridade da sessão da vítima | Inferido. Lab para em HTML bruto na célula irmã |
| Negativo: linha atual | t('@label (current)', ...) | Fechado | Comprovado em lab. <em class="lb-cur">... |
Negativo: irmão através de @label | caminho de gadget corrigido | Fechado | Comprovado em lab. <b class="lb-sib">... |
Fechado neste resíduo: instalação de site Drupal ao vivo (este lab é um gadget); roubo de sessão da UI do Layout Builder como oráculo HTTP medido; RCE; LPE. Visitantes não autenticados não podem abrir Move Block.
Mesmo resíduo de pin: AttributeXss HTMX attrs.
Fiz pin do Drupal 11.4.8 após o SA-CORE-2026-012. O advisory fechou o título do bloco atual. MoveBlockForm.php 210-218:
if ($is_current_block) {
$label['#markup'] = $this->t('@label (current)', ['@label' => $plugin->label()]);
// ...
}
else {
$label['#markup'] = $plugin->label();
}
BlockPluginTrait::label() retorna configuration['label'] quando definido. Renderer::ensureMarkupIsSafe não aplica filtro XSS a MarkupInterface (@label já escapado). Uma string bruta é filtrada com a lista de tags de admin.
Caminhos errados já registrados: tratar a linha atual como ainda bruta (não é); afirmar que isto é RCE; um site Drupal ao vivo como único oráculo (o resíduo são estas funções); um reverse shell. Teatro.
python3 drupal-move-block-markup-Abraxas-Labs.py
ou
cd lab
./run.sh
Alvo apenas http://127.0.0.1:19490. Gadget fiel das funções 11.4.8 (cópia do resíduo de MoveBlockForm, FormattableMarkup, ensureMarkupIsSafe, Xss::filter). Não é um site drupal:11.4.8 ao vivo. A última linha usa 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
Use @label (ou Html::escape) para cada linha, não apenas o bloco atual.
61044508071749629aaf3380aa85971e94df9e84)MoveBlockForm.php · BlockPluginTrait.phpGNU Affero GPL v3.0. Veja LICENSE. Apenas lab em loopback. Sem garantia.