Az - Function Apps

Reading time: 13 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Grundinformationen

Azure Function Apps sind ein serverloser Compute-Dienst, der es Ihnen ermöglicht, kleine Codeabschnitte, die als Funktionen bezeichnet werden, auszuführen, ohne die zugrunde liegende Infrastruktur zu verwalten. Sie sind so konzipiert, dass sie Code als Reaktion auf verschiedene Trigger ausführen, wie z.B. HTTP-Anfragen, Timer oder Ereignisse von anderen Azure-Diensten wie Blob Storage oder Event Hubs. Function Apps unterstützen mehrere Programmiersprachen, darunter C#, Python, JavaScript und Java, was sie vielseitig für den Aufbau von ereignisgesteuerten Anwendungen, die Automatisierung von Workflows oder die Integration von Diensten macht. Sie sind kosteneffektiv, da Sie normalerweise nur für die Rechenzeit bezahlen, die verwendet wird, wenn Ihr Code ausgeführt wird.

hinweis

Beachten Sie, dass Funktionen eine Teilmenge der App-Dienste sind, daher werden viele der hier besprochenen Funktionen auch von Anwendungen verwendet, die als Azure Apps (webapp in cli) erstellt wurden.

Verschiedene Pläne

  • Flex Consumption Plan: Bietet dynamisches, ereignisgesteuertes Skalieren mit nutzungsabhängiger Preisgestaltung, wobei Funktionsinstanzen je nach Bedarf hinzugefügt oder entfernt werden. Es unterstützt virtuelles Networking und vorab bereitgestellte Instanzen, um Kaltstarts zu reduzieren, was es für variable Workloads geeignet macht, die keine Containerunterstützung erfordern.
  • Traditional Consumption Plan: Die Standard-Serverless-Option, bei der Sie nur für Rechenressourcen bezahlen, wenn Funktionen ausgeführt werden. Es skaliert automatisch basierend auf eingehenden Ereignissen und umfasst Optimierungen für Kaltstarts, unterstützt jedoch keine Containerbereitstellungen. Ideal für intermittierende Workloads, die automatisches Skalieren erfordern.
  • Premium Plan: Entwickelt für konstante Leistung, mit vorwärmenden Arbeitern, um Kaltstarts zu eliminieren. Es bietet erweiterte Ausführungszeiten, virtuelles Networking und unterstützt benutzerdefinierte Linux-Images, was es perfekt für geschäftskritische Anwendungen macht, die hohe Leistung und erweiterte Funktionen benötigen.
  • Dedicated Plan: Läuft auf dedizierten virtuellen Maschinen mit vorhersehbarer Abrechnung und unterstützt manuelles oder automatisches Skalieren. Es ermöglicht das Ausführen mehrerer Apps im selben Plan, bietet Rechenisolierung und gewährleistet sicheren Netzwerkzugang über App Service Environments, was es ideal für langfristige Anwendungen macht, die eine konsistente Ressourcenzuteilung benötigen.
  • Container Apps: Ermöglicht das Bereitstellen von containerisierten Funktions-Apps in einer verwalteten Umgebung, zusammen mit Microservices und APIs. Es unterstützt benutzerdefinierte Bibliotheken, die Migration von Legacy-Apps und GPU-Verarbeitung, wodurch die Verwaltung von Kubernetes-Clustern entfällt. Ideal für ereignisgesteuerte, skalierbare containerisierte Anwendungen.

Speicher-Buckets

Beim Erstellen einer neuen nicht containerisierten Function App (aber mit dem Code, der ausgeführt werden soll) werden die Code- und anderen funktionsbezogenen Daten in einem Speicherkonto gespeichert. Standardmäßig erstellt die Webkonsole für jede Funktion ein neues Konto, um den Code zu speichern.

Darüber hinaus wird der Code der App auf den neuen Code geändert und beim nächsten Aufruf der Funktion ausgeführt, wenn der Code im Bucket geändert wird (in den verschiedenen Formaten, in denen er gespeichert werden kann).

vorsicht

Dies ist aus der Perspektive eines Angreifers sehr interessant, da Schreibzugriff auf diesen Bucket es einem Angreifer ermöglichen würde, den Code zu kompromittieren und Berechtigungen für die verwalteten Identitäten innerhalb der Function App zu eskalieren.

Mehr dazu im Abschnitt zur Berechtigungseskalation.

