Статья Cloud Pentesting: методология тестирования облачной инфраструктуры

1777408469231.webp

В облачном пентесте первый скан часто даёт странную картину: наружу торчит мало, веб закрыт CDN и WAF, SSH нет, привычная карта сети почти пустая. При этом внутри аккаунта может лежать куда более опасная цепочка: роль приложения читает секреты production, CI/CD-пайплайн умеет передавать привилегированную роль, trust policy пускает внешний аккаунт, а старая EC2-инстанс всё ещё принимает IMDSv1.

Если идти по классической on-premise-схеме, часть риска останется вне поля зрения. В облаке критичный путь часто проходит не через открытый порт, а через API управления: IAM, STS, resource policies, metadata service, managed identities, service accounts, KMS, storage, serverless и роли деплоя.

Модель угроз в облаке​

Где ломается привычная on-premise-логика​

В on-premise-пентесте много решает сетевой маршрут: подсети, сервисы, домен, локальные учётки, привилегии на хостах, lateral movement через SMB, WinRM, RDP, SSH или AD. В облаке этот слой остаётся, но перестаёт быть главным источником полномочий. Виртуальная машина может быть закрыта от интернета, но её instance profile даёт доступ к Secrets Manager. Lambda может не иметь публичного endpoint, но её execution role умеет читать production bucket. Пайплайн может запускаться только из внутренней GitLab-инстанс, но его cloud role имеет право менять функции и политики.

1.webp


Из-за этого разведка строится вокруг связей. EC2, ECS task, Lambda, Kubernetes node, service account, IAM role, bucket policy и KMS key должны попадать в одну карту. Отдельно найденная широкая IAM-политика ещё не доказывает критичный риск. Риск появляется, когда эта политика связывается с workload, секретом, данными или переходом в другой аккаунт.

Для AWS базовая граница ответственности описана через security of the cloud и security in the cloud: провайдер отвечает за инфраструктуру облака, клиент - за конфигурацию ресурсов, данных, доступов и workloads внутри своей среды. Для пентеста это не формальность. Если в scope попали только публичные IP, тест почти гарантированно пропустит IAM, storage policies, metadata access и межаккаунтные доверия.

Нормальный scope для облака фиксирует аккаунты, регионы, роли, разрешённые API-действия, production-ограничения, порядок работы с секретами и журналы, где команда будет подтверждать следы. В AWS security testing для ряда сервисов можно проводить без предварительного согласования, но C2-сценарии требуют отдельного approval. Это надо зафиксировать до теста, а не после первого спорного finding.

Разведка облачной поверхности​

Внешняя разведка нужна не ради таблицы поддоменов. Её задача - найти облачные привязки, старые окружения и ресурсы, которые потом можно сопоставить с внутренним инвентарём. Поддомен admin-staging, CNAME на старый load balancer, забытый object storage endpoint или сертификат для dev-зоны полезны только тогда, когда понятно, какой workload за ними стоит и какие права он получает.

Минимальный внешний проход обычно закрывает DNS, Certificate Transparency, HTTP(S)-ответы и технологические признаки:
Bash:
subfinder -d example.com -silent -all -o subs.txt

dnsx -l subs.txt -resp -a -aaaa -cname -silent -o resolved.txt

httpx -l subs.txt \
  -title \
  -tech-detect \
  -status-code \
  -follow-redirects \
  -o http.txt
Результат стоит чистить сразу. Мёртвые записи, parked domains и одинаковые ответы CDN не должны превращаться в шум. Гораздо важнее найти живые endpoints, которые указывают на облачные ресурсы: load balancer, API gateway, storage, static hosting, managed app platform. По ним уже можно идти к владельцу, тегам, роли workload и журналам.

После выдачи согласованных credentials разведка начинается с фиксации identity. Без этого отчёт будет плохо воспроизводиться: одна и та же команда под auditor role, workload role и federated user даёт разные результаты.
Bash:
aws sts get-caller-identity
aws configure list
Дальше проверяется региональный инвентарь. У клиентов часто есть основной регион, который все называют на созвонах, и несколько забытых регионов, где остались старые функции, snapshots, AMI, buckets или security groups. Для AWS такой проход обычно начинается с EC2 и балансировщиков:
Bash:
for region in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
  echo "[*] $region"

  aws ec2 describe-instances \
    --region "$region" \
    --query 'Reservations[].Instances[].{Id:InstanceId,State:State.Name,Profile:IamInstanceProfile.Arn,PublicIp:PublicIpAddress,Tags:Tags}' \
    --output table 2>/dev/null

  aws elbv2 describe-load-balancers \
    --region "$region" \
    --query 'LoadBalancers[].{Name:LoadBalancerName,DNS:DNSName,Scheme:Scheme,Type:Type}' \
    --output table 2>/dev/null
done
Здесь важен не сам список инстансов. Сразу смотрим, какие workload имеют IAM profile, какие ресурсы публичны, где нет тегов владельца, какие окружения смешаны, какие сервисы используют старые роли. Разведка должна быстро перейти от inventory к графу доступа.

IAM эксплуатация​

