Background
We Needed A Toolkit To Help Us Quickly Understand How An Azure Active Directory Tenant Is Configured. This Toolkit Needed To Be Able To Perform Actions Such As:
- Exporting The Number Of Admins In The Tenant.
- Exporting Conditional Access Policies In The Tenant.
- Gathering Information About Settings Such As:
- Azure AD Connect Version
- Number Of Users Synced From On-prem
- Number Of Groups
- Memberships Of Groups
- Etc.
This Lead To Me Constructing A Toolkit Which Uses Native PowerShell APIs To Gather Data From A Tenant, And Exporting It In A Readable Manner.
Since I Did Not Want To Re-Invent The Wheel, I Focused On Using Existing PowerShell Modules To Grab the Relevant Data From An Azure Active Directory Tenant.
The Tools I Used For This Endeavour Are:
AADInternals: https://www.powershellgallery….
AzureADPreview: https://www.powershellgallery….
MSOnline: https://www.powershellgallery….
What did we find out?
Playing Around With The Above Modules, I Realized That It Was Perfectly Possible To Get An Access Token For AAD Graph API As An End User, And Actually Exporting Conditional Access Policies Just Like That:
With That Access Token, We Can Now Run Other AADInternals Cmdlets To Poke Around In The Tenant:
Now, The Output Is Not Exactly Readable For The Naked Eye, But If We Expand The “policyDetail” Object On One Of These Policies, We Can See That We Are Getting User Ids, Service Principal Ids, Device Ids, And Under What Circumstances A Particular User Is Affected By A Conditional Access Policy:
Given That A Normal User Also Has Permissions To Connect To Azure Active Directory Using The AzureADPreview Module, I Figured That It Should Be Possible To Extract The Data From These Conditional Access Policies And Use It As Input When Looking Stuff Up.
And It Is. By Doing Just That We Were Able To Not Only Read Conditional Access Policies As An End User, But Also Export Them In A JSON File, With All Names, Excluded Devices etc Fully Readable.
Which Is A Huge Security Risk, Since It Can Allow For An Actor With Nothing Other Than End User Access To A Tenant To Pinpoint Any Or Every Gap In Your Conditional Access Policy Framework.
This Was Reported To The MSRC On March 16th 2023, But The Response From The MSRC Was That This Is “By Design” And Therefore Not A Vulnerability Per Se.
How Can We Protect Our Tenant From This?
The Short Answer Is, You Cannot. Since We Are Not Elevating Any Permissions Outside Of What An End User Can Or Cannot Do, There Is No Way Of Blocking This From Happening.
And As With Many Other Features In Azure Active Directory, Just Getting Information In a GET Request, Is Not Logged.
Not Only Are We Blind, We Are Also Fighting This With Our Hands Tied Behind Our Backs.
But What Can Be Done?
One Thing That This Approach Will Log Is A Sign-In To Azure AD PowerShell, There Is No Way Around That. This Means That If We Can Set Up Monitoring For Non-Admin Sign-ins To Azure AD PowerShell. This Will Potentially Be Noisy, And A Large Portion Of Alerts Will Probably Be False-Positives.
Another Thing That Can Be Done To Prevent This Export Is By Blocking End Users From Reading Other Users In Azure AD PowerShell:
Changing The MsolCompanyInformation Setting “UsersPermissionsToReadOtherUsersEnabled” To $false, Will Effectively Make It Impossible For An End User To Export At Least The User Parts Of The Conditional Access Policies.
However, This Setting Will Also Break The Ability For An End User To Add Members To Microsoft 365 Collaboration Spaces Such As:
- Microsoft Teams
- Microsoft 365 Groups
- SharePoint Online Sites
It Will Also Block Non-Azure AD Admins From Adding Members To Roles Inside Of Azure.
And Require A User With An Azure AD Admin Role To Perform Such Actions Instead.
Conclusions
It Is Perfectly Possible As An End User To Enumerate Almost Anything Inside Of Azure Active Directory, If You Know Where To Look.