Initial access Execution Persistence Privilege escalation Defense evasion Credential access Discovery Lateral movement Collection Impact
Using Cloud Exec into Container Backdoor Container Privileged Container Clear Container Logs List K8s secrets Access the K8s API server Access cloud resources Images from a private repository Data Destruction
Compromised images in registry bash/cmd in container Writable hostPath mount Cluster-admin binding Delete k8s events Mount service principal Access Kubelet API Container service account Ressource hijacking
Kubeconfig file New container Kubernetes CronJob hostPath mount Pod / container name similarity Access container service account Network mapping Cluster internal networking Denial of Service
Application vulnerability Application exploit (RCE) Malicious admission controller Access cloud resources Connect from proxy server Applications credentials in configuration files Access Kubernetes dashboard Applications credentials in configuration files
Exposed sensitive interfaces SSH server running in inside container Disable Namespacing Access managed identity credentials Instance metadata API Writable volume mounts on the host
Sidecar injection Malicious admission controller CoreDNS poisoning
ARP poisoning and IP spoofing

Cluster internal networking

Kubernetes networking behavior allows traffic between pods in the cluster as a default behavior. Attackers who gain access to a single container may use it for network reachability to another container in the cluster.

Example

First we need to create an appropriate demo setup to explain.

# A namespace called "secret"
apiVersion: v1
kind: Namespace
metadata:
  name: secret
---
# A web application in the form of a Pod called "web" in the "secret" namespace
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: web
  name: web
  namespace: secret
spec:
  containers:
  - image: nginx
    name: web
    ports:
    - containerPort: 80
---
# A service which exposes the "web" Pod in the "secret" namespace
apiVersion: v1
kind: Service
metadata:
  labels:
    app: web
  name: web
  namespace: secret
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web
---
# A web application in the form of a Pod called "web-secret-only" in the "secret" namespace
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: web-secret-only
  name: web-secret-only
  namespace: secret
spec:
  containers:
  - image: nginx
    name: web
    ports:
    - containerPort: 80
---
# A service which exposes the "web-secret-only" Pod in the "secret" namespace
apiVersion: v1
kind: Service
metadata:
  labels:
    app: web-secret-only
  name: web-secret-only
  namespace: secret
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web-secret-only
---
# A second namespace which is called "test-namespace"
apiVersion: v1
kind: Namespace
metadata:
  name: test-namespace
---
# A Pod called "test-pod" in the "test-namespacecret" namespace (it doesn't matter that it's also a web application)
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: test-namespace
spec:
  containers:
  - image: nginx
    name: web
$ kubectl exec -it test-pod -n test-namespace -- curl http://web.secret
  # Gives a proper HTTP 200 response
$ kubectl exec -it test-pod -n test-namespace -- curl http://web-secret-only.secret
  # Gives a proper HTTP 200 response
$ kubectl exec -it web -n secret -- curl http://web-secret-only.secret
  # Gives a proper HTTP 200 response

Now we add NetworkPolicy objects which will make sure the web Pod/Service is the only one in the secret namespace that can be reached from containers running in other namespaces. Within the secret namespace Pods can communicate with each other without any restrictions.

Make sure your Kubernetes cluster uses a CNI that supports NetworkPolicy objects and enforces them. Many Kubernetes distributions that are used mainly for development and testing like Minikube and k3d may require additional configuration steps.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  namespace: secret
  name: deny-from-other-namespaces
spec:
  podSelector:
    matchLabels:
  ingress:
  - from:
    - podSelector: {}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: web-allow-all-namespaces
  namespace: secret
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
    - from:
        - namespaceSelector: {}
$ kubectl exec -it test-pod -n test-namespace -- curl http://web.secret
  # Gives a proper HTTP 200 response
$ kubectl exec -it test-pod -n test-namespace -- curl http://web-secret-only.secret
  # Timeout - no connection possible
$ kubectl exec -it web -n secret -- curl http://web-secret-only.secret
  # Gives a proper HTTP 200 response

As we can see, the test-pod can no longer reach the web-secret-only application in the secret namespace as the test-pod is located in the test-namespace namespace. An attacker might therefore target the web Pod as e.g. in the case of it containing a software vulnerability which can then be exploited by an attacker as described in Application exploit (RCE) to use it as a pivot point to target web-secret-only once web is under the attacker’s control.

References