Es ist auch möglich, die Master- und Funktionsschlüssel im Speicherkonto im Container azure-webjobs-secrets im Ordner <app-name> in den JSON-Dateien zu finden, die Sie dort finden können.

Beachten Sie, dass Funktionen auch erlauben, den Code an einem entfernten Ort zu speichern, indem einfach die URL dazu angegeben wird.

Networking

Bei Verwendung eines HTTP-Triggers:

  • Es ist möglich, Zugriff auf eine Funktion von überall im Internet zu gewähren, ohne eine Authentifizierung zu verlangen, oder den Zugriff IAM-basiert zu gewähren. Obwohl es auch möglich ist, diesen Zugriff einzuschränken.
  • Es ist auch möglich, Zugriff auf eine Function App von einem internen Netzwerk (VPC) zu gewähren oder einzuschränken.

vorsicht

Dies ist aus der Perspektive eines Angreifers sehr interessant, da es möglich sein könnte, von einer verwundbaren Funktion, die dem Internet ausgesetzt ist, zu internen Netzwerken zu pivotieren.

Function App-Einstellungen & Umgebungsvariablen

Es ist möglich, Umgebungsvariablen innerhalb einer App zu konfigurieren, die sensible Informationen enthalten könnten. Darüber hinaus werden standardmäßig die Umgebungsvariablen AzureWebJobsStorage und WEBSITE_CONTENTAZUREFILECONNECTIONSTRING (unter anderem) erstellt. Diese sind besonders interessant, da sie den Kontoschlüssel enthalten, um mit VOLLBERECHTIGUNGEN auf das Speicherkonto zuzugreifen, das die Daten der Anwendung enthält. Diese Einstellungen sind auch erforderlich, um den Code aus dem Speicherkonto auszuführen.

Diese Umgebungsvariablen oder Konfigurationsparameter steuern auch, wie die Funktion den Code ausführt, zum Beispiel, wenn WEBSITE_RUN_FROM_PACKAGE existiert, zeigt es die URL an, wo sich der Code der Anwendung befindet.

Function Sandbox

Innerhalb der Linux-Sandbox befindet sich der Quellcode in /home/site/wwwroot in der Datei function_app.py (wenn Python verwendet wird), der Benutzer, der den Code ausführt, ist app (ohne sudo-Berechtigungen).

In einer Windows-Funktion, die NodeJS verwendet, befand sich der Code in C:\home\site\wwwroot\HttpTrigger1\index.js, der Benutzername war mawsFnPlaceholder8_f_v4_node_20_x86 und war Teil der Gruppen: Mandatory Label\High Mandatory Level Label, Everyone, BUILTIN\Users, NT AUTHORITY\INTERACTIVE, CONSOLE LOGON, NT AUTHORITY\Authenticated Users, NT AUTHORITY\This Organization, BUILTIN\IIS_IUSRS, LOCAL, 10-30-4-99\Dwas Site Users.

Verwaltete Identitäten & Metadaten

Genau wie VMs können Funktionen verwaltete Identitäten von 2 Typen haben: Systemzugewiesen und Benutzerzugewiesen.

Die systemzugewiesene Identität ist eine verwaltete Identität, die nur die Funktion, die sie zugewiesen hat, verwenden kann, während die benutzerzugewiesenen verwalteten Identitäten verwaltete Identitäten sind, die von jedem anderen Azure-Dienst verwendet werden können.

hinweis

Genau wie bei VMs können Funktionen 1 systemzugewiesene verwaltete Identität und mehrere benutzerzugewiesene haben, daher ist es immer wichtig, zu versuchen, alle von ihnen zu finden, wenn Sie die Funktion kompromittieren, da Sie möglicherweise Berechtigungen für mehrere verwaltete Identitäten von nur einer Funktion eskalieren können.

Wenn keine systemzugewiesene Identität verwendet wird, aber eine oder mehrere benutzerzugewiesene Identitäten an eine Funktion angehängt sind, können Sie standardmäßig kein Token erhalten.

Es ist möglich, die PEASS-Skripte zu verwenden, um Tokens von der standardmäßigen verwalteten Identität vom Metadaten-Endpunkt zu erhalten. Oder Sie könnten sie manuell erhalten, wie in:

Cloud SSRF - HackTricks

Beachten Sie, dass Sie einen Weg finden müssen, um alle verwalteten Identitäten zu überprüfen, die eine Funktion angehängt hat, da der Metadaten-Endpunkt nur die standardmäßige verwenden wird (siehe den vorherigen Link für weitere Informationen).

Zugriffsschlüssel

hinweis

Beachten Sie, dass es keine RBAC-Berechtigungen gibt, um Benutzern den Zugriff auf die Funktionen zu gewähren. Der Funktionsaufruf hängt vom Trigger ab, der beim Erstellen ausgewählt wurde, und wenn ein HTTP-Trigger ausgewählt wurde, könnte es erforderlich sein, einen Zugriffsschlüssel zu verwenden.

Beim Erstellen eines Endpunkts innerhalb einer Funktion mit einem HTTP-Trigger ist es möglich, das Autorisierungsniveau des Zugriffsschlüssels anzugeben, das erforderlich ist, um die Funktion auszulösen. Drei Optionen sind verfügbar:

  • ANONYMOUS: Jeder kann über die URL auf die Funktion zugreifen.
  • FUNCTION: Der Endpunkt ist nur für Benutzer zugänglich, die einen Funktions-, Host- oder Master-Schlüssel verwenden.
  • ADMIN: Der Endpunkt ist nur für Benutzer mit einem Master-Schlüssel zugänglich.

Arten von Schlüsseln:

  • Funktionsschlüssel: Funktionsschlüssel können entweder standardmäßig oder benutzerdefiniert sein und sind so konzipiert, dass sie ausschließlich den Zugriff auf spezifische Funktionsendpunkte innerhalb einer Function App gewähren, was einen feineren Zugriff auf die Endpunkte ermöglicht.
  • Host-Schlüssel: Host-Schlüssel, die ebenfalls standardmäßig oder benutzerdefiniert sein können, gewähren Zugriff auf alle Funktionsendpunkte innerhalb einer Function App mit FUNCTION-Zugriffslevel.
  • Master-Schlüssel: Der Master-Schlüssel (_master) dient als administrativer Schlüssel, der erhöhte Berechtigungen bietet, einschließlich Zugriff auf alle Funktionsendpunkte (ADMIN-Zugriffslevel eingeschlossen). Dieser Schlüssel kann nicht widerrufen werden.
  • Systemschlüssel: Systemschlüssel werden von bestimmten Erweiterungen verwaltet und sind erforderlich, um auf Webhook-Endpunkte zuzugreifen, die von internen Komponenten verwendet werden. Beispiele sind der Event Grid-Trigger und Durable Functions, die Systemschlüssel verwenden, um sicher mit ihren jeweiligen APIs zu interagieren.

tipp

Beispiel für den Zugriff auf einen Funktions-API-Endpunkt mit einem Schlüssel:

https://<function_uniq_name>.azurewebsites.net/api/<endpoint_name>?code=<access_key>

Basis-Authentifizierung

Genau wie in App Services unterstützen Funktionen auch die Basis-Authentifizierung, um sich mit SCM und FTP zu verbinden, um Code mit einem Benutzernamen und Passwort in einer URL bereitzustellen, die von Azure bereitgestellt wird. Weitere Informationen dazu finden Sie in:

Az - Azure App Services

Github-basierte Bereitstellungen

Wenn eine Funktion aus einem Github-Repo generiert wird, ermöglicht die Azure-Webkonsole, automatisch einen Github-Workflow in einem bestimmten Repository zu erstellen, sodass der Code der Funktion aktualisiert wird, wann immer dieses Repository aktualisiert wird. Tatsächlich sieht die Github Action YAML für eine Python-Funktion so aus:

Github Action Yaml
yaml
# Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action
# More GitHub Actions for Azure: https://github.com/Azure/actions
# More info on Python, GitHub Actions, and Azure Functions: https://aka.ms/python-webapps-actions

name: Build and deploy Python project to Azure Function App - funcGithub

on:
push:
branches:
- main
workflow_dispatch:

env:
AZURE_FUNCTIONAPP_PACKAGE_PATH: "." # set this to the path to your web app project, defaults to the repository root
PYTHON_VERSION: "3.11" # set this to the python version to use (supports 3.6, 3.7, 3.8)

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Python version
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Create and start virtual environment
run: |
python -m venv venv
source venv/bin/activate

- name: Install dependencies
run: pip install -r requirements.txt

# Optional: Add step to run tests here

