Microsoft Secure Score Multi-Client Key Metric

Microsoft Secure Score Multi-Client Key Metric

I currently work at a Managed Security Service Provider (MSSP), delivering comprehensive security solutions to over twenty clients. One of our primary objectives is to enhance clients’ security resilience by utilizing Microsoft Secure Score as a key metric. We aim to elevate the Secure Score to a minimum of 75 percent. Given the number of clients, I recognized the need for a centralized dashboard to monitor all scores efficiently. In this blog post, I will outline the process of creating a fully automated Power BI dashboard to provide an overview of the Secure Scores for all clients simultaneously.

Presented below is an example of the outcome.

Image 1: Secure Score and KPI for multiple clients

Introduction

I aimed to obtain an overview of the Secure Scores for all clients through full automation, ideally utilizing native Microsoft tools. While numerous approaches exist to achieve this, I opted to use a storage account to store the Secure Score history, an automation account to automatically collect the data from our clients using the Graph API, and Power BI to visualize the data.

Image 2: Architectural Overview

We start by creating a storage account to store the data.

Storage Account

I opted to store the data from the Graph API in a blob storage within Azure. First, we create a Storage Account in a newly created Resource Group with the following settings.

Image 3: Creating a storage account

To store the data, we create a Container.

Image 4: Create a container with default settings

Once we have a Storage Account and a container, we must use an app registration to interact with the Graph API and store the data in the container. But before creating the app registration, we need to generate a certificate to authenticate to the App Registration.

Note: Navigate to “Security + Networking,” select “Access keys,” and copy the key for use in a subsequent step.

Certificate

To authenticate to the Storage Account, we create a self-signed certificate and export the certificate with and without the private key. Use the following script to generate and export the certificates to authenticate to the Storage Account.

$certname = "SecureScore"
$cert = New-SelfSignedCertificate -Subject "CN=$certname" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature -KeyLength 2048 -KeyAlgorithm RSA -HashAlgorithm SHA256

Export-Certificate -Cert $cert -FilePath "$certname.cer"

$mypwd = ConvertTo-SecureString -String "StrongPassword" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath "$certname.pfx" -Password $mypwd

Note: The “.CER” file is the certificate without the private key, and the “.PFX” file is the certificate with the private key. We use the “.CER” file for the App Registration and the “.PFX” file for the Automation Account.

With the required certificate in hand, we will proceed to create an App Registration. This registration will facilitate communication with the Graph API to retrieve the Secure Score data.

App Registration

In Entra ID, we select “App registrations” and click “New Registration” to register a new application.

Image 5: Create a new application

We give the application a name and click “Register.”

Image 6: Register the application

In our newly created app, we select “Certificates & secrets,” select “Certificates,” and upload the certificate we generated in the previous step.

Image 7: Upload certificate for authentication

Note: Please save the certificate’s thumbprint, as you will need it for future steps. We also need the ClientID of the App Registration and TenantID which can be found at the overview of the App Registration.

Once the certificate is uploaded, we select “API permissions” and click “Add a permission.” At the top, we select “Microsoft Graph,” followed by “Application permissions.” Search for “SecurityEvents.Read.All” and click “Add permissions.”

Image 8: Add Graph API permissions

To grant the permissions, click “Grant admin consent for domain” and select “Yes.”

Image 9: Grant admin consent

Upon completion of the App Registration, data retrieval can be automatically managed using an Automation Account.”

Automation Account

Within the newly created Resource Group, we will add an Automation Account. Upon deploying the Automation Account, navigate to ‘Certificates’ and upload the certificate created in the preceding step.

Image 10: Add certificate automation account

We will create variables for sensitive data, such as the Storage Account Key, and then use them within the script.

Create the following variables under “Shared Resources / Variables with the correct values we saved previously.

  • CertificateThumbprint
  • StorageAccountKey
  • TenantIDClient01
  • ClientIdClient01

Now that we have the variables used in the script, it is time to create a Runbook.

Go to “Process Automation” and select “Runbooks.” Click “Create runbook” and enter the client’s name, type PowerShell and Runtime version 7.2 followed by “Review + Create.”

Image 11: Creating a runbook

On the top, click “Edit” followed by “Edit in portal.” Copy the script into the editor and click “Save” and “Publish.”

