# Az - Function Apps {{#include ../../../banners/hacktricks-training.md}} ## 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 **``** 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**](vms/index.html) 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**](vms/index.html) 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**](https://github.com/peass-ng/PEASS-ng) 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: {{#ref}} https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html#azure-vm {{#endref}} 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://.azurewebsites.net/api/?code=` ### 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: {{#ref}} az-app-services.md {{#endref}} ### 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:/:ref:refs/heads/` 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 {{#tabs }} {{#tab name="az cli" }} ```bash # List all the functions az functionapp list # List functions in an function-app (endpoints) az functionapp function list \ --name \ --resource-group # Get details about the source of the function code az functionapp deployment source show \ --name \ --resource-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 \ --resource-group # Get settings (and privesc to the sorage account) az functionapp config appsettings list --name --resource-group # Get access restrictions az functionapp config access-restriction show --name --resource-group # Check if a domain was assigned to a function app az functionapp config hostname list --webapp-name --resource-group # Get SSL certificates az functionapp config ssl list --resource-group # Get network restrictions az functionapp config access-restriction show --name --resource-group # Get acess restrictions az functionapp config access-restriction show --name --resource-group # Get connection strings az rest --method POST --uri "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//config/connectionstrings/list?api-version=2022-03-01" az rest --method GET --uri "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//config/configreferences/connectionstrings?api-version=2022-03-01" # Get SCM credentials az functionapp deployment list-publishing-credentials --name --resource-group # Get function, system and master keys az functionapp keys list --name --resource-group # Get Host key az rest --method POST --uri "https://management.azure.com//resourceGroups//providers/Microsoft.Web/sites//functions//listKeys?api-version=2022-03-01" # Get source code with Master Key of the function curl "?code=" curl "https://.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=" -v # Get source code using SCM access (Azure permissions or SCM creds) az rest --method GET \ --url "https://.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=" \ --resource "https://management.azure.com/" # Get source code with Azure permissions az rest --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//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" ``` {{#endtab }} {{#tab name="Az Powershell" }} ```bash Get-Command -Module Az.Functions # Lists all Function Apps in the current subscription or in a specific resource group. Get-AzFunctionApp -ResourceGroupName # Displays the regions where Azure Function Apps are available for deployment. Get-AzFunctionAppAvailableLocation # Retrieves details about Azure Function App plans in a subscription or resource group. Get-AzFunctionAppPlan -ResourceGroupName -Name # Retrieves the app settings for a specific Azure Function App. Get-AzFunctionAppSetting -Name -ResourceGroupName ``` {{#endtab }} {{#endtabs }} ## Privilegieneskalation {{#ref}} ../az-privilege-escalation/az-functions-app-privesc.md {{#endref}} ## Referenzen - [https://learn.microsoft.com/en-us/azure/azure-functions/functions-openapi-definition](https://learn.microsoft.com/en-us/azure/azure-functions/functions-openapi-definition) {{#include ../../../banners/hacktricks-training.md}}