Nuevos labs cada semana — Accede a todos desde 5€/mes

Nivel BásicoGratis

CSRF (Cross-Site Request Forgery) — explicado completo con bypasses

CSRF: cómo se explota, defensas comunes (tokens, SameSite, Origin), bypasses (method change, JSON, double-submit, content-type) y dónde buscarlo en cualquier app.

Gorka El Bochi9 de mayo de 202612 min

Respuesta rápida

CSRF (Cross-Site Request Forgery) fuerza al usuario a ejecutar acciones no deseadas en una app donde está autenticado. Ataca state-changing requests (cambiar email, transferir dinero) montadas desde otro dominio. Se mitiga con tokens CSRF validados en servidor, SameSite cookie, validación de Origin/Referer y rechazo de Content-Types inesperados. Se rompe cuando el desarrollador valida mal cualquiera de esas defensas.


Cómo funciona el ataque

CSRF aprovecha que el navegador adjunta automáticamente cookies a requests cross-site. Si la víctima está logueada en bank.tld y visita attacker.tld, una página del atacante puede hacer que el navegador envíe un POST a bank.tld/transfer con la cookie de sesión incluida.

Si el servidor solo valida la cookie, la transferencia se ejecuta como si la víctima la hubiera iniciado. Eso es CSRF.


Defensas comunes (y cómo se rompen)

1. CSRF Tokens

El servidor inyecta un token aleatorio en cada formulario. El cliente lo manda en cada request. Si no coincide → 403.

Bypasses típicos:

  • Token ausente. Eliminar el parámetro del request → ¿el servidor sigue aceptando? Algunos backends solo validan si está presente.
  • Token vacío. csrf_token= (string vacío) → algunos validadores lo aceptan.
  • Token débil. ¿Es un valor fijo por cuenta? ¿Se reutiliza? Captura el tuyo, monta la PoC para la víctima con tu token.
  • Sólo parte del token validado. Si solo se valida la mitad o un prefix, manda un token cualquiera con ese prefix válido.
  • Token expira pero no se invalida. Si reutilizar tokens viejos pasa → CSRF.

Atributo de cookie que controla cuándo se envía cross-site:

  • SameSite=Strict — nunca cross-site. Mata CSRF de raíz.
  • SameSite=Lax (default actual en Chrome/Firefox) — solo en navegación top-level (click en link). NO en POST cross-site → bloquea CSRF clásico.
  • SameSite=None; Secure — siempre se envía. Vulnerable.

Bypasses:

  • Si la app usa SameSite=Lax, los GET requests sí cruzan. Si una acción crítica acepta GET (/password_change?new=...), CSRF posible.
  • Apps legacy con cookies sin SameSite declarado se comportan como None en algunos navegadores.

3. Origin / Referer Header

El servidor compara el header Origin (o Referer) con su propio dominio.

Bypasses:

  • Eliminar Referer. <meta name="referrer" content="no-referrer"> en la página atacante. Si el servidor "deja pasar" cuando no hay Referer → bypass.
  • Spoofing parcial. Referer: example.tld.attacker.tld (subdominio que contiene el dominio target como prefix). Si el chequeo es startsWith() o contains(), pasa.
  • Origin null. Sandbox iframes envían Origin: null → si el servidor lo acepta, bypass.

4. Content-Type validation (para JSON APIs)

Si el endpoint exige Content-Type: application/json, no es trivial montarlo en un form HTML clásico. Pero:

  • Form con enctype="text/plain" puede generar JSON-shaped bodies:
html
<form action="https://target.tld/api/email" method="POST" enctype="text/plain">
  <input name='{"email":"atk@evil.tld","x":"' value='"}'>
</form>

El body resultante: {"email":"atk@evil.tld","x":"="} — JSON válido si el servidor lo parsea.

  • Cambiar Content-Type. Si la API también acepta application/x-www-form-urlencoded además de JSON → simple form CSRF.
  • Plain/text. Algunos backends ignoran Content-Type y parsean el body directamente.

Bypass en JSON requests

Ejemplo real:

html
<html>
  <head><meta name="referrer" content="unsafe-url"></head>
  <body>
  <form name="hacker" method="POST" action="https://target.tld/api/phone.json" enctype="text/plain">
    <input type="hidden" name='{"phone":"+34666000000","a":"' value='"}'>
  </form>
  <script>
    document.forms[0].submit();
  </script>
  </body>
</html>

Body enviado: {"phone":"+34666000000","a":"="}. Si el server parsea como JSON, ataque exitoso.


CSRF + ClickJacking

Si el server bloquea CSRF pero la página se puede embeber en <iframe>, se monta un clickjacking:

html
<iframe src="https://target.tld/settings/password" width="500" height="500"></iframe>

Posicionando el iframe sobre un botón visible del attacker, el click llega al iframe target. El navegador adjunta cookies + el server procesa la acción.

Mitigación: X-Frame-Options: DENY o CSP frame-ancestors 'none'.


Endpoints donde buscar CSRF

  • Cambio de email (lleva a ATO si el usuario no re-confirma).
  • Cambio de contraseña.
  • Cambio de 2FA settings (deshabilitar el 2FA → ATO).
  • Adición de SSH keys / API keys del perfil.
  • Transferencias / pagos / suscripciones.
  • Eliminación de cuenta (defacement vector).
  • Vinculación de cuentas OAuth/SSO (puede llevar a takeover si la víctima vincula la cuenta del atacante).
  • Cambios de rol / permisos en apps con admin panel.

Patrón: CSRF relay endpoints

Algunas apps tienen endpoints internos tipo /api/proxy?url=/api/endpoint que reenvían internamente y inyectan automáticamente el CSRF token del usuario. Para el atacante, basta con que la víctima visite la URL — no necesita robar el token.

Buscar endpoints con nombres proxy, redirect, forward, relay, dialog, _DONOTUSE, _DEBUG, _INTERNAL. Si reenvían requests autenticados → posible CSRF universal.


Checklist de hunting

  • ¿El servidor acepta el request sin token CSRF?
  • ¿El token vacío pasa? ¿El token de otra cuenta pasa?
  • ¿Hay endpoints sensibles que aceptan GET? (revisa methodOverride también).
  • ¿SameSite está declarado? ¿Es Lax/None?
  • ¿Origin/Referer se valida estrictamente o solo "contains"?
  • ¿Content-Type es validado o se ignora?
  • ¿Existe relay/proxy endpoint que inyecte token automáticamente?
  • ¿X-Frame-Options está, para descartar clickjacking?

Labs relacionados

Practica CSRF + bypasses con apps reales que validan tokens, Origin y Content-Type: labs de CSRF.

Practica esto en un lab

Csrf

Resolver

Sigue aprendiendo · cuenta gratis

Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.

Crear cuenta

Artículos relacionados