$ClientIdClient01= Get-AutomationVariable -Name 'ClientIdClient01'
$TenantIdClient01 = Get-AutomationVariable -Name 'TenantIdClient01'
$CertificateThumbprint = Get-AutomationVariable -Name 'CertificateThumbprint'
$StorageAccountKey = Get-AutomationVariable -Name 'StorageAccountKey'

Connect-MgGraph -clientId $ClientIdClient01 -tenantId $TenantIdClient01 -certificatethumbprint $CertificateThumbprint
Get-MgSecuritySecureScore | ConvertTo-Json | Out-File -FilePath "Client01.json"

$ctx = New-AzStorageContext -StorageAccountName "securescore001" -StorageAccountKey $StorageAccountKey
$container = Get-AzStorageContainer -Name "securescore" -Context $ctx

$filesToUpload = Get-ChildItem "Client01.json" -Recurse -File
Set-AzStorageBlobContent -File $filesToUpload.fullname -Container $container.Name -Blob $targetPath -Context $ctx -Force:$Force | Out-Null

If everything went ok, we can see the published Runbook as “Published” in the “Runbooks” section of the Automation Account.

Image 12: Published Runbook

We want to automate the process. Luckily, you can add a schedule that runs once daily, which you can then add to the Runbook.

Under “Shared Resources,” you will see “Schedules.” Click “Add a schedule” at the top and enter the following settings to add a daily schedule.

Image 13: Add new schedule

Now that we have a daily schedule, we can add the schedule to the Runbook.

Image 14: Add schedule to Runbook

The last thing we need to do is add the correct modules used in the script.

Image 15: Adding modules to Automation Account

With all data preparations complete, we will use Power BI to visualize the Secure Score.

Power BI

After we open the Power BI Desktop application, we import our data by clicking “Get Data” and selecting “Azure Blob Storage.”

Image 16: Importing data from Azure Blob Storage

In the next step, we enter the name of the Storage Account.

Image 17: Enter the name of the Storage Account

We need to connect to the Storage Account using the Access Key.

Image 18: Enter the Account Key of the Storage Account

Tick the container name and click “Load.”

Image 19: Tick the container name and Load the data

The JSON file is a binary object. To convert it to usable data, click the two down-arrows next to “Content.”

Image 20: Convert the JSON object to usable data

The data should look like this.

Image 21: Converted data

You can see the data we will work with on the right side.

Image 22: Table with data

If we add a “Line Chart” and the “CreatedDateTime” for the “X-axis” and “Sum of Current Score” for the Y-axis, we see that the calculation of the Secure Score is incorrect.

Image 23: Adding the date and current score to a line chart

The score is incorrect due to the point system that Microsoft used. We can easily fix this by using a simple calculation.

SecureScoreClient01 = 

DIVIDE(
    SUM('Client01'[CurrentScore]),
    SUM('Client02'[MaxScore])
) * 100

Select the “securescore” table on the right-hand side and click “New Calculation”. Enter the code above and use “SecureScoreClient01” for the Y-axis. The end result should look like this.

Image 24: End-result of the Secure Score

When adding multiple clients, repeat the previous steps. Since the certificate is the same, adding a new client should be easy.

Conclusion

In this blog post, I demonstrated how to create a dashboard of a single client’s Secure Score using a fully automated process and native Microsoft tooling. Repeating the previous steps makes adding multiple clients easy, and using the same certificate makes creating another certificate unnecessary. My initial thought was to create the dashboard with the Secure Score and Key Performance Indicator. When serving multiple clients, the next step is to add which Recommended Action is open for the most clients so I can implement a Recommended Action for all clients.

Microsoft Defender for Identity Bulk Operation

Microsoft Defender for Identity Bulk Operation

Microsoft Defender for Identity supports health issues through the Microsoft Graph API. Unfortunately, at the time of writing, only health issues are supported. When you want to perform a bulk operation, there is no way to do this using the Microsoft Graph API. Using PowerShell in this blog post, I will describe how to add multiple IP addresses to the “Global Excluded Entities” list as a bulk operation.

WARNING: When adding multiple IP addresses to the “Global Excluded Entities” list, it is good to understand Microsoft Defender for Identity will ignore ALL detection from that IP address. This blog post showcases performing a bulk operation, such as adding multiple IP addresses to the “Global Excluded Entities” list.

Automate request with PowerShell

