[ CLUSTER A ] β βββ [ CONTROL PLANE ] ( Cluster Management Software ) β βββ API Server β βββ Scheduler β βββ [ WORKER 1 ] ( Physical Machine ) β βββ Kubelet ( Agent ) β βββ POD A ( Nginx + Git-Sync ) <-- Both containers here β βββ POD B (Java App) β βββ [ WORKER 2 ] ( Physical Machine ) βββ Kubelet ( Agent ) βββ POD A-2 ( Nginx + Git-Sync Replica )
Components
Cluster
A set of nodes, typically composed of a Master Node ( Control Plane ) and several Worker Nodes
Node
Basic unit within a Cluster, it can be either a Control Plane or a Worker Node
Control Plane
Master Node
It is the node responsible for controlling the given K8S cluster. It manages and coordinates all activities within the cluster and it also ensures that the clusterβs desired state is maintained
The Control Plane serves as the management layer. It consists of several crucial components β
SERVICE
TCP PORT[s]
etcd
2379 2380
API Server
6443
Scheduler
10251
Controller Manager
10252
Kubelet API
10250
Read-Only Kubelet API
10255
Minions
Worker Nodes
They serve as the designated location for the running applications. All nodes are managed and regulated by the Control Plane
They are basically physical hosts where PODS ( set of containers ) are located
POD
A set of one or more containers located within a Worder Node
Enumeration - K8S API Server
Port 6443
We cannot interact with the K8Sβ API REST unless we have valid credentials
If not, we will receive a 403 Forbidden error
curl --insecure --silent --location --request GET 'https://<TARGET>:6443'
Enumeration - Kubelet API
Port 10250
Unlike the K8S API Server, it allows, by default, anonymous authentication, so an operator could send several requests to the Kubelet of the given Worker Node in order to list the existing PODs, run system commands on them and so on
PODs Extraction
We can gather interesting information from the output of the command below by inspecting fields such as container images, namespaces, last applied configurations and so on
Curl
curl --insecure --silent --location --request GET 'https://<TARGET>:10250/pods' | jq .
As stated, since a Kubelet API allows anoymous authentication by default, an operator could perform several sensitive actions in order to escalate its privileges
Letβs suppose an adversary compromises a web application, which is running within a K8S container, and gain remote access to it through a Reverse Shell by leveraging an arbitrary File Upload
Then, the attacker carries out a Network Enumeration on the existing subnets and discovers the Worker Node IP Address.
In addition, the TCP port 10250 related to the Kubelet API REST of the Worker Node is open and accesible
So, since this API REST allows anonymous authentication by default, he can list the existing PODs and its namespaces ( containers )
Command Execution on a PODβs Container
Once the operator knows the name of any POD and its container[s], system commands can be executed on any of them as follows
Similarly, we must extract the CA Certificate in order to stablish a valid TLS connection to the Control Planeβs ( Master Node ) API Server ( K8S Api Server β Port 6443 )
As stated, once we have both the POD serviceAccountβs Token and the CA Certificate, we can authenticate to the K8S API REST as the given serviceAccount, which identifies the POD
Therefore, we can enumerate sensitive aspects of the infrastructure
Listing Privileges
To do so, we provide the token and the CA Certificate as follows
Letβs suppose that we have listed the privileges related to the provided token and we discover that we can get, create and list PODS within the Worker Node ( Minion )
So, we can proceed in a similar way to how we do when we have permissions to create Docker or LXD containers
That is, we can use a YML file to create a new POD consisting of a single container and mount the entire Worker Nodeβs filesystem into this container
From there, we could access any hosts system directory and file, so the host is compromised along with the existing PODs and containers within it