- 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>
5.4 KiB
5.4 KiB
Graph + Exchange REST Cheatsheet
All examples assume:
$GT= Graph token (investigatortier)$EXO_R= Exchange read token (investigator-exotier) — Get-* cmdlets$EXO_W= Exchange write token (exchange-optier) — Set-/Remove- cmdlets$UT= User Manager graph token (user-managertier) — user write ops$TID= tenant ID,$UPN/$UID= user identifiers
Acquire tokens:
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
# 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
# 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
/users/$UPN/authentication/methods
# Watch for new methods added within the attack window
OAuth + app role assignments
/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)
# 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
# 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)
/identityProtection/riskyUsers
/identityProtection/riskyUsers/$UID
/identityProtection/riskDetections?$filter=userId eq '$UID'
B2B guests
# 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-exotier) - Write ops (Set-, Remove-): use
$EXO_W— Exchange Operator token (exchange-optier)
Inbox rules (INCLUDING hidden)
{"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
{"CmdletInput":{"CmdletName":"Get-Mailbox","Parameters":{"Identity":"user@domain.com"}}}
Check: ForwardingAddress, ForwardingSmtpAddress, DeliverToMailboxAndForward, GrantSendOnBehalfTo, HiddenFromAddressListsEnabled.
Mailbox permissions (delegates / FullAccess)
{"CmdletInput":{"CmdletName":"Get-MailboxPermission","Parameters":{"Identity":"user@domain.com"}}}
Filter out NT AUTHORITY\\SELF — anything else is a delegate.
SendAs permissions
{"CmdletInput":{"CmdletName":"Get-RecipientPermission","Parameters":{"Identity":"user@domain.com"}}}
Transport rules (tenant-wide mail flow)
{"CmdletInput":{"CmdletName":"Get-TransportRule","Parameters":{}}}
Check for rules that reroute, delete, or exfiltrate mail.
SMTP AUTH
{"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
$topat 999. For >999 results, follow@odata.nextLink. - Exchange REST has undocumented throttling — if you hit 429, back off 30–60s.
- Token is valid ~60 minutes. Script caches for 55 min.