
SureForms <= 2.2.0 - Cross-Site Scripting Armazenado Não Autenticado
Existe uma vulnerabilidade Stored XSS crítica no plugin SureForms. A vulnerabilidade decorre de uma implementação insegura no lado do cliente em entries.js, onde a entrada do usuário é decodificada programaticamente (revertendo a sanitização do lado do servidor) e depois renderizada usando dangerouslySetInnerHTML sem sanitização adequada no lado do cliente. Isso permite que atacantes não autenticados injetem payloads JavaScript maliciosos por meio de campos de formulário padrão, contornando os filtros padrão wp_kses do WordPress.
Para verificar se um site alvo está executando o SureForms, inspecione o cabeçalho do arquivo de tradução, que normalmente contém o número da versão.
URL Alvo:
http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot
Comando de Verificação:
curl -s "http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot" | grep "Project-Id-Version"
A vulnerabilidade reside na interface de administração baseada em React responsável pela visualização de entradas do formulário (entries.js).
No arquivo minificado entries.js, há uma função auxiliar (identificada como Xv na build analisada) projetada para lidar com entidades HTML.
Lógica do Código (Reconstruída):
// Função Xv: Pré-processamento de valores de campo
var Xv = function(input) {
var value = input.value;
// CAUSA RAIZ DA VULNERABILIDADE:
// Se a string contiver entidades HTML (ex.: <), crie uma textarea,
// injete o conteúdo e extraia o valor.
// Isso efetivamente DECODIFICA entidades HTML de volta para tags HTML brutas.
// Exemplo: "<img ...>" torna-se ""
if (typeof value === "string" && value.match(/&[a-zA-Z0-9#]+;/)) {
var textarea = document.createElement("textarea");
textarea.innerHTML = value;
// Lógica para reverter a sanitização
if (textarea.value.includes("<") || textarea.value.includes(">")) {
value = textarea.value; // Agora 'value' contém HTML BRUTO
}
}
return { ...input, value: value };
}
Análise: Esta função anula a segurança do backend. Mesmo que o WordPress armazene corretamente <script> como <script> no banco de dados, esta função o converte de volta para <script> imediatamente após obtê-lo da API.
Após a decodificação, os dados são passados para o componente de renderização (identificado como Jv).
Lógica do Código (Reconstruída):
// Função Jv: Renderização do campo
var Jv = function(props) {
var field = props.field;
var val = field.value; // Este valor agora é HTML bruto (pós-decodificação)
// O GATILHO: Verifica se a string parece HTML
if (typeof val === "string" && val.match(/<[^>]+>/g)) {
// O SINK: Renderiza usando dangerouslySetInnerHTML SEM sanitização do lado do cliente (ex.: DOMPurify)
return React.createElement("span", {
dangerouslySetInnerHTML: { __html: val }
});
}
// Renderização segura para texto não HTML
return React.createElement("span", null, val);
}
Injeção: Um atacante não autenticado envia um formulário no front-end. Em vez de usar tags HTML brutas (que seriam removidas/sanitizadas pelo backend do WordPress), o atacante envia Entidades HTML.
Armazenamento: O WordPress vê a entrada (ex.: <img...) como texto seguro e a armazena no banco de dados.
Execução (A Armadilha):
Xv detecta as entidades e decodifica <img... de volta para ` Entries.Clique na entrada enviada no Passo 1 para visualizar os detalhes.
Resultado: O navegador executará o payload JavaScript (alert('XSS_SUREFORMS')).