The first thing we need to do is copy the request using a browser to replay it. Open the Defender portal and go to the section where you want to perform a bulk operation. In my example, I am opening the IP addresses section for “Global Excluded Entities.” Add any IP address in the text field and click “Add.” Open the developer’s tools and open the “Network” section. Clear the network log to start with a clean sheet.

Image 1: Developers tools to capture request

Once you click “Add IP addresses (0),” check for the request named “Global” and where you see the added IP address. Right-click the request and select “Copy / Copy as PowerShell.”

Image 2: Copy the request as PowerShell

Now copy the PowerShell command in PowerShell and change the IP address to something else.

Image 3: PowerShell request with a new IP address

Now, you see the new IP address in the portal using a PowerShell command.

Image 4: Added IP address using PowerShell

Now, we create a text file with all the IP addresses we want to add with every IP address on a new line.

10.0.0.1
10.0.0.2
10.0.0.3
10.0.0.4
10.0.0.5
10.0.0.6
10.0.0.7
10.0.0.8
10.0.0.9

Before the “Invoke-WebRequest,” we need to add a new body and a for loop.

foreach($IPAddress in [System.IO.File]::ReadLines("C:\Users\thalpius\Downloads\IPAddresses.txt")) {

  $body = @{
    ExclusionType = @("Subnet")
    ExcludedEntityIdentifiers = @($IPAddress) 
  } | ConvertTo-Json

For the body, we use the body variable as input.

-Body $body

Here is an example of the complete script.

$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$session.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0"
$session.Cookies.Add((New-Object System.Net.Cookie("s.SessID", "e0826123-5b02-43ea-a531-031ad1104817", "/", "security.microsoft.com")))
$session.Cookies.Add((New-Object System.Net.Cookie("X-PortalEndpoint-RouteKey", "weuprod_westeurope", "/", "security.microsoft.com")))
$session.Cookies.Add((New-Object System.Net.Cookie("sccauth", "UB2-m0wz3Ws58SPzNbefq9e9WE9EOv2lmLaPw7kKo9kh2PMxFotm7jIah1GdqZrw8VBrpU1Kgm26DgaLSZ6A5ywC-5J8iqlrv6ik0TTeCUiZuVcpwP6eZ19-7yTfR81oQwvYyTtDpuoG2_vBnBpp9q_LHYmLQFQL0PaSuuYUFZWLJvQumgHU-4Ec8kcsUM025w4aDO-CBzP9DzPLkDN2F2EeEREjRAPffqvrf64cg41javXDp52O-D0ZWqpoZYcAVvBPOYYZZPLKulZurWytpwk3y2KDdsL_TUDIwNujgDej7g_sKad5nHv6NTkiEAnXKyueozReEfo_EixVcs_MwhGKkZHPDhVJOnybkYnoDSOuU_SlrlOM7IcITNcc2h6wOqti-oHyB5Zpm0kHGxJXVZeL2A02XCy_0FFmI5GyZ0miFTu2OnoC4LLxAh4zD1mohPnbP2EzBv8X05QiyLYbl_H81LnWrKeCjJ-ZHp01pY9P6CtVJFRKJIuFFtN1lKGwcsX644y4xHAxLvikJOmzyEDSSFo2IdSFfQqo_TCgA_5PwHQ-N0Jvw4CzOyvxbe-4OaloZPgpYqoKJ6SGo3uIxG4-YjJOaXbbaLUsI4GuGqwCRfdZ2frUBqxyv3UPTtMkelKMjHS5CaxKgFjvRP3DSI0PTF_HXe6nRNAfUJ45hNBrRFKM1LY4E3_duPOfSEL1BXlylvSc5JYE2OfMZvZfeFqURlY7tb84tok6vwMnNb-dNKA2ERgAVCnv96hoges_HRLOSGybRAMCnzxV8VeGyZepKUEVqQcachQMIJXcStNbjFFl5K5oysQ2rfzI_p6vTkYSf6n-MC5gTjH5LDPF4LUBIPPx4FjiqKhpQSE9MdsTARNbFn6mWZb3cuK2vVi6emlBic9UQlVfh_IbuD9AolrrT3l4THawS1fZZvsCZoE7nRKNe06KOfj82ierTO9_bJ9N2Ea_mx27WGfAcE9t4KYxu8g1dQQMp2bmfHkUD0g4rOhlvzz5SKFevUwN7hJscZ_24R9O0SlssA3RXWL-nMLMqx6dLsNo5f7CLM66kv9_94CV8c7zg6ZigYho6fxTqC2WctxJJ0q-7bnTRInnZR_bUvACie6jQvtpnAjDOnPFR19_xb0oaT-yYnDdHhyC1pWX8H9Vl7zDGvjDM9pdx07FbK-IswgUhEelvh1GUyEbt78Z-_CeoGmcIO6aVTGxVmfGDX28o9c3-0_ply1ZMj8Hfh3d2issz-cE8bgQCcU-SAQTtwnmAd_PL7ua4ss2M-aw6TQ1P-sjTRg1UqUTT5CJ7V9ahyAQvhTgSKCHMhIlYx-GoFa3WalcW0mCOSxT-gKHuKzTal9CdmX4KS65002uCuU_0A1Rz3W0ke1ki8PpfzTDItqpi-EYG6ajGcIxjLfLPMUU31ArcSDYaATUUBJEw8p5_wDBR1B7wUUUeSNrfDQxXvkLaiagS-U7tE7WC5P5gmSba3NPNY_wj_F6DhSq3ms_ytCPsHy1aKZUDgtoTvc1-_bVEAdmR8S3GZ7VnN0lOmK7hk0dvPexn7qVqdLoLa0w2gOfseeZytTlN4KHbiZicVWxlOdQ_Mae3qGYSmGKxkWltq3kctEOyF5Jjh7NK19rw_XgDmsGal7QnD_TutPLKXDGmAhCNwoJkJ0BBz9uyuiGNowSKI-gxFxr30Dcp29qG6tUL8DKWgmnZjPcQ9Mjegdim4m7rAxO8oZvdgiFQbrz8DpF2avtiRHAPSBMpILo6fp5ZhBXRKjUG4_7ClE_YWTA391VntnQwoVzfJHxXflnSp4A4lRNTNVbpW-2wi2CjrJWZPoNwJmxUrKhnEHGYMoKPFjZ5wThpFeP87vhJ7axY_V7Dc9k2Q9IdYXlbVZU9_AnEtX8iH77qu_9p2lUzAd3HAAPUKgt6xKZc1-ICDAuD7yB0JMGt-DpkcBU2WELxn9zUsHD9zb9RD2jfsDqHgHBqEZoX1Hlhy-cU9lfdo-3MiP_ld3mnpukREt7Zn-Y84b34Zx8EleAfDVyoJxfOhl2eLglGMJW6oaQ-zy2YdLmHG8Thj76FbTwL4jYeU76wsgsd0Y2mey6tQYaeCEVxffbUoPdvW8EFZYFkX-SQBt-PsBf2I2Trz24o7-wc-9L602J6cTGeX2czaBhJ8VIWE8-orkdfj43Ih-rUZasq8O_uuRVk0YWkwQ", "/", "security.microsoft.com")))
$session.Cookies.Add((New-Object System.Net.Cookie("s.Flight", "", "/", "security.microsoft.com")))
$session.Cookies.Add((New-Object System.Net.Cookie("ai_user", "pLdacxhAs64+rre2OP2jWq|2024-11-13T07:27:09.559Z", "/", "security.microsoft.com")))
$session.Cookies.Add((New-Object System.Net.Cookie("MicrosoftApplicationsTelemetryDeviceId", "4a003a38-4e78-463e-a6cd-9c216518c0c6", "/", "security.microsoft.com")))
$session.Cookies.Add((New-Object System.Net.Cookie("SSR", "1731482842137", "/", "security.microsoft.com")))
$session.Cookies.Add((New-Object System.Net.Cookie("XSRF-TOKEN", "yPxQoy4EzwoI_1T3KL-ceaL3A37Qwa_YpYipGReBSKhx8BromY2IzOk69YSR59Hy2oVt1T4Uls4_t_Fepgh-7uk-ED6zV_QfxUEYUFfmDVgWWUE-972C5JdGu0v55LgyX-pxTIQkf1QLLmitQ2%3AF5NtYsmk3iMXBbn8_ejAAgLsf5r45wD8hhR0PiFg41hO4kzw0MetHytNEUflPOKZy9YNpW2WOC-6Um0-Dex564PLDA23vBV_rfjGruTi3wlIfBDprITy_yy1TQcMacdYFFkfNqf8aBEYNGjCoz49eXES6TRcypXelVBmOLyhhFgeOqOKmFY8Ym0iMXp50", "/", "security.microsoft.com")))
$session.Cookies.Add((New-Object System.Net.Cookie("ai_session", "RD4lfgBFP1nJP6terAqmgj|1731485369809|173146039530", "/", "security.microsoft.com")))

foreach($IPAddress in [System.IO.File]::ReadLines("C:\Users\thalpius\Downloads\IPAddresses.txt")) {

  $body = @{
    ExclusionType = @("Subnet")
    ExcludedEntityIdentifiers = @($IPAddress) 
  } | ConvertTo-Json

  Invoke-WebRequest -UseBasicParsing -Uri "https://security.microsoft.com/apiproxy/aatp/api/workspace/configuration/exclusion/Global" `
-Method "POST" `
-WebSession $session `
-Headers @{
"authority"="security.microsoft.com"
  "method"="POST"
  "path"="/apiproxy/aatp/api/workspace/configuration/exclusion/Global"
  "scheme"="https"
  "accept"="application/json, text/plain, */*"
  "accept-encoding"="gzip, deflate, br, zstd"
  "accept-language"="en-us"
  "m-componentname"="SettingsPage"
  "m-connection"="4g"
  "m-name"="SettingsPage[aatp]"
  "m-package"="aatp"
  "m-type"="Page"
  "m-viewid"="globalExclude"
  "origin"="https://security.microsoft.com"
  "priority"="u=1, i"
  "referer"="https://security.microsoft.com/securitysettings/identities?tid=df29849b-6a64-481b-97662-8da3fafcb33b&tabid=globalExclude"
  "request-context"="appId=cid-v1:9f356be5-73bf-45f7-9a98-a86fc98ec84f"
  "request-id"="|4a1abe2879fe44ab8cf1c4fa75a70169.5e69152ec0884513"
  "sec-ch-ua"="`"Chromium`";v=`"130`", `"Microsoft Edge`";v=`"130`", `"Not?A_Brand`";v=`"99`""
  "sec-ch-ua-mobile"="?0"
  "sec-ch-ua-platform"="`"Windows`""
  "sec-fetch-dest"="empty"
  "sec-fetch-mode"="cors"
  "sec-fetch-site"="same-origin"
  "tenant-id"="df29849b-6a67-381b-9162-8da3fafcb33b"
  "x-accepted-statuscode"="3..|4..|50."
  "x-clientpage"="securitysettings.identities@aatp"
  "x-clientpkgversion"="20241112.1"
  "x-edge-shopping-flag"="1"
  "x-tabvisible"="visible"
  "x-tid"="df29849b-6a67-481e-9162-8da3fafcb33b"
  "x-xsrf-token"="yPxQoy4EzwoI_1T3KL-ceaL3A37Qwa_YpYipGROreBSXxJBromY2IzOk69YSR59Hy2oVt1T4Uls4_t_Fepgh-7Guk-ED6zV_QfxUEYfmDVgWWUE-972C5J1Gu0v55dwwX-pxTIQkf1QLLmitQ2:F5NtYsmk3iMXBbn8_ejAAgLsf5r45wD8hhR0PiFg41hO4kzw0MBetHwNEUflPOKZy9YNpW2WOC-6Um0-Dex564PLDA23vBV_rfjGruTi3wfBDprITy_yy1TQcMacdYFFkfNqf8aBEYNGjCfoz49eXEFS6TRcypXelVBmOLewe33hFgeOqOKmFY8Ym0iMXp350"
} `
-ContentType "application/json" `
-Body $body

}

