# Az - Comptes d'automatisation

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

## Informations de base

Les comptes d'automatisation Azure sont des services basés sur le cloud dans Microsoft Azure qui aident à **automatiser des tâches** telles que la gestion des ressources, la configuration et les mises à jour à travers Azure et les environnements sur site. Ils fournissent des **Runbooks** (scripts pour l'automatisation qui sont exécutés), des **horaires** et des **groupes de travailleurs hybrides** pour exécuter des **jobs** d'automatisation, permettant l'infrastructure en tant que code (IaC) et l'automatisation des processus pour améliorer l'efficacité et la cohérence dans la gestion des ressources cloud.

### Paramètres

- **Identifiants** : Le mot de passe n'est accessible que dans un runbook à l'intérieur du compte d'automatisation, ils sont utilisés pour **stocker les noms d'utilisateur et les mots de passe en toute sécurité**.
- **Variables** : Utilisées pour stocker des **données de configuration** qui peuvent être utilisées dans les runbooks. Cela pourrait également être des informations sensibles comme des clés API. Si la variable est **stockée de manière chiffrée**, elle n'est disponible que dans un runbook à l'intérieur du compte d'automatisation.
- **Certificats** : Utilisés pour stocker des **certificats** qui peuvent être utilisés dans les runbooks.
- **Connexions** : Utilisées pour stocker des **informations de connexion** à des services externes. Cela pourrait contenir des **informations sensibles**.
- **Accès réseau** : Il peut être défini comme **public** ou **privé**.

### Runbooks & Jobs

Un Runbook dans Azure Automation est un **script qui exécute des tâches automatiquement** dans votre environnement cloud. Les runbooks peuvent être écrits en PowerShell, Python ou dans des éditeurs graphiques. Ils aident à automatiser des tâches administratives comme la gestion des VM, le patching ou les vérifications de conformité.

Dans le **code** situé à l'intérieur des **Runbooks** pourrait contenir des **informations sensibles** (comme des identifiants).

Un **Job est une instance d'exécution d'un Runbook**. Lorsque vous exécutez un Runbook, un Job est créé pour suivre cette exécution. Chaque job comprend :

- **Statut** : En attente, En cours, Terminé, Échoué, Suspendu.
- **Sortie** : Le résultat de l'exécution du Runbook.
- **Heure de début et de fin** : Quand le job a commencé et s'est terminé.

Un job contient la **sortie** de l'exécution du **Runbook**. Si vous pouvez **lire** les **jobs**, faites-le car ils **contiennent** la **sortie** de l'exécution (potentiellement des **informations sensibles**).

### Horaires & Webhooks

Il existe 3 principales façons d'exécuter un Runbook :

- **Horaires** : Ceux-ci sont utilisés pour **déclencher** des Runbooks à un **moment spécifique** ou à un **intervalle**.
- **Webhooks** : Ce sont des **points de terminaison HTTP** qui peuvent être utilisés pour **déclencher** des Runbooks depuis des **services externes**. Notez que l'URL du webhook **n'est pas visible** après sa création.
- **Déclenchement manuel** : Vous pouvez **déclencher manuellement** un Runbook depuis le portail Azure et depuis la CLI.

### Contrôle de version

Il permet d'importer des Runbooks depuis **Github, Azure Devops (Git) et Azure Devops (TFVC)**. Il est possible d'indiquer de publier les Runbooks du dépôt vers le compte d'automatisation Azure et il est également possible d'indiquer de **synchroniser les modifications du dépôt** vers le compte d'automatisation Azure.

Lorsque la synchronisation est activée, dans le **dépôt Github, un webhook est créé** pour déclencher la synchronisation chaque fois qu'un événement de push se produit. Exemple d'URL de webhook : `https://f931b47b-18c8-45a2-9d6d-0211545d8c02.webhook.eus.azure-automation.net/webhooks?token=DRjQyFiOrUtz%2fw7o23XbDpOlTe1%2bUqPQm4pQH2WBfJg%3d`

Notez que ces webhooks **ne seront pas visibles** lors de la liste des webhooks dans les runbooks associés au dépôt Github. Notez également qu'il est **impossible de changer l'URL du dépôt** d'un contrôle de version une fois qu'il est créé.

Pour que le contrôle de version configuré fonctionne, le **compte d'automatisation Azure** doit avoir une identité gérée (système ou utilisateur) avec le rôle **`Contributor`**. De plus, pour attribuer une identité gérée utilisateur au compte d'automatisation, il est nécessaire d'indiquer l'ID client de l'identité gérée utilisateur dans la variable **`AUTOMATION_SC_USER_ASSIGNED_IDENTITY_ID`**.

### Environnements d'exécution

Lors de la création d'un Runbook, il est possible de sélectionner l'environnement d'exécution. Par défaut, les environnements d'exécution suivants sont disponibles :

- **Powershell 5.1**
- **Powershell 7.1**
- **PowerShell 7.2**
- **Python 3.10**
- **Python 3.8**
- **Python 2.7**

Cependant, il est également possible de **créer vos propres environnements**, en utilisant l'un de ceux-ci comme base. Dans le cas de Python, il est possible de télécharger des packages `.whl` dans l'environnement qui sera utilisé. Dans le cas de PowerShell, il est possible de télécharger des packages `.zip` avec les modules à avoir dans l'exécution.

### Groupes de travailleurs hybrides

Dans Azure Automation, l'environnement d'exécution par défaut pour les runbooks est le **Azure Sandbox**, une plateforme basée sur le cloud gérée par Azure, adaptée aux tâches impliquant des ressources Azure. Cependant, ce sandbox a des limitations, telles que l'accès restreint aux ressources sur site et des contraintes sur le temps d'exécution et l'utilisation des ressources. Pour surmonter ces limitations, des groupes de travailleurs hybrides sont employés. Un groupe de travailleurs hybrides se compose de **un ou plusieurs travailleurs de Runbook hybrides installés sur vos propres machines**, que ce soit sur site, dans d'autres environnements cloud ou des VM Azure. Cette configuration permet aux runbooks de s'exécuter directement sur ces machines, offrant un accès direct aux ressources locales, la capacité d'exécuter des tâches plus longues et plus intensives en ressources, et la flexibilité d'interagir avec des environnements au-delà de la portée immédiate d'Azure.

Lorsqu'un groupe de travailleurs hybrides est créé, il est nécessaire d'indiquer les **identifiants** à utiliser. Il y a 2 options :

- **Identifiants par défaut** : Vous n'avez pas besoin de fournir les identifiants et les runbooks seront exécutés à l'intérieur des VM en tant que **Système**.
- **Identifiants spécifiques** : Vous devez fournir le nom de l'objet d'identifiants à l'intérieur du compte d'automatisation, qui sera utilisé pour exécuter les **runbooks à l'intérieur des VM**. Par conséquent, dans ce cas, il pourrait être possible de **voler des identifiants valides** pour les VM.

Par conséquent, si vous pouvez choisir d'exécuter un **Runbook** dans un **Travailleur Hybride**, vous exécuterez des **commandes arbitraires** à l'intérieur d'une machine externe en tant que **Système** (technique de pivotement intéressante).

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 d'où obtenir le jeton d'identité gérée du compte d'automatisation (**`IDENTITY_ENDPOINT`**).

### Configuration d'état (SC)

> [!WARNING]
> Comme indiqué dans [la documentation](https://learn.microsoft.com/en-us/azure/automation/automation-dsc-overview), la configuration d'état Azure Automation sera retirée le 30 septembre 2027 et remplacée par [Azure Machine Configuration](https://learn.microsoft.com/en-us/azure/governance/machine-configuration/overview).

Les comptes d'automatisation prennent également en charge la **Configuration d'état (SC)**, qui est une fonctionnalité qui aide à **configurer** et à **maintenir** l'**état** de vos VM. Il est possible de **créer** et **d'appliquer** des configurations DSC à des machines **Windows** et **Linux**.

Du point de vue des attaquants, cela était intéressant car cela permettait d'**exécuter du code PS arbitraire dans toutes les VM configurées**, permettant d'escalader les privilèges vers les identités gérées de ces VM, potentiellement en pivotant vers de nouveaux réseaux... De plus, les configurations pourraient contenir des **informations sensibles**.

## Énumération
```bash
# List Automation Accounts
az automation account list --output table

# Get Automation Account details
# Check the network access in `privateEndpointConnections` and `publicNetworkAccess`
# Check the managed identities in `identity`
az automation account show --name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME>

# Get keys of automation account
## These are used for the DSC
az automation account list-keys --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME>

# Get schedules of automation account
az automation schedule list --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME>

# Get connections of automation account
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/connections?api-version=2023-11-01"

# Get connection details
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/connections/<connection-name>?api-version=2023-11-01"

# Get credentials of automation account
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/credentials?api-version=2023-11-01"

# Get credential details
## Note that you will only be able to access the password from inside a Runbook
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/credentials/<credential-name>?api-version=2023-11-01"

# Get certificates of automation account
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/certificates?api-version=2023-11-01"

# Get certificate details
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/certificates/<certificate-name>?api-version=2023-11-01"

# Get variables of automation account
## It's possible to get the value of unencrypted variables but not the encrypted ones
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/variables?api-version=2023-11-01"

# Get variable details
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/variables/<variable-name>?api-version=2023-11-01"

# Get runbooks of an automation account
az automation runbook list --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME>

# Get runbook details
az automation runbook show --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME> --name <RUNBOOK-NAME>

# Get runbook content
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/runbooks/<runbook-name>/content?api-version=2023-11-01"

# Get jobs of an automation account
az automation job list --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME>

# Get job details
az automation job show --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME> --name <JOB-NAME>

# Get job output
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"

# Get the Runbook content when the job was executed
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>/runbookContent?api-version=2023-11-01"

# Get webhooks inside an automation account
## It's possible to see to which runbook it belongs in the given data
## For security reasons it's not possible to see the URL of the webhook after creating it, here is a URL example: https://f931b47b-18c8-45a2-9d6d-0211545d8c02.webhook.eus.azure-automation.net/webhooks?token=dOdnxk6z7ugAxiuyUMKgPuDMav2Jw5EJediMdiN4jLo%3d
## Generating a webhook can be useful from a persistence perspective
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/webhooks?api-version=2018-06-30"

# Get the source control setting of an automation account (if any)
## inside the output it's possible to see if the autoSync is enabled, if the publishRunbook is enabled and the repo URL
az automation source-control list --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME>

# Get custom runtime environments
## Check in defaultPackages for custom ones, by default Python envs won't have anything here and PS1 envs will have "az" and "azure cli"
az automation runtime-environment list \
--resource-group <res-group>> \
--automation-account-name <account-name> \
--query "[?!(starts_with(description, 'System-generated'))]"

# Get State Configurations (SC) of an automation account
az automation dsc configuration list --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME>

# Get State Configuration details
az automation dsc configuration show --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME> --name <DSC-CONFIG-NAME>

# Get State Configuration content
az automation dsc configuration show-content --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME> --name <DSC-CONFIG-NAME>

# Get hybrid worker groups for an automation account
az automation hrwg list --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME>

# Get hybrid worker group details
az automation hrwg show --automation-account-name <AUTOMATION-ACCOUNT> --resource-group <RG-NAME> --name <HYBRID-WORKER-GROUP>

# Get more details about a hybrid worker group (like VMs inside it)
az rest --method GET --url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/hybridRunbookWorkerGroups/<hybrid-worker-group-name>/hybridRunbookWorkers?&api-version=2021-06-22"
```

```bash
# Check user right for automation
az extension add --upgrade -n automation
az automation account list # if it doesn't return anything the user is not a part of an Automation group

# Gets Azure Automation accounts in a resource group
Get-AzAutomationAccount

# List & get DSC configs
Get-AzAutomationAccount | Get-AzAutomationDscConfiguration
Get-AzAutomationAccount | Get-AzAutomationDscConfiguration | where {$_.name -match '<name>'} | Export-AzAutomationDscConfiguration -OutputFolder . -Debug
## Automation Accounts named SecurityBaselineConfigurationWS... are there by default (not interesting)

# List & get Run books code
Get-AzAutomationAccount | Get-AzAutomationRunbook
Get-AzAutomationAccount | Get-AzAutomationRunbook | Export-AzAutomationRunbook -OutputFolder /tmp

# List credentials & variables & others
Get-AzAutomationAccount | Get-AzAutomationCredential
Get-AzAutomationAccount | Get-AzAutomationVariable
Get-AzAutomationAccount | Get-AzAutomationConnection
Get-AzAutomationAccount | Get-AzAutomationCertificate
Get-AzAutomationAccount | Get-AzAutomationSchedule
Get-AzAutomationAccount | Get-AzAutomationModule
Get-AzAutomationAccount | Get-AzAutomationPython3Package
## Exfiltrate credentials & variables and the other info loading them in a Runbook and printing them

# List hybrid workers
Get-AzAutomationHybridWorkerGroup -AutomationAccountName <AUTOMATION-ACCOUNT> -ResourceGroupName <RG-NAME>
```
## Escalade de privilèges & Post-exploitation

{{#ref}}
../az-privilege-escalation/az-automation-accounts-privesc.md
{{#endref}}

## Références

- [https://learn.microsoft.com/en-us/azure/automation/overview](https://learn.microsoft.com/en-us/azure/automation/overview)
- [https://learn.microsoft.com/en-us/azure/automation/automation-dsc-overview](https://learn.microsoft.com/en-us/azure/automation/automation-dsc-overview)
- [https://github.com/rootsecdev/Azure-Red-Team#runbook-automation](https://github.com/rootsecdev/Azure-Red-Team#runbook-automation)

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