Config Fantasma
DOM Clobbering
// OBJETIVO
Sin ejecutar JavaScript, hacer que window.appConfig.isAdmin sea verdadero para desbloquear el rol admin.
// ZONA DE ATAQUE
Corre en un iframe de origen opaco: no puede leer este sitio ni tu progreso. Cuando logres el exploit, la flag aparece dentro de la app — copiala y verificala.
// CONSULTÁ
Pistas
Código vulnerable
El panel confía en variables globales que en realidad puede definir el HTML:
const html = sanitize(userInput); // quita <script>, pero deja id/name
container.innerHTML = html;
const cfg = window.appConfig || {};
if (cfg.isAdmin) unlockAdmin(); // ← window.appConfig lo puede clonar el markup
En el navegador, un elemento con id="appConfig" queda accesible como
window.appConfig, y un control name="isAdmin" dentro de un <form> aparece
como appConfig.isAdmin. Inyectando <form id="appConfig"><input name="isAdmin">
el atacante clona (clobbers) esos globales con nodos del DOM, y el chequeo pasa
sin una sola línea de JavaScript — por eso quitar <script> no alcanza.
Remediación
No leas configuración ni estado de seguridad desde globales que el DOM pueda
definir, y sanitizá con una allowlist real que elimine id/name.
- const cfg = window.appConfig || {};
- if (cfg.isAdmin) unlockAdmin();
+ // La config viene del servidor/JSON, nunca del DOM ni de globales implícitos.
+ if (session.role === 'admin') unlockAdmin();
- const html = sanitize(userInput);
+ const html = DOMPurify.sanitize(userInput, { SANITIZE_DOM: true }); // quita id/name peligrosos
container.innerHTML = html;
Por qué funciona: decidir el rol a partir de datos de sesión —no de
window.appConfig— saca del juego cualquier global clonable por el markup. Y un
sanitizador con protección anti-clobbering (p. ej. DOMPurify con SANITIZE_DOM)
elimina los id/name que habilitan la técnica.