<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
<!-- NERF is a trademark of defconxt. -->
# Shadow Admin Detection — API Reference

## Azure AD Role Assignments (Microsoft Graph)

```bash
# List all directory role members
curl -s -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  "https://graph.microsoft.com/v1.0/directoryRoles?\$expand=members" \
  | jq '.value[] | {displayName, roleTemplateId, members: [.members[] | {displayName, id, "@odata.type"}]}'

# List service principal role assignments
curl -s -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  "https://graph.microsoft.com/v1.0/servicePrincipals?\$select=displayName,appId&\$expand=appRoleAssignments" \
  | jq '.value[] | select(.appRoleAssignments | length > 0) | {displayName, appId, assignments: .appRoleAssignments}'

# Get service principal owners
curl -s -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  "https://graph.microsoft.com/v1.0/servicePrincipals/SP_ID/owners" \
  | jq '.value[] | {displayName, userPrincipalName}'

# List OAuth2 permission grants (delegated permissions)
curl -s -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  "https://graph.microsoft.com/v1.0/oauth2PermissionGrants" \
  | jq '.value[] | {clientId, consentType, scope, principalId}'
```

## Active Directory

```powershell
# Find AdminSDHolder protected users
Get-ADUser -Filter {AdminCount -eq 1} -Properties AdminCount, MemberOf |
  Select-Object SamAccountName, AdminCount

# Enumerate nested group membership
Get-ADGroupMember -Identity "Domain Admins" -Recursive |
  Select-Object Name, objectClass, distinguishedName

# Find DCSync rights holders
(Get-ACL "AD:\DC=contoso,DC=com").Access |
  Where-Object { $_.ObjectType -eq "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2" } |
  Select-Object IdentityReference, AccessControlType
```

## BloodHound Queries (Cypher)

```cypher
// Shortest paths to Global Admin (non-admin users)
MATCH p=shortestPath((u:AZUser)-[*1..]->(r:AZRole {displayname:'Global Administrator'}))
WHERE NOT (u)-[:AZHasRole]->(r)
RETURN p LIMIT 25

// Service principals with admin-equivalent permissions
MATCH (sp:AZServicePrincipal)-[:AZHasRole]->(r:AZRole)
WHERE r.displayname IN ['Global Administrator', 'Privileged Role Administrator']
RETURN sp.displayname, r.displayname
```

## Key Checks

| Check | Method | Expected |
|-------|--------|----------|
| Nested group admins | Recursive group expansion | Documented only |
| SP admin permissions | App role review | No unnecessary admin perms |
| CA exclusions | Policy audit | No blanket exclusions |
| AdminSDHolder accounts | AD query | Matches admin inventory |
| OAuth consent grants | Permission grant review | No admin consent abuse |
