From c0fc8c3d31aa6385e05bd8b186d11ebcba62ad06 Mon Sep 17 00:00:00 2001 From: Praneeth Date: Mon, 15 Dec 2025 09:00:27 +0530 Subject: [PATCH 1/3] rewrote the assessment logic as per new spec --- src/powershell/tests/Test-Assessment.21955.md | 5 +- .../tests/Test-Assessment.21955.ps1 | 88 ++++++++++++++++--- 2 files changed, 77 insertions(+), 16 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.21955.md b/src/powershell/tests/Test-Assessment.21955.md index 09ba1be618..0038c5949c 100644 --- a/src/powershell/tests/Test-Assessment.21955.md +++ b/src/powershell/tests/Test-Assessment.21955.md @@ -1,8 +1,7 @@ -When local administrators on Microsoft Entra joined devices aren't properly managed, threat actors with compromised credentials can execute device takeover attacks by removing organizational administrators and disabling the device's connection to Microsoft Entra. This lack of control results in complete loss of organizational control, creating orphaned assets that can't be managed or recovered. +When local administrators on Microsoft Entra joined devices are not managed by the organization, threat actors who could compromise user accounts can execute device takeover attacks that result in permanent loss of organizational control. Threat actors can leverage compromised account credentials to perform account manipulation by removing all organizational administrators from the device’s local administrators, including the global administrators who normally retain management access. Once threat actors do that, they can modify user account control settings and disable the device's connection to Microsoft Entra, effectively severing the cloud management channel. This attack progression results in a complete device takeover where organizational global administrators lose all administrative pathways to regain control. The device becomes an orphaned asset that cannot be managed any more. **Remediation action** -- [Manage the local administrators on Microsoft Entra joined devices](https://learn.microsoft.com/entra/identity/devices/assign-local-admin?wt.mc_id=zerotrustrecommendations_automation_content_cnl_csasci#manage-the-microsoft-entra-joined-device-local-administrator-role) +- [Manage the local administrators on Microsoft Entra joined devices](https://learn.microsoft.com/en-us/entra/identity/devices/assign-local-admin) %TestResult% - diff --git a/src/powershell/tests/Test-Assessment.21955.ps1 b/src/powershell/tests/Test-Assessment.21955.ps1 index 8959118213..5dbe8a3556 100644 --- a/src/powershell/tests/Test-Assessment.21955.ps1 +++ b/src/powershell/tests/Test-Assessment.21955.ps1 @@ -21,31 +21,93 @@ function Test-Assessment-21955 { Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose + #region Data Collection $activity = 'Checking Manage the local administrators on Microsoft Entra joined devices' - Write-ZtProgress -Activity $activity -Status 'Getting policy' - # Query device registration policy - $policy = Invoke-ZtGraphRequest -RelativeUri 'policies/deviceRegistrationPolicy' -ApiVersion beta + # Query role assignments from database + Write-ZtProgress -Activity $activity -Status 'Getting role assignments' + $deviceLocalAdminRoleId = '9f06204d-73c1-4d4c-880a-6edb90606fd8' - $enableGlobalAdmins = ${policy}?.azureADJoin?.localAdmins?.enableGlobalAdmins + # Query database for assigned and eligible users/groups for this role + $sql = "SELECT principalDisplayName, userPrincipalName, `"@odata.type`", principalId, privilegeType + FROM zt.main.vwRole + WHERE roleDefinitionId = '$deviceLocalAdminRoleId';" - $portalLink = 'https://entra.microsoft.com/#view/Microsoft_AAD_Devices/DevicesMenuBlade/~/DeviceSettings/menuId/Overview' + $roleAssignments = Invoke-DatabaseQuery -Database $Database -Sql $sql + + Write-PSFMessage "Found $($roleAssignments.Count) role assignments for Azure AD Joined Device Local Administrator" -Level Verbose + + # Separate assigned vs eligible + $assignedMembers = $roleAssignments | Where-Object { $_.privilegeType -eq 'Permanent' } + $eligibleMembers = $roleAssignments | Where-Object { $_.privilegeType -eq 'Eligible' } + #endregion Data Collection - $portalLinkMd = "[Global administrator role is added as local administrator on the device during Microsoft Entra join?]($portalLink)`n`n" + #region Assessment Logic - if ($enableGlobalAdmins) { + if ($roleAssignments.Count -gt 0) { $passed = $true - $testResultMarkdown = "Local administrators on Microsoft Entra joined devices are managed by the organization.`n`n" - $testResultMarkdown += $portalLinkMd - $testResultMarkdown += "- **Yes** → ✅" + $testResultMarkdown = "Local administrators on Microsoft Entra joined devices are managed by the organization.`n`n%TestResult%" } else { $passed = $false - $testResultMarkdown = "Local administrators on Microsoft Entra joined devices are not managed by the organization.`n`n" - $testResultMarkdown += $portalLinkMd - $testResultMarkdown += "- **No** → ❌" + $testResultMarkdown = "Local administrators on Microsoft Entra joined devices are not managed by the organization.`n`n%TestResult%" + } + + $portalLink = 'https://entra.microsoft.com/#view/Microsoft_AAD_Devices/DevicesMenuBlade/~/DeviceSettings/menuId/Overview' + $portalLinkMd = "[Device Settings - Global administrator role is added as local administrator]($portalLink)`n`n" + #endregion Assessment Logic + + #region Report Generation + + # Build detailed markdown + $mdInfo = '' + + if ($assignedMembers.Count -gt 0) { + $mdInfo += "`n## Active Microsoft Entra Joined Device Local Administrator assignments`n`n" + $mdInfo += "| Display Name | UPN | Type | Assignment Type |`n" + $mdInfo += "| :----------- | :--- | :-- | :-------------- |`n" + + foreach ($member in ($assignedMembers | Sort-Object -Property principalDisplayName)) { + $objectType = if ($member.'@odata.type' -eq '#microsoft.graph.user') { 'User' } else { 'Group' } + $upn = if ($member.userPrincipalName) { $member.userPrincipalName } else { '-' } + + $portalLink = if ($member.'@odata.type' -eq '#microsoft.graph.user') { + "https://entra.microsoft.com/#view/Microsoft_AAD_UsersAndTenants/UserProfileMenuBlade/~/overview/userId/$($member.principalId)" + } else { + "https://entra.microsoft.com/#view/Microsoft_AAD_IAM/GroupDetailsMenuBlade/~/Overview/groupId/$($member.principalId)" + } + + $mdInfo += "| [$(Get-SafeMarkdown($member.principalDisplayName))]($portalLink) | $upn | $objectType | $($member.privilegeType) |`n" + } + } + + if ($eligibleMembers.Count -gt 0) { + $mdInfo += "`n## Eligible Microsoft Entra Joined Device Local Administrator assignments`n`n" + $mdInfo += "| Display Name | UPN | Type | Assignment Type |`n" + $mdInfo += "| :----------- | :--- | :-- | :-------------- |`n" + + foreach ($member in ($eligibleMembers | Sort-Object -Property principalDisplayName)) { + $objectType = if ($member.'@odata.type' -eq '#microsoft.graph.user') { 'User' } else { 'Group' } + $upn = if ($member.userPrincipalName) { $member.userPrincipalName } else { '-' } + + $portalLink = if ($member.'@odata.type' -eq '#microsoft.graph.user') { + "https://entra.microsoft.com/#view/Microsoft_AAD_UsersAndTenants/UserProfileMenuBlade/~/overview/userId/$($member.principalId)" + } else { + "https://entra.microsoft.com/#view/Microsoft_AAD_IAM/GroupDetailsMenuBlade/~/Overview/groupId/$($member.principalId)" + } + + $mdInfo += "| [$(Get-SafeMarkdown($member.principalDisplayName))]($portalLink) | $upn | $objectType | $($member.privilegeType) |`n" + } } + if ($roleAssignments.Count -eq 0) { + $mdInfo = "`n❌ No assigned or eligible users/groups found for the Microsoft Entra Joined Device Local Administrator role.`n" + } + + # Replace placeholder with detailed information + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo + #endregion Report Generation + $params = @{ TestId = '21955' Status = $passed From a70ed6d76223ed3d695d4779db2f01a9e99ae198 Mon Sep 17 00:00:00 2001 From: Praneeth Date: Mon, 15 Dec 2025 09:04:55 +0530 Subject: [PATCH 2/3] added missing db param --- src/powershell/tests/Test-Assessment.21955.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/powershell/tests/Test-Assessment.21955.ps1 b/src/powershell/tests/Test-Assessment.21955.ps1 index 5dbe8a3556..dcdd33344b 100644 --- a/src/powershell/tests/Test-Assessment.21955.ps1 +++ b/src/powershell/tests/Test-Assessment.21955.ps1 @@ -17,7 +17,9 @@ function Test-Assessment-21955 { UserImpact = 'Low' )] [CmdletBinding()] - param() + param( + $Database + ) Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose From c1aa4103feaa19dd9cd3027ce1fc4ccaf7435af3 Mon Sep 17 00:00:00 2001 From: Praneeth Date: Thu, 18 Dec 2025 09:19:06 +0530 Subject: [PATCH 3/3] removed old portal link --- src/powershell/tests/Test-Assessment.21955.ps1 | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.21955.ps1 b/src/powershell/tests/Test-Assessment.21955.ps1 index dcdd33344b..32aafe7116 100644 --- a/src/powershell/tests/Test-Assessment.21955.ps1 +++ b/src/powershell/tests/Test-Assessment.21955.ps1 @@ -54,9 +54,6 @@ function Test-Assessment-21955 { $passed = $false $testResultMarkdown = "Local administrators on Microsoft Entra joined devices are not managed by the organization.`n`n%TestResult%" } - - $portalLink = 'https://entra.microsoft.com/#view/Microsoft_AAD_Devices/DevicesMenuBlade/~/DeviceSettings/menuId/Overview' - $portalLinkMd = "[Device Settings - Global administrator role is added as local administrator]($portalLink)`n`n" #endregion Assessment Logic #region Report Generation