-
Notifications
You must be signed in to change notification settings - Fork 8
/
get-suspiciousoauth.ps1
137 lines (99 loc) · 4.94 KB
/
get-suspiciousoauth.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
function Get-SuspiciousOAuthGrants {
<#
.SYNOPSIS
Searches Azure AD for suspicious user OAuth Grants
Author: Douglas Bienstock (@doughsec)
License: GPL 3.0
Required Dependencies: None
Optional Dependencies: None
.DESCRIPTION
When a user consents to an OAuth application in Office365 it creates
an OAuth "grant" associated with that user's account and the Service
Principal Object of the application that resides in that user's tenant.
This function searches for those OAuth grants, attempting to find
suspicious grants based on certain characteristics.
.PARAMETER All
Boolean. Specifies if you want to return all OAuth grants in the tenant
.PARAMETER Scopes
A list of suspicious scopes to search for. Defaults to "offline_access" only.
.PARAMETER Threshold
A Service Principal with fewer OAuth grants than the Threshold is considered
suspicious automatically. Set to a number that represents a small percentage of
your tenant total user count. Defaults to 10.
#>
param(
[Switch]
$All,
[String[]]
$Scopes = @("offline_access"),
[Int]
$Threshold = 10,
[Switch]
$Output,
[String]
$OutputPath= "suspicious grants.csv"
)
try {
$var = Get-AzureADTenantDetail;
} catch [Microsoft.Open.Azure.AD.CommonLibrary.AadNeedAuthenticationException] {
Connect-AzureAd;
}
$tenantWhitelist = @(
"f8cdef31-a31e-4b4a-93e4-5f571e91255a" #the Microsoft Services tenant. Where a lot of O365 services live
)
Get-AzureADServicePrincipal | Where-Object { !$tenantWhitelist.contains( $_.AppOwnerTenantID ) } | ForEach-Object {
$spn = $_;
$objID = $spn.ObjectID;
$grants = Get-AzureADServicePrincipalOAuth2PermissionGrant -ObjectId $objID;
$suspicious = $FALSE;
# If the SPN has fewer OAuth grants than the threshold, we mark all the grants as suspicious
if($grants.length -lt $Threshold) { $suspicious= $TRUE; }
if($grants) {
foreach ($grant in $grants) {
if($All) {
$user = Get-AzureADUser -ObjectId $grant.PrincipalId;
$userGrant = New-Object PSObject;
$userGrant | Add-Member Noteproperty 'ObjectID' $grant.objectId;
$userGrant | Add-Member Noteproperty 'User' $user.UserPrincipalName;
$userGrant | Add-Member Noteproperty 'AppDisplayName' $spn.DisplayName;
$userGrant | Add-Member Noteproperty 'AppPublisherName' $spn.PublisherName;
$userGrant | Add-Member Noteproperty 'AppReplyURLs' $spn.ReplyUrls;
$userGrant | Add-Member Noteproperty 'GrantConsentType' $grant.consentType;
$userGrant | Add-Member Noteproperty 'GrantScopes' $grant.scope;
Write-Output $userGrant;
if($Output) {
$userGrant.AppReplyUrls = [string]::join(";",$userGrant.AppReplyUrls);
$userGrant | Export-CSV -notypeinformation -append $OutputPath;
}
}
# If any of the suspicious scopes are part of this grant, we mark it as suspicious
foreach($scope in $Scopes) {
if($grant.scope.contains($scope)) {
$suspicious= $TRUE;
break;
}
}
# If the SPN was granted to all users via an admin we ignore it as legit
if($grant.consentType -eq "AllPrincipals") {
$suspicious= $FALSE;
}
if(!$All -and $suspicious -eq $TRUE ) {
$user = Get-AzureADUser -ObjectId $grant.PrincipalId;
$userGrant = New-Object PSObject;
$userGrant | Add-Member Noteproperty 'ObjectID' $grant.objectId;
$userGrant | Add-Member Noteproperty 'User' $user.UserPrincipalName;
$userGrant | Add-Member Noteproperty 'AppDisplayName' $spn.DisplayName;
$userGrant | Add-Member Noteproperty 'AppPublisherName' $spn.PublisherName;
$userGrant | Add-Member Noteproperty 'AppReplyURLs' $spn.ReplyUrls;
$userGrant | Add-Member Noteproperty 'GrantConsentType' $grant.consentType;
$userGrant | Add-Member Noteproperty 'GrantScopes' $grant.scope;
Write-Output $userGrant;
if($Output) {
$userGrant.AppReplyUrls = [string]::join(";",$userGrant.AppReplyUrls);
$userGrant | Export-CSV -notypeinformation -append $OutputPath;
}
}
}
}
}
}