Microsoft Defender for Identity Lateral Movement from Forest to Forest without a Forest trust

Microsoft Defender for Identity Lateral Movement from Forest to Forest without a Forest trust

In my previous blog post, I described the inner workings of the Microsoft Defender for Identity REST API. In this blog post, I will explain how multi-forest authentication works, how you can use the REST API endpoint to hop from forest to forest without a forest trust, and the risks associated with using Directory Service Account within Microsoft Defender for Identity.

Introduction

I want to take this opportunity to thank the Microsoft Defender for Identity team for their support. I am in close contact with the Microsoft Defender for Identity team, so they know most things I do. Microsoft Defender for Identity is an excellent product, and they also have a great team. Thank you ūüôŹ

My previous blog post described how you could decrypt all encrypted passwords in the sensor’s log file. I reported this to the Microsoft Defender for Identity team, who acknowledged it was an issue and fixed it within a week or so. From sensor version 2.194, the log file shows only masked passwords.

Image 1: Log file contains encrypted bytes in v2.193
Image 2: Log file only shows masked passwords in v2.194

Respect for the Microsoft Defender for Identity team for quickly acknowledging and fixing the issue.

Note: When you change anything regarding the Directory Service Accounts in the Microsoft 365 Defender portal, the sensor fetches the changes periodically using a REST API request and saves the configuration in the log file, including the encrypted passwords. Since version 2.194, it only shows masked passwords.

Let me describe how Microsoft Defender for Identity uses Directory Service Accounts in a multi-forest environment to understand the risks of these accounts.

Multi-Forest Authentication

Microsoft Defender for Identity supports a multi-forest environment allowing you to easily monitor activity and profile users across forests. Authentication must occur in a different forest when the sensor wants to collect data cross-forest. So, the type of authentication depends if there is a forest trust between the forest and if you use a Directory Service Account or a Group Managed Service account.

The documentation by Microsoft needs to be more explicit when using a multi-forest environment, to be honest. The documentation does state only one Directory Service Account is required to support all forests with a two-way trust and requires a Directory Service Account per forest without a forest trust. When there is a forest trust, any user in the trusted forest can perform LDAP queries, so there is no need for an additional Directory Service Account. It is different when you use a Group Managed Service Account for authentication, though. Since only the principals added to the “msDS-ManagedPassword” property of the Group Managed Service Account can get the password for the account, additional configuration is needed.

The recommendation is to create a Domain Local group in the trusted forest and add the “Domain Controllers” group from the trustee forest. Then add the Domain Local group to the “msDS-ManagedPassword” property of the Group Managed Service Account so all domain controllers can read the account’s password, including cross-forests domain controllers.

Plain Text Passwords

Since all domain controllers in all domains are allowed to retrieve the managed password in the setup described above, once an attacker gets hold of a single Microsoft Defender for Identity sensor, the attacker can read the password for the Group Managed Service Account in plain text.

The Microsoft documentation states that using a Directory Service Account with limited privileges is essential. Still, it is a way for attackers to get the plain-text password for identities in a different forest, even when using Group Managed Service Accounts.

So, no trust, no worries?

An additional Directory Service Account is needed per forest to support untrusted forests. Since the sensor needs to perform the authentication, the sensor also needs to be aware of the Directory Service Account, including the password.

Note: Since there is no trust, the account can not be a Group Managed Service Account.

How does the sensor get the Directory Service Accounts? The sensor sends a REST API request to the cloud to get all Directory Service Accounts, including their encrypted password.

Image 3: Using a REST API request, you can still get the encrypted passwords using my tool.

Mimicking a Microsoft Defender for Identity sensor using my tool makes it possible to get all encrypted passwords using a REST API request. As described in a previous blog post, it is possible to decrypt all passwords and get plain text passwords from all Directory Service Accounts, excluding Group Managed Service Accounts.

Note: I updated my Microsoft Defender for Identity API Fiddler, which now includes encrypting and decrypting the passwords.

Image 4: I added the encryption and decryption of the passwords in my tool.

