SSRF - Server-Side Request Forgery (Labs & Técnicas)

🔍 ¿Qué es SSRF?

Server-Side Request Forgery (SSRF) es una vulnerabilidad de seguridad web que permite a un atacante engañar a una aplicación del lado del servidor para que realice solicitudes HTTP (u otros protocolos) hacia destinos no previstos o controlados por el atacante.

🧨 En un ataque SSRF, el servidor puede ser manipulado para acceder a:

⚠️ Impacto de los ataques SSRF

Un ataque SSRF exitoso puede tener consecuencias graves, tales como:

🔁 Ejemplo común de ataque SSRF

Dibujo sin título.jpg
Imagina una aplicación de compras donde el usuario puede consultar el stock de un producto en diferentes tiendas. El frontend envía una URL al servidor para consultar la API de stock:

POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded

stockApi=http://stock.weliketoshop.net:8080/product/stock/check?productId=6&storeId=1

Sin embargo, un atacante puede modificar esta petición para forzar al servidor a acceder a una ruta interna protegida:

POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded

stockApi=http://localhost/admin:8080

✅ Esto hace que el servidor mismo acceda a http://localhost/admin:8080, una ruta normalmente protegida y accesible solo desde dentro.

🔓 Desde el navegador del atacante, esta URL estaría bloqueada. Pero al hacer que el propio servidor realice la petición, se bypassean los controles de acceso, ya que parece una solicitud legítima desde el entorno interno.

Así, el atacante logra acceder a información o funciones a las que no debería tener acceso, aprovechando la confianza que tiene la aplicación en sí misma.

🧪 Laboratorios prácticos

Ahora que ya entiendes qué es un ataque SSRF, ¡es momento de ponerlo en práctica!
Vamos a explorar algunos laboratorios interactivos de la academia de seguridad web de Burp Suite.

🔗 Accede aquí a los laboratorios de SSRF de PortSwigger:
**Accede aquí a los laboratorios de SSRF de PortSwigger

💡 Necesitarás crear una cuenta gratuita en PortSwigger para acceder a los labs.

Basic SSRF against the local server

📜 Enunciado del laboratorio:

This lab has a stock check feature which fetches data from an internal system.

To solve the lab, change the stock check URL to access the admin interface at `http://localhost/admin` and delete the user `carlos`.

En este laboratorio estamos ante una tienda en línea simulada, con un catálogo de productos ficticios:
Pasted image 20250406194206.png
📦 Al hacer clic en un producto, tenemos la opción de consultar el stock disponible en distintas ciudades.
Esto desencadena una consulta que el navegador envía al servidor.
Pasted image 20250406194346.png
Cuando interceptamos la solicitud con Burp Suite, observamos que el parámetro stockApi contiene la URL que el servidor utilizará para consultar la API de stock:

stockApi=http%3A%2F%2Fstock.weliketoshop.net%3A8080%2Fproduct%2Fstock%2Fcheck%3FproductId%3D1%26storeId%3D1

🔎 Si hacemos Ctrl + Shift + U en Burp Suite, podemos decodificar esta URL y ver el valor real:

http://stock.weliketoshop.net:8080/product/stock/check?productId=1&storeId=1

Según el enunciado del laboratorio, el objetivo es hacer que el servidor acceda a su propia interfaz interna de administración, ubicada en` http://localhost/admin
➡️ Simplemente modificamos la solicitud interceptada en Burp Suite así:

stockApi=http://localhost/admin

Y pum ya estamos en el panel de administrador
Pasted image 20250406195251.png
Ahora nos falta eliminar el usuario carlos. Para eso tenemos que hacer

stockApi=http://localhost/admin/admin/delete?username=carlos

Pasted image 20250406195601.png

Basic SSRF against another back-end system

📜 Enunciado del laboratorio:

This lab has a stock check feature which fetches data from an internal system.

To solve the lab, use the stock check functionality to scan the internal `192.168.0.X` range for an admin interface on port `8080`, then use it to delete the user `carlos`.

Pasted image 20250406201618.png
Al igual que en el laboratorio anterior, entramos en cualquier producto y capturamos la solicitud enviada al consultar el stock.

El parámetro clave es stockApi, que contiene una URL codificada. 🔓 Decodificamos con Ctrl + Shift + U en Burp Suite.

📌 Usamos Ctrl + I para enviar esta solicitud a Intruder, y configuramos el ataque de la siguiente forma:

stockApi=http://192.168.0.$1$:8080/admin

Seleccionamos el número 1 con doble clic y pulsamos "Add $" para marcarlo como un payload dinámico.
Vamos a la pestaña Payloads, y elegimos:

Esto generará una IP por cada intento:
192.168.0.1, 192.168.0.2, ..., 192.168.0.254

📊 Esto simula un escaneo de red interna.
Pasted image 20250406211018.png
Al ordenar la columna Status Code en Burp Intruder de menor a mayor, detectamos que la IP: http://192.168.0.15:8080/admin Respondió con **Status Code 200**, lo que indica una conexión **exitosa** al panel de administración interno. 🟢 ![Pasted image 20250406211018.png](/img/user/Gorosolea/Imagenes/Pasted%20image%2020250406211018.png) 👉 Una vez identificada la IP interna (192.168.0.15), enviamos la petición a **Repeater** (Ctrl + R), modificamos el valor del parámetro stockApiporhttp://192.168.0.15:8080/admin/delete?username=carlos` y presionamos Send. ¡El laboratorio está completado con éxito! ✅
Pasted image 20250406211233.png

