Welcome to the four part lab (1/4) regarding implementing ”Zero Trust”, or identity perimeter-ish controls for your’re hybrid environment:
First part is about unifying access controls for cloud-and on prem users (this part)
Second part is hardening of the remaining on-prem entry vectors
Third part is hardening of the remaining cloud entry vectors
Fourth part is about hardening and monitoring – what happens after authentication and authorization have taken place
Hybrid Modern Authentication + Kerberos Constrained Delegation
One of the most understated, and welcome enhancements introduced lately for Hybrid setups, is the so called ”Hybrid Modern Authentication” – It mostly fixes the problem, of having mix set of users with Legacy Authentication and modern authentication in hybrid environment – Example an environment where all the mailboxes are in on-prem (for compliance reasons) but, other services are consumed from Cloud.
What I mean by mostly, is that I noticed the documentation for HMA left out the Outlook Web Access and ECP out of the possibilities
No Oauth for OWA? No problem
”Full blown HMA” with Azure AD + KEMP
You get to protect on-prem OWA with Conditional Access , and users get the SSO benefits of Azure AD Device Login (HDJ, Registration and similar options) – besides MAPI,EWS,ACTIVESYNC and OAB
OWA Azure AD Login
(Click pictures to open gallery view)
Outlook Hybrid Modern Authentication
(Click pictures to open gallery view)
You get to see all Exchange On-prem logins on Azure AD (Click pictures to open gallery view)
You have the same 2FA experience for on-prem, and cloud mailbox users
Unified policies based on the use case for both on-prem and cloud mailbox users
You get Identity protection for on-prem users, and on-prem Apps as well
Important configuration notes
Understand how SPN’s work in Azure AD and Active Directory
I wanted to ensure, that SPN for OWA doesn’t end-up in Exchange Online list SPN’s for Oauth2 relying partys, so I ensured that OWA has its own FQDN which is later used processing of KCD
Customize KEMP SAML SP to parse Identity from custom Azure AD attribute
I will go into hardening on a next blog – Nonetheless I highlight that I disabled already for MAPI, ActiveSync, OAB some of the legacy authentication options for testing.
I am not going to delve into Exchange, DNS and AD Namespaces here, nonetheless its good to understand, that SPN’s and FQDN’s are deeply in play here enabling how Azure AD authentication can be extended to on-premises apps
Create Service Account for KEMP_KCD and assign the delegation for SPN’s
We will take an new look into this part the second blog
Configure SSO for OWA in Azure AD
Use the Service Principal Name as Entity ID
Download certificate and XML to be used KEMP configuration SSO config
Implement user assignment if you want to have additional layering of ACL between AAD and OWA
Create Conditional Access Policy for Exchange and OWA
Attach the KCD account to Client Side configuration in SSO settings
Ensure that reverse resolution for IP to DNS name works
See it in action!
For anyone curious I’ve attached the initial flow type example for ActiveSync below with IOS accounts app
These initial flows happen before application starts to mostly work with grant_type=refresh token
If there is single sentence I would emphasize regarding all things AAD, then it would be ”You can’t hide things in AAD” – This sentence is based on the premise, that in order for services and users to work and interact there has to be visibility between objects in the directory.
One of the most common examples is, that sometimes a new hire in a large company directory has been ”hidden” by setting ”msExchHideFromAddressLists” value to true. This done in order to hide the user from Exchange Address List, but that really is the only thing that setting does. It does absolutely nothing to hide the user from AAD, (or from on-prem AD),
Azure AD Directory Members can enumerate lot of stuff in AAD
All other users in the tenant, including guest users
In a large tenant, there might be external users in as non-guest members, they can query all the same stuff than the internal users. For example, they can see who of their competitors are also working at the same customer, and if the customer is using Office 365 Groups, then they might by just looking at group names, descriptions and members deduct some insights of the project
Groups, and group members
Applications and permissions registered for the tenant
All visible user attributes (this mainly only excludes the Authentication attributes)
Alternative Email Address
And also see occurred changes in all above objects by using the delta listeners in Graph API
Lets start by saying that Graph API is The most powerful invention Microsoft has devised in the last few years. You can already see that many of the Microsoft Client Apps fetch their oAuth2 Access Tokens with resource graph defined as their preferred resource. If you’re AAD or Office Dev this thing is going make you’re life so much easier! For me it represents the greatest thing since sliced bread :)…
This means, that when such powerful API exists, there must be also in-depth understanding of it’s capabilities:
Below is demo of a standard user creating a ”listener for all delta changes” in the directory.
One can only imagine, how much an persistent presence having attacker would benefit on this kind of listener, that lists delta changes such as addition of new groups, phone numbers, title changes, changes in group memberships etc.
What standard non-privileged user can get by using delta subscription?
All new attribute changes
All new groups, and their members, or just group member changes
New invited users from other tenants
Query Any Delta Change for directory objects, after you’ve defined what to listen first in the initial request
Any internal user will work, regardless Directory Role = Normal, even unlicensed user account can do this
you must have ADAL library files to run this example
#App parameters and endpoints
Global Powershell Multitenant = ClientID 1b730954-1685-4b74-9bfd-dac224a7b894
redirect URI’s = ”urn:ietf:wg:oauth:2.0:oob”
Endpoint = https://login.windows.net/common/
”scp”: ”AuditLog.Read.All Directory.AccessAsUser.All Directory.ReadWrite.All Group.ReadWrite.All
-When you use Powershell as ClientID you will get these static scopes for all users, regardless of the user permissions (User Permissions are separately then checked against AAD)
Read MS docs to understand how delta subscriptions work.
You can’t just run the script with F5 in ISE, or execute directly. The script is meant to be used so that you create subscription, and then run another row on the script to get deltas added into existing array
I could finesse the script bit more, but for now its used to demonstrate how non-privileged user can use it just like an admin user
How does it work?
Attacker creates multi-tenant app, and adds non-admin requiring API permissions for the desired API’s. Attacker then delivers the link to end user, which after clicking the link only has to consent (Approve) the API permissions for the attacker.
Attacker has then access to user mail, this happens because attacker exfiltrates in the background the Access Token and uses it against the Exchange Online API
Down below I describe why it might be hard for the user to discern good app from the bad app.
Why it works?
Multi-tenants app by default have access to end users data, unless your Azure AD Admin have disabled the particular defaults that enable this behavior.
Graph API + Other API’s
Create multi-tenant Azure AD Web-App/API + Azure Web App that delivers the JS. client side code to browser from Node.JS Web App
I am using minified ADAL.JS as <script src in the code. Other than that, I’ve just added few custom functions to the code, and studied wide variety of existing Vanilla ADAL JS Apps in GitHub
Figure out a way to deliver the link to the victim/victims in other AAD / Office 365 tenants
I’ve opted to forge existing Microsoft Newsletter with link to malicious Azure Web App to
When user clicks the link consent dialog is prompted.
Consent – This as any other dialog, you would get prompted for when consent framework kicks in (This is where the confidence part happens)
The process is same for benign apps, so there is superficially nothing to separate the good app from the bad (except caution, which is often unheeded, if you consider how often an mobile application presenting similar dialog is approved for multiple permissions in mobile phone)
User is redirected to the malicious app with seemingly benign OIDC-Flow (response_type=id_token)… no mention here of the OAuth2 Implicit Grant Flow (yet)
Hidden iFrame executes the OAuth2 Implicit Grant Flow, and gains Access Token to resource
AJAX HTTP is used to post the Access Token as Payload to external exfil service
In case you wonder, that I’d left the function key there :)… Just try
User is redirected to the original link requested in the mail
<- Users timeline stops here
– >Perpetrators timeline begins here
Token is copied by the malicious actor from Azure Functions where it was posted
A Separate Powershell session running in some dark corner of the world is now searching users mail content for several keywords, and playing with the Access Token for the next 3600 seconds
Fair warning: While I have disclaimer in the bottom of the page, and blog title basically emphasizes it… Do not try this in production unless you’re in very comfortable terms with Azure AD and Active Directory in general.
Azure AD Domain Services is Azure Managed version of Active Directory – Basically in exchange for your domain admin credentials, you get two managed endpoints to direct your resources at.
When to use it?
Example: You don’t want to extend your on premises network to Azure, but you still want to offer LDAP & Kerberos to your services deployed in the cloud.
Every now and then I’ve wondered whether its possible provide these endpoints to VM running Active Directory Federation Services -> Based on my tests it is possible with some limitations
Good to know before proceeding
There exists no officially supported scenario of deploying AD FS, where you won’t need Domain Admin credentials to install AD FS as a member server to the target forest.
Options 1 & 2 require Domain Admin
You can let the wizard create the objects given you’re armed with domain admin privileges
Or ask for domain admin to pre-create the required objects, and then install AD FS with -AdminConfig switch, where you detail the pre-configured container for AD FS
By combining the two following guides, you can get AD FS working on AAD DS:
Guide 1: ”Create an Organizational Unit (OU) on an Azure AD Domain Services managed domain”
Guide 2: Starting with AD FS in Windows Server 2016, you can run the cmdlet Install-AdfsFarm as a local administrator on your federation server, provided your Domain Administrator has prepared Active Directory
From Guide 1
Create an OU, where you create the container for DKM
Modify the original script to accumulate the new OU ($InitialPath) – Or alternatively bind new parameters to pass the $InitialPath
# THIS IS NOT THE FULL SCRIPT- original @ https://docs.microsoft.com/fi-fi/windows-server/identity/ad-fs/deployment/Install-AD-FS-Delegated-Admin
# The OU Name is a randomly generated Guid
[string]$guid = [Guid]::NewGuid()
write-host ("OU Name" + $guid)
$ouName = $guid
$initialPath = "CN=fscon,OU=NotInLocalDomain,DC=azure4d,DC=onmicrosoft,DC=com"
Install AD FS
Create certificates before the install.
If you don’t create certs before the install, the install will fail (in theory it should use the same path for CERTS, but in my tests it didn’t. I might try again at some point, if there is valid case for such install, but for now I am satisfied with creating the certificates before hand)
In this case I used the public cert for all three certificates.
Any service where AD FS has to write data into synced object, such as RegisteredDevices OU, or similar functionality won’t be in the scope of this installation. In this form AD FS is only able to authenticate, and authorize accounts.
See it in action
Synced on-prem user logging into Azure VM, and using integrated auth to login into Claims Xray (adfshelp.com)