So, once an attacker gets the plain text password for a different forest, the attacker can authenticate to the other forest even when there is no forest trust.

Important: When you compromise a single Microsoft Defender for Identity sensor, you can get all Directory Service Accounts passwords in plain text, including those of forests without a forest trust, and including Group Managed Service Accounts.

Password Decryption

How does the sensor decrypt the password of the Directory Service Account from another forest? That is a good question!

All Directory Service Accounts are encrypted using all sensor’s public keys. Microsoft encrypts all passwords with every public key of all sensors to be sure that every sensor can decrypt all passwords. The sensor sends a REST API request to the cloud to get all encrypted passwords matching its certificate and decrypt all passwords for all Directory Service Accounts, excluding Group Managed Service Accounts, as they do not have a password.

Conclusion

Although some authentication is by design in a Windows environment, when there is no forest trust, an attacker can still authenticate using a plain text password to the different forest using a REST API request using my tool. So, getting plain text passwords for another forest introduces a possibility for attackers to hop from forest to forest, including those without a forest trust. There is no mitigation for getting the encrypted password using my tool, as the sensor uses this authentication method.

Remember, though, never reuse passwords as attackers use the password for password sprays, potentially compromise other identities, and only use low-privilege accounts, as Microsoft’s documentation states.

Microsoft Defender for Identity JSON API

Microsoft Defender for Identity JSON API

In my previous blog post, I described the inner workings of the Microsoft Defender for Identity REST API during the deployment of the sensor. In this blog post, I will explain the inner workings of the REST API when communicating with the cloud and how to interact with it using my updated Microsoft Defender for Identity API Fiddler tool.

Introduction

My previous blog post describes that you need the WorkSpaceID and AccessKey to interact with the REST API during the deployment. Microsoft Defender for Identity installation creates a self-signed certificate to communicate with the cloud after the deployment of the sensor. So, only during the sensor installation will you need the AccessKey. Thus, it is safe to regenerate a new AccessKey after the installation since the authentication with the REST API endpoint takes place using the self-signed certificate.

I identified three REST API endpoints during my research: sensorDeployment, protobuf, and json. In this blog post, I am referring to the following REST API endpoint:

Authentication

After installing the sensor, if you look at the Local Machine Certificate Store, you will find a self-signed certificate with the name “Azure ATP Sensor”.

Image 1: Microsoft Defender for Identity Certificate

The authentication takes place by encrypting the payload sent to the REST API endpoint. In my previous blog post, you see a CreateSensorRequest REST API request which sends the self-signed certificate public key to the cloud. The cloud can then identify which sensor sends the encrypted payload by decrypting it using the public key of the self-signed certificate and identity which sensor sends the REST API request.

The private key of the self-signed certificate is not exportable. Well, not by default. So, to send any REST API requests, you either need to send the request from the Domain Controller or export the self-signed certificate using a tool like Mimikatz. Mimikatz exports certificates in the PKCS#12 format. The PKCS#12 format includes the private key you need to send a REST API request. Here are the commands to export the self-signed certificate using Mimikatz.

Image 2: Extracting certificates with Mimikatz
Image 3: Extracted certificate

You can use the PFX file, extracted by Mimikatz, to send REST API requests using my Microsoft Defender for Identity API Fiddler tool.

API Requests

Here is an example of a REST API request.

{
  "$type": "DeleteSensorRequest"
}

As you can see, the request does not include the sensor’s name or any identification to identify which sensor sends the request. As I mentioned at the beginning of the blog post, the cloud uses the public keys to match which sensor sends the request to identify the sensor.

Here are some other REST API requests.

