
SureForms <= 2.2.0 - Cross-Site Scripting Almacenado No Autenticado
Existe una vulnerabilidad crítica de XSS Almacenado en el plugin SureForms. La vulnerabilidad se origina en una implementación insegura del lado del cliente en entries.js, donde la entrada del usuario se decodifica programáticamente (revirtiendo la sanitización del lado del servidor) y luego se renderiza usando dangerouslySetInnerHTML sin una sanitización adecuada en el cliente. Esto permite a atacantes no autenticados inyectar cargas útiles de JavaScript malicioso a través de campos de formulario estándar, evadiendo los filtros predeterminados de WordPress.
wp_ksesPara verificar si un sitio objetivo está ejecutando SureForms, inspeccione el encabezado del archivo de traducción, que normalmente contiene el número de versión.
URL objetivo:
http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot
Comando de verificación:
curl -s "http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot" | grep "Project-Id-Version"
La vulnerabilidad reside en la interfaz administrativa basada en React encargada de ver las entradas del formulario (entries.js).
En el archivo entries.js minificado, existe una función auxiliar (identificada como Xv en la compilación analizada) diseñada para manejar entidades HTML.
Lógica del código (reconstruida):
// Function Xv: Pre-processing field values
var Xv = function(input) {
var value = input.value;
// VULNERABILITY ROOT CAUSE:
// If the string contains HTML entities (e.g., <), create a textarea,
// inject the content, and extract the value.
// This effectively DECODES HTML entities back to raw HTML tags.
// Example: "<img ...>" becomes ""
if (typeof value === "string" && value.match(/&[a-zA-Z0-9#]+;/)) {
var textarea = document.createElement("textarea");
textarea.innerHTML = value;
// Logic to revert sanitization
if (textarea.value.includes("<") || textarea.value.includes(">")) {
value = textarea.value; // Now 'value' contains RAW HTML
}
}
return { ...input, value: value };
}
Análisis: Esta función anula la seguridad del backend. Incluso si WordPress almacena correctamente <script> como <script> en la base de datos, esta función lo convierte de nuevo a <script> inmediatamente después de obtenerlo de la API.
Después de la decodificación, los datos se pasan al componente de renderizado (identificado como Jv).
Lógica del código (reconstruida):
// Function Jv: Rendering the field
var Jv = function(props) {
var field = props.field;
var val = field.value; // This value is now raw HTML (post-decoding)
// THE TRIGGER: Check if the string looks like HTML
if (typeof val === "string" && val.match(/<[^>]+>/g)) {
// THE SINK: Render using dangerouslySetInnerHTML WITHOUT client-side sanitization (e.g., DOMPurify)
return React.createElement("span", {
dangerouslySetInnerHTML: { __html: val }
});
}
// Safe render for non-HTML text
return React.createElement("span", null, val);
}
Inyección: Un atacante no autenticado envía un formulario en el frontend. En lugar de usar etiquetas HTML crudas (que serían eliminadas/sanitizadas por el backend de WordPress), el atacante envía Entidades HTML.
Almacenamiento: WordPress ve la entrada (por ejemplo, <img...) como texto seguro y la almacena en la base de datos.
Ejecución (La Trampa):
Xv detecta las entidades y decodifica <img... de vuelta a ` Entries.Haga clic en la entrada enviada en el Paso 1 para ver los detalles.
Resultado: El navegador ejecutará la carga útil de JavaScript (alert('XSS_SUREFORMS')).