- name: Zip artifact for deployment
run: zip release.zip ./* -r

- name: Upload artifact for deployment job
uses: actions/upload-artifact@v4
with:
name: python-app
path: |
release.zip
!venv/

deploy:
runs-on: ubuntu-latest
needs: build

permissions:
id-token: write #This is required for requesting the JWT

steps:
- name: Download artifact from build job
uses: actions/download-artifact@v4
with:
name: python-app

- name: Unzip artifact for deployment
run: unzip release.zip

- name: Login to Azure
uses: azure/login@v2
with:
client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_6C3396368D954957BC58E4C788D37FD1 }}
tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_7E50AEF6222E4C3DA9272D27FB169CCD }}
subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_905358F484A74277BDC20978459F26F4 }}

- name: "Deploy to Azure Functions"
uses: Azure/functions-action@v1
id: deploy-to-function
with:
app-name: "funcGithub"
slot-name: "Production"
package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}

Darüber hinaus wird eine Managed Identity erstellt, damit die Github Action aus dem Repository sich damit bei Azure anmelden kann. Dies geschieht durch die Generierung einer föderierten Anmeldeinformation über die Managed Identity, die den Issuer https://token.actions.githubusercontent.com und den Subject Identifier repo:<org-name>/<repo-name>:ref:refs/heads/<branch-name> ermöglicht.

caution

Daher kann jeder, der dieses Repository kompromittiert, die Funktion und die daran angehängten Managed Identities kompromittieren.

Containerbasierte Bereitstellungen

Nicht alle Pläne erlauben die Bereitstellung von Containern, aber für die, die es tun, wird die Konfiguration die URL des Containers enthalten. In der API wird die linuxFxVersion Einstellung etwas wie: DOCKER|mcr.microsoft.com/... haben, während in der Webkonsole die Konfiguration die Bildeinstellungen anzeigen wird.

Darüber hinaus wird kein Quellcode im Speicher-Konto gespeichert, das mit der Funktion verbunden ist, da dies nicht erforderlich ist.

Enumeration

bash
# List all the functions
az functionapp list

# List functions in an function-app (endpoints)
az functionapp function list \
--name <app-name> \
--resource-group <res-group>

# Get details about the source of the function code
az functionapp deployment source show \
--name <app-name> \
--resource-group <res-group>
## If error like "This is currently not supported."
## Then, this is probalby using a container

# Get more info if a container is being used
az functionapp config container show \
--name <name> \
--resource-group <res-group>

# Get settings (and privesc to the sorage account)
az functionapp config appsettings list --name <app-name> --resource-group <res-group>

# Get access restrictions
az functionapp config access-restriction show --name <app-name> --resource-group <res-group>

# Check if a domain was assigned to a function app
az functionapp config hostname list --webapp-name <app-name> --resource-group <res-group>

# Get SSL certificates
az functionapp config ssl list --resource-group <res-group>

# Get network restrictions
az functionapp config access-restriction show --name <app-name> --resource-group <res-group>

# Get acess restrictions
az functionapp config access-restriction show --name <app-name> --resource-group <res-group>

# Get connection strings
az rest --method POST --uri "https://management.azure.com/subscriptions/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/config/connectionstrings/list?api-version=2022-03-01"
az rest --method GET --uri "https://management.azure.com/subscriptions/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/config/configreferences/connectionstrings?api-version=2022-03-01"

# Get SCM credentials
az functionapp deployment list-publishing-credentials --name <app-name> --resource-group <res-group>

# Get function, system and master keys
az functionapp keys list --name <app-name> --resource-group <res-group>

# Get Host key
az rest --method POST --uri "https://management.azure.com/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions/<function-endpoint-name>/listKeys?api-version=2022-03-01"

# Get source code with Master Key of the function
curl "<script_href>?code=<master-key>"
curl "https://<func-app-name>.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=<master-key>" -v

# Get source code using SCM access (Azure permissions or SCM creds)
az rest --method GET \
--url "https://<func-app-name>.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=<master-key>" \
--resource "https://management.azure.com/"

# Get source code with Azure permissions
az rest --url "https://management.azure.com/subscriptions/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01"
## Another example
az rest --url "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Web/sites/ConsumptionExample/hostruntime/admin/vfs/HttpExample/index.js?relativePath=1&api-version=2022-03-01"

Privilegieneskalation

Az - Functions App Privesc

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks