pod_escape_log
Pod Log Escape via hostPath Symlink Manipulation
This document demonstrates a security vulnerability where a pod with hostPath access to /var/log can manipulate log files of other pods on the same node. By replacing a target pod's log file (e.g., 0.log) with a symbolic link to a sensitive file on the node (like /etc/passwd or /etc/kubernetes/kubelet.conf), an attacker can potentially read these sensitive files by accessing the logs through the Kubelet's log endpoint.
Caution: Granting pods hostPath access, especially to sensitive directories like /var/log, carries significant security risks. This example illustrates one such risk. Always follow the principle of least privilege.
1. Attacker Pod Setup (escaper)
escaper)First, we deploy a pod (escaper) that mounts the node's /var/log directory into its own /var/log/host path.
Create the
escaperPod manifest (escaper.yaml):cat << EOF > escaper.yaml apiVersion: v1 kind: Pod metadata: name: escaper spec: containers: - name: escaper image: nginx # Any image that allows shell access can be used volumeMounts: - name: logs mountPath: /var/log/host # nodeSelector: # Optionally, select a specific node to run this pod on # kubernetes.io/hostname: your-target-node volumes: - name: logs hostPath: path: /var/log/ # Mounts the entire /var/log from the host type: Directory EOFDeploy the
escaperPod:kubectl create -f escaper.yaml
2. Targeting Another Pod's Logs
Next, from within the escaper pod, we will navigate to the log directory of a target pod and replace its log files with symbolic links to sensitive files on the node.
Access the
escaperpod's shell:Inside the
escaperpod, perform the following:Navigate to the host's pod log directory:
List available pod log directories to identify a target. Each directory here typically corresponds to
NAMESPACE_POD-NAME_POD-UID.Choose a target pod's log directory and container log subdirectory. Each pod log directory is typically named in the format
NAMESPACE_PODNAME_PODUID. For example, if you find a directory nameddefault_victim-pod_some-uidand it has a container log subdirectoryvictim-container, you would:(Replace
NAMESPACE_PODNAME_PODUIDandCONTAINER_NAMEwith actual names from your environment.)Manipulate the log files. For instance, replace
0.logwith a symlink to/etc/passwdand1.logwith a symlink to/etc/kubernetes/kubelet.conf. You might need to remove existing log files first.(Corrected "passswd" to "passwd". Used
ln -sffor force overwrite if link exists.)Exit the
escaperpod's shell:
3. Attempting Access via API Server (kubectl logs)
kubectl logs)Attempting to read the manipulated logs via kubectl logs (which goes through the Kubernetes API server) will likely fail or show an error, as the API server expects actual log files, not arbitrary file content via symlinks that point outside the standard log structure.
Identify the target pod and its namespace. (This is the pod whose logs you manipulated, e.g.,
victim-podin namespacedefault).Attempt to fetch logs:
You will likely see an error message, such as "unsupported log format" or similar, because the content of
/etc/passwdis not whatkubectl logsexpects.
4. Direct Access via Kubelet Log Endpoint
The Kubelet on each node also serves logs directly via an HTTPS endpoint (typically port 10250). If an attacker can reach this endpoint with appropriate credentials (often found on the node, e.g., /etc/kubernetes/pki/apiserver-kubelet-client.key and .crt), they can read the content of the files pointed to by the symbolic links.
Note: The following commands are typically run from the Kubernetes node itself or a machine that has network access to the node's Kubelet port and possesses the necessary client certificates.
Identify the target node's IP address (e.g.,
10.10.2.35in the original example) and the full path to the manipulated log file as seen by the Kubelet. This path is usually/var/log/pods/NAMESPACE_POD-NAME_POD-UID/CONTAINER-NAME/X.log.Use
curlto fetch the content: ReplaceNODE_IP,NAMESPACE_PODNAME_PODUID, andCONTAINER_NAMEwith actual values.To get the content of
/etc/passwd(linked to0.log):To get the content of
/etc/kubernetes/kubelet.conf(linked to1.log):To get the content of the copied
passwd_copy_testfile:
Example curl Output
curl OutputThe following is an example of verbose output from one such curl command, showing successful retrieval of file content (in this case, resembling /etc/passwd):
(Marked as text and generalized placeholders. Also added comments for clarity.)
Last updated