Description
We have a kubernetes cluster setup and the flag is in the secrets. You think you can get it?
Setup
Launch the challenge instance and SSH in.
A kubeconfig or service account token will be available in the environment.
Solution
Walk me through it- Step 1Check the Kubernetes contextVerify kubectl works and read kubectl auth can-i --list carefully: you want get or list on the secrets resource. create or patch without get is read-blind (you can write but not read), which is a different game.bash
kubectl config current-contextbashkubectl get namespacesbashkubectl auth can-i --listbashkubectl auth can-i get secretsbashkubectl auth can-i list secretsLearn more
Kubernetes (k8s) is an open-source container orchestration platform. It organises containerised workloads into pods (groups of containers), and groups pods into namespaces (logical isolation boundaries).
kubectlis the command-line client that communicates with the Kubernetes API server.A kubeconfig file (typically at
~/.kube/config) stores cluster connection details, credentials, and the current context (which cluster and namespace you are targeting). Thekubectl config current-contextcommand shows which context is active.kubectl auth can-i --listshows all actions the current user is permitted to perform - this is the first step in Kubernetes privilege assessment during a penetration test.In cloud environments, Kubernetes clusters are commonly managed by cloud providers (Amazon EKS, Google GKE, Azure AKS). Each pod can be assigned a service account with associated permissions. When a pod is compromised, attackers often find the service account token at
/var/run/secrets/kubernetes.io/serviceaccount/tokenand use it to authenticate to the API server. - Step 2List Kubernetes secretsRun kubectl get secrets first to see the names. If the flag-bearing secret isn't obvious from the name, dump every secret as YAML and grep for the picoCTF prefix in the base64-decoded data.bash
kubectl get secretsbashkubectl get secrets --all-namespacesbash# If the relevant secret isn't obviously named, search every value:bashkubectl get secrets -o yaml | grep -i flagbash# Or decode every value to find the one that starts with picoCTF{:bashkubectl get secrets -o jsonpath='{range .items[*]}{.metadata.name}{": "}{range .data.*}{@}{"\n"}{end}{end}' | while read line; do echo "$line"; doneLearn more
Kubernetes Secrets are API objects designed to store sensitive data like passwords, tokens, and certificates. They are stored in etcd(the cluster's distributed key-value store) and can be mounted into pods as files or exposed as environment variables. The built-in Secrets object provides namespacing and RBAC-controlled access, but it does not provide encryption by default - values are stored base64-encoded, not encrypted.
The key Kubernetes RBAC permission for this challenge is
getandliston thesecretsresource. A cluster that grants broad secret-read permissions to any service account is a common misconfiguration. Real-world Kubernetes security incidents like the Tesla cryptojacking breach (2018) and several CI/CD supply chain attacks exploited overly permissive service account tokens to exfiltrate secrets.Kubernetes also supports integration with external secret management systems like HashiCorp Vault (via the Vault Agent Injector or CSI Driver), AWS Secrets Manager (via the External Secrets Operator), and Sealed Secrets (which encrypts secrets as SealedSecret CRDs that are safe to commit to git). These provide encryption at rest and fine-grained access control beyond what native Kubernetes Secrets offer. See the Linux CLI guide for more on enumerating cluster state from the command line.
- Step 3Retrieve the flag secretDescribe or get the flag secret and decode the base64-encoded value.bash
kubectl get secret flag-secret -o yamlbashkubectl get secret flag-secret -o jsonpath='{.data.flag}' | base64 -dLearn more
Kubernetes Secret values are stored base64-encoded in etcd and in the YAML output of
kubectl get secret. This encoding is not encryption - it is purely to allow arbitrary binary data to be stored in the YAML format. Anyone with read access to the secret can trivially decode the value withbase64 -d. This is why access control on thesecretsresource is critical.The
-o jsonpathflag applies a JSONPath expression to the API response and extracts just the requested field.{.data.flag}navigates to thedatamap and then theflagkey. Piping throughbase64 -ddecodes the value in one command. The equivalent usingjqiskubectl get secret flag-secret -o json | jq -r '.data.flag' | base64 -d.Encryption at rest for Kubernetes Secrets requires configuring the API server with an
EncryptionConfigurationthat specifies an encryption provider (AES-GCM, AES-CBC, or a KMS provider backed by an external key management system). Without this configuration, secrets in etcd are only base64-encoded and readable by anyone with direct etcd access. Most managed Kubernetes services (EKS, GKE) enable encryption at rest by default; self-managed clusters must configure it explicitly.
Flag
picoCTF{k8s_s3cr3ts_...}
Kubernetes secrets are stored base64-encoded; kubectl get secret with -o jsonpath decodes them.