Refreshing the portal will allow you to see all the IP addresses added to the “Global Excluded Entities” list.

Image 5: Added IP addresses using PowerShell

Conclusion

There are better ways to perform bulk operations than this method using PowerShell, but it does work. I do not see a lot of companies needing to use a bulk operation for Microsoft Defender for Identity, but when you do, automation is beneficial.

Microsoft Defender for Identity Recommended Actions: Change Domain Controller computer account old password

Microsoft Defender for Identity Recommended Actions: Change Domain Controller computer account old password

Microsoft Secure Score helps organizations get insights into security posture based on security-related measurements. Microsoft Defender for Identity leverages Secure Score with twenty-seven recommended actions. In a series of blog posts, I will go through all twenty-seven recommended actions and what they mean, a plan of approach, their impact, and my security recommendations, hopefully helping others. The sixteenth one in the series is the “Change Domain Controller computer account old password” recommended action.

Introduction

You have twenty-seven recommendations if you filter the Secure Score recommended actions for Microsoft Defender for Identity.

Some recommended actions are easy to configure, but others require time, proper planning, auditing, and expertise. This blog post will review the recommended action of “Change Domain Controller computer account old password.”

Update: Microsoft keeps updating the recommended actions list. I will do my best to keep the list up-to-date.

Computer Objects Password

