AzureHound
MFA work around:
First Execute:
$body = @{
"client_id" = "1950a258-227b-4e31-a9cf-717495945fc2"
"resource" = "https://graph.microsoft.com"
}
$UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
$Headers=@{}
$Headers["User-Agent"] = $UserAgent
$authResponse = Invoke-RestMethod `
-UseBasicParsing `
-Method Post `
-Uri "https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0" `
-Headers $Headers `
-Body $body
$authResponse
Then execute:
$body=@{
"client_id" = "1950a258-227b-4e31-a9cf-717495945fc2"
"grant_type" = "urn:ietf:params:oauth:grant-type:device_code"
"code" = $authResponse.device_code
}
$Tokens = Invoke-RestMethod `
-UseBasicParsing `
-Method Post `
-Uri "https://login.microsoftonline.com/Common/oauth2/token?api-version=1.0" `
-Headers $Headers `
-Body $body
$Tokens
Execute Azure hound:
# download latest release from:
# https://github.com/BloodHoundAD/AzureHound
.\azurehound.exe list -t offsecad.onmicrosoft.com -u USER@TEST.onmicrosoft.com -p "PASSWORD" -o azurehound.json
## If using Refresh token:
.\azurehound.exe list -r $Tokens.refresh_token -o .\Cloud\azurehound.json -t offsecad.onmicrosoft.com
Azure Bloodhound custom queries:
Save the following @ ~/appdata/roaming/customerqueries.json
~/appdata/roaming/customerqueries.json
{
"queries": [
{
"name": "Return All Azure Users that are part of the 'Global Administrator' Role",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH p =(n)-[r:AZGlobalAdmin*1..]->(m) RETURN p"
}]
},
{
"name": "Return All On-Prem users with edges to Azure",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH p=(m:User)-[r:AZResetPassword|AZOwns|AZUserAccessAdministrator|AZContributor|AZAddMembers|AZGlobalAdmin|AZVMContributor|AZOwnsAZAvereContributor]->(n) WHERE m.objectid CONTAINS 'S-1-5-21' RETURN p"
}]
},
{
"name": "Find all paths to an Azure VM",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH p = (n)-[r]->(g:AZVM) RETURN p"
}]
},
{
"name": "Find all paths to an Azure KeyVault",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH p = (n)-[r]->(g:AZKeyVault) RETURN p"
}]
},
{
"name": "Return All Azure Users and their Groups (Warning: Heavy)",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH p=(m:AZUser)-[r:AZMemberOf*1..]->(n) WHERE NOT m.objectid CONTAINS 'S-1-5' RETURN p"
}]
},
{
"name": "Return GUEST Azure Users and their Groups",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH p=(m:AZUser)-[r:AZMemberOf*1..]->(n) WHERE NOT m.objectid CONTAINS 'S-1-5' AND m.userprincipalname=~ '(?i).*#EXT#.*' RETURN p"
}]
},
{
"name": "Return All Azure Users and their Admin Roles",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH p=(n)-[:AZHasRole|AZMemberOf*1..]->(:AZRole) RETURN p"
}]
},
{
"name": "Return All Azure Users and their owned Devices (Warning: Heavy)",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH p=(d:AZDevice)<-[r1:AZOwns]->(m:AZUser) RETURN p"
}]
},
{
"name": "Return All Azure Admins and their owned Devices",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH p=(d:AZDevice)<-[r1:AZOwns]->(m:AZUser)<-[r2:AZHasRole]->(n) RETURN p"
}]
},
{
"name": "Return All Azure AD Groups that are synchronized with On-Premise AD",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH (n:Group) WHERE n.objectid CONTAINS 'S-1-5' AND n.azsyncid IS NOT NULL RETURN n"
}]
},
{
"name": "Find all Privileged Service Principals",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH p = (g:AZServicePrincipal)-[r]->(n) RETURN p"
}]
},
{
"name": "Find all Owners of Azure Applications",
"category": "Azure",
"queryList": [{
"final": true,
"query": "MATCH p = (n)-[r:AZOwns]->(g:AZApp) RETURN p"
}]
},
{
"name": "Find the Shortest path to a high value target from an owned object",
"category": "Azure",
"queryList": [
{
"final": true,
"query": "MATCH p=shortestPath((g {owned:true})-[*1..]->(n {highvalue:true})) WHERE g<>n return p"
}
]
},
{
"name": "Find the Shortest path to a unconstrained delegation system from an owned object",
"category": "Azure",
"queryList": [
{
"final": true,
"query": "MATCH (n) MATCH p=shortestPath((n)-[*1..]->(m:Computer {unconstraineddelegation: true})) WHERE NOT n=m AND n.owned = true RETURN p"
}
]
},
{
"name": "Return all Members of the 'Global Administrator' Role",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH p =(n)-[r:AZGlobalAdmin*1..]->(m) RETURN p"
}
]
},
{
"name": "Return all Members of High Privileged Roles",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH p=(n)-[:AZHasRole|AZMemberOf*1..2]->(r:AZRole WHERE r.displayname =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|PRIVILEGED AUTHENTICATION ADMINISTRATOR') RETURN p"
}
]
},
{
"name": "Return all Members of High Privileged Roles that are synced from OnPrem AD",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH p=(n WHERE n.onpremisesyncenabled = true)-[:AZHasRole|AZMemberOf*1..2]->(r:AZRole WHERE r.displayname =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|PRIVILEGED AUTHENTICATION ADMINISTRATOR') RETURN p"
}
]
},
{
"name": "Return all Azure Users that are synced from OnPrem AD",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH (n:AZUser WHERE n.onpremisesyncenabled = true) RETURN n",
"allowCollapse": true
}
]
},
{
"name": "Return all Azure Groups that are synced from OnPrem AD",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH (g:AZGroup {onpremsyncenabled: True}) RETURN g"
}
]
},
{
"name": "Return all Owners of Azure Applications",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH p = (n)-[r:AZOwns]->(g:AZApp) RETURN p"
}
]
},
{
"name": "Return all Azure Subscriptions",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH (n:AZSubscription) RETURN n"
}
]
},
{
"name": "Return all Azure Subscriptions and their direct Controllers",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH p = (n)-[r:AZOwns|AZUserAccessAdministrator]->(g:AZSubscription) RETURN p"
}
]
},
{
"name": "Return all principals with the UserAccessAdministrator Role against Subscriptions",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH p = (u)-[r:AZUserAccessAdministrator]->(n:AZSubscription) RETURN p"
}
]
},
{
"name": "Return all prinicpals with the UserAccessAdministrator Role",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH p = (u)-[r:AZUserAccessAdministrator]->(n) RETURN p"
}
]
},
{
"name": "Return all Azure Users that DON'T hold an Azure Role but the RBAC Role \"User Access Administrator\"",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH (u:AZUser) WHERE NOT EXISTS((u)-[:AZMemberOf|AZHasRole*1..]->(:AZRole)) AND EXISTS((u)-[:AZUserAccessAdministrator]->()) RETURN u"
}
]
},
{
"name": "Return all Azure Principals that DON'T hold an Azure Role but the RBAC Role \"User Access Administrator\"",
"category": "Azure - General",
"queryList": [
{
"final": true,
"query": "MATCH (u) WHERE NOT EXISTS((u)-[:AZMemberOf|AZHasRole*1..]->(:AZRole)) AND EXISTS((u)-[:AZUserAccessAdministrator]->()) RETURN u"
}
]
},{
"name": "Find all Azure Users with a Path to High Value Targets",
"category": "Azure - Paths",
"queryList": [
{
"final": true,
"query": "MATCH (m:AZUser),(n {highvalue:true}),p=shortestPath((m)-[r*1..]->(n)) WHERE NONE (r IN relationships(p) WHERE type(r)= \"GetChanges\") AND NONE (r in relationships(p) WHERE type(r)=\"GetChangesAll\") AND NOT m=n RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find OnPrem synced Users with Paths to High Value Targets",
"category": "Azure - Paths",
"queryList": [
{
"final": true,
"query": "MATCH (m:AZUser WHERE m.onpremisesyncenabled = true),(n {highvalue:true}),p=shortestPath((m)-[r*1..]->(n)) WHERE NONE (r IN relationships(p) WHERE type(r)= \"GetChanges\") AND NONE (r in relationships(p) WHERE type(r)=\"GetChangesAll\") AND NOT m=n RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find shortest Paths to High Value Roles",
"category": "Azure - Paths",
"queryList": [
{
"final": true,
"query": "MATCH (n:AZRole WHERE n.displayname =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|PRIVILEGED AUTHENTICATION ADMINISTRATOR'), (m), p=shortestPath((m)-[r*1..]->(n)) WHERE NOT m=n RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find Azure Applications with Paths to High Value Targets",
"category": "Azure - Paths",
"queryList": [
{
"final": true,
"query": "MATCH (m:AZApp),(n {highvalue:true}),p=shortestPath((m)-[r*1..]->(n)) WHERE NONE (r IN relationships(p) WHERE type(r)= \"GetChanges\") AND NONE (r in relationships(p) WHERE type(r)=\"GetChangesAll\") AND NOT m=n RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find all Paths to Azure VMs",
"category": "Azure - Paths",
"queryList": [
{
"final": true,
"query": "MATCH p = (n)-[r]->(g:AZVM) RETURN p"
}
]
},
{
"name": "Find shortest Path from Owned Azure Users to VMs",
"category": "Azure - Paths",
"queryList": [
{
"final": true,
"query": "MATCH (n:AZVM) MATCH p = shortestPath((m:AZUser{owned: true})-[*..]->(n)) RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find all Paths to Azure KeyVaults",
"category": "Azure - Paths",
"queryList": [
{
"final": true,
"query": "MATCH p = (n)-[r]->(g:AZKeyVault) RETURN p"
}
]
},
{
"name": "Find all Paths to Azure KeyVaults from Owned Principals",
"category": "Azure - Paths",
"queryList": [
{
"final": true,
"query": "MATCH p = ({owned: true})-[r]->(g:AZKeyVault) RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find shortest Paths to Azure Subscriptions",
"category": "Azure - Paths",
"queryList": [
{
"final": true,
"query": "MATCH (n:AZSubscription), (m), p=shortestPath((m)-[r*1..]->(n)) WHERE NOT m=n RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find the Paths to Resources from Azure Users that DON'T hold an Azure Role but the RBAC Role \"User Access Administrator\"",
"category": "Azure - Paths",
"queryList": [
{
"final": true,
"query": "MATCH p=(u:AZUser)-[:AZUserAccessAdministrator]->(target) WHERE NOT EXISTS((u)-[:AZMemberOf|AZHasRole*1..]->(:AZRole)) RETURN u, p",
"allowCollapse": true
}
]
},
{
"name": "Find the Paths to Resources from Azure Principals that DON'T hold an Azure Role but the RBAC \"User Access Administrator\"",
"category": "Azure - Paths",
"queryList": [
{
"final": true,
"query": "MATCH p=(u)-[:AZUserAccessAdministrator]->(target) WHERE NOT EXISTS((u)-[:AZMemberOf|AZHasRole*1..]->(:AZRole)) RETURN u, p",
"allowCollapse": true
}
]
},{
"name": "Return all Service Principals with MS Graph AZMGGrantAppRoles rights -> PrivEsc Path to Global Admin",
"category": "Azure - MS Graph",
"queryList": [
{
"final": true,
"query": "MATCH p=(n)-[r:AZMGGrantAppRoles]->(o:AZTenant) RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Return all Service Principals with MS Graph App Role Assignments",
"category": "Azure - MS Graph",
"queryList": [
{
"final": true,
"query": "MATCH p=(m:AZServicePrincipal)-[r:AZMGAppRoleAssignment_ReadWrite_All|AZMGApplication_ReadWrite_All|AZMGDirectory_ReadWrite_All|AZMGGroupMember_ReadWrite_All|AZMGGroup_ReadWrite_All|AZMGRoleManagement_ReadWrite_Directory|AZMGServicePrincipalEndpoint_ReadWrite_All]->(n:AZServicePrincipal) RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Return all direct Controllers of MS Graph",
"category": "Azure - MS Graph",
"queryList": [
{
"final": true,
"query": "MATCH p = (n)-[r:AZAddOwner|AZAddSecret|AZAppAdmin|AZCloudAppAdmin|AZMGAddOwner|AZMGAddSecret|AZOwns]->(g:AZServicePrincipal {appdisplayname: \"Microsoft Graph\"}) RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find shortest Paths to MS Graph",
"category": "Azure - MS Graph",
"queryList": [
{
"final": true,
"query": "MATCH (n) WHERE NOT n.displayname=\"Microsoft Graph\" WITH n MATCH p = shortestPath((n)-[r*1..]->(g:AZServicePrincipal {appdisplayname: \"Microsoft Graph\"})) WHERE n<>g RETURN p",
"allowCollapse": true
}
]
},{
"name": "Return all Azure Service Principals",
"category": "Azure - Service Principals",
"queryList": [
{
"final": true,
"query": "MATCH (sp:AZServicePrincipal) RETURN sp",
"allowCollapse": true
}
]
},
{
"name": "Find all VMs with a tied Managed Identity",
"category": "Azure - Service Principals",
"queryList": [
{
"final": true,
"query": "MATCH p=(:AZVM)-[:AZManagedIdentity]->(n) RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Return all Azure Service Principals that are Managed Identities",
"category": "Azure - Service Principals",
"queryList": [
{
"final": true,
"query": "MATCH (sp:AZServicePrincipal {serviceprincipaltype: 'ManagedIdentity'}) RETURN sp",
"allowCollapse": true
}
]
},
{
"name": "Find all Azure Privileged Service Principals",
"category": "Azure - Service Principals",
"queryList": [
{
"final": true,
"query": "MATCH p = (g:AZServicePrincipal)-[r]->(n) RETURN p"
}
]
},
{
"name": "Find shortest Paths from Owned Azure Users to Azure Service Principals",
"category": "Azure - Service Principals",
"queryList": [
{
"final": true,
"query": "MATCH (u:AZUser {owned: true}), (m:AZServicePrincipal) MATCH p = shortestPath((u)-[*..]->(m)) RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find shortest Paths from Owned Azure Users to Azure Service Principals that are Managed Identities",
"category": "Azure - Service Principals",
"queryList": [
{
"final": true,
"query": "MATCH (u:AZUser {owned: true}), (m:AZServicePrincipal {serviceprincipaltype: 'ManagedIdentity'}) MATCH p = shortestPath((u)-[*..]->(m)) RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find shortest Paths from all Azure Users to Azure Service Principals that are Managed Identities",
"category": "Azure - Service Principals",
"queryList": [
{
"final": true,
"query": "MATCH (u:AZUser), (m:AZServicePrincipal {serviceprincipaltype: 'ManagedIdentity'}) MATCH p = shortestPath((u)-[*..]->(m)) RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find all Service Principals that are Managed Identities an have a Path to an Azure Key Vault",
"category": "Azure - Service Principals",
"queryList": [
{
"final": true,
"query": "MATCH (m:AZServicePrincipal {serviceprincipaltype: 'ManagedIdentity'})-[*]->(kv:AZKeyVault) WITH collect(m) AS managedIdentities MATCH p = (n)-[r]->(kv:AZKeyVault) WHERE n IN managedIdentities RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find Paths from Managed Identities tied to a VM with a path to a Key Vault",
"category": "Azure - Service Principals",
"queryList": [
{
"final": true,
"query": "MATCH p1 = (:AZVM)-[:AZManagedIdentity]->(n) WITH collect(n) AS managedIdentities MATCH p2 = (m:AZServicePrincipal {serviceprincipaltype: 'ManagedIdentity'})-[*]->(kv:AZKeyVault) WHERE m IN managedIdentities RETURN p2",
"allowCollapse": true
}
]
},{
"name": "Return all Users and Azure Users possibly related to AADConnect",
"category": "Azure - AADConnect",
"queryList": [
{
"final": true,
"query": "MATCH (u) WHERE (u:User OR u:AZUser) AND (u.name =~ '(?i)^MSOL_|.*AADConnect.*' OR u.userprincipalname =~ '(?i)^sync_.*') OPTIONAL MATCH (u)-[:HasSession]->(s:Session) RETURN u, s",
"allowCollapse": true
}
]
},
{
"name": "Find all Sessions of possibly AADConnect related Accounts",
"category": "Azure - AADConnect",
"queryList": [
{
"final": true,
"query": "MATCH p=(m:Computer)-[:HasSession]->(n) WHERE (n:User OR n:AZUser) AND ((n.name =~ '(?i)^MSOL_|.*AADConnect.*') OR (n.userPrincipalName =~ '(?i)^sync_.*')) RETURN p",
"allowCollapse": true
}
]
},
{
"name": "Find all AADConnect Servers (extracted from the SYNC_ Account names)",
"category": "Azure - AADConnect",
"queryList": [
{
"final": true,
"query": "MATCH (n:AZUser) WHERE n.name =~ '(?i)^SYNC_(.*?)_(.*?)@.*' WITH n, split(n.name, '_')[1] AS computerNamePattern MATCH (c:Computer) WHERE c.name CONTAINS computerNamePattern RETURN c",
"allowCollapse": true
}
]
},
{
"name": "Find shortest Paths to AADConnect Servers from Owned Users",
"category": "Azure - AADConnect",
"queryList": [
{
"final": true,
"query": "MATCH (n:AZUser) WHERE n.name =~ '(?i)^SYNC_(.*?)_(.*?)@.*' WITH n, split(n.name, '_')[1] AS computerNamePattern MATCH (c:Computer) WHERE c.name CONTAINS computerNamePattern WITH collect(c) AS computers MATCH p = shortestPath((u:User)-[*]-(c:Computer)) WHERE c IN computers AND length(p) > 0 AND u.owned = true RETURN u, p",
"allowCollapse": true
}
]
}
]
}
Last updated