IN_LOCALGROUP
Summary
FSProtect ACL Alias
IN_LOCALGROUP
Affected Object Types
Users, Groups
Exploitation Certainty
Unlikely
Description
IN_LOCALGROUP
permission in an Active Directory environment grants an account membership in one of the local groups on a specific system. By obtaining this membership, a user gains the rights and privileges associated with that local group, ranging from the ability to read certain files or registry keys to elevated permissions that might allow software installations or configuration changes. This capability is especially valuable for environments where delegated administration is required on a per-machine basis, ensuring that support teams or application owners can manage system-level tasks without receiving full domain-wide privileges.
However, if misconfigured, the IN_LOCALGROUP
permission can introduce serious security vulnerabilities. An attacker who obtains membership in a privileged local group could leverage that foothold to bypass security controls, read or modify sensitive system settings, and potentially escalate privileges. This could allow the attacker to install malicious software, manipulate scheduled tasks, or even tamper with system services—actions that might lead to persistent unauthorized access or lateral movement within the network. Ultimately, improperly managed IN_LOCALGROUP
membership can compromise the overall security posture of the organization, jeopardizing critical systems and sensitive data.
Identification
PowerShell
Active Directory Module
Using the ActiveDirectory PowerShell module, you can enumerate IN_LOCALGROUP
entries.
1. Find-IN_LOCALGROUP function
function Find-IN_LOCALGROUP {
[CmdletBinding()]
param([string]$SearchBase,[string[]]$ComputerName,[string]$OutputPath = "LocalGroupMembers.csv",[System.Management.Automation.PSCredential]$Credential)
Import-Module ActiveDirectory -ErrorAction Stop
if (-not $ComputerName) {
$adFilter = 'Enabled -eq $true'
$ComputerName = if ($SearchBase) {Get-ADComputer -Filter $adFilter -SearchBase $SearchBase -Properties Name |Select-Object -ExpandProperty Name} else {Get-ADComputer -Filter $adFilter -Properties Name |Select-Object -ExpandProperty Name}}
$scriptBlock = {
param($comp)
$groups = Get-LocalGroup -ErrorAction SilentlyContinue
foreach ($group in $groups) {
$members = Get-LocalGroupMember -Group $group.Name -ErrorAction SilentlyContinue
foreach ($member in $members) {
$isDomain = $false
if ($member.PSObject.Properties['PrincipalSource']) {$isDomain = ($member.PrincipalSource -eq 'ActiveDirectory')} else {$cn = $env:COMPUTERNAME;$isDomain = $member.Name -notmatch "^(NT AUTHORITY|BUILTIN|$([regex]::Escape($cn)))\\"}
if ($isDomain) {
[PSCustomObject]@{
ComputerName = $comp
GroupName = $group.Name
MemberName = $member.Name
MemberType = $member.ObjectClass
}}}}}
$icmParams = @{
ScriptBlock = $scriptBlock
ErrorAction = 'Stop'}
if ($Credential) { $icmParams.Credential = $Credential }
$results = foreach ($c in $ComputerName) {try {Invoke-Command -ComputerName $c @icmParams -ArgumentList $c} catch {Write-Host "Unable to connect to $c" -ForegroundColor Red}}
$results | Where-Object { $_ } | Select-Object ComputerName, GroupName, MemberName, MemberType | Export-Csv -Path $OutputPath -NoTypeInformation}
2. Scan all domain computers
Find-IN_LOCALGROUP
3. Scan a specific computer
Find-IN_LOCALGROUP -ComputerName vm01
.NET Directory Services
By leveraging PowerShell’s built-in .NET DirectoryServices namespace, you can enumerate IN_LOCALGROUP
entries without relying on any external modules or dependencies.
1. Find-IN_LOCALGROUPSimple function
function Find-IN_LOCALGROUPSimple {
[CmdletBinding()]
param([string[]]$ComputerName,[string]$OutputPath = "LocalGroupMembers.csv")
$getComputers = {
if ($args[0]) {
try {
$entry = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$($args[0])")
} catch { Write-Error "Failed to bind to '$($args[0])': $_"; return @() }
$objClass = ($entry.Properties["objectClass"] | Select-Object -Last 1)
if ($objClass -and $objClass -match '^computer$') {
$name = $entry.Properties["name"][0];return @($name)
} else {
try {
$searcher = [System.DirectoryServices.DirectorySearcher]::new($entry);$searcher.Filter = "(&(objectCategory=computer)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"
$searcher.PageSize = 1000;[void]$searcher.PropertiesToLoad.Add("name")
($searcher.FindAll() | ForEach-Object { $_.Properties["name"][0] }) | Where-Object { $_ }} catch { Write-Error "LDAP search failed: $_"; @() }}} else {
try {
$root = New-Object System.DirectoryServices.DirectoryEntry("LDAP://RootDSE");$baseDN = $root.Properties["defaultNamingContext"].Value
$base = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$baseDN");$search = [System.DirectoryServices.DirectorySearcher]::new($base)
$search.Filter = "(&(objectCategory=computer)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))";$search.PageSize = 1000
[void]$search.PropertiesToLoad.Add("name");($search.FindAll() | ForEach-Object { $_.Properties["name"][0] }) | Where-Object { $_ }
} catch { Write-Error "Failed to enumerate computers via LDAP: $_"; @() }}}
if (-not $ComputerName -or $ComputerName.Count -eq 0) {$ComputerName = & $getComputers $null}
$scriptBlock = {
param($comp)
$emit = {
param($c,$g,$mName,$mType)
[PSCustomObject]@{
ComputerName = $c
GroupName = $g
MemberName = $mName
MemberType = $mType
}
}
$haveLocalAccounts = (Get-Command Get-LocalGroup -ErrorAction SilentlyContinue) -and (Get-Command Get-LocalGroupMember -ErrorAction SilentlyContinue)
if ($haveLocalAccounts) {
$groups = Get-LocalGroup -ErrorAction SilentlyContinue
foreach ($group in $groups) {
$members = Get-LocalGroupMember -Group $group.Name -ErrorAction SilentlyContinue
foreach ($member in $members) {
$isDomain = $false
if ($member.PSObject.Properties['PrincipalSource']) {$isDomain = ($member.PrincipalSource -eq 'ActiveDirectory')} else {
$cn = $env:COMPUTERNAME;$isDomain = $member.Name -notmatch "^(NT AUTHORITY|BUILTIN|$([regex]::Escape($cn)))\\"}
if ($isDomain) {
& $emit $comp $group.Name $member.Name $member.ObjectClass}}}} else {
try {
$machine = [ADSI]"WinNT://$env:COMPUTERNAME"
$machine.Children | Where-Object { $_.SchemaClassName -eq 'Group' } | ForEach-Object {
$g = $_
try {
($g.psbase.Invoke('Members') | ForEach-Object {
$_.GetType().InvokeMember('Name','GetProperty',$null,$_,$null)
}) | ForEach-Object {
$name = $_
$cn = $env:COMPUTERNAME
$isLocal = $name -match "^(Administrators|Users|Guests|Remote Desktop Users|$([regex]::Escape($cn))\\)"
if (-not $isLocal) {
& $emit $comp $g.Name $name 'User'}}} catch {}}} catch {}}}
$icmParams = @{
ScriptBlock = $scriptBlock
ErrorAction = 'Stop'}
$results = foreach ($c in $ComputerName) {if (-not $c) { continue }
try {Invoke-Command -ComputerName $c @icmParams -ArgumentList $c} catch {Write-Host "Unable to connect to $c" -ForegroundColor Red}}
$results | Where-Object { $_ } | Select-Object ComputerName, GroupName, MemberName, MemberType | Export-Csv -Path $OutputPath -NoTypeInformation}
2. Scan all domain computers
Find-IN_LOCALGROUPSimple
3. Scan a specific computer
Find-IN_LOCALGROUPSimple -ComputerName vm01
Active Directory Users and Computers
To identify IN_LOCALGROUP
using Computer Management
, follow the steps below
1. Open Active Directory Users and Computers
.
2. Right-click on the Computer.
3. Select Manage
from the context menu.
4. In the Computer Management window, navigate to the Local Users And Groups
section.
5. In the Local Users And Groups
, double-click the local group to open it.
6. In the Members list, locate Users and Groups.
7. Click OK to close the dialogs.

Exploitation
Membership in a local group does not necessarily imply an exploitable path.
Mitigation
You can mitigate IN_LOCALGROUP
with the following steps:
1. Open Active Directory Users and Computers
.
2. Right-click on the Computer.
3. Select Manage
from the context menu.
4. In the Computer Management window, navigate to the Local Users And Groups
section.
5. In the Local Users And Groups
, double-click the local group to open it.
6. In the Members list, select the unwanted user or group, then click Remove
.
7. Click OK to close the dialogs.

Detection
Adding new Access Control Entries to Active Directory objects changes the ntSecurityDescriptor
attribute of the objects themselves. These changes can be detected with Event IDs 5136 and 4662 to identify dangerous modifications.
5136
A directory service object was modified.
ntSecurityDescriptor
https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-5136
4662
An operation was performed on an object.
AccessList, AccessMask
https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4662
References
Last updated
Was this helpful?