Discovering user consented apps with Microsoft M365 E3
This time Detexian’s CTO Adrian Kitto gets into the nitty gritty of this blog series, tackling discovering user consented applications. He even includes some code samples for you!
In case you missed it last time, please check out:
Part 1: Who / What / Why does the mid-market all have Microsoft M365 E3 licenses
Part 2: How does Microsoft M365 E3 work with the non-Microsoft ecosystem applications?
In January 2023 Microsoft and Proofpoint announced details about a series of malicious third-party OAuth applications that had been discovered targeting UK-based organizations' Microsoft 365 hosted email and calendar applications.
The announcements included significant details about how these apps were identified, removed from the marketplace, and the risks they posed, but they provided little information about how a customer could take steps to review user-consented applications that their users might have added.
Microsoft offers solutions such as Microsoft Defender for Office 365 and Microsoft 365 Defender to enable mature and sophisticated security teams to discover, evaluate, and revoke potentially malicious user-consented applications.
However, the Microsoft E5 Ecosystem solution set's cost uplift to Microsoft M365 E5 and the maturity and size of the security team required to operate it pose a problem for mid-market companies. As a result, only 6% of mid-sized enterprises are licensed for M365 E5 security, and they need to find a workaround to reduce the risks that malicious user-consented applications expose their organization to.
To discover all applications that users have consented to, there are two paths for a customer with M365 E3. The first is browsing to the Enterprise Applications blade in Azure AD, manually clicking on each application, browsing to the permissions tab and then user consent and viewing each of the scopes individually.
This is not a scalable solution for most Azure AD administrators. Therefore, the need to use PowerShell to connect to Azure AD Graph API and export the results into CSV arises.
# Set the API endpoint and parameters
$graphEndpoint = "https://graph.windows.net/myorganization/servicePrincipals"
$graphParams = @{
"api-version" = "1.6"
"\$select" = "displayName"
"\$filter" = "appRoles/any()"
}
# Send the API request and retrieve the response
$accessToken = "INSERT_ACCESS_TOKEN_HERE"
$graphResponse = Invoke-RestMethod -Method GET -Uri $graphEndpoint -Headers @{ "Authorization" = "Bearer $accessToken" } -Query $graphParams
# Export the output to a CSV file
$csvPath = "C:\output.csv"
$graphResponse.value | Select-Object -ExpandProperty displayName | Export-Csv -Path $csvPath -NoTypeInformation
However, this method only gives all applications without a relationship to users. If you’re looking to focus on applications with access to send email on the users' behalf (or other risky scopes), then a filter should be applied, and the output must include the user's name.
# Set the API endpoint and parameters
$graphEndpoint = "https://graph.windows.net/myorganization/servicePrincipals"
$graphParams = @{
"api-version" = "1.6"
"\$select" = "displayName,appId,appRoles"
"\$filter" = "appRoles/any(roleName eq 'Mail.Send' and resourceAccess/any(scope eq 'Mail.Send'))"
}
# Send the API request and retrieve the response
$accessToken = "INSERT_ACCESS_TOKEN_HERE"
$graphResponse = Invoke-RestMethod -Method GET -Uri $graphEndpoint -Headers @{ "Authorization" = "Bearer $accessToken" } -Query $graphParams
# Process the response and output to a CSV file
$csvPath = "C:\output.csv"
$results = foreach ($app in $graphResponse.value) {
$users = Get-AzureADServiceAppRoleAssignment -ObjectId $app.objectId
foreach ($user in $users) {
if ($user.AppRoleId -eq $app.appRoles.RoleId) {
[PSCustomObject]@{
ApplicationName = $app.displayName
ApplicationObjectId = $app.appId
UserName = $user.PrincipalDisplayName
Scopes = ($app.appRoles | Where-Object { $_.RoleId -eq $user.AppRoleId }).AllowedMemberTypes
}
}
}
}
$results | Export-Csv -Path $csvPath -NoTypeInformation
Here are a few examples of what are considered risky OAuth scopes:
Directory.ReadWrite.All - Allows the application to read and write all directory objects in the tenant, including users, groups, and applications. This scope can be particularly dangerous if granted to a malicious application, as it would give the application full access to the tenant's directory.
User.ReadWrite.All - Allows the application to read and write all user profiles in the tenant. This scope can be used to harvest sensitive information about users or modify user accounts.
Mail.Send - Allows the application to send mail on behalf of the signed-in user. If granted to a malicious application, this scope could be used to send phishing emails or other types of malicious messages.
Mail.ReadWrite - Allows the application to read and write the signed-in user's email messages, including sending and deleting emails. If granted to a malicious application, this scope could be used to steal sensitive information from emails or send phishing messages.
Calendars.ReadWrite - Allows the application to read and write the signed-in user's calendar. If granted to a malicious application, this scope could be used to steal sensitive information about the user's schedule or create or modify events on the user's calendar.
Contacts.ReadWrite - Allows the application to read and write the signed-in user's contacts. If granted to a malicious application, this scope could be used to steal sensitive contact information or add, modify, or delete contacts.
Files.ReadWrite.All - Allows the application to read and write all files in the tenant's SharePoint and OneDrive for Business sites. If granted to a malicious application, this scope could be used to steal sensitive information from documents or modify them in a way that would be detrimental to the organization.
To see a full listing of available Azure AD Graph API scopes please visit
Microsoft Graph REST API v1.0 endpoint reference
Once a listing of users with applications with risky scopes has been identified you can navigate to, perform detailed investigation of and potentially revoke each application by adding the ObjectID from the CSV https://portal.azure.com/#view/Microsoft_AAD_IAM/ManagedAppMenuBlade/~/Overview/objectId/[ObjectID]
As a further thought, it is important also to regularly review user application consents as they can change daily. Once a reliable robust script has been written it is important that it is regularly run, the output analyzed and actions taken.
My recommendation is that user application consents are reviewed at least every two weeks to prevent privilege creep, malicious applications stealing sensitive information and invoicing fraud.
Join me next time when I get into the details about “Identifying and removing inactive users with Microsoft M365 E3.”
I’ll give you a spoiler folks, this one is going to make you look like a star when you identify cost savings for your CFO!
Security thought for the week
Did you know that some companies use "mantraps" as a physical security measure? A mantrap is an enclosed area with two or more doors, where only one door can be opened at a time. This ensures that only one person can enter the secured area at a time, preventing unauthorized access. Mantraps are often used in high-security facilities, such as data centers or government buildings.
Till then, stay secure.
Adrian