← All Threat Hunting ReportsThreat Hunting Exercise

Threat Hunting Exercise: Analyzing AWS IAM PassRole Privilege Escalation Dataset

Returning to CloudTrail for T1078.004: Valid Accounts - Cloud Accounts combined with IAM privilege escalation, where a compromised low-privilege IAM user with an over-permissioned iam:PassRole + lambda:CreateFunction combination creates a Lambda function that assumes a highly-privileged role, executing arbitrary AWS API calls as if it were an administrator - one of the most common real-world AWS privesc paths (à la the "PrivEsc" cheat sheets).

Step 1: Hypothesis Formation

Hypothesis: A compromised IAM user with no direct admin rights, but with iam:PassRole and lambda:CreateFunction/lambda:InvokeFunction permissions, creates a new Lambda function, passes it an existing high-privilege execution role (e.g., the org's AdminLambdaRole), and invokes it to run privileged API calls (e.g., creating a new IAM admin user or attaching AdministratorAccess policy) - all attributable back to the Lambda's assumed role rather than the original user, evading simple "who did X" review. Indicators:

Null Hypothesis: Legitimate DevOps deployment of a new Lambda function using a shared execution role per IaC pipeline convention. Invalidate via the specific combination of a brand-new, narrowly-scoped user creating admin-equivalent IAM objects immediately after Lambda invocation, and absence of any CI/CD user-agent or CloudFormation/Terraform stack correlation.

Rationale: This complements the earlier EC2/S3 exfiltration hunt in this series by covering a different cloud attack surface - privilege escalation through IAM misconfiguration rather than direct data theft - a critical and underhunted AWS pattern.

Step 2: Data Sources and Scope

Step 3: Key Findings

Parsed CloudTrail events (9 shown) confirm the full escalation chain: role-passing Lambda creation, invocation, and resulting admin-equivalent IAM object creation, all within 3 minutes.

Timestamp (UTC)Event NameUser IdentityKey DetailsIOC/Why Suspicious?
2022-04-07 11:20:02GetCallerIdentityIAMUser: contractor-devopsuserAgent=aws-cli/2.4.6; sourceIPAddress=185.220.101.33 (Tor exit node range).Recon IOC: Basic identity check right after obtaining leaked credentials - common first move for stolen-key validation.
2022-04-07 11:20:05ListRolesIAMUser: contractor-devopsEnumerates all IAM roles in the account.Actor surveys available roles to find one to abuse via PassRole.
2022-04-07 11:20:30GetRoleIAMUser: contractor-devopsroleName=AdminLambdaRole; policy attached=AdministratorAccess.Targeting IOC: Identifies the over-privileged Lambda execution role - the actual vulnerability being exploited.
2022-04-07 11:21:00CreateFunctionIAMUser: contractor-devopsfunctionName=maintenance-task; role=arn:aws:iam::123456789123:role/AdminLambdaRole; runtime=python3.9; code=inline zip (60 lines).Core IOC: contractor-devops has no direct admin rights but successfully passes an admin-equivalent role to a new Lambda - the PassRole+CreateFunction combination is the actual privesc primitive.
2022-04-07 11:21:30InvokeFunctionIAMUser: contractor-devopsfunctionName=maintenance-task; invocationType=RequestResponse.Triggers the function, which now runs with AdminLambdaRole's permissions.
2022-04-07 11:21:32CreateUserAssumedRole: AdminLambdaRole (via Lambda)userName=svc-backup-sync (innocuous-looking name); sourceIPAddress=AWS internal (Lambda execution environment).Escalation IOC: New IAM user created by the assumed role, not by contractor-devops directly - obscures attribution at a glance.
2022-04-07 11:21:35AttachUserPolicyAssumedRole: AdminLambdaRole (via Lambda)userName=svc-backup-sync; policyArn=arn:aws:iam::aws:policy/AdministratorAccess.Privilege IOC: Full admin policy attached to the newly created, innocuously-named backdoor user.
2022-04-07 11:21:40CreateAccessKeyAssumedRole: AdminLambdaRole (via Lambda)userName=svc-backup-sync; accessKeyId=AKIA...(new).Persistent long-lived credential created for the backdoor account - survives Lambda deletion.
2022-04-07 11:23:00DeleteFunctionIAMUser: contractor-devopsfunctionName=maintenance-task.Cleanup IOC: Function deleted immediately after use - removes the obvious CreateFunction/InvokeFunction trail from casual console review.

Validation:

Step 4: Recommendations & Next Steps

Hypothesis confirmed - IAM privilege escalation via Lambda PassRole abuse, complete with a persistent admin backdoor account! CloudTrail's AssumedRole attribution chain was essential to unmask the true actor behind the "anonymous" admin actions.