{
  "$type": "TestRequest"
}
{
  "$type": "GetSensorKnownDomainCredentialIdentifiersRequest"
}
{
  "$type": "GetAdfsServerDnsNamesRequest"
}
{
  "$type": "GetPendingRemediationActionsRequest"
}
{
  "$type": "GetSensorComputerIpAddressAssertionsRequest"
}
{
  "$type": "GetSensorKnownDomainCredentialIdentifiersRequest"
}
{
  "$type": "GetSensorTypesAndRunningComputerIdsRequest"
}
{
  "$type": "GetSensorWindowsEventLogReaderBookmarksRequest"
}
{
  "$type": "GetTaggedEntitySidsAndIdsRequest"
}
{
  "$type": "GetWorkspaceSyslogMessageDatasRequest"
}
{
  "$type": "GetSensorMinorDeploymentPackageSensorApiRequest",
  "Version": "2.193.15824.20477"
}
{
  "$type": "GetSensorSoftwareUpdateDataRequest",
  "Version": "2.193.15824.20477"
}

There are some exciting REST API requests, but more on that in a later blog post.

Microsoft Defender for Identity API Fiddler

I updated my tool so you can also send a request to the REST API endpoint. I also included the encryption and decryption of the passwords, which will be relevant in my next blog post.

Image 4: Updated Microsoft Defender for Identity API Fiddler

For more information about how to use the tool, check this repository.

Conclusion

We can now also fiddle around with the REST API endpoint and see what response we get when sending these requests. Using my tool makes it easier to send the request. In the next blog post, I will show you how you can use an REST API request to get the encrypted passwords described in my previous blog posts and hop from one forest to another, even when there is no trust between the forests.

Microsoft Defender for Identity Auditing Checker using Sentinel

Microsoft Defender for Identity Auditing Checker using Sentinel

A few months ago, I wrote a tool to check the Microsoft Defender for Identity Configuration, which you run on a domain controller. Running the tool is a snapshot at that time. What if you want to monitor the configuration using your SOAR solution for misconfigurations? Well, I created a PowerShell script that creates an event in the event viewer which is sent to the cloud to monitor the configuration using your favorite SOAR solution. In this blog post, I will describe how to monitor this using Microsoft Sentinel.

Introduction

I wanted to know how to monitor the Microsoft Defender for Identity configuration twenty-four-seven. Even though the tool I created works fine, it is a snapshot at a particular time. At the time of writing, Microsoft Defender for Identity does not notify you about any misconfigurations, even though enabling auditing is extremely important. No auditing means no detections for specific attacks. For this reason, I came up with a solution to send the Microsoft Defender for Identity configuration to the cloud and make it possible to monitor any misconfigurations using Microsoft Sentinel.

Collect Data using PowerShell

Since Microsoft Defender for Identity does not support sending the configuration to the cloud, I needed a low-cost solution to ingest the data. But first, I needed to collect the data. The solution I came up with is a PowerShell script, as you can run it using a scheduled task, and it is easy to read.

As of the time of writing, the PowerShell script collects all auditing configurations needed for Microsoft Defender for Identity to detect all attacks. I wanted to use as many standard solutions as possible, so I wrote the data to the application log in the event viewer. This way, filtering and ingesting the data to any SOAR solution is easy.

Image 1: Event in event viewer

A simple true or false statement indicates any misconfiguration. To continuously monitor the configuration, create a scheduled task that runs the PowerShell script once daily, for example.

Azure Monitor Agent

Now that we have the data in the event viewer, we want the data to ingest into Microsoft Sentinel. Since the Azure Monitor Agent supports custom events, we can “filter” for only certain events sent to the cloud using Azure Collection Rules.

To collect the event from an on-premises server, you must install the Azure Monitor Agent from the Azure Arc blade.

Note: If the server runs in Azure, you only need to add an Azure Collection Rule which I will describe later.

In my case, I am running the server in an on-premises environment, so I installed the Azure Monitor Agent using a script that I downloaded from the Azure Arc blade:

Image 2: Generate script for the AMA agent

The installation is straightforward. Execute the script to install the agent using PowerShell. The script asks you to authenticate to the correct tenant during the installation:

Image 3: Installing the AMA agent

Once installed, we can create the Azure Collection Rules.

Azure Collection Rules

If we look at the data connectors in Microsoft Sentinel, we see a connector named “Windows Forwarded Events.” Once we open the connector page, we can add a Data Collection Rule:

Image 4: Adding the collection rule

