Статья Смотрим немного базовых уязвимостей в K8S

k8s.png

Всем привет, сегодня хотел бы разобрать самые базовые дыры в Kubernetes (или сокращенно K8S). Но давайте сначала разберемся с базовыми понятиями в K8S.

Зачем вообще нужен Kubernetes (K8S)?

K8S предназначен для следующих целей:
  • Предназначен для контейнизированных приложений
  • Автоматизация развертывания приложений
  • Автоматизации масштабирования приложений
  • Автоматизация управлением приложением
Помимо этого в K8S используется Docker, это важно заметить

Основной используемый компонент K8S - Cluster ()
K8S Cluster создается с помощью Nodes (некого сервера)
Есть два типа Nodes:
  1. Worker Node - сервер на котором запускаются и работают контейнеры
  2. Master Node - сервер, который управляет Worker Node
Когда вы посылаете cli-команды, то они отправляются на Master Node
Master Node имеет три главных процесса k8s:
  • kube-apiserver
  • kube-controller-manager
  • kube-scheduler
Worker Node имеет два процесса k8s:
  • kubelet
  • kube-proxy
Честно, думаю что подробно разбирать данные процессы нам не потребуется, поэтому идем дальше

Функции у K8S следующие:
  • Service discovery and load balancing - k8s дает доступ к контейнеру через IP/Worker Node-порт/DNS. При создании копии контейнера k8s сделает load balancing вашего контейнера
  • Storage orchestration - присоединение локального (или AWS, Docker Hub) диска к одному или нескольким контейнерам
  • Automated rollouts and rollbacks - автоматическое обновление docker image на новую/старую версию
  • Automating bin packing - когда вы указываете сколько ресурсов нужно для вашего контейнера, то k8s выбирает подходящую Worker Node для этого контейнера.
  • Self Healing - замена нерабочего контейнера на рабочий
  • Secret and configuration management - позволяет хранить конфиденциальную информацию вне контейнера.
Главные объекты K8s:
  1. Pod - состоит из контейнера/контейнеров
  2. Deployment - копия podов
  3. Service - дает доступ к deployment
  4. Node - сервер где работает service
  5. Cluster - объединение нескольких Node
Про kubectl

Основное взаимодействие с K8S происходит через kubectl, который позволяет выполнять команды для ваших кластеров. Снизу я разобрал буквально несколько команды, но все остальные приколы можете найти
Список всех pod:

kubectl get pods

Запуск pod:

kubectl run <nickname_for_pod> –image=<name_of_image>

Теперь предлагаю перейти уже к самим вулнам

Sensitive keys in codebases

Этот сценарий призван обратить внимание на некоторые популярные ошибки разработчиков и DevOps-команд при упаковке артефактов и кодовой базы приложений. Это имеет реальные последствия, такие как компрометация организаций и их инфраструктуры
Цель этого сценария - определить ключи, имеющиеся в кодовой базе. Которая включает в себя код приложения, контейнер и инфраструктуру.
С помощью ffuf/gobuster можно попытаться найти ключи. Иногда эти ключи могут лежать в .git

http://localhost:1230/.git

1682631255010.png


Давайте глянем конфиги

http://localhost:1230/.git/config

1682631404460.png


С помощью git-dumper мы можем клонировать весь репозиторий

git-dumper http://localhost:1230/.git k8s-goat-git

И потом можно посмотреть логи с помощью git log

А с помощью git checkout берем любой коммит и потом смотрим .env файл где есть ключики

1682631551253.png


DIND (docker in docker) exploitation

В этом сценарии мы сосредоточимся на распространенных и стандартных способах создания систем и pipeline, использующих контейнерные сокеты для создания, сборки и запуска контейнеров из базовой среды выполнения контейнеров. Этим пользовались с первых дней существования контейнерной экосистемы, и до сих пор мы видим эту неправильную конфигурацию/случаи использования в реальном мире.
Большинство систем CI/CD и pipeline систем используют базовый хост Docker runtime для создания контейнеров для вас в рамках pipeline, используя нечто под названием DIND (docker-in-docker). В данном сценарии мы пытаемся использовать эту неправильную конфигурацию и получить доступ к хост-системе, выйдя из контейнера docker.
Целью этого сценария является выход из запущенного докер-контейнера на хост-систему, где запущен контейнер, и возможность доступа и выполнения действий на хост-системе. Вообще как вы можете понять из названия и описания, данная атака затрагивает больше приколы Docker нежели чем K8S.
1682631572365.png


