CORS (Cross-Origin Resource Sharing)

Practica de explotación CORS

Imaginemos que tenemos esta pagina de aqui:

dashboard.php

<?php
session_start();
header('b0x-Powered-By: White beard Pirates 8-)');

// Verificar si el usuario está logueado
if (!isset($_SESSION['logged2']) || $_SESSION['logged2'] !== true) {
    header('Location: login.php', true, 302);
    exit;
}

// Configurar encabezados CORS
if (isset($_SERVER['HTTP_ORIGIN'])) {
    // Permitir el origen dinámicamente, dependiendo de la solicitud
    header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
    header('Access-Control-Allow-Credentials: true');

    // Especificar los encabezados que serán expuestos para CORS
    header('Access-Control-Expose-Headers: TOKEN, Access-Control-Allow-Origin, User-Name, Client-IP');
}

// Mostrar el token en la página
$api_token = $_SESSION['api_token'];

// Capturar el nombre de usuario de la sesión (ya que está logueado)
$username = $_SESSION['username'] ?? 'No username provided';  // Extraer el nombre de usuario desde la sesión
$client_ip = $_SERVER['REMOTE_ADDR'];  // La IP sigue siendo la de la solicitud (no cambia)


// Enviar el token, nombre de usuario y la IP en los encabezados de respuesta, solo si es una solicitud GET
if ($_SERVER['REQUEST_METHOD'] === 'GET' && !isset($_SERVER['HTTP_TOKEN'])) {
    // Añadir el token, nombre de usuario y la IP a los encabezados de la respuesta
    header('TOKEN: ' . $api_token);
    header('User-Name: ' . $username);
    header('Client-IP: ' . $client_ip);
}
?>

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard</title>
</head>
<body>
    <div align="center" style="margin: 30px;">
        Bienvenido. Obtenga la respuesta HTTP de esta página web mediante una solicitud CORS. ¡Listo! Lección aprendida: nunca confíe en un "Origin:" arbitrario.
    </div>

    <p>Your API Token: <?= htmlspecialchars($api_token) ?></p>
    <p>Your Username: <?= htmlspecialchars($username) ?></p>
    <p>Your IP Address: <?= htmlspecialchars($client_ip) ?></p>

    <p>This token is also sent in the request headers as <strong>TOKEN</strong>.</p>

    <!-- Formulario para actualizar el perfil -->
    <form action="dashboard.php" method="POST">
        <label for="username">Nuevo usuario:</label>
        <input type="text" name="username" id="username" required><br>

        <label for="password">Nueva contraseña:</label>
        <input type="password" name="password" id="password" required><br>

        <!-- Campo oculto para enviar el API token en el POST -->
        <input type="hidden" name="api_token" value="<?= htmlspecialchars($api_token) ?>">

        <input type="submit" value="Actualizar perfil">
    </form>

    <script>
        // Enviar el token, nombre de usuario y IP como parte del encabezado de la solicitud GET
        fetch(window.location.href, {
            method: 'GET',
            headers: {
                'TOKEN': '<?= htmlspecialchars($api_token) ?>', // Enviar el token en el encabezado
                'User-Name': '<?= htmlspecialchars($username) ?>', // Enviar el nombre de usuario
                'Client-IP': '<?= htmlspecialchars($client_ip) ?>' // Enviar la IP del cliente
            }
        })
        .then(response => response.text())
        .then(data => {
            console.log('Request successful:', data);
        })
        .catch((error) => {
            console.error('Error:', error);
        });
    </script>

</body>
</html>

Veremos que esta parte de aqui es la vulnerable a CORS:

Si entramos dentro de la pagina, veremos un login, las credenciales por defecto seran las siguiente:

Una vez que estemos dentro veremos algo asi:

Por lo que estamos viendo nos muestra la informacion del usuario, junto con su TOKEN, etc... Vamos a capturar la peticion con BuprSuite recargando la pagina y dentro de la misma añadiremos en la cabecera despues del parametro Connect lo siguiente:

Nos quedara algo asi:

Antes de enviarlo activaremos en BurpSuite el que obtengamos las respuestas del servidor:

Una vez activado vamos a enviarlo y veremos en la respuesta lo siguiente:

Vemos que nos esta habilitando la conexion de forma insegura con nuestro servidor de la maquina atacante, por lo que vamos a crear un exploit y subirlo a nuestro apache2 del atacante, para habilitar una pagina maliciosa.

cors.html

(Cambiamos la parte de <IP_VICTIM> por la IP de la maquina victima donde esta la vulnerabilidad)

Tambien tendremos que crear lo que va a procesar la solicitud y volcarlo en un .txt para que lo podamos ver:

