https://github.com/jsa2/AADAppAudit
This tool is not maintained anymore, please consider using- License
- Consent and Azure AD application Analytics solution
- Use cases
- Intentional gaps
- Prerequisites
- Running the tool
- After initial run with main.js
- without autoRun
- Checking results again
- Check App Proxy Apps
- Check Saml App expiration
- Use existing storage account
- Use with different context after setting up the needed storage account
- Use existing account with IP limitations
- Regenerate SAS tokens for existing data
- Alternative Sorting (per API)
- With SignInLogs (only shows apps that have sign-in data - requires workspace with signins)
- With SignIn and auditLogs (only shows apps that have sign-in data - requires workspace with signins)
- Check permissionless use of possibly malicious multitenant ServicePrincipals
- Check for plaintext redirectURI's
- Update log
- Known issues
License
⚠ Only use this tool if you know what you are doing and have reviewed the code
⚠ Always test the tool first in test environments, with non-sensitive data
As the licenses says, 0% Liability 0% Warranty
https://github.com/jsa2/AADAppAudit
This tool is not maintained anymore, please consider usingConsent and Azure AD application Analytics solution
https://github.com/jsa2/AADAppAudit
This tool is not maintained anymore, please consider usingAzure AD consent framework analysis is important step to strengthen security posture in every organization that is using Azure Active Directory. This tool was initially developed to analyze possible illicit consent grant attacks & in help of analyzing Azure AD consent grant framework but has been developed further since to provide answers to the most typical security related questions around Azure AD integrated apps and permissions.
Illicit Consent Grant
During Covid-19 there has been huge increase in consent phishing emails where the idea is to abuse OAuth request links to trick recipients into granting attacker owned apps permission to access sensitive data. Consent grant is perfect tool to create backdoor, and MFA bypasses in the victim’s environment. After the illicit application has been granted consent, it has account-level access to data without the need for an organizational account.
There are two scenarios for attacker to pursue targeting individual users:
-
Individual consent grants for non-admin permissions
-
Targeting admins for requiring permissions that only admins can grant
Both scenarios allows data exfiltration, while the latter also offers perfect backdooring entry (App permissions for multi-tenant app). More information about the attack and analysis can be found from the following sources:
Use cases
Use Case Name | Notes |
---|---|
✅ Inventory of apps and permissions | All Azure AD apps and the apps registered permissions including Workload Identities |
✅ Detect applications that share app and user permissions / scopes | By default Apps that have delegated permissions should not include Application permissions |
✅ Detect password use on applications, and expiring/expired passwords | Two types of credentials available: password-based or certificate-based authentication |
✅ Detect AppType (Managed, Multi, single etc) | Tenancy in Azure AD |
✅ Review replyURLs | Verify are there any malicious reply URLs used in the apps |
✅ Detect recent sign-ins | Get insights on how apps are used in the organization (this API is setting not enabled by default) |
✅ Detect servicePrincipals in admin roles | It is in most cases recommended to use API permissions instead of AAD roles |
✅ Detect dangling redirect_uri | If the app service is deleted, but redirect_uri is not deleted from the Azure AD app registration, attacker could register the App Service instance for malicious intent. |
✅ User assignment | review if app has user assigment enabled |
✅ HasPublicClient | review if app allows public client flows (non redirect uri based flows) |
✅ WarningAppPrivs | is multitenant application with app permissions this permission type is very potent for the attacker, because the app owner does not needed signed-in user content (delegation) in the victim tenant to access services granted to the app |
✅ expiration | Detect SAML certificate and client credential |
✅ Owners | review app owners |
✅ audit app proxy applications | this one requires further permissions: microsoft.directory/connectors/allProperties/read - Read all properties of application proxy connectors |
✅Check permissionless use of possibly malicious multitenant ServicePrincipals | Check permissionless use of possibly malicious multitenant ServicePrincipals |
✅ Check for plaintext redirectURI's | Check for plaintext redirectURI's |
Intentional gaps
Prerequisites
Requirement | description |
---|---|
✅ Access to Azure Cloud Shell Bash | Uses pre-existing software on Azure CLI, Node etc |
✅ Permissions to Azure subscription to create needed resources | Tool creates a storage account and a resource group. Possible also to use existing storage account. In both scenarios tool generates short lived read-only shared access links (SAS) for the externalData() -operator |
✅ User is Azure AD member | Cloud-only preferred with read-only Azure AD permissions. More permissions are needed if sign-in events are included |
✅ Existing Log Analytics Workspace | This is where you paste the output from this tool |
About the generated KQL
- The query is valid for 10 minutes, as SAS tokens are only generated for 10 minutes
- If you want to regenerate the query follow these steps
Running the tool
- Log in to Azure Cloud Shell (BASH ) and paste following line to the shell
curl -o- https://raw.githubusercontent.com/jsa2/CloudShellAadApps/public/remote.sh | bash
Once complete you should see following screen, which includes that you can paste to Log Analytics space
After initial run with main.js
- nvm use 14, is only needed in cloud shell
- If you are having problems with the tool start by ensuring, that existing installation of the tool does on exist in cloudShell:
admin@Azure:~$ rm CloudShellAadApps/ -r -f
without autoRun
curl -o- https://raw.githubusercontent.com/jsa2/CloudShellAadApps/public/remoteInit.sh | bash
Each of this step requires that you then copy the query kql/runtime.kql and paste it in log analytics
As pointed out earlier, these can be run, once you've run the initial run with main.js
Checking results again
cd Cloud CloudShellAadApps
nvm use 14; node main.js
Check App Proxy Apps
- Requires further permissions like the sign-in logs query (while all other checks here work with reader)
cd Cloud CloudShellAadApps
node main --appProxyApps
nvm use 14; node schemaForAppProxyApps.js --appProxyApps
Check Saml App expiration
Checks for email addresses and time till SAML certificate expires.
cd Cloud CloudShellAadApps
nvm use 14; node schemaForSaml.js
Use existing storage account
rg=queryStorage-23428
storageAcc=storagehowrjcehuw
git clone https://github.com/jsa2/CloudShellAadApps
cd CloudShellAadApps
az storage account show-connection-string -g $rg -n $storageAcc -o json > src/config.json
npm install
nvm use 14; node main.js
Use with different context after setting up the needed storage account
az account clear
az login --use-device-code --allow-no-subscriptions
Use existing account with IP limitations
az account set --name "scan"
storageAcc=dogs
rg=queryStorage-29991
location=westeurope
net=$(curl a.dewi.red)
az storage account show-connection-string -g $rg -n $storageAcc -o json > src/config.json
#Add cloud shell IP
az storage account network-rule add -g $rg --account-name $storageAcc --ip-address $net
# Remove the storage account rule for Cloud shell
az storage account network-rule remove -g $rg --account-name $storageAcc --ip-address $net
Regenerate SAS tokens for existing data
cd Cloud CloudShellAadApps
nvm use 14; node schemaForExternalData.js
code kql/runtime.kql
Alternative Sorting (per API)
cd Cloud CloudShellAadApps
nvm use 14; node schemaForAPIdriven.js
code kql/runtime.kql
With SignInLogs (only shows apps that have sign-in data - requires workspace with signins)
Requires following sources (AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs, AADManagedIdentitySignInLogs, SigninLogs)
cd Cloud CloudShellAadApps
nvm use 14; node schemaForExternalDataLAsignins.js
code kql/runtime.kql
With SignIn and auditLogs (only shows apps that have sign-in data - requires workspace with signins)
cd Cloud CloudShellAadApps
nvm use 14; node schemaForExternalDataLAsignisAndAudit.js
code kql/runtime.kql
Check permissionless use of possibly malicious multitenant ServicePrincipals
- Checks if possibly malicious multitenant SPN's with no app permissions present are using client credentials based flows against apps in your tenant
cd Cloud CloudShellAadApps
nvm use 14; node schemaForMaliciousMultiTenant.js
code kql/runtime.kql
Check for plaintext redirectURI's
- append this part to runtime.kql after node schemaForExternalData.js is run
nvm use 14; node schemaForExternalData.js
code kql/runtime.kql;
final
| mv-apply url = set_replyUrls to typeof(string) on (
where (url contains "http://" and url !contains "http://localhost")
)
Example of insecure non localhost redirectURI:
Update log
- 19.05.2022 SAML App Expiration checking
- 15.05.2022 added AppProxy auditing
- 15.03.2022 added alternative sorting (per API) and with LA
Previously
- Malicious use case: If the app service is deleted, but redirect_uri is not deleted from the Azure AD app registration, attacker could register the App Service instance for malicious intent. After registering the App Service instance Attacker would then redirect user sessions authorization codes/tokens to attacker controlled service.
- This enables the attacker to phish for access tokens without having control of the redirect URI as the attacker is able to set up an page asking for the device code.
- Users are likely less susceptible to device code based phishing * compared to pure SSO based phishing with seamless redirect to attacker controlled service) - Nonetheless public client on a redirect enabled application presents a valid attack vector.
Known issues
Continous Access Evaluation
Azure CLI is unable to obtain new access tokens for sessions, that rely on IP restrictions and are targeteted by strict enforcement
az account get-access-token --resource=https://graph.microsoft.com --query accessToken --output json
Multiple tenants
If the identity you are using doesn't have Azure subscription access or has access to multiple tenants use
az login --allow-no-subscriptions ## (no access to Azure subscriptions)
az login --tenant <tenant id> ## (If user has identity in multiple tenants)