На примере нам предлагают пропинговать локальный хост и сразу же туда можно попробовать сделать command injection, что дает возможность получить инфу и с помощью команды mount мы видим, что /custom/docker/docker.sock смонтирован в файловой системе, и если предположить, что он смонтирован из хост-системы, нам нужно обратиться к нему для связи с UNIX.

1682631572418.png


Далее мы можем загрузить официальный статический бинарник docker https://download.docker.com/linux/static/stable/. После разархивируем и теперь мы можем получить доступ к хост-системе, выполнив docker с передачей UNIX-сокета docker.sock

1682631802446.png


SSRF in the Kubernetes (K8S)

Этот сценарий призван продемонстрировать популярную уязвимость безопасности приложений, которая повсеместно эксплуатируется в облачных средах. Теперь мы попытаемся увидеть, как она влияет на кластеры Kubernetes, внутренние службы и микросервисы. Мы посмотрим, как можно использовать уязвимость SSRF, для получения доступа к метаданным облачного экземпляра, а также к информации метаданных внутренних сервисов. В частности, мы видим возможности встроенных функций Kubernetes, таких как обнаружение сервисов, для использования и получения доступа к другим внутренним микросервисам.

169.254.169.254 - это динамически конфигурируемый адрес. Он действителен только в одном сегменте сети и не подлежит маршрутизации. Большинство облачных провайдеров используют этот адрес для метаданных вычислений для экземпляров, включая таких крупных провайдеров, как AWS, GCP Azure, Digital Ocean и др.

Мы можем получить доступ к службе метаданных экземпляра по умолчанию, используя 169.254.169.254. Нам также нужно определить, какой облачный провайдер использует службу для запуска этого вычисления, чтобы мы могли использовать определенные заголовки и запросы. Если он не размещен в облаке провайдера, то мы можем пропустить это и перейти к запросам внутренней службы, как это делают другие микросервисы и внутренние службы в кластере Kubernetes.

1682632073827.png


Мы можем начать с энумерации, чтобы понять, какие службы запущены в текущем экземпляре и других сетях, основываясь на доступной информации
Мы также можем запросить текущий контейнер/подсистему, чтобы узнать, запущены ли другие сервисы, запросив различные порты и адреса.
Давайте сделаем запрос к 5000 порту в том же контейнере.
http://127.0.0.1:5000

1682632073859.png


И потом после перебора c помощью ffuf/gobuster, мы получаем такой путь:



1682632073894.png


Видим что это base64 и декодируем полученное

NodePort exposed services

Когда Kubernetes создает службу NodePort, она выделяет порт из диапазона, указанного во флагах, которые определены в конфигурации вашего кластера Kubernetes. (По умолчанию это порты в диапазоне 30000-32767).

В этом сценарии мы видим еще одну неправильную конфигурацию, которая может дать злоумышленникам доступ к внутренним службам и нераскрытым службам. Это одна из простых ошибок, допущенных при создании служб Kubernetes, а также при установке и конфигурации кластера.

Если кто-то из пользователей открыл какой-либо сервис в кластере Kubernetes с помощью NodePort, это означает, что на узлах, где запущены кластеры Kubernetes, не включен брандмауэр/сетевая безопасность. Нам нужно увидеть неаутентифицированные и неавторизованные сервисы.

Получаем список информации о внешних IP-адресах узлов Kubernetes, выполнив следующую команду
kubectl get nodes -o wide

1682631848955.png


Теперь давайте выясним открытые порты. В этом случае вы можете использовать традиционные утилиты сканирования, такие как nmap. Как только мы определили, что существует открытый порт NodePort, мы можем просто проверить его, подключившись и получив к нему доступ

1682631848966.png


Теперь мы видим, что мы можем получить доступ к внутренним службам, которые не выставлены на всеобщее обозрение, к ним можно получить доступ и обойти их благодаря конфигурации NodePort

RBAC least privileges misconfiguration

