13 KiB
Pentesting Kubernetes Services
{{#include ../../../banners/hacktricks-training.md}}
Kubernetes usa varios servicios de red específicos que podrías encontrar expuestos a Internet o en una red interna una vez que hayas comprometido un pod.
Finding exposed pods with OSINT
Una forma podría ser buscar Identity LIKE "k8s.%.com" en crt.sh para encontrar subdominios relacionados con kubernetes. Otra forma podría ser buscar "k8s.%.com" en github y buscar archivos YAML que contengan la cadena.
Señales externas útiles de recon para correlacionar antes de escanear:
- Nombres de DNS y certificate transparency que contengan
k8s,kube,api,apiserver,eks,gke,aks,cluster,ingress,argocd,grafana,prometheus,harbor,registry,dashboard,dev,stageo nombres de región. - Nombres de cloud load balancer, CNAMEs, tags y hostnames del proveedor que puedan vincular una aplicación expuesta o una interfaz de plataforma con un cluster.
- Repositorios públicos, logs de CI, valores de Helm, estado de Terraform, manifests renderizados, container images y documentación que filtren kubeconfigs, URLs del API server, namespaces, service accounts,
type: LoadBalancer,type: NodePort, hosts de Ingress, listeners de Gateway o configuraciones del dashboard. - Inventario de managed Kubernetes, cuando las credenciales de cloud están dentro del alcance: acceso público/privado al endpoint de EKS y CIDRs públicos, configuración de control-plane público/privado en GKE y redes autorizadas, y configuración de IP autorizadas para clusters privados/API server en AKS.
- Herramientas de plataforma expuestas alrededor del cluster como Argo CD, Prometheus, Grafana, Harbor, registries, dashboards de CI/CD, dashboards de service mesh y endpoints de administración o métricas del ingress-controller.
Trata estas pistas como indicios de atribución y priorización. Una aplicación pública de Ingress es normal en muchos clusters, mientras que kubelet, etcd, dashboard, control de despliegue de CI/CD o material de kubeconfig filtrado expuestos deben priorizarse mucho más.
How Kubernetes Exposes Services
Puede resultarte útil entender cómo Kubernetes puede exponer servicios públicamente para encontrarlos:
{{#ref}} ../exposing-services-in-kubernetes.md {{#endref}}
Finding Exposed pods via port scanning
Los siguientes puertos podrían estar abiertos en un cluster de Kubernetes:
| Port | Process | Description |
|---|---|---|
| 443/TCP | kube-apiserver | Puerto de la API de Kubernetes |
| 2379/TCP | etcd | |
| 6666/TCP | etcd | etcd |
| 4194/TCP | cAdvisor | Métricas del contenedor |
| 6443/TCP | kube-apiserver | Puerto de la API de Kubernetes |
| 8443/TCP | kube-apiserver | Puerto de la API de Minikube |
| 8080/TCP | kube-apiserver | Puerto de API inseguro |
| 10250/TCP | kubelet | API HTTPS que permite acceso en modo completo |
| 10255/TCP | kubelet | Puerto HTTP de solo lectura sin autenticación: pods, pods en ejecución y estado del nodo |
| 10256/TCP | kube-proxy | Servidor de comprobación de salud de Kube Proxy |
| 9099/TCP | calico-felix | Servidor de comprobación de salud para Calico |
| 6782-4/TCP | weave | Métricas y endpoints |
| 30000-32767/TCP | NodePort | Proxy a los servicios |
| 44134/TCP | Tiller | Servicio de Helm en escucha |
Nmap
nmap -n -T4 -p 443,2379,6666,4194,6443,8443,8080,10250,10255,10256,9099,6782-6784,30000-32767,44134 <pod_ipaddress>/16
Kube-apiserver
Este es el servicio API de Kubernetes con el que los administradores hablan normalmente usando la herramienta kubectl.
Puertos comunes: 6443 y 443, pero también 8443 en minikube y 8080 como inseguro.
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
Consulta la siguiente página para aprender cómo obtener datos sensibles y realizar acciones sensibles hablando con este servicio:
{{#ref}} ../kubernetes-enumeration.md {{#endref}}
Kubelet API
Este servicio se ejecuta en cada nodo del cluster. Es el servicio que controlará los pods dentro del nodo. Habla con el kube-apiserver.
Si encuentras este servicio expuesto, podrías haber encontrado una RCE sin autenticación.
Kubelet API
curl -k https://<IP address>:10250/metrics
curl -k https://<IP address>:10250/pods
Si la respuesta es Unauthorized, entonces requiere autenticación.
Si puedes listar nodes, puedes obtener una lista de endpoints de kubelets con:
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}')
port=$(echo $node | awk '{print $2}')
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 (Solo lectura)
curl -k https://<IP Address>:10255
http://<external-IP>:10255/pods
API de etcd
curl -k https://<IP address>:2379
curl -k https://<IP address>:2379/version
etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
Tiller
helm --host tiller-deploy.kube-system:44134 version
Podrías abusar de este service para escalar privilegios dentro de Kubernetes:
cAdvisor
Service útil para recopilar métricas.
curl -k https://<IP Address>:4194
NodePort
Cuando un puerto se expone en todos los nodos mediante un NodePort, el mismo puerto se abre en todos los nodos proxificando el tráfico hacia el Service declarado. Por defecto, este puerto estará en el rango 30000-32767. Así que nuevos servicios no comprobados podrían ser accesibles a través de esos puertos.
sudo nmap -sS -p 30000-32767 <IP>
Service mesh and proxy surfaces
Los clústeres que usan Istio, Linkerd, Cilium service mesh, o gateways basados en Envoy añaden otra capa de servicios para enumerar. Un mesh puede proporcionar mTLS, identidad de workload, routing L7, authorization policy, telemetry y controles de gateway/egress, pero solo protege el tráfico que realmente está inscrito e interceptado por el mesh.
Comprobaciones útiles desde el acceso a Kubernetes:
kubectl get ns --show-labels | egrep 'istio|linkerd|mesh|cilium'
kubectl get crd | egrep 'istio.io|linkerd.io|gateway.networking.k8s.io|cilium.io'
kubectl get mutatingwebhookconfiguration,validatingwebhookconfiguration | egrep 'istio|linkerd|cilium'
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,CONTAINERS:.spec.containers[*].name'
kubectl get svc -A | egrep 'istio|envoy|linkerd|kiali|jaeger|prometheus|grafana|zipkin|hubble'
Review:
- 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.
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 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.
Useful checks:
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"
Si las resource APIs devuelven 403, el API server puede haber clasificado la request como system:anonymous pero la authorization la bloqueó. Si las resource APIs devuelven 200 sin credentials, busca RoleBindings o ClusterRoleBindings hacia system:anonymous o system:unauthenticated, una configuración permisiva de authorizer-chain, o un error de authentication en la front-door.
Checking for ETCD Anonymous Access
ETCD almacena los cluster secrets, configuration files y más datos sensitive. Por default, ETCD no puede ser accedido anonymously, pero siempre es bueno comprobarlo.
Si ETCD puede ser accedido anonymously, quizá necesites usar la etcdctl tool. El siguiente comando obtendrá todas las keys almacenadas:
etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
Kubelet RCE
La Kubelet documentation explica que, por default, el acceso anónimo al servicio está permitido:
Enables anonymous requests to the Kubelet server. Requests that are not rejected by another authentication method are treated as anonymous requests. Anonymous requests have a username of
system:anonymous, and a group name ofsystem:unauthenticated
Para entender mejor cómo funciona la authentication y authorization de la Kubelet API revisa esta página:
{{#ref}} kubelet-authentication-and-authorization.md {{#endref}}
El servicio Kubelet API is not documented, pero el código fuente se puede encontrar aquí y descubrir los endpoints expuestos es tan fácil como ejecutar:
curl -s https://raw.githubusercontent.com/kubernetes/kubernetes/master/pkg/kubelet/server/server.go | grep 'Path("/'
Path("/pods").
Path("/run")
Path("/exec")
Path("/attach")
Path("/portForward")
Path("/containerLogs")
Path("/runningpods/").
Todos suenan interesantes.
Puedes usar la herramienta Kubeletctl para interactuar con Kubelets y sus endpoints.
/pods
Este endpoint lista los pods y sus contenedores:
kubeletctl pods
/exec
Este endpoint permite ejecutar código dentro de cualquier contenedor muy fácilmente:
kubeletctl exec [command]
Note
Para evitar este ataque, el servicio kubelet debe ejecutarse con
--anonymous-auth falsey el servicio debe estar segregado a nivel de red.
Checking Kubelet (Read Only Port) Information Exposure
Cuando un kubelet read-only port está expuesto, es posible que partes no autorizadas recuperen información desde la API. La exposición de este puerto puede llevar a la divulgación de varios cluster configuration elements. Aunque la información, incluidos pod names, locations of internal files, and other configurations, puede no ser crítica, su exposición sigue representando un riesgo de seguridad y debe evitarse.
Un ejemplo de cómo puede explotarse esta vulnerabilidad implica que un atacante remoto acceda a una URL específica. Al navegar a http://<external-IP>:10255/pods, el atacante puede recuperar información sensible del kubelet:
References
{{#ref}} https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-2 {{#endref}}
{{#ref}} https://labs.f-secure.com/blog/attacking-kubernetes-through-kubelet {{#endref}}
{{#include ../../../banners/hacktricks-training.md}}

