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>
This commit is contained in:
144
.claude/skills/remediation-tool/references/graph-endpoints.md
Normal file
144
.claude/skills/remediation-tool/references/graph-endpoints.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# 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 30–60s.
|
||||
- Token is valid ~60 minutes. Script caches for 55 min.
|
||||
Reference in New Issue
Block a user