Pass-the-Hash Is Dead: Long Live LocalAccountTokenFilterPolicy

Nearly three years ago, I wrote a post named “Pass-the-Hash is Dead: Long Live Pass-the-Hash” that detailed some operational implications of Microsoft’s KB2871997 patch. A specific sentence in the security advisory, “Changes to this feature include: prevent network logon and remote interactive logon to domain-joined machine using local accounts…” led me to believe (for the last 3 years) that the patch modified Windows 7 and Server 2008 behavior to prevent the ability to pass-the-hash with non-RID 500 local administrator accounts. My colleague Lee Christensen recently pointed out that this was actually incorrect, despite Microsoft’s wording, and that the situation is more nuanced than we initially believed. It’s worth noting that pwnag3’s seminal “What Did Microsoft Just Break with KB2871997 and KB2928120” article also suffers from the same misunderstandings that my initial post did.

We now have a better understanding of these topics and wanted to set the record straight as best we could. This is my mea culpa for finally realizing that KB2871997, in the majority of situations, had absolutely nothing to do with stopping “complicating” the use of pass-the-hash in Windows enterprises. Apologies for preaching the incorrect message for nearly 3 years- I hope to atone for my sins :) And as always, if there are errors in this post, please let me know and I will update!

Clarifying KB2871997

So what did this patch actually do if it didn’t automatically “prevent network logon and remote interactive logon to domain-joined machines using local accounts”? As Aaron Margosis describes, the patch introduced, among many other changes, two new security identifiers (SIDs): S-1-5-113 (NT AUTHORITY\Local account) and S-1-5-114 (NT AUTHORITY\Local account and member of Administrators group). As detailed in the Microsoft article, these SIDs can be used through group policy to effectively block the use of all local administrative accounts for remote logon. Note that while KB2871997 backported these SIDs to Windows 7 and Server 2008/2012, they were incorporated by default in the Windows operating system from Windows 8.1 and Server 2012 R2+. This is something that Sean Metcalf has previously mentioned and Aaron specifically clarified in the comments of that Microsoft post.

Sidenote: Luckily for us, this also means that any user authenticated on the domain can enumerate these policies and see what machines have these restrictions set. I’ll cover how to perform this type of enumeration and correlation in a future post.

I assumed, incorrectly, that this patch modified existing behavior on Windows 7 machines. Since Windows Vista, attackers have been unable to pass-the-hash to local admin accounts that weren’t the built-in RID 500 Administrator (in most situations, see more below). Here we can see that KB2871997 is not installed on a basic Windows 7 install:

Yet executing pass-the-hash with the ‘admin’ non-RID 500 account that’s a member of local Administrators fails:

So this behavior existed even before the KB2871997 release. Part of this confusion was due to the language used in the security advisory, but I take responsibility for not testing the situation fully and relaying the correct information. While we do highly recommend Aaron’s recommendations of deploying GPOs with these new SIDs to help mitigate lateral spread, we also reserve the right to still smirk at the KB’s original title ;)

Remote Access and User Account Control

So if the patch isn’t affecting this behavior, what is preventing us from using pass-the-hash with local admin accounts? And why does the RID 500 account operate as a special case? Adding to that, why are domain accounts that are members of local administrators exempt from this blocking behavior as well? Also, over the past several years we’ve also noticed on some engagements that pass-the-hash will still work with non-RID 500 local admin accounts, despite the patch being applied. This behavior always bugged us but we think we can finally explain all these inconsistencies.

The actual culprit for all these questions is user account control (UAC) token filtering in the context of remote access. I always thought of UAC solely in the context of local host actions but there are various implications for remote situations as well. The ”User Account Control and Remote Scenarios” section of the Microsoft “Windows Vista Application Development Requirements for User Account Control Compatibility” document and “Description of User Account Control and remote restrictions in Windows Vista” post both explain a lot of this behavior, and clarified several points for me personally.

Tl;dr for any non-RID 500 local admin account remotely connecting to a Windows Vista+ machine, whether through WMI, PSEXEC, or other methods, the token returned is “filtered” (i.e. medium integrity) even though the user is a local administrator. Since there isn’t a method to remotely escalate to a high-integrity context, except through RDP (which needs a plaintext password unless ‘Restricted Admin’ mode is enabled) the token remains medium integrity. So when the user attempts to access a privileged resource remotely, e.g. ADMIN$, they receive an “Access is Denied” message despite technically having administrative access. I’ll get to the RID 500 exception in a bit ;)

For local user accounts in a local “Administrators” group, the “Windows Vista Application Development Requirements for User Account Control Compatibility” document describes the following behavior:

When a user with an administrator account in a Windows Vista computer’s local Security Accounts Manager (SAM) database remotely connects to a Windows Vista computer, the user has no elevation potential on the remote computer and cannot perform administrative tasks.

Microsoft’s “Description of User Account Control and remote restrictions in Windows Vista” post describes this in another way:

When a user who is a member of the local administrators group on the target remote computer establishes a remote administrative connection…they will not connect as a full administrator. The user has no elevation potential on the remote computer, and the user cannot perform administrative tasks. If the user wants to administer the workstation with a Security Account Manager (SAM) account, the user must interactively log on to the computer that is to be administered with Remote Assistance or Remote Desktop.

And for domain user accounts in a local “Administrators” group, the document states:

When a user with a domain user account logs on to a Windows Vista computer remotely, and the user is a member of the Administrators group, the domain user will run with a full administrator access token on the remote computer and UAC is disabled for the user on the remote computer for that session.

So that explains why local admin accounts fail with remote access (except through RDP) as well as why domain accounts are successful. But why does the built-in RID 500 Administrator account act as a special case? Because by default the built-in administrator account (even if renamed) runs all applications with full administrative privileges (“full token mode”), meaning that user account control is effectively not applied. So when remote actions are initiated using this account, a full high-integrity (i.e. non-filtered) token is granted, allowing for proper administrative access!

There is one exception- “Admin Approval Mode”. The key that specifies this is at HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\FilterAdministratorToken and is disabled by default. However, if this key is enabled, the RID 500 account (even if it’s renamed) is enrolled in UAC protection. This means that remote PTH to the machine using that account will then fail. But there’s a silver lining for attackers- this key is often set through Group Policy, meaning that any domain authenticated user can enumerate what machines do and do not have FilterAdministratorToken set through the application of GPOs. While this will miss cases where the key is set on a standard “gold” image, performing this key enumeration from the initial machine an attacker lands on, combined with GPO enumeration, should cover most situations.

And remember that while Windows disables the built-in -500 Administrator account by default, it’s still fairly common to see it enabled across enterprises. My original pass-the-hash post covered basic remote enumeration of this information, and this post goes into even more detail.


There’s another silver lining for us attackers, something that has much more defensive implications than we initially realized. Jonathan Renard touched on some of this (as well as Admin Approval Mode) in his “*Puff* *Puff* PSExec” post, but I wanted to expand just a bit in relation to the overall pass-the-hash discussion.

If the HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\LocalAccountTokenFilterPolicy key exists (which doesn’t by default) and is set to 1, then remote connections from all local members of Administrators are granted full high-integrity tokens during negotiation. This means that a non-RID 500 account connections aren’t filtered and can successfully pass-the-hash!

So why would you possibly set this registry entry? Googling for the key name will turn up different scenarios where this functions as a workaround, but there’s one frequent violator: Windows Remoting. There is a non-trivial amount of Microsoft documentation that recommends setting LocalAccountTokenFilterPolicy to 1 as a workaround or solution to various issues:

In addition, I believe there are some situations where the WinRM quickconfig may even set this key automatically, but I was not able to reliably recreate this scenario. Microsoft’s “Obtaining Data from a Remote Computer” document further details:

Because of User Account Control (UAC), the remote account must be a domain account and a member of the remote computer Administrators group. If the account is a local computer member of the Administrators group, then UAC does not allow access to the WinRM service. To access a remote WinRM service in a workgroup, UAC filtering for local accounts must be disabled by creating the following DWORD registry entry and setting its value to 1: [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System] LocalAccountTokenFilterPolicy.

This is bad advice, BAD BAD BAD BAD BAD! I realize that this setting may be needed to facilitate some specific WinRM deployment scenarios, but once LocalAccountTokenFilterPolicy is set to 1 then ANY local administrator account on a machine can be used to pass-the-hash to the target. I feel that most people, myself included, have not realized the actual security implications of this modification. The only real warning I saw through all of the Microsoft documentation was “Caution: The LocalAccountTokenFilterPolicy entry disables user account control (UAC) remote restrictions for all users of all affected computers. Consider the implications of this setting carefully before changing the policy”. As this setting enables a large amount of risk for an enterprise environment, I hoped for a better set of definitive guidance and warnings from Microsoft beyond “consider the implications”, but ¯\_(ツ)_/¯

Operationally (from an offensive perspective) it’s good to check if your pivot machine has the LocalAccountTokenFilterPolicy key set to 1, as other machines in the same subnet/OU may have the same setting. You can also enumerate Group Policy settings to see if this key is set through GPO, something again that I will cover in a future post. Finally, you can use PowerView to enumerate any Windows 7 and Service 2008 machines with Windows Remoting enabled, hoping that they have run some kind of Windows Remoting setup incorrectly:

Get-DomainComputer -LDAPFilter "(|(operatingsystem=*7*)(operatingsystem=*2008*))" -SPN "wsman*" -Properties dnshostname,serviceprincipalname,operatingsystem,distinguishedname | fl

It’s also worth noting that Microsoft’s LAPS effectively renders everything here moot. As LAPS randomizes the local administrator password for machines on a periodic basis, pass-the-hash will effectively still work, but it greatly limits the ability to recover and reuse local key material. This renders traditional PTH attacks (with local accounts at least) largely ineffective.

Have fun!

15 thoughts on “Pass-the-Hash Is Dead: Long Live LocalAccountTokenFilterPolicy”

  1. I believe the native powershell command “enable-psremoting” (for which one of its subtasks is winrm quickconfig), will set LocalAccountTokenFilterPolicy.

    1. After speaking with a few friends, I *believe* that this is only the case if the machine is NOT domain joined, since it’s more or less a necessary setting in a WORKGROUP setting as Vista+ disables the RID-500.

  2. LocalAccountTokenFilterPolicy must be set to 1 in order to facilitate remote credentialed vulnerability scans using products like Nessus. That’s the only time I’ve seen that registry value in the wild.

  3. Actually been indirectly aware of this for a long time.

    Nessus users (and this probably applies to most if not all similar products) will know that Tenable recommend that LocalAccountTokenFilterPolicy be set for machines in a Workgroup. More specifically because one should be using a separate (non RID-500) account – the Workgroup aspect is rather inconsequential.

    In 99% of cases, those who use it in an enterprise will use a Domain Admin (w00p) account for Nessus, which means most people will not be aware of this issue. But I have seen some edge cases where local accounts are used and therefore, this setting has had to be applied across a domain too.

  4. Microsoft’s GPO-based security guidance (see other posts on the secguide blog) explicitly recommends: enforcing admin approval mode (token filtering) for the -500 admin; enforcing the Windows default by creating the LocalAccountTokenFilterPolicy value and setting it to 0; denying network logon to S-1-5-113 (or S-1-5-114); using LAPS. Some of these aren’t as feasible in non-domain-join scenarios, because local accounts are all you have.
    BTW, I’ve taken to using the expression “administrative local accounts” instead of constructs like “local admin[istrative] accounts.” If my domain account is in the local Administrators group but not in a domain-privileged group, it’s a “local admin account.” The phrase “administrative local account” makes it clear when I’m talking only about local accounts that have administrative rights.

    1. Aaron, my concern centers around the fact that with a large amount of Microsoft documentation, some administrators get confused with the number of entries and sometimes “seemingly” contradictory suggestions. While the GPO-based guidance may be correct, that’s not the only chunk of documentation that deals with these settings.

      I realize that LocalAccountTokenFilterPolicy being set to 1 appears to only really occur when enabling Windows Remoting while provisioning systems that are not domain-joined, but this is the reality in some environments who use a gold image model. Even if admins aren’t executing the process “correctly”, many don’t realize the risk exposure concerning this particular policy setting.

      Concerning “PTH with local accounts works only when you have administrative local accounts with the same username and password on multiple computers, and none of these other mitigations“, I obviously agree. However, cloned local accounts is something we still see very commonly, so I felt it was worthwhile to document how these components play out operationally. While an “operational ideal” is obviously possible, it’s not what we commonly encounter on engagements.

  5. BTW, also wanted to make it clearer that PTH with local accounts works only when you have administrative local accounts with the same username and password on multiple computers, and none of these other mitigations.

  6. Pingback: From Pass-the-Hash to Pass-the-Ticket with No Pain

  7. All,

    Why is LAPS necessary, when local users with local administrator permissions can’t use psexec because of UAC?

    Is there any risk for local users in administrators-group with identical passwords on several machines? As far as I understand PtH is dead, there’s no risk?

    – Chris

    1. Chris,

      PtH != dead, as detailed for various reasons in the post. PtH is in regards to authentication to the remote machine, not the remote access method itself, i.e. it is not resigned to just PSEXEC.

      Putting aside that domain accounts can still PtH w/ local admin membership (as described), the biggest remaining issue is that the built-in administrator RID-500 account still exists in many environments. Exactly because of remote UAC, this account will still work due auto-elevation. So if the password is the same for said account across an environment, PtH is still on the same from a local account standpoint.

      Even if the specified account is not the RID-500 account, if an attacker is able to crack the hash for a non-RID-500 local admin account, or any other account that’s a member of “Remote Desktop Users” on a machine, re-usable RDP access with a plaintext would still be on the table. Most agree that offering up potential re-usable access to an attacker is “generally a bad idea”, hence our strong recommendation of using something like LAPS. So yes, I would say there still is an increased risk.


  8. Great post ! This still leaves some unclarity as to how useful is it to use S-1-5-113 and/or S-1-5-114 to reduce exposure ?

    If local admin accounts (non RID-500) won’t allow PtH anyway and these SIDs don’t apply to either RDI-500 or domain accounts within the local Adminstrators group anyway – What are they good for ?

    All I can see is preventing RDP with non-RDI 500 local admin accounts (?) if associated with “Deny log on through Remote Desktop Services”

  9. Pingback: Ways of pwning a Workgroups (non domain-joined) network of patched Windows 10 machines (version 1809)? – Network Security Noblemen

  10. Pingback: Active Directory Kill Chain Attack 101 – syhack

  11. Pingback: CVE-2019-14510 - Abusing the Kaseya LAN Cache FSAdmin - Red Team Edition | Lockstep Technology Group Lockstep Technology Group

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.