Weaponizing Group Policy Objects Access
Recently, I was on an engagement where I discovered I had plaintext credentials to an account that could modify Active Directory Group Policy Objects (GPOs). This proved to be a fun challenge, as Group Policy files and properties can be bent to our will even when hacking through a straw (SOCKS only, in this case).
Goal: Use Group Policy to pull down a file from our attack machine to the Domain Controllers. Note: If you need something simpler, like modifying a registry entry, you can use the GPO cmdlets provided by Microsoft.
A few prerequisites:
- Plaintext credentials for a user with modify rights to a GPO (in our case, the Domain Controller's GPO)
- A SOCKS proxy to your victim network
- A Windows attack VM with PowerView cmdlets loaded (you can also use Active Directory cmdlets if port 9389 (ADWS) is open on a target domain controller)
Overview
Note: You do not need Full Control privileges to the GPO — you simply need to modify the object itself. This is how I typically see it in environments I test. In our case, we have plaintext credentials to lab.com\elevated1.
GPOs themselves are stored as files in \\domain.com\SYSVOL\domain\Policies. The folders themselves are represented by GUIDs that are assigned when the policy object is created. An interesting thing is that users and groups that are assigned privileges in Group Policy Management Console (GPMC) also have those privileges carry down to the folders and files.
I know it might be tempting to think that you simply modify the policy files themselves and just let gpupdate take care of the rest. It may work that way in some cases, but in our scenario, we require a Group Policy client-side extension to run, specifically the file extension. There are two types of extensions: client-side extensions (CSEs) and Administrative tool extensions, which plug in to the GPMC tool itself so you can edit the policy. Making matters more complicated, GPO extensions also have unique GUIDs, with the most common being listed out by Microsoft here.
Each GPO is listed in Active Directory as a groupPolicyContainer class object in CN=Policies,CN=System,DC=domain,DC=com.
Each of these objects has attributes detailing information about the GPO itself. The attribute that specifies which CSEs are required by the policy is gPCMachineExtensionNames.
In my case, my Default Domain Controller's GPO has a gPCMachineExtensionNames value of
[{827D319E-6EAC-11D2-A4EA-00C04F79F83A}{803E14A0-B4FB-11D0-A0D0-00A0C90F574B}]
Note the format here: [{GUID1}{GUID2}]. This represents a single GPO extension pair, which is really [{Client-Side Extension}{Admin Tool Extension}]. Not all policies have both extensions applied. Some policies will not have any extensions applied, so you may see NULL values for this attribute. For more information on extension pairs, see this excellent article from Microsoft. Also, not all extensions are listed in the other article I linked to. They are, however, stored in the registry of the DC (and presumably systems that have GPMC installed) under HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\GPExtensions.
Some more useful references on extension pairs and abusing GPOs:
- Andy’s Red Teamer’s Guide To GPO & OU Abuse is absolutely fantastic - https://wald0.com/?p=179
- Great article from Sean Metcalf on Sneaky AD Persistence: https://adsecurity.org/?p=2716
The best way to know which extension pairs are needed for the desired GPO modification is to test and then retrieve the deltas via ADSIEdit or PowerShell. In our case, we wish to use Computer Preferences > Windows Settings > File extension to retrieve a file from our attack system.
From testing, this has corresponding extension pairs of: [{00000000-0000-0000-0000-000000000000}{3BAE7E51-E3F4-41D0-853D-9BB9FD47605F}][{7150F9BF-48AD-4DA4-A49C-29EF4A8369BA}{3BAE7E51-E3F4-41D0-853D-9BB9FD47605F}].
Our goal is to append the desired extension pairs onto any existing pairs listed in gPCMachineExtensionNames.
Important Note: You must carefully document any existing extension pairs as well as the correct new extension pairs, so things are updated properly. If you add an incorrect extension pair to the GPO (e.g., a GUID with a typo), you will break Group Policy updates on the target and there will be cryptic errors in the System log.
Now that we know about extension pairs, what about permission on the object itself? Fortunately, Active Directory has you covered. When you update a GPO via GPMC with new user edit rights, those rights carry to the object and attributes as well. :-)
The Attack
For the SOCKS plumbing, I am using Proxifier on my Windows host. I love Proxifier because it lets me proxy entire applications, such as PowerShell, without having to remember to use something like proxychains. In my case, I am proxying the powershell.exe process through my beacon on SOCKS port 10000.
Side quest: In the screenshot above, if you look carefully, you will see I have proxied Azure Data Studio, which is an awesome GUI for directly interacting with MSSQL on your target network and Azure cloud databases. if you want to proxy out Azure Data Studio, you have to proxy the following binaries:
azuredatastudio.exe; MicrosoftSqlToolsServiceLayer.exe; SqlToolsResourceProviderService.exe; MicrosoftSqlToolsCredentials.exe
Use Test-NetConnection to make sure you can get through your proxy to a target domain controller. If you can, you are good to go. We now have three remaining steps:
- Add the correct files to the GPO folders.
- Increment the version number in GPT.ini
- Update the gPCMachineExtensionNames attribute of our target policy with any necessary extension pairs.
I cannot stress this enough—test in your lab first. If you don’t know what you are doing, you can break Group Policy processing on a truckload of systems. If you don’t have an Active Directory lab, build one.
1. Updating the GPO Folder
To perform our specific attack, we need to replicate the following folder structure in the GPO folder on the Domain Controller.
- GUID Folder
---- MACHINE
-------- Preferences
------------ Files
---------------- Files.xml
If the folders do not exist, create them. I’m showing Windows Explorer in the screenshots for , but through the SOCKS, I’d be using something like Impacket’s smbclient. The File.xml file uses a specific format. Notice the UNC path to my attack machine. I have not researched the first two clsid GUIDs, but from what I have observed, they are the same across installations. The uid GUID appears to be random.
2. Incrementing the Version
In the root GPO GUID folder, there is a file, GPT.ini, that contains a Version property. Simply increment this file so gpupdate will know there is a delta and apply the new settings.
Up to this point, if you stopped here and got things wrong, nothing will break (that I know of). The Group Policy will update just fine but will not do anything with your File.xml because we have not specified the correct extension pairs yet.
3. Update the Extension Pairs
In my case, I used PowerView to update the extension pairs with the correct values. We start first with some reconnaissance and documentation.
In order of the commands listed:
- Specify a domain credential with Get-Credential.
- Use Get-ADObject (PowerView version) to retrieve the GPO objects.
- Filter the objects down to just ones with 'Controller' in the name (e.g., Default Domain Controller Object).
- Note: Copy the existing extension pair values!! You will need these later to revert your changes and if you fubar something.
Now the fun part. I know the correct extension pairs to use, so I am going to use Set-ADObject to update the proper attribute.
Again, in order of the commands listed:
- Specify the target GPO by GUID. That’s the only one we are going to modify.
- Prepend the correct extension pair before the existing extension pairs.
- Use Set-ADObject -Replace to update the gPCMachineExtensionNames attribute with our new values.
- Retrieve the object again and make sure everything looks good. If not, use Set-ADObject to replace with the correct values from the $dcgpomain object.
…. Wait .. patiently….. for ….. gpupdate to run….
If everything goes well, you should see the authentication hit from the DC.
This was just an example of what can be done with GPO modifications. There is no reason you could not copy down a binary then execute it. I will leave that as an exercise to the reader. :-)
Defensive Measures
There are both preventative and detective actions you can take to thwart attacks like these.
On the preventative side, the best policy is to ensure you routinely audit the permissions associated to your GPOs. This can be tedious, especially when factoring in things such as nested groups, but tools like BloodHound can provide visual assistance and help you get a handle on who can do what in your environment.
For detections, you can enable the GPO setting Audit Directory Service Changes in Computer Configuration > Policies > Windows Settings > Security Settings > Advanced Audit Policy Configuration > Audit Policies > DS Access. This will provide you with Event ID 5136 in the Security event log on the Domain Controller when GPO policies are modified, including the
gPCMachineExtensionNames attribute. A good project for the defense might include mapping out the rarely used extension pairs that could result in local code execution of the host running the group policy.
If you have questions or comments, I would love to hear from you. Feel free to reach out on Twitter or find me on the TrustedSec Discord.