Enumerating remote access policies through GPO

By William Knowles and Jon Cave on 30 January, 2018

William Knowles and Jon Cave

30 January, 2018

When attempting to remain covert as part of a simulated attack it is typically useful to enumerate policies that will influence the outcome of an action before attempting it. In part to avoid wasting time on unobtainable attack paths, and in part to minimise the risk of detection.

One such example of this is where local administrator password hashes or plain text credentials are obtained, and there is a desire to use them to authenticate elsewhere in an environment.  Two notable remote access policies within Windows which affect the outcome of such actions are User Account Control (UAC) and User Rights Assignment (URA).  Depending upon their configuration, each of these can lead to a failure to perform lateral movement, which in turn may generate artefacts that lead to an increased likelihood of detection.

Such remote access policies can be enforced locally (e.g., as part of a gold image) or remotely (e.g., through group policy in Active Directory).  This post will provide two contributions in this latter domain:

  1.  It will provide a reference for how to enumerate group policy for particular policy settings, and then associate those with the computer objects on which they may be enforced. A use case of remote access policies is used.
  2.  It will introduce some proof-of-concept PowerView extensions to enable these activities.

For the red team this post will provide some operational security considerations and arm you with some tooling to aid targeted lateral movement.  For the blue team this will provide guidance on attacker tradecraft for your playbooks, and new material for generating indicators of compromise for your threat hunting teams.  If you want to skip to the code it has been made available on Github (https://github.com/mwrlabs/gists/blob/master/PowerView-with-RemoteAccessPolicyEnumeration.ps1).  Alternatively, read on for a primer on UAC and URA, and the details on how group policy can be abused to map its settings to particular computer objects.

A use case of remote access policies: User Account Control and User Rights Assignment

This section highlights some of the UAC and URA configuration options which can be set through group policy and how they affect the remote authentication process.  Where they are stored and how they can be enumerated is explored later in this post.

User Account Control: LocalAccountTokenFilterPolicy, FilterAdministratorToken, and ... EnableLUA?

The purpose of UAC is to provide a means of isolating processes by enabling them to run at different integrity levels (or levels of trustworthiness).  The settings that affect UAC behaviour are stored as registry key properties at the following location within the HKEY_LOCAL_MACHINE registry hive:


There are three notable properties which affect UAC behaviour during remote authentication.  Each of these settings determines how access tokens are filtered for remote connections by users within the local administrators group.  In practical terms, it controls whether it is possible to perform remote authentication and obtain a high integrity access token, or whether it is filtered to a lower integrity level.  From a security assessment perspective, a high integrity access token is required to establish remote administrative access.

  • EnableLUA – Used to enable (1, the default) or disable (0) “Admin Approval” mode for the computer. The effect of this setting is rarely mentioned within security literature; however, it is integral to the functioning of UAC.  If disabled, all UAC policies are also disabled.  When disabled, it is possible to perform privileged remote authentication with any member of the local administrators group using plaintext credentials or password hashes.  All access tokens for local administrators are set to high integrity during remote authentication.  When enabled, privileged remote authentication capability is determined by the settings of LocalAccountTokenFilterPolicy and FilterAdministratorToken.
  • LocalAccountTokenFilterPolicy – Used to control the policy for filtering the access tokens of remote connections for all local users within the local administrators group. When set to 0 (the default), remote connections with high integrity access tokens are only possible using either the plaintext credential or password hash of the RID 500 local administrator (and only then depending on the setting of FilterAdministratorToken).  For non-RID 500 local administrators access tokens for remote connections are filtered (i.e., medium integrity).  If set to 1, the policy allows remote connections with high integrity access tokens from any member of the local administrators group using either their plaintext credentials or password hashes.  Will Schroeder (@harmj0y) provides further detail on the role of LocalAccountTokenFilterPolicy within his blog post that clarifies the impact of KB2871997 on passing-the-hash (or lack thereof).   Note that even if LocalAccountTokenFilterPolicy is set to 0, if EnableLUA is disabled (0), EnableLUA takes precedence as there is no UAC enforced to provide filtering.
  • FilterAdministratorToken - Used to enable (1) or disable (0, the default) “Admin Approval” mode for the RID 500 local administrator. When enabled the access token for the RID 500 local administrator is filtered (i.e., medium integrity), and therefore, it is not possible to perform privileged remote authentication using the RID 500 local administrator using either plaintext credentials or password hashes.  In a standard Windows build, the default setting of LocalAccountTokenFilterPolicy and FilterAdministratorToken explain why it is only possible to perform privileged remote authentication with the RID 500 local administrator account.  Although this is disabled by default, an example situation which may occur is where FilterAdministratorToken is enabled through a gold image, but then selectively disabled through group policy for particular computer objects.  Such situations may enable lateral movement using any identified credential material for the RID 500 local administrator.

Although all three of these registry key properties reside within the same location in the Windows registry, there is a difference in the way that they are configured through group policy, and how they are stored within the group policy configuration files.  Understanding this is integral to understanding how they can be enumerated.

Configuring EnableLUA and FilterAdministratorToken

Both EnableLUA and FilterAdministratorToken have explicit configuration options within the Group Policy Management Editor.   For EnableLUA this is “User Account Control: Run all administrators in Admin Approval Mode” and for FilterAdministratorToken “User Account Control: Admin Approval Mode for the built-in Administrator account”.  These settings can be found at:

-> Computer Configuration
-> Policies
-> Windows Settings
-> Security Settings
-> Local Policies
-> Security Options
-> “User Account Control: Admin Approval Mode for the built-in Administrator account”
-> “User Account Control: Run all administrators in Admin Approval Mode”

The “Security Options” settings are stored within an INF configuration file with the name "gpttmpl.inf” in the relevant group policy container on the SYSVOL share hosted by each domain controller.

\\<Domain>\Policies\{<GUID>}\Machine\Microsoft\Windows NT\SecEdit\GptTmpl.inf

The following figure shows a situation where “EnableLUA” is disabled.

Configuring LocalAccountTokenFilterPolicy

LocalAccountTokenFilterPolicy can not be set through an explicit configuration option within the Group Policy Management Editor.  Instead it needs to be set through the definition of a custom registry key property.  Within the Group Policy Management Editor this can be done at the following location:

-> Computer Configuration
-> Preferences
-> Windows Settings
-> Registry
-> <Custom Key and Property Definition>

The consequence of this is that the configuration is stored in a different location within the group policy container.  This time it is an XML document named Registry.xml.


The following figure shows an example Registry.xml configuration where LocalAccountTokenFilterPolicy is enabled (1).

User Rights Assignment: SeDeny*?

The purpose of URA is to dictate the manner in which a user can authenticate to a system, while also providing a further means of granting that user certain privileges.   The settings that affect URA behaviour are not readily available to be queried within the Windows registry.

There are two notable URA settings which affect remote authentication.  Each of these begins with the SeDeny* prefix and can be configured through group policy.

  • SeDenyNetworkLogonRight – Used to deny certain users or groups the ability to perform network authentication, which is used, for example, by the Remote Process Call (RPC) Endpoint Mapper and Server Message Block (SMB) services.
  • SeDenyRemoteInteractiveLogonRight – Used to deny certain users or groups the ability to perform remote interactive authentication, which is used by the Remote Desktop Protocol (RDP) service.

If a user or group is associated with either of these settings, the required authentication for lateral movement over the associated protocols will not be possible.  That is, by associating them with the setting (or right), they are denied the ability to perform certain types of authentication.

One means of preventing the abuse of local credential material is by associating the built-in “Administrators” group these settings.  This does have a secondary effect which is commonly misunderstood, and is worth mentioning here.  Namely that this affects all objects within this group, including domain users and groups that have been included within it.  For example, as the “Domain Admins” group is by default placed within the built-in “Administrators” group on domain joined computer objects, it will also not be possible to authenticate over the relevant protocols using these accounts, despite their privileged nature within the wider domain.

In addition to the above URA settings, it should also be noted that similar SeDeny* settings exist for denying users or groups the ability to perform local authentication, authentication as a service, and authentication as a batch job.

Configuring SeDenyNetworkLogonRight and SeDenyRemoteInteractiveLogonRight

SeDenyNetworkLogonRight and SeDenyRemoteInteractiveLogonRight have explicit configuration options within the Group Policy Management Editor.   For SeDenyNetworkLogonRight this is “Deny access to this computer from the network” and for SeDenyRemoteInteractiveLogonRight “Deny log on through Remote Desktop Services”.  These settings can be found at:

-> Computer Configuration
-> Policies
-> Windows Settings
-> Security Settings
-> Local Policies
-> User Rights Assignment
-> “Deny access to this computer from the network”
-> “Deny log on through Remote Desktop Services”

The “User Rights Assignments” settings are stored within the same "gpttmpl.inf” SYSVOL file as was used for “Security Options” with the UAC settings.

\\<Domain>\Policies\{<GUID>}\Machine\Microsoft\Windows NT\SecEdit\GptTmpl.inf

The following figure shows a situation where SeDenyNetworkLogonRight and SeDenyRemoteInteractiveLogonRight are configured to include the built-in “Administrators” group.  This group is automatically represented in the configuration by its well-known SID “S-1-5-32-544” rather than the group name.

Enumerating remote access policies with PowerView

With the understanding of UAC and URA policies and how they impact remote authentication, along with how these policies are stored within group policy containers, we can begin to enumerate them.  For this, the ever fruitful PowerView within the PowerSploit framework is used heavily (here the development branch is used as a base).  In addition, three functions have been created to facilitate the enumeration of remote access policies: Find-ComputersWithRemoteAccessPolicies, Get-DomainGPORemoteAccessPolicy, and Get-RegistryXML.  The code for these functions can be found on MWR Labs Github (https://github.com/mwrlabs/gists/blob/master/PowerView-with-RemoteAccessPolicyEnumeration.ps1) are described in brief below.

Get-DomainGPORemoteAccessPolicy contains the core functionality of the additional functions, and identifies GPOs that establish the remote access policies of interest.  This functionality closely parallels the existing Get-DomainGPOLocalGroup.  The details of each GPO is retrieved using PowerView’s Get-DomainGPO, and the contents of each group policy container is inspected for the GptTmpl.inf and Registry.xml files.  PowerView makes this process painless by providing the path to the group policy container within the ”gpcfilesyspath” property of each GPO object as shown in the following figure.  As described in the previous sections, the files of interest then exist within a known subdirectory structure.

PowerView already provides a function for parsing the GptTmpl.inf file in Get-GptTmpl.  Therefore, Get-DomainGPORemoteAccessPolicy simply needs to examine the returned object for the registry keys of interest.  However, no such existing function exists for Registry.xml.  Despite this the required functionality closes parallels PowerView’s Get-GroupsXML.  Get-RegistryXML performs similar actions for Registry.xml but instead returns a list of PSObjects containing each registry modification.

The following code snippet shows a subset of Get-DomainGPORemoteAccessPolicy’s functionality for performing the above actions; namely, retrieving each GPO and checking if it disables UAC by setting the EnableLUA property to 0.

Get-DomainGPO @SearcherArguments | ForEach-Object {
$GPOdisplayName = $_.displayname
$GPOname = $_.name
$GPOPath = $_.gpcfilesyspath
# EnableLUA and FilterAdministratorToken check via GptTmpl.inf
$ParseArgs = @{ 'GptTmplPath' = "$GPOPath\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf" }
if ($PSBoundParameters['Credential']) { $ParseArgs['Credential'] = $Credential }
# parse the GptTmpl.inf file (if it exists) for this GPO
$Inf = Get-GptTmpl @ParseArgs
if($Inf -and ($Inf.psbase.Keys -contains "Registry Values"))
$EnableLUA = $Inf["Registry Values"]["MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableLUA"]
if ($EnableLUA -and ($EnableLUA[0] -eq 4) -and ($EnableLUA[1] -eq 0))
Write-Verbose "The following GPO enables pass-the-hash by disabling EnableLUA: $GPOdisplayName - $GPOname"
# append to EnableLUA GPO list if it is not already there
if ($RemoteAccessPolicies.EnableLUA -notcontains $GPOname) { $RemoteAccessPolicies.EnableLUA += $GPOname }

Get-DomainGPORemoteAccessPolicy returns a hash table where the key is the name of each property being searched for (e.g., EnableLUA), and the value is a list of GPOs in which that property was set to the value of interest.

Get-DomainGPORemoteAccessPolicy was not intended to be called directly but to act as an auxiliary function for Find-ComputersWithRemoteAccessPolicies.  Find-ComputersWithRemoteAccessPolicies acts as a wrapper which takes the output of Get-DomainGPORemoteAccessPolicy, determines what organisational units the GPO is linked to, and then determines what computer objects are in those organisational units.  PowerView, once again, makes the process of establishing the link between organisational units and GPOs simple, as the objects returned by the Get-DomainOU function contains a “gplink” property which describes linked GPOs.

A code snippet from Find-ComputersWithRemoteAccessPolicies is shown below which performs the process described above.  The computer objects on which the remote access policies are set are added to a hash table, where the key is policy, and the value is a list of DNS hostnames.

$RemoteAccessPolicies = Get-DomainGPORemoteAccessPolicy @gpoSearchArguments
$RemoteAccessPolicies.PSObject.Properties | ForEach-Object {
$policy = $_.Name # EnableLUA, etc
foreach ($guid in $RemoteAccessPolicies.$policy) {
# set arguments for OU search (readding $SearchBase to limit the scope)
$ouSearchArguments = @{}
$ouSearchArguments = $ouSearchArguments + $SearcherArguments
$ouSearchArguments['GPLink'] = $guid
Get-DomainOU @ouSearchArguments | ForEach-Object {
$compSearchArguments = @{}
$compSearchArguments = $compSearchArguments + $SearcherArguments
$compSearchArguments['SearchBase'] = $_.distinguishedname
$OUComputers = Get-DomainComputer @compSearchArguments
$OUComputers | ForEach-Object {
if ($ComputerObjectsWithRemoteAccessPolicies.$policy -notcontains $_.dnshostname) { $ComputerObjectsWithRemoteAccessPolicies.$policy += $_.dnshostname }

The following figure shows this object returned by Find-ComputersWithRemoteAccessPolicies and how it can be leveraged to identify targets for lateral movement.

For this theoretical scenario, if a gold image with local administrative credential reuse is assumed for all computer objects, the results can be interpreted as follows.  UAC has been disabled (through EnableLUA) on three computer objects which creates the opportunity for reusing non-RID 500 credential material; however, the “Administrators” group is included within the SeDenyNetworkLogonRight settings for two of these hosts (“HR-COMPUTER-1” and “HR-COMPUTER-2”) which prevents lateral movement to them using network authentication (e.g., as is required with psexec).  This would also prevent lateral movement using the RID 500 “Administrator” account.  For the remaining computer object (“DEV-COMPUTER-1”) lateral movement through the reuse of any local administrative credentials (both RID 500 and non-RID 500) would remain possible.  For all computer objects, if the plaintext credentials for users in the built-in “Administrators” group could be obtained, these could be used for remote interactive authentication (e.g., RDP).  This is because such authentication has not been explicitly disallowed through the SeDenyRemoteInteractiveLogonRight. A flow chart visualisation of these attack paths is shown below.


This post set out to describe the process of enumerating group policy for particular policy settings, and determining computer objects to which they may apply.  The use case was one of remote access policies.  In particular, for determining computer objects to which local credential material may be able to be reused due to UAC and URA settings for remote authentication. A set of PowerView extensions were also produced to enable such activities, which have been made available on MWR Labs Github (https://github.com/mwrlabs/gists/blob/master/PowerView-with-RemoteAccessPolicyEnumeration.ps1).

Although remote access policies were the core focus of this post, it provides a simple illustration of how the same approach could be applied to any other policy setting.  For example, this could be used by an attacker to identify computer objects that are running (or in certain circumstances potentially not running) a piece of software if the settings are enforced through group policy.  Such an approach would also be challenging for the blue teams to detect due to the quantity of legitimate traffic that interacts with SYSVOL.

There are two key limitations of the current implementation and opportunities for future work:

  • The association between organisational units and GPOs is a simple associative relationship, and not a PowerShell reimplementation of Resultant Set of Policies (RSoP); therefore, it does not account for group policy hierarchy (e.g., one GPO overwriting the settings of another). A further implication of this is that targeted searches (e.g., through “-SearchBase <organisational unit>”) will not capture settings established in other organisational units.
  • It also does not account for security filtering on GPOs, which are used to configure a GPO to apply to only a subset of objects within the organisational unit to which it is applied.

Despite these limitations, the approach does provide a means of rapidly triaging potential computer objects with interesting remote access policies for lateral movement.