Hardening Requirement: Configure User Rights Assignments
Target Scope
- Applicable Systems: Member Servers, Tier 2 Clients (Windows 10/11)
- Operating Systems: Windows Server 2016 (and above), Windows 10/11 Enterprise/Professional
Implementation Details
- Priority: High
- GPO Path / Registry Location:
- GPO Path:
Computer Configuration\Policies\Windows Settings\Security Settings\Local Policies\User Rights Assignment - Registry Location: Stored inside the local Security Database (
seceditunder User Rights Area).
- GPO Path:
Rationale
User Rights Assignments (URAs) govern the specific actions that security principals (users, groups, and service accounts) can perform on a system. Insecure default URA mappings can be abused by attackers to elevate privileges, compromise credentials, or establish persistence:
- LSASS Memory Dumping (
SeDebugPrivilege): The Debug Programs privilege allows a process to attach to and debug any system process. If this privilege is held by a compromised admin account or a local service, tools like Mimikatz can read LSASS memory to extract cleartext passwords and Kerberos keys. It must be restricted strictly to local Administrators. - Token Impersonation (
SeImpersonatePrivilege/SeCreateGlobalPrivilege): The Impersonate Client privilege allows a service or user to run code in the security context of another user. Attackers exploit this privilege (using "Potato" exploits) to coerce local services (like Print Spooler or IIS) into authenticating to them, allowing the attacker to steal the service's SYSTEM token. It must be restricted to Administrators and local service identities. - Backup and Restore Access (
SeBackupPrivilege/SeRestorePrivilege): The Backup/Restore privileges bypass all file-system Access Control Lists (ACLs) to read or write any file. Attackers use these rights to dump the local SAM database, registry hives, or confidential directories. - Network and Local Logon Access (
SeNetworkLogonRight/SeInteractiveLogonRight): Restricting network logon permissions limits lateral movement options for standard domain accounts, containing potential compromises.
Legacy Impact & Compatibility
- Service Account Operations: Certain third-party agents, backup programs, database servers, and monitoring platforms require specific privileges (such as
SeBackupPrivilege,SeImpersonatePrivilege, orSeServiceLogonRight) to function. Standard service accounts must be analyzed and added to the GPO if legitimate operations fail. - Administrative Tooling: Administrative tools that require system debugging or hardware level configuration may require
SeDebugPrivilegeorSeLoadDriverPrivilegewhich remain allocated to the local Administrators group.
Implementation Steps
Option A: Group Policy Object (GPO) Configuration (Preferred)
- Open the Group Policy Management Console (
gpmc.msc) on a management workstation. - Create or edit a GPO targeting endpoints (e.g.,
GPO_Hardening_UserRights_Workstations). - Navigate to:
Computer Configuration\Policies\Windows Settings\Security Settings\Local Policies\User Rights Assignment - Configure the following policies as specified:
| Policy Setting | Allowed Security Principals (SIDs / Groups) |
|---|---|
| Access Credential Manager as a trusted caller | No one (Empty) |
| Access this computer from the network | BUILTIN\Administrators, BUILTIN\Remote Desktop Users |
| Act as part of the operating system | No one (Empty) |
| Allow log on locally | BUILTIN\Administrators, BUILTIN\Users |
| Back up files and directories | BUILTIN\Administrators |
| Create a pagefile | BUILTIN\Administrators |
| Create a token object | No one (Empty) |
| Create global objects | Administrators, LOCAL SERVICE, NETWORK SERVICE, SERVICE |
| Create permanent shared objects | No one (Empty) |
| Debug programs | BUILTIN\Administrators |
| Enable computer and user accounts to be trusted for delegation | No one (Empty) |
| Force shutdown from a remote system | BUILTIN\Administrators |
| Impersonate a client after authentication | Administrators, LOCAL SERVICE, NETWORK SERVICE, SERVICE |
| Load and unload device drivers | BUILTIN\Administrators |
| Lock pages in memory | No one (Empty) |
| Manage auditing and security log | BUILTIN\Administrators |
| Modify firmware environment values | BUILTIN\Administrators |
| Perform volume maintenance tasks | BUILTIN\Administrators |
| Profile single process | BUILTIN\Administrators |
| Restore files and directories | BUILTIN\Administrators |
| Take ownership of files or other objects | BUILTIN\Administrators |
- Link the GPO to the appropriate Organizational Unit (OU).
Option B: PowerShell & Registry Configuration (Remediation / Non-GPO)
Configure User Rights Assignments locally using secedit.exe and PowerShell.
Download Script: Set-UserRightsAssignments.ps1
# Set-UserRightsAssignments.ps1
# Description: Enforces the local user rights assignments baseline configuration using secedit templates.
Write-Host "Applying User Rights Assignments hardening..." -ForegroundColor Cyan
# 1. Create a secure temporary path for security templates
$SecTempDir = Join-Path $env:TEMP "SecurityTemplates"
if (-not (Test-Path $SecTempDir)) {
New-Item -Path $SecTempDir -ItemType Directory -Force | Out-Null
}
$CfgFile = Join-Path $SecTempDir "user_rights.cfg"
$LogFile = Join-Path $SecTempDir "secedit.log"
$DbFile = Join-Path $SecTempDir "secedit.sdb"
# 2. Export current security configuration
Write-Host "[*] Exporting current security configuration..." -ForegroundColor Gray
$Process = Start-Process secedit -ArgumentList "/export /cfg `"$CfgFile`"" -Wait -NoNewWindow -PassThru
if ($Process.ExitCode -ne 0) {
Write-Error "Failed to export current security database settings."
return
}
# 3. Read and modify the configuration file
$ConfigText = Get-Content -Path $CfgFile -Raw
$HasPrivilegeSection = $ConfigText -match "\[Privilege Rights\]"
if (-not $HasPrivilegeSection) {
$ConfigText += "`r`n[Privilege Rights]`r`n"
}
# Define the baseline User Rights Assignments
$BaselineRights = @{
"SeTrustedCredManAccessPrivilege" = ""
"SeNetworkLogonRight" = "*S-1-5-32-544,*S-1-5-32-555"
"SeTcbPrivilege" = ""
"SeInteractiveLogonRight" = "*S-1-5-32-544,*S-1-5-32-545"
"SeBackupPrivilege" = "*S-1-5-32-544"
"SeCreatePagefilePrivilege" = "*S-1-5-32-544"
"SeCreateTokenPrivilege" = ""
"SeCreateGlobalPrivilege" = "*S-1-5-19,*S-1-5-20,*S-1-5-32-544,*S-1-5-6"
"SeCreatePermanentPrivilege" = ""
"SeDebugPrivilege" = "*S-1-5-32-544"
"SeEnableDelegationPrivilege" = ""
"SeRemoteShutdownPrivilege" = "*S-1-5-32-544"
"SeImpersonatePrivilege" = "*S-1-5-19,*S-1-5-20,*S-1-5-32-544,*S-1-5-6"
"SeLoadDriverPrivilege" = "*S-1-5-32-544"
"SeLockMemoryPrivilege" = ""
"SeSecurityPrivilege" = "*S-1-5-32-544"
"SeSystemEnvironmentPrivilege" = "*S-1-5-32-544"
"SeManageVolumePrivilege" = "*S-1-5-32-544"
"SeProfileSingleProcessPrivilege" = "*S-1-5-32-544"
"SeRestorePrivilege" = "*S-1-5-32-544"
"SeTakeOwnershipPrivilege" = "*S-1-5-32-544"
}
# Re-build [Privilege Rights] section line-by-line
$Lines = $ConfigText -split "`r?`n"
$NewLines = @()
$InPrivilegeSection = $false
foreach ($Line in $Lines) {
if ($Line -match "^\[(.*)\]$") {
$SectionName = $Matches[1]
if ($SectionName -eq "Privilege Rights") {
$InPrivilegeSection = $true
$NewLines += $Line
continue
} else {
$InPrivilegeSection = $false
}
}
if ($InPrivilegeSection) {
# Skip line if it contains a URA we manage
$IsManaged = $false
foreach ($Key in $BaselineRights.Keys) {
if ($Line -match "^\s*$($Key)\s*=") {
$IsManaged = $true
break
}
}
if (-not $IsManaged) {
$NewLines += $Line
}
} else {
$NewLines += $Line
}
}
# Append our managed settings into the Privilege section
$FinalLines = @()
foreach ($Line in $NewLines) {
$FinalLines += $Line
if ($Line -eq "[Privilege Rights]") {
foreach ($Key in $BaselineRights.Keys) {
$Val = $BaselineRights[$Key]
$FinalLines += "$($Key) = $($Val)"
}
}
}
$FinalLines -join "`r`n" | Out-File -FilePath $CfgFile -Encoding ascii -Force
# 4. Import the modified configuration file
Write-Host "[*] Importing updated security configuration template..." -ForegroundColor Gray
$Process = Start-Process secedit -ArgumentList "/configure /db `"$DbFile`" /cfg `"$CfgFile`" /areas USER_RIGHTS /log `"$LogFile`"" -Wait -NoNewWindow -PassThru
if ($Process.ExitCode -eq 0) {
Write-Host "[+] User Rights Assignments applied successfully." -ForegroundColor Green
} else {
Write-Error "Failed to apply user rights assignments. Exit Code: $($Process.ExitCode)"
}
# Clean up temp files
Remove-Item -Path $SecTempDir -Recurse -Force -ErrorAction SilentlyContinue
To audit local User Rights Assignments: Download Script: Test-UserRightsAssignments.ps1
# Test-UserRightsAssignments.ps1
# Description: Exports local user rights assignments and checks them against the baseline.
Write-Host "--- Auditing User Rights Assignments ---" -ForegroundColor Cyan
$SecTempDir = Join-Path $env:TEMP "AuditSecurityTemplates"
if (-not (Test-Path $SecTempDir)) {
New-Item -Path $SecTempDir -ItemType Directory -Force | Out-Null
}
$CfgFile = Join-Path $SecTempDir "user_rights_audit.cfg"
$Process = Start-Process secedit -ArgumentList "/export /cfg `"$CfgFile`"" -Wait -NoNewWindow -PassThru
if ($Process.ExitCode -ne 0) {
Write-Error "Failed to export current configuration database."
return
}
$ConfigContent = Get-Content -Path $CfgFile -Raw
$BaselineRights = @{
"SeTrustedCredManAccessPrivilege" = ""
"SeNetworkLogonRight" = "*S-1-5-32-544,*S-1-5-32-555"
"SeTcbPrivilege" = ""
"SeInteractiveLogonRight" = "*S-1-5-32-544,*S-1-5-32-545"
"SeBackupPrivilege" = "*S-1-5-32-544"
"SeCreatePagefilePrivilege" = "*S-1-5-32-544"
"SeCreateTokenPrivilege" = ""
"SeCreateGlobalPrivilege" = "*S-1-5-19,*S-1-5-20,*S-1-5-32-544,*S-1-5-6"
"SeCreatePermanentPrivilege" = ""
"SeDebugPrivilege" = "*S-1-5-32-544"
"SeEnableDelegationPrivilege" = ""
"SeRemoteShutdownPrivilege" = "*S-1-5-32-544"
"SeImpersonatePrivilege" = "*S-1-5-19,*S-1-5-20,*S-1-5-32-544,*S-1-5-6"
"SeLoadDriverPrivilege" = "*S-1-5-32-544"
"SeLockMemoryPrivilege" = ""
"SeSecurityPrivilege" = "*S-1-5-32-544"
"SeSystemEnvironmentPrivilege" = "*S-1-5-32-544"
"SeManageVolumePrivilege" = "*S-1-5-32-544"
"SeProfileSingleProcessPrivilege" = "*S-1-5-32-544"
"SeRestorePrivilege" = "*S-1-5-32-544"
"SeTakeOwnershipPrivilege" = "*S-1-5-32-544"
}
foreach ($Key in $BaselineRights.Keys) {
$Expected = $BaselineRights[$Key]
# Parse the exported config text to extract the privilege row
if ($ConfigContent -match "(?m)^\s*$($Key)\s*=\s*(.*)\s*$") {
$Actual = $Matches[1].Trim()
} else {
$Actual = ""
}
# Compare
$Color = "Red"
if ($Actual -eq $Expected) {
$Color = "Green"
}
Write-Host " - Privilege: $($Key) | Actual: '$($Actual)' (Expected: '$($Expected)')" -ForegroundColor $Color
}
Remove-Item -Path $SecTempDir -Recurse -Force -ErrorAction SilentlyContinue
Sources & Compliance References
- CIS Microsoft Windows 10/11 Benchmark: Section 2.2 (User Rights Assignment)
- ANSSI AD Hardening Guide: Recommendations on restricting privileged capabilities and limiting local privileges on administrative workstations