From 1c333d4cab7b02a27aabb6ab054f1f8ef44d837b Mon Sep 17 00:00:00 2001 From: Carlos Polop Date: Tue, 7 Jan 2025 00:43:37 +0100 Subject: [PATCH] static web --- src/SUMMARY.md | 2 + .../az-static-web-apps-privesc.md} | 130 ++++++++++++++++-- .../az-services/az-static-web-apps.md | 36 ++++- 3 files changed, 154 insertions(+), 14 deletions(-) rename src/pentesting-cloud/azure-security/{az-post-exploitation/az-static-web-apps-post-exploitation.md => az-privilege-escalation/az-static-web-apps-privesc.md} (51%) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index f14f299ff..442c03b1c 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -418,6 +418,7 @@ - [Az - Queue Storage](pentesting-cloud/azure-security/az-services/az-queue-enum.md) - [Az - Service Bus](pentesting-cloud/azure-security/az-services/az-servicebus-enum.md) - [Az - SQL](pentesting-cloud/azure-security/az-services/az-sql.md) + - [Az - Static Web Applications](pentesting-cloud/azure-security/az-services/az-static-web-apps.md) - [Az - Storage Accounts & Blobs](pentesting-cloud/azure-security/az-services/az-storage.md) - [Az - Table Storage](pentesting-cloud/azure-security/az-services/az-table-storage.md) - [Az - Virtual Machines & Network](pentesting-cloud/azure-security/az-services/vms/README.md) @@ -461,6 +462,7 @@ - [Az - Queue Storage Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-queue-privesc.md) - [Az - Service Bus Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-servicebus-privesc.md) - [Az - Virtual Machines & Network Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-virtual-machines-and-network-privesc.md) + - [Az - Static Web App Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-static-web-apps-privesc.md) - [Az - Storage Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-storage-privesc.md) - [Az - SQL Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-sql-privesc.md) - [Az - Persistence](pentesting-cloud/azure-security/az-persistence/README.md) diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-static-web-apps-post-exploitation.md b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-static-web-apps-privesc.md similarity index 51% rename from src/pentesting-cloud/azure-security/az-post-exploitation/az-static-web-apps-post-exploitation.md rename to src/pentesting-cloud/azure-security/az-privilege-escalation/az-static-web-apps-privesc.md index 66591865d..a4fafaa98 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-static-web-apps-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-static-web-apps-privesc.md @@ -77,9 +77,9 @@ curl -H "Authorization: Bearer " \ ### Overwrite file - Overwrite routes, HTML, JS... -It's possible to **overwritte a fie inside the Github repo** containing the app through Azure having the **Github token** sending a request such as the following which will indicate the path of the file to overwrite, the content of the file and the commit message. +It's possible to **overwrite a file inside the Github repo** containing the app through Azure having the **Github token** sending a request such as the following which will indicate the path of the file to overwrite, the content of the file and the commit message. -This can be abused by attackers to basically **change the content of the web app** to serve malicious content (steal credentials, mnemonic keys...) or just to **re-route certain paths** to their own servers by oevrwritting the `staticwebapp.config.json` file. +This can be abused by attackers to basically **change the content of the web app** to serve malicious content (steal credentials, mnemonic keys...) or just to **re-route certain paths** to their own servers by overwriting the `staticwebapp.config.json` file. > [!WARNING] > Note that if an attacker manages to compromise the Github repo in any way, they can also overwrite the file directly from Github. @@ -142,31 +142,118 @@ az rest --method put \ ### Microsoft.Web/staticSites/listSecrets/action -This permission allows to get the **API key deployment token** for the static app. - -This token allows to deploy the app +This permission allows to get the **API key deployment token** for the static app: ```bash az rest --method POST \ --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/staticSites//listSecrets?api-version=2023-01-01" ``` -Then, in order to update an app you could run the following command. Note that this command was extracted checking **how to Github Action [https://github.com/Azure/static-web-apps-deploy](https://github.com/Azure/static-web-apps-deploy) works**, as it's the one Azure set by default ot use. So the image and paarements could change in the future. +Then, in order to **update an app using the token** you could run the following command. Note that this command was extracted checking **how to Github Action [https://github.com/Azure/static-web-apps-deploy](https://github.com/Azure/static-web-apps-deploy) works**, as it's the one Azure set by default ot use. So the image and paarements could change in the future. 1. Download the repo [https://github.com/staticwebdev/react-basic](https://github.com/staticwebdev/react-basic) (or any other repo you want to deploy) and run `cd react-basic`. 2. Change the code you want to deploy 3. Deploy it running (Remember to change the ``): ```bash -docker run -it --rm -v $(pwd):/mnt mcr.microsoft.com/appsvc/staticappsclient:stable INPUT_AZURE_STATIC_WEB_APPS_API_TOKEN= INPUT_APP_LOCATION="/mnt" INPUT_API_LOCATION="" INPUT_OUTPUT_LOCATION="build" /bin/staticsites/StaticSitesClient upload --verbose +docker run --rm -v $(pwd):/mnt mcr.microsoft.com/appsvc/staticappsclient:stable INPUT_AZURE_STATIC_WEB_APPS_API_TOKEN= INPUT_APP_LOCATION="/mnt" INPUT_API_LOCATION="" INPUT_OUTPUT_LOCATION="build" /bin/staticsites/StaticSitesClient upload --verbose ``` +>[!WARNING] +> Even if you have the token you won't be able to deploy the app if the **Deployment Authorization Policy** is set to **Github**. For using the token you will need the permission `Microsoft.Web/staticSites/write` to change the deployment method to use th APi token. + ### Microsoft.Web/staticSites/write -With this permission it's possible to **change the source of the static web app to a different Github repository**, however, it won't be automatically provisioned as this must be done from a Github Action usually with the token that authorized the action as this token is not automatically updated inside the Githb secrets of the repo (it's just added automatically when the app is created). +With this permission it's possible to **change the source of the static web app to a different Github repository**, however, it won't be automatically provisioned as this must be done from a Github Action. + +However, if the **Deployment Authotization Policy** is set to **Github**, it's possible to **update the app from the new source repository!**. + +In case the **Deployment Authorization Policy** is not set to Github, you can change it with the same permission `Microsoft.Web/staticSites/write`. ```bash +# Change the source to a different Github repository az staticwebapp update --name my-first-static-web-app --resource-group Resource_Group_1 --source https://github.com/carlospolop/my-first-static-web-app -b main + +# Update the deployment method to Github +az rest --method PATCH \ +--url "https://management.azure.com/subscriptions/>/resourceGroups//providers/Microsoft.Web/staticSites/?api-version=2022-09-01" \ +--headers 'Content-Type=application/json' \ +--body '{ + "properties": { + "allowConfigFileUpdates": true, + "stagingEnvironmentPolicy": "Enabled", + "buildProperties": { + "appLocation": "/", + "apiLocation": "", + "appArtifactLocation": "build" + }, + "deploymentAuthPolicy": "GitHub", + "repositoryToken": "" # az rest --method GET --url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01" + } +}' +``` + +Example Github Action to deploy the app: + +```yaml +name: Azure Static Web Apps CI/CD + +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened, closed] + branches: + - main + +jobs: + build_and_deploy_job: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') + runs-on: ubuntu-latest + name: Build and Deploy Job + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@v3 + with: + submodules: true + lfs: false + - name: Install OIDC Client from Core Package + run: npm install @actions/core@1.6.0 @actions/http-client + - name: Get Id Token + uses: actions/github-script@v6 + id: idtoken + with: + script: | + const coredemo = require('@actions/core') + return await coredemo.getIDToken() + result-encoding: string + - name: Build And Deploy + id: builddeploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: "12345cbb198a77a092ff885782a62a15d5aef5e3654cac1234509ab54547270704-4140ccee-e04f-424f-b4ca-3d4dd123459c00f0702071d12345" # A valid formatted token is needed although it won't be used for authentication + action: "upload" + ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### + # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig + app_location: "/" # App source code path + api_location: "" # Api source code path - optional + output_location: "build" # Built app content directory - optional + github_id_token: ${{ steps.idtoken.outputs.result }} + ###### End of Repository/Build Configurations ###### + + close_pull_request_job: + if: github.event_name == 'pull_request' && github.event.action == 'closed' + runs-on: ubuntu-latest + name: Close Pull Request Job + steps: + - name: Close Pull Request + id: closepullrequest + uses: Azure/static-web-apps-deploy@v1 + with: + action: "close" ``` ### Microsoft.Web/staticSites/resetapikey/action @@ -178,6 +265,33 @@ az rest --method POST \ --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/staticSites//resetapikey?api-version=2019-08-01" ``` +### Microsoft.Web/staticSites/createUserInvitation/action + +This permission allows to **create an invitation to a user** to access protected paths inside a static web app ith a specific given role. + +The login is located in a path such as `/.auth/login/github` for github or `/.auth/login/aad` for Entra ID and a user can be invited with the following command: + +```bash +az staticwebapp users invite \ + --authentication-provider Github # AAD, Facebook, GitHub, Google, Twitter \ + --domain mango-beach-071d9340f.4.azurestaticapps.net # Domain of the app \ + --invitation-expiration-in-hours 168 # 7 days is max \ + --name my-first-static-web-app # Name of the app\ + --roles "contributor,administrator" # Comma sepparated list of roles\ + --user-details username # Github username in this case\ + --resource-group Resource_Group_1 # Resource group of the app +``` + +### Pull Requests + +By default Pull Requests from a branch in the same repo will be automatically compiled and build in a staging environment. This could be abused by an attacker with write access over the repo but without being able to bypass branch protections of the production branch (usually `main`) to **deploy a malicious version of the app** in the statagging URL. + +The staging URL has this format: `https://-..` like: `https://ambitious-plant-0f764e00f-2.eastus2.4.azurestaticapps.net` + +> [!TIP] +> Note that by default external PRs won't run workflows unless they have merged at least 1 PR into the repository. An attacker could send a valid PR to the repo and **then send a malicious PR** to the repo to deploy the malicious app in the stagging environment. HOWEVER, there is an unexpected protection, the default Github Action to deploy into the static web app need access to the secret containing the deployment token (like `secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_PLANT_0F764E00F`) eve if the deployment is done with the IDToken. This means that because an external PR won't have access to this secret and an external PR cannot change the Workflow to place here an arbitrary token without a PR getting accepted, **this attack won't really work**. + + {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-services/az-static-web-apps.md b/src/pentesting-cloud/azure-security/az-services/az-static-web-apps.md index 2c626cbc1..31778c534 100644 --- a/src/pentesting-cloud/azure-security/az-services/az-static-web-apps.md +++ b/src/pentesting-cloud/azure-security/az-services/az-static-web-apps.md @@ -5,13 +5,19 @@ ## Static Web Apps Basic Information -Azure Static Web Apps is a cloud service for hosting **static web apps with automatic CI/CD from repositories like GitHub**. It offers global content delivery, serverless backends, and built-in HTTPS, making it secure and scalable. However, risks include misconfigured CORS, insufficient authentication, and content tampering, which can expose apps to attacks like XSS and data leakage if not properly managed. +Azure Static Web Apps is a cloud service for hosting **static web apps with automatic CI/CD from repositories like GitHub**. It offers global content delivery, serverless backends, and built-in HTTPS, making it secure and scalable. However, even if the service is called "static", it doesn't mean it's completely safe. Risks include misconfigured CORS, insufficient authentication, and content tampering, which can expose apps to attacks like XSS and data leakage if not properly managed. + +### Deployment Authentication > [!TIP] -> When a Static App is created you can choose the **deployment authorization policy** between **Deployment token** and **GitHub Actions workflow**. +> When a Static App is created you can choose the **deployment authorization policy** between **Deployment token** and **GitHub Actions workflow**. + +- **Deployment token**: A token is generated and used to authenticate the deployment process. Anyone with **this token is enough to deploy a new version of the app**. A **Github Action is deployed automatically** in the repo with the token in a secret to deploy a new version of the app every time the repo is updated. +- **GitHub Actions workflow**: In this case a very similar Github Action is also deployed in the repo and the **token is also stored in a secret**. However, this Github Action has a difference, it uses the **`actions/github-script@v6`** action to get the IDToken of repository and use it to deploy the app. + - Even If in both cases the action **`Azure/static-web-apps-deploy@v1`** is used with a token in the `azure_static_web_apps_api_token` param, in this second case a random token with a format valid like `12345cbb198a77a092ff885781a62a15d51ef5e3654ca11234509ab54547270704-4140ccee-e04f-424f-b4ca-3d4dd123459c00f0702071d12345` is just enough to deploy the app as the authorization is done with the IDToken in the `github_id_token` param. -### Web App Authentication +### Web App Basic Authentication It's possible to **configure a password** to access the Web App. The web console allows to configure it to protect only staging environments or both staging and the production one. @@ -29,7 +35,7 @@ az rest --method GET \ However, this **won't show the password in clear text**, just something like: `"password": "**********************"`. -### Routes +### Routes & Roles Routes define **how incoming HTTP requests are handled** within a static web app. Configured in the **`staticwebapp.config.json`** file, they control URL rewriting, redirections, access restrictions, and role-based authorization, ensuring proper resource handling and security. @@ -63,6 +69,19 @@ Some example: } ``` +Note how it's possible to **protect a path with a role**, then, users will need to authenticate to the app and be granted that role to access the path. It's also possible to **create invitations** granting specific roles to specific users login via EntraID, Facebook, GitHub, Google, Twitter which might be useful to escalate privileges within the app. + +> [!TIP] +> Note that it's possible to configure the App so **changes to the `staticwebapp.config.json`** file aren't accepted. In this case, it might not be enough to just change the file from Github, but also to **change the setting in the App**. + +The staging URL has this format: `https://-..` like: `https://ambitious-plant-0f764e00f-2.eastus2.4.azurestaticapps.net` + +### Managed Identities + +Azure Static Web Apps can be configured to use **managed identities**, however, as mentioned in [this FAQ](https://learn.microsoft.com/en-gb/azure/static-web-apps/faq#does-static-web-apps-support-managed-identity-) they are only supported to **extract secrets from Azure Key Vault for authentication purposes, not to access other Azure resources**. + +For more info you can find an Azure guide use a vault secret in a static app in https://learn.microsoft.com/en-us/azure/static-web-apps/key-vault-secrets. + ## Enumeration ```bash @@ -92,6 +111,9 @@ az rest --method GET \ ## Once you have the database connection name ("default" by default) you can get the connection string with the credentials az rest --method POST \ --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/staticSites//databaseConnections/default/show?api-version=2021-03-01" + +# Check connected backends +az staticwebapp backends show --name --resource-group ``` ## Examples to generate Web Apps @@ -102,10 +124,12 @@ You cna find a nice example to generate a web app in the following link: [https: 2. In the Azure portal create a Static Web App configuring the Github access and selecting th previously forked new repository 3. Create it, and wait some minutes, and check your new page! -## Post Exploitation +## Privilege Escalation and Post Exploitation + +All the information about privilege escalation and post exploitation in Azure Static Web Apps can be found in the following link: {{#ref}} -../az-privilege-escalation/az-static-web-apps-post-exploitation.md +../az-privilege-escalation/az-static-web-apps-privesc.md {{#endref}} ## References