Files
claudetools/.claude/skills/remediation-tool/references/graph-endpoints.md
Mike Swanson 1c7df5018e Session log: multi-user setup, audit + gap fixes, Howard onboarding package
Two session logs:
- session-logs/2026-04-16-session.md: cross-cutting (multi-user, audit, infrastructure)
- guru-rmm session log appended: MSI installer, Len's Auto Brokerage, Uranus, migration drift

Gap fixes: GrepAI initialized + MCP server added, Ollama models pulling,
settings.json created (bypassPermissions), MCP_SERVERS.md written.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 18:56:26 -07:00

145 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Graph + Exchange REST Cheatsheet
All examples assume `$GT` = Graph token, `$EXO` = Exchange token, `$TID` = tenant ID, `$UPN`/`$UID` = user identifiers.
## Graph API (`https://graph.microsoft.com/v1.0`)
### User lookup / status
```bash
# By UPN
curl -s -H "Authorization: Bearer $GT" \
"https://graph.microsoft.com/v1.0/users/$UPN?\$select=id,displayName,userPrincipalName,mail,accountEnabled,createdDateTime,lastPasswordChangeDateTime"
# All users (filter, paged)
curl -s -H "Authorization: Bearer $GT" \
"https://graph.microsoft.com/v1.0/users?\$top=999&\$filter=accountEnabled%20eq%20true"
```
### Mailbox
```bash
# Visible inbox rules (Graph v1.0 — does NOT return hidden rules)
/users/$UPN/mailFolders/inbox/messageRules
# Mailbox settings (auto-reply, delegates meeting option, NOT forwarding flags)
/users/$UPN/mailboxSettings
# Recent sent / deleted
/users/$UPN/mailFolders/sentitems/messages?$top=25&$orderby=sentDateTime%20desc
/users/$UPN/mailFolders/deleteditems/messages?$top=25&$orderby=receivedDateTime%20desc
```
### Authentication methods
```bash
/users/$UPN/authentication/methods
# Watch for new methods added within the attack window
```
### OAuth + app role assignments
```bash
/users/$UPN/oauth2PermissionGrants # user-level consents
/users/$UPN/appRoleAssignments # apps assigned to this user
/servicePrincipals/$SP_ID/appRoleAssignments # what scopes a SP has
```
### Sign-ins (needs Entra ID P1 or higher)
```bash
# Interactive sign-ins v1.0 (does NOT include non-interactive/service-principal)
/auditLogs/signIns?$filter=userId eq '$UID' and createdDateTime ge $FROM&$top=200
# All sign-in event types (beta endpoint)
/beta/auditLogs/signIns?$filter=userId eq '$UID' and (signInEventTypes/any(t:t eq 'nonInteractiveUser'))
# Foreign successful sign-ins tenant-wide
/auditLogs/signIns?$filter=(status/errorCode eq 0) and (location/countryOrRegion ne 'US')
```
### Directory audits
```bash
# Changes targeting a specific user
/auditLogs/directoryAudits?$filter=targetResources/any(t:t/id eq '$UID')
# Tenant-wide consent / auth-method / role events
/auditLogs/directoryAudits?$filter=activityDateTime ge $FROM
# Then client-side filter by activityDisplayName ~ Consent|Authentication Method|Add service principal|Add member to role
```
### Identity Protection (needs IdentityRiskyUser.Read.All)
```bash
/identityProtection/riskyUsers
/identityProtection/riskyUsers/$UID
/identityProtection/riskDetections?$filter=userId eq '$UID'
```
### B2B guests
```bash
# Get guest by gmail/external address
/users?$filter=startswith(userPrincipalName,'dunedolly21')
# Invite audits
/auditLogs/directoryAudits?$filter=activityDisplayName eq 'Invite external user'
```
## Exchange Online REST (`https://outlook.office365.com/adminapi/beta/{tenant-id}/InvokeCommand`)
POST with JSON body `{"CmdletInput":{"CmdletName":"<cmdlet>","Parameters":{...}}}`. Token scope: `https://outlook.office365.com/.default`.
### Inbox rules (INCLUDING hidden)
```json
{"CmdletInput":{"CmdletName":"Get-InboxRule","Parameters":{"Mailbox":"user@domain.com","IncludeHidden":true}}}
```
Why this matters: attackers commonly create hidden rules that Graph v1.0 cannot see.
### Mailbox forwarding / properties
```json
{"CmdletInput":{"CmdletName":"Get-Mailbox","Parameters":{"Identity":"user@domain.com"}}}
```
Check: `ForwardingAddress`, `ForwardingSmtpAddress`, `DeliverToMailboxAndForward`, `GrantSendOnBehalfTo`, `HiddenFromAddressListsEnabled`.
### Mailbox permissions (delegates / FullAccess)
```json
{"CmdletInput":{"CmdletName":"Get-MailboxPermission","Parameters":{"Identity":"user@domain.com"}}}
```
Filter out `NT AUTHORITY\\SELF` — anything else is a delegate.
### SendAs permissions
```json
{"CmdletInput":{"CmdletName":"Get-RecipientPermission","Parameters":{"Identity":"user@domain.com"}}}
```
### Transport rules (tenant-wide mail flow)
```json
{"CmdletInput":{"CmdletName":"Get-TransportRule","Parameters":{}}}
```
Check for rules that reroute, delete, or exfiltrate mail.
### SMTP AUTH
```json
{"CmdletInput":{"CmdletName":"Get-CASMailbox","Parameters":{"Identity":"user@domain.com"}}}
```
Check `SmtpClientAuthenticationDisabled`. To disable SMTP AUTH on a single mailbox (remediation): `Set-CASMailbox -SmtpClientAuthenticationDisabled $true`.
## Rate limits / pagination
- Graph signIns endpoints cap `$top` at 999. For >999 results, follow `@odata.nextLink`.
- Exchange REST has undocumented throttling — if you hit 429, back off 3060s.
- Token is valid ~60 minutes. Script caches for 55 min.