With “Select a scope,” we can select the servers where we installed the Azure Monitor Agent:

Image 5: Selecting the server to collect the events

At “Collect,” we select “Custom” and add the following expression:

Image 6: Collect expression

Now that we have ingested the data into the cloud, the last step is to create an analytics rule in Microsoft Sentinel.

Microsoft Sentinel Alert

After we trigger a new event using the PowerShell script, or the scheduled task in the event viewer, we can check the logs for the result:

Image 7: Check logs for results

Once we have the result, we can create the alert. We can map the hostname using entity mapping to know which host triggered the alert:

Image 8: Select entity mapping

The result is an alert in Microsoft Sentinel if Microsoft Defender for Identity is not configured correctly, including the hostname:

Image 9: Alert in Microsoft Sentinel

The PowerShell script and the Kusto Query is just an example. Feel free to write anything fancier to make it more to your liking.

Conclusion

Maybe, in the future, Microsoft Defender for Identity will send the configuration settings to the cloud, but this is a good solution for now. Especially in an organization with 100+ domain controllers and ESPECIALLY considering how important it is to enable auditing for Microsoft Defender for Identity to detect correctly.

Microsoft Defender for Identity sensorDeployment API

Microsoft Defender for Identity sensorDeployment API

Microsoft Defender for Identity is a cloud-based security solution to monitor your on-premises identities. Since it is a cloud-based security solution, it must communicate with the cloud. In this blog post, I will describe how Microsoft Defender for Identity communicates with the cloud during the installation of the sensor.

Introduction

I started monitoring the installer using Burp Suite. After intercepting the first request, I see that the body includes some jibberish. The body looks encrypted or compressed. Since the installer does not contain a certificate, the body is probably compressed and not encrypted.

Here is an example of an intercept in Burp.

POST /api/sensorDeployment/v1.0 HTTP/1.1
Authorization: Basic <WorkSpaceID>:<AccessKey>
Host: thalpius-onmicrosoft-comsensorapi.atp.azure.com
Content-Length: 41
Expect: 100-continue
Connection: close