SSRF with blacklist-based input filter

📜 Enunciado del laboratorio:

This lab has a stock check feature which fetches data from an internal system.

To solve the lab, change the stock check URL to access the admin interface at `http://localhost/admin` and delete the user `carlos`.

The developer has deployed two weak anti-SSRF defenses that you will need to bypass.

En este caso, la URL http://localhost/admin no funciona debido a una lista negra de entrada que bloquea el acceso directo a localhost. Para evadir esta protección, intentamos varias combinaciones de cómo representar 127.0.0.1, incluyendo variaciones como 127.1. Observamos que 127.1 es aceptado, pero al agregar /admin en la URL, también es bloqueado. Esto indica que el sistema detecta y bloquea direcciones que comienzan con 127.0.0.1 y que tenga /admin.

Para superar esta restricción, aplicamos doble codificación en la ruta /admin. Esta técnica permitió eludir el filtro y acceder finalmente a la URL protegida. Así, la URL modificada para eliminar al usuario carlos se convierte en:

stockApi=http://127.1/%25%36%31%25%36%34%25%36%64%25%36%39%25%36%65/delete?username=carlos

Para encodear el admin en tipo URL:
Pasted image 20250407194247.png
Pasted image 20250407194444.png

SSRF with whitelist-based input filter

📜 Enunciado del laboratorio:

This lab has a stock check feature which fetches data from an internal system.

To solve the lab, change the stock check URL to access the admin interface at `http://192.168.0.12:8080/admin` and delete the user `carlos`.

The stock checker has been restricted to only access the local application, so you will need to find an open redirect affecting the application first.

Veamos como lo que bloquae poniendo stockApi=http://127.1/admin. No s pone "External stock check host must be stock.weliketoshop.net"
Pasted image 20250407195304.png
La redirección abierta es una vulnerabilidad que permite a un atacante redirigir a un usuario a un sitio web arbitrario. Esta vulnerabilidad ocurre cuando una aplicación permite que un parámetro de URL contenga una dirección URL externa no validada, permitiendo que se redirija a cualquier sitio

En este caso, hemos identificado una vulnerabilidad de redirección abierta en el sitio. Al hacer clic en el botón "Next product" en la página, observamos que se produce una redirección a otra URL basada en los parámetros pasados. Comprobamos esto al cambiar el parámetro path para redirigir a un sitio externo, como https://www.marca.com/, lo que efectivamente nos llevó a esa página.

/product/nextProduct?currentProductId=1&path=/product?productId=2
/product/nextProduct?currentProductId=1&path=https://www.marca.com/

Pasted image 20250407203209.png

Al explotar esta vulnerabilidad, podemos manipular el parámetro path para que en lugar de redirigirnos a una página externa legítima, redirijamos a un sistema interno del servidor. Modificamos la URL de la siguiente manera:

stockApi=/product/nextProduct?currentProductId=1&path=http://192.168.0.12:8080/admin

Pasted image 20250407203052.png
Esto nos llevará a la página de administración del servidor interno. Luego, para eliminar al usuario carlos, modificamos la URL de la siguiente manera:

stockApi=/product/nextProduct?currentProductId=1&path=http://192.168.0.12:8080/admin/delete?username=carlos

SSRF with whitelist-based input filter

📜 Enunciado del laboratorio:

This lab has a stock check feature which fetches data from an internal system.

To solve the lab, change the stock check URL to access the admin interface at `http://localhost/admin` and delete the user `carlos`.

The developer has deployed an anti-SSRF defense you will need to bypass.

Paso inicial:

  1. Modifica el parámetro stockApi a http://127.0.0.1/.

    Resultado:
    ✅ Esto confirma que el servidor está usando una lista blanca (whitelist), que solo permite URLs que apunten al dominio stock.weliketoshop.net.

    Comportamiento:
    El desarrollador implementó una protección que verifica que el host de la URL sea exactamente stock.weliketoshop.net. Si no coincide, bloquea la solicitud. Este tipo de defensa es común, pero puede ser engañada si el análisis de la URL no está bien implementado.
    Pasted image 20250409185030.png

¿Cómo podemos evadir esta protección?

1. Ingresando credenciales embebidas en la URL:

Prueba con la siguiente URL:

stockApi=http://localhost@stock.weliketoshop.net/

Introducción del # (fragmento de la URL):

Prueba añadiendo el fragmento #:

stockApi=http://localhost#@stock.weliketoshop.net/

¿Qué hace el símbolo # en una URL?

Fragmento de URL (hash):

https://example.com/page#section1

🔁 El navegador solo envía:

GET /page HTTP/1.1

El navegador ignora completamente #section1. Este fragmento nunca se envía al servidor.

Doble codificación del #

Para evitar que el filtro detecte el fragmento, aplicamos doble codificación al #:

stockApi=http://localhost%2523@stock.weliketoshop.net/

¿Qué hace este payload?

Payload final para eliminar el usuario carlos

Una vez que hemos logrado evadir la validación, para acceder a la interfaz de administración y eliminar al usuario carlos, utilizamos este payload:

stockApi=http://localhost%2523@stock.weliketoshop.net/