Пути повышения привилегий​

IAM-эскалация редко выглядит как один очевидный admin policy. Чаще цепочка собирается из разрешённых действий. Пользователь может создать Lambda. Эта Lambda может получить роль через iam:PassRole. Роль умеет читать секрет. Секрет открывает доступ к пайплайну. Пайплайн деплоит в production. На каждом шаге API работает штатно, но вся цепочка выводит пентестера за исходный уровень доступа.

В cloud-средах такие цепочки часто упираются не в пользовательские учётки, а в сервисные аккаунты, токены и non-human identities: OAuth-приложения, API-ключи, CI/CD-токены и Kubernetes ServiceAccounts живут дольше обычных сессий, хуже инвентаризируются и часто получают права шире своего реального сценария.

Проверка начинается с текущей identity и её политик:
Bash:
aws sts get-caller-identity

aws iam list-attached-role-policies --role-name ROLE 2>/dev/null
aws iam list-role-policies --role-name ROLE 2>/dev/null
В inline и attached policies ищем не просто wildcard. Смотрим действия, которые меняют полномочия или позволяют запустить код от другой роли: iam;PassRole, iam:CreatePolicyVersion, iam:SetDefaultPolicyVersion, iam:AttachRolePolicy, lambda:CreateFunction, lambda:UpdateFunctionCode, ec2:RunInstances, ecs:RunTask, доступ к Secrets Manager, SSM Parameter Store, KMS и storage. Широкий Resource: "*" опасен там, где он пересекается с такими действиями.

Cross-account доступ в AWS обычно строится через IAM role с trust policy, которая разрешает principal из другого аккаунта выполнить AssumeRole. AWS прямо описывает cross-account IAM role как роль с trust policy для principal из другого аккаунта.
Bash:
aws iam get-role \
  --role-name TargetRole \
  --query 'Role.AssumeRolePolicyDocument'
Плохой признак - trust на весь внешний аккаунт без дополнительных условий:
JSON:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
Сам по себе такой документ ещё не равен компрометации. Нужно проверить, кто в доверенном аккаунте реально может вызвать sts:AssumeRole, какие SCP и permission boundaries действуют, есть ли MFA-условия, ограничения по source IP и отдельный ExternalId для third-party-доступа. AWS рекомендует использовать external ID в сценариях, где третья сторона получает доступ к аккаунтам клиентов, чтобы снизить риск confused deputy.

Более контролируемый вариант trust policy ограничивает конкретную роль и требует внешний идентификатор:
JSON:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:role/vendor-prod-access"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "customer-specific-external-id"
        }
      }
    }
  ]
}
Валидация AssumeRole должна быть отдельно разрешена в scope. Безопасный минимум - подтвердить сам переход и сразу зафиксировать новую identity:
Bash:
aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/TargetRole \
  --role-session-name pentest-validation \
  --external-id AGREED_EXTERNAL_ID
Bash:
aws sts get-caller-identity
Дальше отчёт строится не вокруг JSON-политики, а вокруг маршрута. Исходная identity, разрешённое действие, trust relationship, итоговая роль, доступные ресурсы, данные или workloads, которые становятся достижимы. Если этот путь не показан, finding останется общей претензией к IAM.

Следы в CloudTrail​

IAM и STS API-вызовы попадают в CloudTrail как события. AWS отдельно указывает, что CloudTrail захватывает IAM и AWS STS API calls, включая вызовы из консоли и через API. Для пентеста это удобно: можно не только доказать путь, но и проверить, видит ли его blue team.

Для IAM-цепочек полезны события AssumeRole, PassRole, UpdateAssumeRolePolicy, AttachRolePolicy, PutRolePolicy, CreatePolicyVersion, SetDefaultPolicyVersion. В отчёте лучше не выдумывать нестандартные поля, а фиксировать проверяемые элементы: время, caller identity, target role ARN, source account, session name, source IP, user agent, регион и результат вызова.

Если действие воспроизводится, но команда не может найти его в журналах, это отдельный результат теста. В облаке отсутствие наблюдаемости по control plane почти так же опасно, как слабая политика доступа. Атакующий будет использовать те же API, что и легитимная automation.

Metadata service attacks​

IMDS как стык AppSec и IAM​

SSRF в обычном приложении часто ограничивается доступом к внутренним HTTP-ресурсам. В облаке тот же баг может привести к workload credentials. Если приложение работает на EC2 с ролью, на Azure VM с managed identity или в GCP VM с service account, metadata endpoint становится мостом от веб-уязвимости к cloud API.

SSRF в облаке опасен не самим фактом server-side request, а тем, что уязвимый fetcher может стать транспортом к link-local metadata endpoint; поэтому SSRF в современных API приходится проверять не по regex-фильтру в коде, а по реальному поведению HTTP-клиента: redirects, DNS rebinding, нормализация URL, методы и заголовки.

В AWS IMDSv2 требует session token: сначала клиент получает токен через PUT, затем передаёт его в запросах к metadata. IMDSv1 токен не требует. AWS позволяет настроить инстанс так, чтобы принимались только IMDSv2-запросы; для запуска новых инстансов через CLI это соответствует HttpTokens=required.

