Introduction
On the 31st of January 2023, Microsoft announced a new feature called cross-tenant synchronization(CRS). With CRS you can enable synchronization between two tenants for users and groups. The picture below shows CRS between three tenants.
Since this is a very new feature and still in preview there’s no attacks observed yet, however it definitely has the potential to be abused. In this blog we will show you how to perform and investigate a possible CRS attack.
Scenario
Using CRS could be an interesting method for persistence and a way for a threat actor to hide their presence and stay persistent in an Azure environment. At this moment we can only speculate about an attack, but let’s follow the assume breach principle. A threat actor successfully breached an Azure Tenant and wants to keep continued access. Setting up a cross-tenant synchronisation between an attacker controlled tenant and a victim tenant might help to achieve that goal. To perform this attack a threat actor needs to configure this on their Target(victim) tenant and on the Source(threat actor) tenant. To configure CRS a few steps need to be taken, the table below shows the required steps, it’s taken from the Microsoft site.
For our scenario we will call the Target tenant the Victim tenant and the Source tenant the Attacker tenant.
Attack & Defend
Step 1 — Enable Victim tenant to allow Cross-Tenant access
The first step is enabling CRS in the Victim tenant by the threat actor, to do this the threat actor needs to have the Hybrid Administrator Role.
The good news is that this activity is recorded in multiple places in the Victim tenant.
Audit logs
In the Audit Logs as part of the Azure AD the following activities recorded.
The “Add/Update Policy” activity type can be used to determine the user performing the activity. There’s also an IP address in the logs, unfortunately Microsoft doesn’t record the actual source IP, but an IP address from their own range.
Another log entry in the audit log, “Add a partner to cross-tenant access setting” is a very valuable activity type to detect and alert on for possible CRS abuse. In the event under Modified Properties you can see the tenant ID of the attacker tenant.
Interestingly enough there’s no record that shows the tenant name only the tenant ID, even if you configure it with the tenant name. You can use a little trick in the cross-tenant access settings to perform a lookup from Tenant ID → Tenant Name. In the cross-tenant access settings (link) click on ‘add an organization’ enter a tenant ID and Azure will tell you the associated Tenant Name.
Maybe this is a little Red-Team tip, but it works both ways and for all tenants as you see :)
When you configure CRS it also gives you the below pop-up.
However, this activity is only recorded in the GUI and not in the Activity log. There is also no record in the Provisioning logs.
To summarise based on the Audit Log we can detect cross-tenant setup and see the Tenant ID of the attacker and the user that configured this setting. The other logs in Azure AD (Sign-in/Provisioning) and the Activity log are not useful to detect this.
Let’s move to the next step.
Step 2 — Automatic redemption on both tenants
Still in the Victim tenant we enable user sync and suppress consent prompts so now on the Victim tenant everything is configured. Again this results in two pop-ups in the Azure Portal that are not recorded in the Activity log.
We are going to do the same in the Attacker tenant, where we have to add the Victim tenant and the settings. It’s not realistic we have access to the Attacker tenant for the investigation, however we see the same evidence when we add an organization.
Step 3 — Determine the synchronisation settings in the Attack tenant
In the Attacker tenant we configure a cross-tenant configuration that determines what gets synchronized. In this step we will also test the connection between the Attacker and the Victim tenant. Since this is all on the Attacker tenant as a responder we normally don’t have access to this. For the sake of completeness the following log entries were created as part of the configuration and testing in the Audit Log.
To store configuration details related to the CRS an application and an associated Server Principal will be created in the Attacker tenant. Another interesting find is that the events on the Attacker side record the actual source IP address and not the Microsoft IP address.
Step 4 — Testing
Now we have setup the connection we will create a user in the Attacker tenant and perform synchronization and determine what evidence we can find in the Victim tenant. We created a ‘test_sync_user_1’ and perfomed automatic synchronization. When we switch over to the Victim tenant Azure AD we can see that this was succesful under users we now have an additional user.
If we click on ExternalAzureAD we can see the source AzureAD (invictusirtraining.onmicrosoft.com)
Let’s dive into the Audit Logs to see if we can identify where this activity originated from.
As you can see there’s quite a few events generated to the creation of the user, but how do we determine this was as a result from CRS?
We can use a combination of the following details to determine this is originating from CRS.
The presence of B2B and the External Azure AD can help us establish that this came from a different tenant, however normal B2B will also generate similar results. So the (only) way to determine this was a result from CRS is checking the Audit Logs for the initial setup of CRS.
KQL Query
The below KQL query can be used to detect this type of attack, it extract the Source & Target tenant as well as the user that performed the action.
AuditLogs| where OperationName == "Add a partner to cross-tenant access setting"| where parse_json(tostring(TargetResources[0].modifiedProperties))[0].displayName == "tenantId"| extend initiating_user=parse_json(tostring(InitiatedBy.user)).userPrincipalName| extend source_ip=parse_json(tostring(InitiatedBy.user)).ipAddress| extend target_tenant=parse_json(tostring(TargetResources[0].modifiedProperties))[0].newValue| project TimeGenerated, OperationName,initiating_user,source_ip, AADTenantId,target_tenant| project-rename source_tenant= AADTenantId
The result should look something like this.
Conclusion
In this blog we have shown you what evidence is available when a threat actor abuses the new feature Cross-tenant synchronization. On the victim side the most important log source is the Audit Log this is the only log that records activity related to CRS. In the Audit Log the Activity “Add a partner to cross-tenant access setting” indicates CRS is being created. To determine what users were synchronized to a Victim tenant a combination of Activities and and Categories of events must be used.
Hopefully, this blog was not an inspiration for the threat actors to start abusing this. If there are any smart red-teamers that have already figured out a different scenario to abuse this let me know and I’ll be happy to add it to the blog.