Introduction

Kubernetes, the automation and containerisation platform, has a function for sharing files between nodes and pods named “volumes”. These are very useful for developers that need two separate containerised programs to use the same resources or giving pods permanent storage no matter what node they are ran on. There are many different types of volumes within Kubernetes, and due to the number of types of volumes, it is challenging to keep all of them secure. This whitepaper highlights three different code injection / remote code execution vulnerabilities within certain volume types. 

HostPath Volumes Command Injection (CVE-2021-25741)

In September 2023, a researcher named Tomer Peled found a vulnerability in Kubernetes running on Windows systems. This vulnerability allowed for malicious code to be injected into a YAML file, which would then be executed by the system. 

 The volume we are focused on for this exploit is hostPath volumes, which mount a file / directory directly from the host server into the pod. These volumes are defined by a YAML file within the pod. 

This YAML file has previously been an attack vector, as in 2021, a vulnerability was found within the subPath field, where a malicious symlink could be added which would lead to code injection, this was given a CVE identifier (CVE-2021-25741) and remediated. 

The patch for this vulnerability introduced a new function “isLinkPath”, which looks like this: 

This solution uses “exec.Command” to run a PowerShell command, but uses unsanitised user input within this command, making it highly likely to be susceptible to command injection. The command is built using string formatting functions and then passed as an argument to “powershell /c” which runs the string as a command directly, regardless of control characters. 

Using PowerShell’s evaluating expressions syntax, we can input a command into the “subPath” Field and it will be executed by the server when the mounting process starts. As this happens during the mounting process, mounting is done with SYSTEM privileges, therefore our injected command will run as system, allowing us to get a system shell on this pod.

Kubernetes YAML

This was given the identifier CVE-2023-3676 and a CVSS 3.1 rating of 8.8. 

This exploit requires a Windows node to be running, and for your user to be able to create pods. 

With these pre-requisites in place, all that is needed to perform this exploit is to apply a malicious yaml to the server, which will then run the exploit as SYSTEM. 

Here is a video showcasing a PoC pod shown above, being ran within the Kubernetes 1.27.4 environment that I created: 

This vulnerability was patched by changing the way that the user input was used by the command. Rather than putting unsanitised user input directly into the command, the patch made it so that the user input is put into an environment variable, which is then called in the command, in turn removing the command injection vulnerability.

But wait… there’s more (CVE-2023-5528) 

In March of 2024, the same researcher found a similar issue in the Persistent Volumes function of Kubernetes. 

This vulnerability is similar to the last, where a field in a YAML file is inserted into a command without sanitisation, allowing for command injection. This time however, the attack vector is slightly different, as rather than attacking hostPath volumes, persistent volumes are used in this attack.  

Persistent volumes are areas of storage that are separate to the pod, often being stored in the cloud or on a NAS, however, local persistent volumes can be created which is where this vulnerability lies. When creating a local persistent volume, there is a “path” attribute within the YAML configuration file, this attribute was found to be vulnerable due to the way that Kubernetes handles mounting. 

When mounting a local volume to a pod, Kubernetes calls a function that creates a symlink between the local path and the path within the pod. To achieve this, Kubernetes calls a PowerShell command with unsanitised user input (again), which can be exploited to execute commands on the system.

As Kubelet runs as NTAUTHORITY\SYSTEM, any injected commands will also be run as SYSTEM, allowing for full system takeover if a shell is acquired. 

his screenshot shows the exploit running on a 1.27.4 cluster, running notepad. However, in order to exploit the vulnerability, I had to create the ”C:\&notepad.exe&&” directory on the node directly, otherwise the exploit would fail as the directory does not exist therefore cannot be symlinked to. 

Along with this, to create a persistent volume, you need extra privileges, which makes this vulnerability harder to exploit. This affects the overall impact and CVSS score of this vulnerability, as the privileges required becomes high, however it still comes out as a high severity vulnerability, but with a lower score than the previous exploit. 

Below is a PoC of this exploit in use: 

This gained the CVE identifier CVE-2023-5528, and this vulnerability is present on all default Windows Kubernetes versions below 1.28.4.  

This was patched by removing the command that checked for a symlink, and replacing it with a native GO function that has the same functionality. 

What about Linux? (CVE-2024-10220)

So far, both vulnerabilities mentioned only affected Windows worker nodes, which are far less common than Linux worker nodes. However, that does not mean that Linux nodes are immune to volume code injection attacks. In July 2024, a vulnerability was found within the “gitRepo” volume type, affecting Linux systems. 

The “gitRepo” volume is a simple volume that creates an empty directory on the pod and then clones a specified git repository into the new directory. This volume takes three arguments, repository (the git repo to be cloned), revision (the branch / commit hash to be checked out to) and directory (the directory in which Kubelet will run the git checkout command). The issue lies within the implementation of the git commands. With the directory argument, you can specify any level of subdirectory for the repo to be checked out to (for example /example/test), but all commands after the git clone will run in the main directory (/example rather than /example/test). This may not immediately seem like a serious vulnerability, however git offers a way of executing commands when certain events happen, called git hooks.  

Git hooks are scripts that are automatically ran after a certain event occurs, these scripts are held in the “.git/hooks” folder. This exploit uses a “post-checkout” git hook to execute commands on the underlying node.  

To execute this vulnerability, a malicious git repository must be created, which mirrors a “.git” folder structure, including the “post-checkout” git hook, which has malicious shell code inside (In this example, “id > /tmp/poc” was the command used). Creation of this malicious repo can be seen below: 

This malicious repo is then cloned by a pod, where the directory is set to /example/.git:

This will mount the malicious git repo into “/gitrepo/example/.git” in the pod. This will in turn create a “/gitrepo/example/.git/.git” directory, which is the non-malicious, default .git created by git. However, due to all commands after the clone being ran in the main directory, the checkout command will be ran in “/gitrepo/example”, which triggers the githook in “/gitrepo/example/.git/hooks/post-checkout”, executing our malicious code. As Kubelet runs as root, this command will also be run as root. 

Below is an example of the exploit running within a 1.27.4 Kubernetes cluster: 

Is it fixed? 

This issue was fixed in Kubernetes 1.31 and was retroactively given the CVE CVE-2024-10220, however, it is still present on these Kubernetes versions: 

  • kubelet v1.30.0 to v1.30.2 
  • kubelet v1.29.0 to v1.29.6 
  • kubelet <= v1.28.11 

Along with this fix, the “gitRepo” volumes documentation was updated to add a warning that the volume is deprecated and should not be used. 

Included within the warning is a method of restricting the use of gitRepo, which forces the cluster to reject all gitRepo volumes. 

The suggested workaround ensures that any git hooks are executed in the container, rather than on the underlying host pod. This works to limit the potential impact of running untrusted git hooks. 

References

[1] https://www.akamai.com/blog/security-research/kubernetes-critical-vulnerability-command-injection 

[2] https://www.akamai.com/blog/security-research/kubernetes-local-volumes-command-injection-vulnerability-rce-system-privileges 

[3] https://irsl.medium.com/sneaky-write-hook-git-clone-to-root-on-k8s-node-e38236205d54