Most people are aware that user objects in Active Directory have a password. Few people know that computer objects also have a password within Active Directory. Technically, a password is the hash of a password. By default, the device initiates a password change every thirty days. The recommended action talks about Domain Controllers with an old password. Since it is an automated process every thirty days, a Domain Controller with a password older than thirty days is unusual.

Computer Password Risks

Anyone with a password of a computer object can authenticate as that computer. When a malicious actor owns a password for a Domain Controller, the malicious actor can perform many attacks, including a DCSync attack. With a DCSync attack, a malicious actor dumps secrets like hashes of a Domain Controller controlling the entire domain.

The password for the computer object is auto-generated and extremely hard to guess. I do not see a security risk when the password is not changing for forty-five days, but not changing the password at all could introduce a risk in the long run. However, I do not see anyone brute-forcing the correct hash of a computer object in a decent time.

Recommendations

Microsoft describes four recommendation steps.

  1. Verify Registry Values
  2. Reset Incorrect Values
  3. Check NETLOGON service
  4. Validate Password Synchronization

By default, a computer object’s password changes every thirty days. It is weird when Microsoft Defender for Identity identifies Domain Controller objects with a password older than thirty days. When a password is older than thirty days, either there is a policy forcing a password reset longer than thirty days.

Image 1: Domain Policy to change the maximum password age
Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters -Name DisablePasswordChange

Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters -Name MaximumPasswordAge
Image 2: Registry values to disable or change the age of the password