Kubernetes предоставляет ряд встроенных механизмов для аутентификации API-серверов, однако они, скорее всего, подходят только для непроизводственных или небольших кластеров.

RBAC существует, для реализации принципа безопасности наименьших привилегий. Тем не менее, большинство реальных рабочих нагрузок и ресурсов в итоге имеют более широкие привилегии, чем предполагалось. В этом сценарии мы увидим, как простая неправильная конфигурация может получить доступ к секретам, ресурсам и информации.

В реальном мире мы часто видим, как разработчики и команды DevOps склонны предоставлять дополнительные привилегии, чем требуется. Это предоставляет злоумышленникам больше контроля и привилегий, чем они предполагали. В этом сценарии вы можете использовать учетную запись службы, привязанную к pod, для предоставления доступа webhookapikey, но с ее помощью злоумышленник может получить контроль над другими секретами и ресурсами.

По умолчанию Kubernetes хранит всю информацию о токенах и учетных записях служб в стандартном месте
В нашем случае переходим по следующему пути:

cd /var/run/secrets/kubernetes.io/serviceaccount/

1682632539310.png


Теперь мы можем использовать эту информацию для запроса и общения со службой API Kubernetes с доступными разрешениями и привилегиями. Чтобы указать на имя хоста внутреннего сервера API, мы можем экспортировать его

export APISERVER=https://${KUBERNETES_SERVICE_HOST}

Устанавливаем путь к токену ServiceAccount

export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount

Экспортируем неймспейсы

export NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)

Чтобы прочитать токен ServiceAccount, также его экспортируем

export TOKEN=$(cat ${SERVICEACCOUNT}/token)

Указать путь ca.crt, чтобы мы могли использовать его при запросе в запросах curl

export CACERT=${SERVICEACCOUNT}/ca.crt

Теперь мы можем исследовать API Kubernetes с помощью токена и построенных запросов

curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api

1682632539330.png


Чтобы запросить доступные секреты в пространстве имен по умолчанию, выполните следующую команду

curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/secrets

1682632539346.png


Для запроса секретов, специфичных для пространства имен

curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/${NAMESPACE}/secrets

1682632539363.png


Для запроса pod в определенном пространстве имен

curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/${NAMESPACE}/pods

1682632539380.png


И получаем значение k8svaulapikey

curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/${NAMESPACE}/secrets | grep k8svaultapikey

1682632539396.png


Ура, теперь можем расшифровать закодированное значение base64 с помощью следующей команды

echo "azhzLWdvYXQtODUwNTc4NDZhODA0NmEyNWIzNWYzOGYzYTI2NDlkY2U=" | base64 -d

И еще про Kubernetes CIS benchmarks analysis

The Center for Internet Security (CIS) Kubernetes Benchmark - это набор рекомендаций по настройке Kubernetes для поддержки надежной защиты. Эталон привязан к конкретному выпуску Kubernetes. CIS Kubernetes Benchmark написан для дистрибутива Kubernetes с открытым исходным кодом и призван быть максимально универсальным для всех дистрибутивов.
Этот сценарий очень полезен при проведении аудитов и оценок безопасности Kubernetes. Здесь мы научимся проводить популярный эталонный аудит CIS для кластера Kubernetes и использовать результаты для дальнейшего использования или устранения неправильных конфигураций и уязвимостей. Это очень важно и обязательно, если вы занимаетесь аудитом и обеспечением соответствия в современном мире контейнеров, Kubernetes и облачных экосистем.
Мы можем развернуть Kubernetes CIS benchmarks, выполнив следующую команду

kubectl apply -f scenarios/kube-bench-security/node-job.yaml

Теперь мы можем получить список заданий и информацию о связанных с ними стручках, выполнив следующую команду

kubectl get jobs

kubectl get pods

1682633146601.png


После того, как мы определили pod, мы можем получить результаты аудита, посмотрев логи.

1682633146622.png


Мы видим, что он возвращает все проблемы вашего кластера.

На этом все :)

Данные проблемы я смог разобрать, благодаря kube-goat (некий аналог OWASP Juice Shop), который предоставляет вам заранее подготовленный кластер с проблемами выше.
 
Последнее редактирование модератором:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!