steal.php

Tambien crearemos un archivo llamado stolen_tokens.txt que este en el mismo directorio.

OPCIONAL

Si queremos borrar el contenido del archivo stolen_tokens.txt para realizar de forma sucesiva el ataque, podremos crear lo siguiente:

clear.php

Y en el mismo directorio tendra que ir el siguiente archivo:

clear.sh

Todo este contenido del exploit tiene que estar en nuestro /var/www/html e iniciaremos el servicio de apache2:

Ahora tendremos que acceder a nuestro cors.html desde la web:

Ahora estando a la escucha con BurpSuite tendremos que darle al boton Obtener Datos. BurpSuite capturara la peticion y cambiaremos la parte de Cookie: PHPSESSID=<COOKIE_VICTIM> quedando algo asi:

Y si le damos al boton directamente de Intercep on veremos en la consola que salio todo perfecto:

Y si vamos al archivo donde se guarda todo, veremos que funciono:

Ahora si probamos a meter donde la pagina de cors.html en TOKEN del usuario admin en este campo:

Veremos que es el correcto, por lo que habremos aprovechado de forma corercta la obtencion de informacion como el TOKEN del usuario, aprovechando la vulnerabilidad CORS y haciendo que el servidor confie en el origen de nuestro servidor.

Explicación detallada de CORS

Vulnerabilidad CORS en Hacking Web

¿Qué es CORS?

CORS (Cross-Origin Resource Sharing) es un mecanismo de seguridad implementado en los navegadores web que restringe las solicitudes HTTP de origen cruzado. Esto significa que una página web en un dominio (ejemplo.com) no puede hacer solicitudes AJAX a otro dominio diferente (api.otrodominio.com), a menos que el servidor de destino lo permita explícitamente mediante cabeceras HTTP.

El objetivo principal de CORS es prevenir ataques como el Cross-Site Request Forgery (CSRF) y otros ataques de origen cruzado.

¿Cómo funciona CORS?

Cuando una aplicación web hace una petición a un dominio diferente, el navegador agrega la cabecera Origin en la solicitud. El servidor debe responder con la cabecera Access-Control-Allow-Origin para indicar si permite o no la petición desde ese origen.

Ejemplo de una solicitud CORS:

Si el servidor permite la petición, responderá con:

Si no está permitido, el navegador bloqueará la respuesta.

¿Cómo se explota CORS en hacking web?

Una mala configuración de CORS puede permitir a un atacante robar datos sensibles de un usuario autenticado en una aplicación web. Algunas configuraciones peligrosas incluyen:

Permitir cualquier origen (*)

Si el servidor responde con:

Entonces cualquier sitio puede hacer solicitudes al servidor y acceder a la respuesta.

Reflejar el valor del Origin

Algunos servidores devuelven el valor de la cabecera Origin en Access-Control-Allow-Origin sin validación:

Esto permite a un atacante alojar un sitio malicioso y robar datos de los usuarios autenticados en el dominio víctima.

Permitir credenciales con configuraciones inseguras

Si el servidor permite credenciales (cookies, tokens, etc.) con Access-Control-Allow-Credentials: true y combina esto con Access-Control-Allow-Origin: *, entonces un atacante puede robar sesiones de usuarios.

Esta combinación es extremadamente peligrosa.

Payloads y Bypasses para Explotación de CORS

Escenario
Payload/Bypass

Prueba básica de CORS

fetch('https://victima.com/endpoint', {credentials: 'include'}).then(res => res.text()).then(data => console.log(data))

Comprobar si el servidor refleja Origin

Origin: https://attacker.com

Bypass cuando Access-Control-Allow-Origin usa null

sandboxed iframe o data:// scheme

Usar subdominios para explotar regex débil

https://sub.attacker.com si el servidor permite *.attacker.com

Engañar validaciones débiles de dominio

https://trusted.com.attacker.com si el servidor usa endsWith() en validación

¿Cómo prevenir ataques CORS?

  • No usar Access-Control-Allow-Origin: * en servicios con información sensible.

  • No reflejar el valor de Origin sin validarlo correctamente.

  • Evitar Access-Control-Allow-Credentials: true a menos que sea estrictamente necesario.

  • Usar una lista blanca de orígenes permitidos en el servidor.

Conclusión

La vulnerabilidad CORS ocurre cuando la configuración del servidor permite orígenes no confiables acceder a datos sensibles. Es una de las fallas más comunes en aplicaciones web y puede tener consecuencias graves si se combina con el robo de credenciales o datos de usuarios autenticados. Configurar CORS correctamente es fundamental para la seguridad web.

Last updated