¬ę√¶√•RPPR)¬©,HU¬≤RP
I-.qI-√ą√ȬĮ√ĆM√ć+	J-,
(√Īr√ē

The body looks compressed, so the question is: What does the body look like after decompression?

Microsoft Defender for Identity API Fiddler

There are different ways to decompress the bytes, but I created a tool to add more features to test the API endpoints in the future.

The tool includes a compressor and a decompressor. When we copy the compressed bytes from Burp to see what the body looks like decompressed, we can see it is a JSON object.

Image 1: Decompressed bytes

Because I do not want to compress and decompress a JSON object all the time, I created a simple API requester that compresses and decompresses the body automatically. Using my tool, you can send a request in JSON format without compressing it, making it much simpler.

Image 2: Send request without compressing bytes

The installer does not contain a certificate, so how does it authenticate to the cloud?

Authentication

The Burp interception shows an authentication header which is basic authentication.

Authorization: Basic <WorkSpaceID>:<AccessKey>

There is a comment in the Microsoft 365 Defender portal which says, “Access key is only used during the sensor installation.”

The installer creates a certificate for all future communication to the cloud. For that reason, the access key is used only during the installation. I added a settings option in my tool to set the authorization needed to send a valid request.

API Endpoints

I identified three API endpoints during my research: sensorDeployment, protobuf, and json. The URI of the endpoints are:

Note: The installation only used the sensorDeployment API endpoint‚ÄĒmore on the protobuf and json endpoints in a later blog post.

API Requests

Now that we know how the authentication takes place and we can decompress the body, let us see what the installer sends to the API endpoint during the installation.

Here are the API requests:

{
  "$type": "TestDeploymentRequest"
}
{
  "$type": "ValidateCreateSensorRequest",
  "Version": "2.193.15824.20477"
}
{
  "$type": "GetSensorMinorDeploymentPackageSensorApiDeploymentRequest",
  "Version": "2.193.15824.20477"
}
{
  "$type": "CreateSensorRequest",
  "Certificate": {
    "$type": "X509Certificate2",
    "RawData": "MIIDbj<SNIP>rjjb88"
  },
  "DnsName": "THALPIUS.thalpius.local",
  "NetbiosName": "THALPIUS",
  "NetworkAdapters": [
    {
      "$type": "NetworkAdapter",
      "Id": "{9846C447-1A36-4739-B469-E03769E013DE}",
      "Name": "Ethernet",
      "State": "EnabledConnected",
      "IpAddresses": [
        "10.211.55.83",
        "[fdb2:2c26:f4e4:0:558b:329c:4fd7:477e]",
        "[fe80::558b:329c:4fd7:477e%9]"
      ]
    }
  ],
  "ShouldEnableDelayedUpdate": false,
  "Type": "DomainControllerIntegrated",
  "Version": "2.193.15824.20477"
}

Download Sensor

For example, the GetSensorMinorDeploymentPackageSensorApiDeploymentRequest downloads a cabinet file of the latest sensor. You can see the response in my tool, which automatically decompresses the result.

Image 3: Downloading the latest sensor

If we take the base64 encoded string and decode it using certutil, we see we got the latest sensor.

Image 4: Decoding the encoded string
Image 5: Downloaded the sensor

Conclusion

My intention in researching the API is to understand better how the product works and see what I can do with it as an attacker. I will soon add more functionality to my tool, such as the JSON API endpoint, and post my findings testing that API in a future blog post.

Microsoft Defender for Identity Encrypted Password

Microsoft Defender for Identity Encrypted Password

After installing a Microsoft Defender for Identity sensor, the SensorConfiguration.json contains information about the sensor, including an encrypted password when using an authenticated proxy server. I wanted to see if I could decrypt the password and if I could set a proxy without the need to reinstall the Microsoft Defender for Identity sensor. I found more exciting things during this research, which I will describe in this blog post.

Introduction

The recommended practice from Microsoft to use a proxy server for the Microsoft Defender for Identity sensor is to run the setup with some arguments. There are alternative ways to configure a proxy, but that affects all services for the entire system. Configuring a proxy for Microsoft Defender for Identity using the command line means reinstalling the sensor. Microsoft provides no way to set up a proxy server after you install the sensor without reinstalling the sensor using the command line. During the setup, the password gets encrypted and stored in SensorConfiguration.json, which is why you need to reinstall the sensor when using a proxy server.

Proxy Server Without Authentication

When using no authentication for the proxy server, you can edit SensorConfiguration.json, so you do not have to reinstall the sensor. Here is an example of a SensorConfiguration.json with no authentication for the proxy server.

{
  "$type": "SensorMandatoryConfiguration",
  "SecretManagerConfigurationCertificateThumbprint": "F9E489827037BBC8ADFE82E43A3C63FCB6C717A9",
  "SensorProxyConfiguration": {
    "$type": "SensorProxyConfiguration",
    "Url": "http://localhost:8080",
    "UserName": null,
    "EncryptedUserPasswordData": null
  },
  "WorkspaceApplicationSensorApiWebClientConfigurationServiceEndpoint": {
    "$type": "EndpointData",
    "Address": "thalpius-onmicrosoft-comsensorapi.atp.azure.com",
    "Port": 443
  }
}

Proxy Server With Authentication

Things get a little trickier when you use authentication for the proxy server since the password is encrypted and stored in SensorConfiguration.json.

Here is an example of a SensorConfiguration.json with authentication for the proxy server.

{
  "$type": "SensorMandatoryConfiguration",
  "SecretManagerConfigurationCertificateThumbprint": "B6DED748E000B5A62D3F4C45058E1DCF64BB55B9",
  "SensorProxyConfiguration": {
    "$type": "SensorProxyConfiguration",
    "Url": "http://localhost:8080",
    "UserName": "thalpius.local\\thalpius",
    "EncryptedUserPasswordData": {
      "$type": "EncryptedData",
      "EncryptedBytes": "FecQfIeoURIu/oCGrvzkSsVP3IIBHDnOchSRQ0hjwzoZSvxLFMnleVNoPSZuCDCy7MVpi1qyFSdBWcrS1nmfgXpzQUFmY4XItKug4OlEYST6F96LY5mWW7H9noOIF5LOGNeltQkJYqeo3MKrXZdoh87EnjBbhKV5cSCgrMOwUXUMsiXd6KvEmsevAkIHvRHZnYbrdG/2pIqI/l4/oyRgU7fOunDlyZF9Ne/xgxApjcMa/sEdnoqBu+0Rs3XVN8K6RbjdxtiGHlbaCM5WUYQ4h+Qznd3GkhNo4iGaXvpa75tedpUbi/aofNMA9w0W+z2ScXqPEBuZhxE6O1t28I5feA==",
      "CertificateThumbprint": "B6DED748E000B5A62D3F4C45058E1DCF64BB55B9",
      "SecretVersion": null
    }
  },
  "WorkspaceApplicationSensorApiWebClientConfigurationServiceEndpoint": {
    "$type": "EndpointData",
    "Address": "thalpius-onmicrosoft-comsensorapi.atp.azure.com",
    "Port": 443
  }
}

You need to know the encryption to decrypt the password. Luckily the sensor is written in C# and is easy to decompile. Looking at the code, we can see that the encryption takes place using the public key from a certificate with RSA and OAEP padding.

public EncryptedData Encrypt(byte[] data)
{
    Ensure.NotNull("data", data);
    return new EncryptedData(this._rsaCng.Encrypt(data, ApplicationCryptoKey._rsaEncryptionPadding), null, this.SecretVersion);
}

public byte[] Decrypt(EncryptedData encryptedData)
{
    Ensure.NotNull("encryptedData", encryptedData);
    Ensure.That("attempt to decrypt certificate-encrypted data [encryptedData.CertificateThumbprint=" + encryptedData.CertificateThumbprint.Sanitize() + "]", encryptedData.CertificateThumbprint == null);
    return this._rsaCng.Decrypt(encryptedData.EncryptedBytes, ApplicationCryptoKey._rsaEncryptionPadding);
}

private static readonly RSAEncryptionPadding _rsaEncryptionPadding = RSAEncryptionPadding.OaepSHA256;

I created a tool that encrypts and decrypts the password using the certificate found on the server, which has the sensor installed. Using the tool and encrypting the password makes it possible to set up an authenticated proxy server in SensorConfiguration.json without reinstalling the sensor. Encrypt the password and use the example above by replacing the EncryptedBytes property to set the authenticated proxy server in SensorConfiguration.json.

Decrypt ALL Directory Services Accounts

During my research, I discovered that I could decrypt all passwords found for all non-gMSA accounts entered in the portal at “Directory Services Accounts” since the sensor-updater log contains all encrypted passwords for all accounts during an update. The weird thing is that I can decrypt all passwords with a single certificate. So, once a single server is compromised, which holds the Microsoft Defender for Identity sensor, all passwords are known in plain text using my tool, including all passwords across forests or domains

Recommended Practice

Here are my recommended practice regarding decrypting passwords for the Microsoft Defender for Identity sensor.

  • Do not re-use passwords for any account since the decryption of the password shows the password in plain text.
  • Use a gMSA account for connecting the sensor to Active Directory domains.
  • Be aware when using multiple domains or even forests that the decryption of a password shows the password in plain text for that particular domain or forest. So, anyone with access to a server which holds a sensor can decrypt the password.
  • Although an attacker already needs to compromise AD DS to perform this attack, remember the AD FS servers which also can contain a sensor. So getting a foothold on an AD FS server makes it possible to achieve this attack without touching AD DS. Handle an AD FS server the same as an AD DS server (TIER-0).

Conclusion

Although an attacker already needs a foothold on an AD DS server, an AD FS can also hold a sensor if installed. From the AD FS server, an attacker can decrypt all passwords entered as a Directory Services Account in the portal without touching AD DS. Using only gMSA accounts mitigates everything, and it is a recommended practice anyway.