Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

klogExtract

Error-based file extraction of k8s node.

The exploit

Arbitrary host file read from /var/log mount

If a pod's container mounts the host's /var/log folder (or any pod log file, usually located in /var/log/pods/namespace_pod-name_id/container-name/0.log) in write mode, attackers with control of the container can read any file of the underlying node filesystem by creating a symlink. You can find more details here.

The extraction used to be quite straightforward by contacting the kubelet or the API, as it seems there was no log format validation at the time of discovery of this misconfiguration abuse. I assume it changed when k8s migrated to cri-containerd and dropped dockershim (I guess dockershim didn't do any validation, but I might be wrong on which component exactly was responsible). The new implementation checks that the log line starts with a timestamp or is of json format: source which seems like it would prevent us from retrieving the line.

Error-base extraction

If the first line of the "log" file does not match one of the accepted format, the whole line is returned

If you created a symlink 0.log -> /var/lib/kubelet/pki/kubelet-key.pem and you try to retrieve the pod's logs:

kubectl logs my-vuln-pod
> failed to get parse function: unsupported log format: "-----BEGIN EC PRIVATE KEY-----\n"

We can use the tail option of k8s logging to retrieve all the lines: the cri-client first seek the tail starting points, then reads the first line to pass it to the function trying all the parsers, so by setting tail to 1, then 2, then 3 etc. we can effectively read the whole file.

Usage

Build

git clone https://github.com/Minosity-VR/klogExtract.git
cd klogExtract
go build

Run

./klogextract -n (NAMESPACE) -p (POD_NAME) -c [CONTAINER_NAME] -r [REPEAT_LIMIT]

The CLI requires two arguments, -n for the target namespace and -p for the target pod. If the controlled container is not the main pod container but a sidecar, you can switch target with -c.

As we can't know for sure when we reach the top of the file, we keep increasing the tail size until a line is repeated REPEAT_LIMIT times (then we ignore those repeated lines and keep only one). Defaults to 5.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages