Az - Function Apps

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks

Podstawowe informacje

Azure Function Apps to usługa obliczeniowa bezserwerowa, która pozwala na uruchamianie małych fragmentów kodu, zwanych funkcjami, bez zarządzania infrastrukturą. Zostały zaprojektowane do wykonywania kodu w odpowiedzi na różne wyzwalacze, takie jak żądania HTTP, timery lub zdarzenia z innych usług Azure, takich jak Blob Storage czy Event Hubs. Function Apps obsługują wiele języków programowania, w tym C#, Pythona, JavaScript i Javę, co czyni je wszechstronnymi do budowania aplikacji opartych na zdarzeniach, automatyzacji procesów roboczych lub integracji usług. Są opłacalne, ponieważ zazwyczaj płacisz tylko za czas obliczeniowy używany podczas uruchamiania kodu.

Note

Zauważ, że Funkcje są podzbiorem App Services, dlatego wiele funkcji omówionych tutaj będzie również używanych przez aplikacje tworzone jako Azure Apps (webapp w cli).

Różne plany

  • Plan Flex Consumption: Oferuje dynamiczne, oparte na zdarzeniach skalowanie z ceną płatności za użycie, dodając lub usuwając instancje funkcji w zależności od popytu. Obsługuje wirtualne sieci i wstępnie przydzielone instancje, aby zredukować zimne uruchomienia, co czyni go odpowiednim dla zmiennych obciążeń, które nie wymagają wsparcia kontenerów.
  • Plan Traditional Consumption: Domyślna opcja bezserwerowa, w której płacisz tylko za zasoby obliczeniowe, gdy funkcje są uruchamiane. Automatycznie skaluje się w zależności od nadchodzących zdarzeń i zawiera optymalizacje zimnego uruchomienia, ale nie obsługuje wdrożeń kontenerów. Idealny dla przerywanych obciążeń wymagających automatycznego skalowania.
  • Plan Premium: Zaprojektowany dla spójnej wydajności, z wstępnie podgrzanymi pracownikami, aby wyeliminować zimne uruchomienia. Oferuje wydłużone czasy wykonania, wirtualne sieci i obsługuje niestandardowe obrazy Linux, co czyni go idealnym dla aplikacji krytycznych dla misji, które potrzebują wysokiej wydajności i zaawansowanych funkcji.
  • Plan Dedicated: Działa na dedykowanych maszynach wirtualnych z przewidywalnym rozliczeniem i obsługuje ręczne lub automatyczne skalowanie. Umożliwia uruchamianie wielu aplikacji na tym samym planie, zapewnia izolację obliczeniową i zapewnia bezpieczny dostęp do sieci za pośrednictwem Środowisk Usług Aplikacji, co czyni go idealnym dla aplikacji długoterminowych wymagających spójnej alokacji zasobów.
  • Container Apps: Umożliwia wdrażanie kontenerowych aplikacji funkcji w zarządzanym środowisku, obok mikroserwisów i interfejsów API. Obsługuje niestandardowe biblioteki, migrację aplikacji dziedzicznych i przetwarzanie GPU, eliminując zarządzanie klastrami Kubernetes. Idealny dla opartych na zdarzeniach, skalowalnych aplikacji kontenerowych.

Koszyki pamięci

Podczas tworzenia nowej aplikacji funkcji, która nie jest kontenerowa (ale daje kod do uruchomienia), kod i inne dane związane z funkcją będą przechowywane w koncie pamięci. Domyślnie konsola internetowa utworzy nową dla każdej funkcji, aby przechować kod.

Co więcej, modyfikując kod wewnątrz koszyka (w różnych formatach, w jakich może być przechowywany), kod aplikacji zostanie zmodyfikowany na nowy i wykonany następnym razem, gdy funkcja zostanie wywołana.

Caution

To jest bardzo interesujące z perspektywy atakującego, ponieważ dostęp do zapisu w tym koszyku pozwoli atakującemu na kompromitację kodu i eskalację uprawnień do zarządzanych tożsamości wewnątrz aplikacji funkcji.

Więcej na ten temat w sekcji eskalacji uprawnień.

Możliwe jest również znalezienie kluczy głównych i funkcji przechowywanych w koncie pamięci w kontenerze azure-webjobs-secrets wewnątrz folderu <app-name> w plikach JSON, które można tam znaleźć.

Zauważ, że Funkcje pozwalają również na przechowywanie kodu w zdalnej lokalizacji, wskazując po prostu URL do niej.

Sieci

Używając wyzwalacza HTTP:

  • Możliwe jest udzielenie dostępu do funkcji z całego Internetu bez wymagania jakiejkolwiek autoryzacji lub udzielenie dostępu na podstawie IAM. Chociaż możliwe jest również ograniczenie tego dostępu.
  • Możliwe jest również udzielenie lub ograniczenie dostępu do aplikacji funkcji z wewnętrznej sieci (VPC).

Caution

To jest bardzo interesujące z perspektywy atakującego, ponieważ może być możliwe przełączenie się na wewnętrzne sieci z podatnej funkcji wystawionej na Internet.

Ustawienia aplikacji funkcji i zmienne środowiskowe

Możliwe jest skonfigurowanie zmiennych środowiskowych wewnątrz aplikacji, które mogą zawierać wrażliwe informacje. Co więcej, domyślnie zmienne środowiskowe AzureWebJobsStorage i WEBSITE_CONTENTAZUREFILECONNECTIONSTRING (wśród innych) są tworzone. Te są szczególnie interesujące, ponieważ zawierają klucz konta do kontrolowania z PEŁNYMI uprawnieniami konta pamięci zawierającego dane aplikacji. Te ustawienia są również potrzebne do wykonania kodu z konta pamięci.

Te zmienne środowiskowe lub parametry konfiguracyjne kontrolują również, jak funkcja wykonuje kod, na przykład jeśli WEBSITE_RUN_FROM_PACKAGE istnieje, wskaże URL, gdzie znajduje się kod aplikacji.

Piaskownica funkcji

Wewnątrz piaskownicy linux kod źródłowy znajduje się w /home/site/wwwroot w pliku function_app.py (jeśli używany jest Python), użytkownik uruchamiający kod to app (bez uprawnień sudo).

W funkcji Windows używającej NodeJS kod znajdował się w C:\home\site\wwwroot\HttpTrigger1\index.js, nazwa użytkownika to mawsFnPlaceholder8_f_v4_node_20_x86 i był częścią grup: 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.

Zarządzane tożsamości i metadane

Podobnie jak VMs, Funkcje mogą mieć Zarządzane Tożsamości dwóch typów: przypisane systemowo i przypisane przez użytkownika.

Zarządzana tożsamość przypisana systemowo będzie to zarządzana tożsamość, którą tylko funkcja, która ją ma przypisaną, będzie mogła używać, podczas gdy zarządzane tożsamości przypisane przez użytkownika to zarządzane tożsamości, które każda inna usługa Azure będzie mogła używać.

Note

Podobnie jak w VMs, Funkcje mogą mieć 1 zarządzaną tożsamość przypisaną systemowo i wiele przypisanych przez użytkownika, więc zawsze ważne jest, aby spróbować znaleźć wszystkie z nich, jeśli skompromitujesz funkcję, ponieważ możesz być w stanie eskalować uprawnienia do kilku zarządzanych tożsamości z jednej funkcji.

Jeśli nie jest używana zarządzana tożsamość systemowa, ale jedna lub więcej zarządzanych tożsamości użytkownika są przypisane do funkcji, domyślnie nie będziesz w stanie uzyskać żadnego tokena.

Możliwe jest użycie skryptów PEASS do uzyskania tokenów z domyślnej zarządzanej tożsamości z punktu końcowego metadanych. Lub możesz je ręcznie uzyskać, jak wyjaśniono w:

Cloud SSRF - HackTricks

Zauważ, że musisz znaleźć sposób na sprawdzenie wszystkich zarządzanych tożsamości, które funkcja ma przypisane, ponieważ jeśli tego nie wskażesz, punkt końcowy metadanych użyje tylko domyślnej (sprawdź poprzedni link, aby uzyskać więcej informacji).

Klucze dostępu

Note

Zauważ, że nie ma uprawnień RBAC, aby udzielić użytkownikom dostępu do wywoływania funkcji. Wywołanie funkcji zależy od wyzwalacza wybranego podczas jej tworzenia, a jeśli wybrano wyzwalacz HTTP, może być konieczne użycie klucza dostępu.

Podczas tworzenia punktu końcowego wewnątrz funkcji za pomocą wyzwalacza HTTP możliwe jest wskazanie poziomu autoryzacji klucza dostępu potrzebnego do wywołania funkcji. Dostępne są trzy opcje:

  • ANONYMOUS: Każdy może uzyskać dostęp do funkcji przez URL.
  • FUNCTION: Punkt końcowy jest dostępny tylko dla użytkowników korzystających z klucza funkcji, hosta lub głównego.
  • ADMIN: Punkt końcowy jest dostępny tylko dla użytkowników z kluczem głównym.

Rodzaje kluczy:

  • Klucze funkcji: Klucze funkcji mogą być domyślne lub zdefiniowane przez użytkownika i są zaprojektowane, aby przyznać dostęp wyłącznie do konkretnych punktów końcowych funkcji w aplikacji funkcji, co pozwala na bardziej szczegółowy dostęp do punktów końcowych.
  • Klucze hosta: Klucze hosta, które mogą być również domyślne lub zdefiniowane przez użytkownika, zapewniają dostęp do wszystkich punktów końcowych funkcji w aplikacji funkcji z poziomem dostępu FUNCTION.
  • Klucz główny: Klucz główny (_master) służy jako klucz administracyjny, który oferuje podwyższone uprawnienia, w tym dostęp do wszystkich punktów końcowych funkcji (w tym poziom dostępu ADMIN). Ten klucz nie może być cofnięty.
  • Klucze systemowe: Klucze systemowe są zarządzane przez konkretne rozszerzenia i są wymagane do uzyskania dostępu do punktów końcowych webhooków używanych przez wewnętrzne komponenty. Przykłady obejmują wyzwalacz Event Grid i Durable Functions, które wykorzystują klucze systemowe do bezpiecznej interakcji z ich odpowiednimi interfejsami API.

Tip

Przykład dostępu do punktu końcowego API funkcji za pomocą klucza:

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

Podstawowa autoryzacja

Podobnie jak w Usługach Aplikacji, Funkcje również obsługują podstawową autoryzację do łączenia się z SCM i FTP w celu wdrożenia kodu za pomocą nazwa użytkownika i hasło w URL dostarczonym przez Azure. Więcej informacji na ten temat w:

Az - Azure App Services

Wdrożenia oparte na Githubie

Gdy funkcja jest generowana z repozytorium Github, konsola internetowa Azure pozwala na automatyczne utworzenie Workflow Github w określonym repozytorium, więc za każdym razem, gdy to repozytorium jest aktualizowane, kod funkcji jest aktualizowany. W rzeczywistości YAML akcji Github dla funkcji w Pythonie wygląda tak:

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 }}

</details>

Ponadto, **Zarządzana Tożsamość** jest również tworzona, aby akcja Github z repozytorium mogła się zalogować do Azure. Odbywa się to poprzez wygenerowanie poświadczenia federacyjnego dla **Zarządzanej Tożsamości**, umożliwiającego **Wydawcy** `https://token.actions.githubusercontent.com` oraz **Identyfikatorowi Podmiotu** `repo:<org-name>/<repo-name>:ref:refs/heads/<branch-name>`.

> [!CAUTION]
> Dlatego każdy, kto skompromituje to repozytorium, będzie mógł skompromitować funkcję oraz Zarządzane Tożsamości do niej przypisane.

### Wdrożenia Oparte na Kontenerach

Nie wszystkie plany pozwalają na wdrażanie kontenerów, ale dla tych, które to robią, konfiguracja będzie zawierać URL kontenera. W API ustawienie **`linuxFxVersion`** będzie miało coś takiego jak: `DOCKER|mcr.microsoft.com/...`, podczas gdy w konsoli internetowej konfiguracja pokaże **ustawienia obrazu**.

Ponadto, **żaden kod źródłowy nie będzie przechowywany w koncie** magazynowym związanym z funkcją, ponieważ nie jest to potrzebne.

## Enumeracja

{{#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 <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"

{{#endtab }}

{{#tab name=“Az Powershell” }}

Get-Command -Module Az.Functions

# Lists all Function Apps in the current subscription or in a specific resource group.
Get-AzFunctionApp  -ResourceGroupName <String>

# 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 <String> -Name <String>

# Retrieves the app settings for a specific Azure Function App.
Get-AzFunctionAppSetting -Name <FunctionAppName> -ResourceGroupName <ResourceGroupName>

{{#endtab }} {{#endtabs }}

Eskalacja Uprawnień

Az - Functions App Privesc

Odniesienia

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks