Select Page

One of the advantages of messing around with Group Policy since before it shipped, is that there is a lot of stuff rattling around in my head that I’ve been re-thinking in the context of today’s modern threat landscape.  This allows me to think about current day problems in the context of how it “used to be”. For example, how many of you remember that, long before GP Preferences was acquired by Microsoft, they used to refer to any Administrative Template settings that did not set values in the 4 magic registry keys, as…wait for it…preferences. That’s right, there were “preferences” long before there were Preferences. One of those things that I wrote about a longggg time ago, was the registry policy “archive file”, and it’s role in allowing Group Policy to not “tattoo” the registry (i.e. leave the value stuck in the registry) when an Admin Template setting was removed. Essentially, when you set a policy in a GPO from “Enabled” to “Not Configured”, any systems that had previously received/processed that Enabled policy/underlying registry value, would get that value removed automagically on the next policy processing cycle. This was a big deal at the time, because the predecessor to Group Policy in NT 4, called “system policy”, could not claim such a capability, and it was a big pain in the ass, to put it nicely.

So, along comes Group Policy with it’s nifty capability to remove registry policy when it no longer applies (note that this feature applies to any policy area that implements its settings in registry.pol (for the most part)) and we all rejoiced. So let’s review how this magic actually works.

The Four Magic Keys

Remember that for the non-tattooing behavior to work, a policy setting must store it’s value in one of the 4 magic registry keys (2 are per computer and 2 are per user) as shown here:



You’ll notice an interesting thing about these 4 keys. The permissions on them are such that only privileged users (in this case, members of the local Administrators group and LocalSystem–the machine account) can write to them. Everyone else has read access only. This allows GP to enforce settings on users, in particular, that regular users cannot muck with. So, even though the rest of the HKEY_CURRENT_USER hive is writable by the user who owns that user profile, they cannot make changes to the 2 per-user policy keys (normally).

The Archive File

The job of the registry archive file is simple. When GP is processed (e.g. you type gpupdate from the command line, or a user logs into a workstation) the GP engine consults the archive file to determine what registry settings have been delivered to the computer or user. It first removes the registry values found in the archive file, and then, after a few milliseconds, any settings are re-applied from the currently applicable GPOs. So, for example, let’s say I have the following registry entries delivered to the user’s HKCU hive:


When policy next runs, it will actually remove these 5 values from the registry, based on what it found in the archive file. Then, it will figure out what GPOs *now* apply to the user, and apply the correct registry values to their respective keys, and those new keys would be written to the archive file.

If, for example, the GPO containing the DisableTaskMgr value from the list above, was unlinked from the user’s OU, that value would be removed via the archive file and then of course, not re-applied because the GPO containing that value is no longer in scope. In this way, GP supports the concept of non-tattooing registry policy. Simple and elegant! You can actually see this behavior in action if you enable GPSVC logging on a given system, as shown here:

Viewing the non-tattooing behavior of registry policy in gpsvc.log

Viewing the non-tattooing behavior of registry policy in gpsvc.log



As you can see from this screenshot, the values are first deleted (DeleteRegistryValue call), then the applied GPO’s registry.pol file is read (in this case there’s only one GPO applying to the user) and the SetRegistryValue commands apply the current policy to the user’s profile.

So where is this magic archive file? Well, it so happens that there is one of each of these files for the computer and user. The file itself is called ntuser.pol and if you look at it’s file attributes, it is set with both System and Hidden attributes. On the computer side, the file is stored in %systemdrive%\ProgramData. On the user side, the file is stored in the user’s profile root (e.g. c:\users\darren). Not surprisingly, the per-computer file is meant for per-computer (i.e. HKLM hive in the registry) registry values only, and is writable only by members of the local Administrators group or the LocalSystem (machine account) user. On the user side however, the registry archive file is also writable by the user themselves. This presents us with some interesting opportunities, as you’ll see below. But beyond these facts, it’s important to note that the ntuser.pol file uses the same policy file format that is used by registry.pol files found in SYSVOL within GPOs. This format is documented by Microsoft.

There’s one other interesting point about the archive file and how it works. Only registry values that are applied via a GPO, will make their way into the registry archive file–ntuser.pol. This means that if you deliver a registry value to one of the 4 magic policy keys by some means outside of a GPO (e.g. via script or other configuration mechanism), that value will not find it’s way into the archive file and therefore will not get “cleaned up” during each policy refresh. What this means is that settings delivered that way essentially tattoo the system in a way that GP does not. Finally, remember my discussion of “old-style” preferences (i.e. settings that don’t write to one of the 4 policy keys)–these settings will get written to ntuser.pol, but they will NOT be removed during a refresh cycle. They also essentially tattoo the registry, which is interesting.

Abusing the Archive File

There are two main avenues to abuse of this registry archive file. Both are a bit insidious in their own way. Let’s look at each:

The first avenue takes advantage of the fact that the per-user ntuser.pol file in the user’s profile is writable by a non-privileged user (the user will need to first remove the system and hidden attributes on the file, using the attrib command). The path of interest here is in using the ntuser.pol file to remove registry entries from the 2 per-user policy keys that would otherwise not be writeable by a non-privileged user. It’s a sort of privilege escalation, after a fashion, in that a non-privileged user can piggyback on the normal operation of the per-user ntuser.pol file to remove any registry entries in the 2 per-user policy keys that were not placed there via GP. For example, let’s say an administrator had distributed policy to every user to control the behavior of device drivers that are not digitally signed. This policy can be set under HKCU\Policies\Microsoft\Windows NT\Driver Signing\BehaviorOnFailedVerify. If this policy were distributed via GPO, then it would already be in the registry archive file and would get replaced at each policy refresh. But if it were implemented out of Group Policy (e.g. using a logon script or similar) then adding it to the per-user ntuser.pol file would have the affect of removing it from the user’s HKCU hive when policy next processed (remember that all the entries found in the ntuser.pol are first removed before new policy is applied, and in this case, no new policy will be applied.) You can write entries into ntuser.pol just like you can write them into registry.pol. I recently created and shared a utility called SetPol that allows you to do just that–write entries into any .pol file (registry.pol or ntuser.pol). So in this example, if a regular, non privileged user, ran setpol and added this registry value to the per-user ntuser.pol, as shown here:

setpol.exe "c:\users\tomj\ntuser.pol" "Software\Policies\Microsoft\Windows NT\Driver Signing" "REG_DWORD" "BehaviorOnFailedVerify" 1

This would have the affect of adding this entry to ntuser.pol, and the next time GP processing ran, it would be removed from that registry location, since it’s in the archive file, but obviously not added back, since it was not distributed via GP in the first place. In this example, I’ve essentially issued a command as a non-privileged user, that has removed a registry entry out of a privileged location in the registry.

The second avenue is interesting in a different way. A while ago I wrote a utility, which is very popular on the site, called Registry Policy Viewer. This utility, shown in the screenshot here:

Registry Policy Viewer Utility

Registry Policy Viewer Utility












presents the contents of any .pol file. One side effect of this utility, is that it creates an open file handle on the pol file that’s under scrutiny. This means that the pol file, while open, cannot be deleted or moved by another process on the box—say, GP Processing itself. As a normal user, if I fire up this tool and open up ntuser.pol for either the computer (c:\programdata) or user (within the user’s profile), it has the effect of breaking policy processing in an interesting way. Namely, the archive file is read and registry entries are removed for the user or computer, but then the new archive file can’t be re-built, and as such, policy application of the new policy settings can’t proceed. You can see this in effect in the GPSvc.log file here:

A fiailed, open archive file

A fiailed, open archive file




The result of this failure is that the new registry values are not re-written to the machine. In effect, a non-privileged user, simply opening the archive file for read, has prevented the registry Group Policy from processing on either the computer or user side (depending upon which archive file they open). This means that the machine is essentially un-protected during this time, without the user having any privileged access to do so.


Unfortunately, because of the nature of these two abuse patterns, there is not a lot you can do to prevent them. These files have to be readable and writable by the user for policy processing to work. Or at least, they *probably* do. Ever since Microsoft released MS16-072, the security context in which GP processing runs has changed, at least for the user. Per-user policy used to run in the user’s security context, but that was changed to run in the machine security context, impersonating the user only when needed to write settings to the appropriate per-user locations. So it’s entirely possible that user accounts do not need read or write access to the archive files for GP Processing to function. I plan to test that in the near future and will report back here if that is a protection that you can successfully add to your Windows systems to prevent either of these abuses.