Проверка на согласованной тестовой EC2-инстансе:
Bash:
TOKEN=$(curl -sS -X PUT \
  "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

curl -sS \
  -H "X-aws-ec2-metadata-token: $TOKEN" \
  "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
В отчёт не нужно вставлять временные ключи. Достаточно имени роли, режима IMDS, факта доступности metadata и оценки прав этой роли. Access key, secret key, session token, значения секретов и содержимое параметров должны быть замаскированы. Иначе отчёт сам становится чувствительным артефактом.

Конфигурация IMDS проверяется через EC2 API:
Bash:
aws ec2 describe-instances \
  --query 'Reservations[].Instances[].{InstanceId:InstanceId,Metadata:MetadataOptions,IamProfile:IamInstanceProfile.Arn,State:State.Name}' \
  --output table
Слабая цепочка обычно собирается из нескольких условий: IMDSv1 разрешён, workload имеет роль с лишними правами, приложение делает server-side fetch по пользовательскому URL, egress к 169.254.169.254 не ограничен, а после обращения к metadata в логах нет нормальной корреляции с последующими STS или cloud API-вызовами.

У Azure и GCP похожая зона риска, но другая механика. Azure IMDS доступен из VM по 169.254.169.254, Microsoft указывает, что трафик к IMDS не покидает host и HTTP-клиенты должны обходить proxy при обращении к нему. В Google Cloud metadata server доступен через metadata.google.internal и 169.254.169.254, а запросы в примерах выполняются с заголовком Metadata-Flavor: Google; Google также пишет, что запросы с X-Forwarded-For metadata server отклоняет.

Цепочки SSRF​

Фраза SSRF to IMDS слишком часто используется раньше, чем доказана цепочка. Для IMDSv2 важно, умеет ли уязвимый fetcher отправлять PUT, управлять заголовками, следовать redirect, работать с link-local адресами и не ломает ли он URL после нормализации. SSRF, который делает только GET без пользовательских headers, может не пройти дальше первой проверки.

Хорошо видно это на цепочках, где SSRF превращается в RCE через внутренний Redis: первичная веб-ошибка остаётся той же, но итоговый риск зависит от того, куда сервер может ходить изнутри, какие протоколы доступны и какие cloud credentials оказываются рядом с уязвимым workload.

Корректная валидация идёт по ступеням. Сначала подтверждается server-side request через контролируемый endpoint. Затем проверяются redirects, private ranges, link-local, DNS rebinding, методы и заголовки. Только после этого проверяется metadata endpoint, если это прямо разрешено scope. Данные credentials не извлекаются без необходимости: для finding достаточно доказать доступ к имени роли и связать её permissions с impact.

Защита здесь тоже не сводится к одному HttpTokens=required. Роль workload'a должна быть минимальной. Server-side fetch должен резать link-local и private ranges после нормализации URL. Egress к metadata endpoint стоит ограничивать на уровне host, контейнера или namespace. В Kubernetes поверх облачных нод нужно отдельно проверять, какая cloud identity доступна pod'у, не может ли pod достучаться до node metadata и не заменяет ли Kubernetes RBAC реальную проверку IAM.

Lateral movement в облаке​

В облаке переход между зонами чаще проходит через identities и managed-сервисы. Компрометированный workload получает роль. Роль читает параметр или secret. Secret даёт доступ к CI/CD. Пайплайн принимает deployment role. Deployment role меняет workload в production. В этой цепочке может не быть ни одного интерактивного shell на соседнем сервере.

2.webp


После initial access проверяются не только соседние подсети. Смотрим, какие secrets доступны текущей identity, какие buckets открываются через ресурсную политику, какие KMS keys позволяют расшифровку, какие роли можно принять, какие функции можно обновить, какие container images можно читать или перезаписать.
Bash:
aws sts get-caller-identity

aws secretsmanager list-secrets
aws ssm describe-parameters
aws s3api list-buckets
aws kms list-keys
Эти команды дают только точки для проверки. Нельзя автоматически приравнивать list к доступу на чтение чувствительных данных. Дальше нужна аккуратная валидация: metadata вместо значения секрета, policy simulation вместо изменения политики, read-only API вместо destructive action, отдельное согласование для действий, которые меняют состояние.

Вместо заключения​

Хороший cloud pentest редко заканчивается одной исправленной политикой. Обычно он вытаскивает наружу старые архитектурные решения: staging, который годами имел доступ к production; роли деплоя, пережившие три миграции; external trust без владельца; workload, которому выдали широкие права на время релиза и забыли вернуть обратно.

В облаке опасна не только отдельная ошибка, а связность между ошибками. SSRF сам по себе может быть средним риском. Широкая роль workload - тоже. Секрет CI/CD в Parameter Store - спорная, но встречающаяся практика. Вместе они превращаются в маршрут до production. Поэтому ценность cloud pentest - не в длинном списке misconfigurations, а в доказанных цепочках, которые показывают, где среда теряет границы.
 
Последнее редактирование:
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab