Files
claudetools/.claude/skills/remediation-tool/references/graph-endpoints.md
Mike Swanson 26df2c47b9 Session log: remediation skill rewrite (5-app tiered arch) + Cascades breach check John Trozzi
- Rewrote get-token.sh: tiered app system (investigator/exchange-op/user-manager/tenant-admin/defender)
- Updated SKILL.md, command, gotchas, checklist, graph-endpoints for new app suite
- Cascades breach check: mailbox clean, inbound phishing received by John, DMARC gap noted

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 11:35:18 -07:00

160 lines
5.4 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 (`investigator` tier)
- `$EXO_R` = Exchange read token (`investigator-exo` tier) — Get-* cmdlets
- `$EXO_W` = Exchange write token (`exchange-op` tier) — Set-*/Remove-* cmdlets
- `$UT` = User Manager graph token (`user-manager` tier) — user write ops
- `$TID` = tenant ID, `$UPN`/`$UID` = user identifiers
Acquire tokens:
```bash
GT=$(bash .claude/skills/remediation-tool/scripts/get-token.sh $TID investigator)
EXO_R=$(bash .claude/skills/remediation-tool/scripts/get-token.sh $TID investigator-exo)
EXO_W=$(bash .claude/skills/remediation-tool/scripts/get-token.sh $TID exchange-op) # remediation only
UT=$(bash .claude/skills/remediation-tool/scripts/get-token.sh $TID user-manager) # remediation only
```
## 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":{...}}}`.
- **Read ops** (Get-*): use `$EXO_R` — Security Investigator token (`investigator-exo` tier)
- **Write ops** (Set-*, Remove-*): use `$EXO_W` — Exchange Operator token (`exchange-op` tier)
### 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.