You can turn off the password change using the registry or set the days the password is forced to change. Use the following PowerShell commands to check the values.

Microsoft recommends using the default value 0 for DisablePasswordChange and 30 for MaximumPasswordAge, which is the “Reset Incorrect Values” recommendation.

When you validate the default values, and Microsoft Defender for Identity still identifies old passwords for Domain Controllers, be sure the NETLOGON service is running.

Image 3: Netlogon service running

The last recommendation by Microsoft is to validate the password synchronization by running the command “NLTEST.”

nltest /SC_VERIFY:<Domain Name>

NLTEST is a built-in command tool for resetting and testing a secure channel between Domain Controllers. The “sc_verify” parameter specifically checks the secure channel status established by the NetLogon service.

Note: Be sure to run the NLTEST command as administrator.

Conclusion

When Microsoft Defender for Identity identifies all domain controllers as having old passwords, it is most likely a domain policy that changes the default values. If it identifies a single domain controller with an old password, it is most likely a registry setting on that domain controller, or the NETLOGON service is not running.

Microsoft Defender for Identity Recommended Actions: Accounts with non-default Primary Group ID

Microsoft Defender for Identity Recommended Actions: Accounts with non-default Primary Group ID

Microsoft Secure Score helps organizations get insights into security posture based on security-related measurements. Microsoft Defender for Identity leverages Secure Score with twenty-seven recommended actions. In a series of blog posts, I will go through all twenty-seven recommended actions and what they mean, a plan of approach, their impact, and my security recommendations, hopefully helping others. The fifteenth  one in the series is the “Accounts with non-default Primary Group ID” recommended action.

Introduction

You have twenty-seven recommendations if you filter the Secure Score recommended actions for Microsoft Defender for Identity.

Some recommended actions are easy to configure, but others require time, proper planning, auditing, and expertise. This blog post will review the recommended action of “Accounts with non-default Primary Group ID.”

Update: Microsoft keeps updating the recommended actions list. I will do my best to keep the list up-to-date.

Primary Group ID

As the name suggests, the Primary Group Identifier (PGID) is the primary group of a user object within Active Directory. By default, it is the Relative Identifier (RID) of the Domain Users group. An RID is assigned to objects and is part of the Security Identifier (SID), which identifies an object within Active Directory. The most crucial part is that every user, by default, has the Domain Users as its default group. Every user is then a member of the Domain Users group. Once you create a user within Active Directory, the user is always a member of the Domain Users group.

Here is an example of a user account with the RID of the Domain Users group.

Image 1: The default PGID of a Domain User

513 is the Domain Users Primary Group Identifier. As we can see in Microsoft’s documentation, 512 is the Primary Group Identifier for the Domain Admins group.

The Attack

If you change the Primary Group Identifier from 513 to 512, the object’s default group is the Domain Admins group. However, someone noticed that not all tooling shows that the object is a member of the Domain Admins group after changing its Primary Group Identifier, hiding the object from privileged groups. The malicious actor needs complete control over the object, so this attack is not used for privilege escalation but for persistence and stealth.

Changing the Primary Group Identifier takes work. If you change the PGID using PowerShell, you will see the following error.

Image 2: Changing the PGID using PowerShell resulting in an error

You get an error because validation occurs to check if the PGID matches the group the object is a member of. Another smart cookie discovered that this check does not occur when changing the object as a fake Domain Controller and then syncing the object to the production Domain Controllers. The attack mentioned above is called “DCShadow Attack.”

A DCShadow attack creates a Roque Domain Controller by placing objects in the configuration partition, triggering a synchronization, and removing them from the configuration partition. The best-known tool for performing a DCShadow attack is Mimikatz. After changing the RID of the object in Active Directory to 512, it looks like this.

Image 3: Changed the PGID from 513 to 512

Unfortunately, I did not find any tools that do not show the object’s group membership. I have seen some screenshots online that do not show the group membership, but Active Directory Users and Computers show the group membership after changing the PGID.

Image 4: How the default group looks like in Active Directory Users & Computers

Accounts with non-default Primary Group ID

Microsoft Defender for Identity monitors user and computer objects in Active Directory for non-default group IDs, such as 513 for Domain Users and 515 for Domain Computers. A domain Administrator account default PGID is a Domain User with an added Domain Admin group. There is no need to change the PGID to become a Domain Administrator.

Conclusion

If no POSIX standard, which dates back to the beginning of the 1980s, is used, there is no need to change any object PGID. However, if an object is a user or computer object, change the object PGID to 513 and add the correct groups to mitigate the attack. Luckily, Microsoft Defender for Identity helps us identify objects within Active Directory using this Recommended action.

Microsoft Defender for Identity Recommended Actions: Start your Defender for Identity deployment, installing Sensors on DC’s and other eligible servers

Microsoft Defender for Identity Recommended Actions: Start your Defender for Identity deployment, installing Sensors on DC’s and other eligible servers

Microsoft Secure Score helps organizations get insights into security posture based on security-related measurements. Microsoft Defender for Identity leverages Secure Score with twenty-seven recommended actions. In a series of blog posts, I will go through all twenty-seven recommended actions and what they mean, a plan of approach, their impact, and my security recommendations, hopefully helping others. The fourteenth  one in the series is the “Start your Defender for Identity deployment, installing Sensors on DC’s and other eligible servers” recommended action.

Introduction

You have twenty-seven recommendations if you filter the Secure Score recommended actions for Microsoft Defender for Identity.

Some recommended actions are easy to configure, but others require time, proper planning, auditing, and expertise. This blog post will review the recommended action of “Start your Defender for Identity deployment, installing Sensors on DC’s and other eligible servers.”

Update: Microsoft keeps updating the recommended actions list. I will do my best to keep the list up-to-date.

Installing sensors on Domain Controllers and other eligible servers

In one of my previous blog posts, I mentioned installing Microsoft Defender for Identity on all domain controllers because not all data synchronizes between them. Not installing a sensor on a Domain Controller increases the risk of a successful compromise if a malicious actor attacks that Domain Controller. For that reason, Microsoft recommends installing a sensor on all Domain Controllers. This recommended action looks the same as my previous blog post, but there is a difference. This recommended action is for workspaces with a license but no sensors. With “no sensor,” I mean the Active Directory Domain Services servers (AD DS), Active Directory Federation Services servers (AD FS), Active Directory Certificate Services servers (AD CS), and AD Connect servers, hence “other eligible servers.”

Conclusion

The description is confusing, as there is a recommended action about installing the sensors already. Still, as confirmed by Microsoft, this recommended action describes when no sensors are installed at all. Once again, it is crucial to install sensors on all eligible servers, as it is a security risk not to install a sensor since there are ways to detect whether a server contains a sensor mentioned in my previous blog post.