I had a chance to attend my first BlackHat/Defcon conference last week in Las Vegas. I also attended the very excellent BSides conference, happening concurrently. Besides being shaken to my core from the skills demonstrated during the week :-), I got a chance to see some excellent talks related to Windows security and some super cool tools that “Red Teamers” can use to improve the posture of their Windows and AD/Group Policy environments. I wanted to share some of these observations with you all in this post, and also include some guidance I’ve come to around GPO permissioning, in the wake of the recent MS16-072 patch and some of the things I saw at the conference.
BloodHound and “Derivative Local Admin”
By far the coolest thing I saw during last week’s show was a solution called Bloodhound, which was released to open source at Defcon by the folks at Veris Group. Bloodhound uses graph theory to leverage data generated by PowerShell red teaming tools like PowerView to create a visual representation of paths of privilege escalation across an organization’s Windows AD network–a path to so-called “Derivative Local Admin” which is the notion that, through discovering who has admin access on which machines within a network, and compromising the credentials of those accounts through well-known means (e.g. mimikatz), you can essentially “walk” your way to increased privileges on more interesting systems within an AD domain.
Bloodhound applies graph theory to this kind of incremental discovery of the relationships between computers, users and their rights and group memberships, to help draw a visual map of how you can go from one low-value user/target, to another high-value one. And it’s pretty cool ( see example of running it on my test network bel0w):
One interesting facet of Bloodhound, or more specifically the PowerView PowerShell tools that provide the data for Bloodhound, is the developers’ use of Group Policy to partially fill out the data they collect. More on this in my discussion of Group Policy Discoverability below. For more information about Bloodhound or to see the presentation from BSides by the authors of the tool, I highly recommend you check out this YouTube Video from the talk:
Another talk I attended, given by two security researchers at Microsoft, presented the “Remote Butler” attack–a variation on the older “Evil Maid” exploit that allows an attacker with physical access to a Windows machine, to take advantage of certain vulnerabilities in a client’s interaction with a domain controller during a password change event, to trick the machine into thinking that a rogue DC was the real one. The Remote Butler attack was presented as a remote variation on Evil Maid, and brought up some similar deficiencies in unpatched versions of Windows. So why am I talking about this in a section entitled, “MS16-072”? Precisely because during this talk, the researchers mentioned MS16-072 as being a by-product of this type of vulnerability in client-DC interactions as it relates to Group Policy processing. If you’ll recall from my above-mentioned blog post on MS16-072, the change that Microsoft made, was to make per-user GP processing no longer impersonate the user account processing GP, but rather instead use the computer account to read GPOs that were permissioned using per-user security group filtering. But the question came up in many minds–“why does this fix the problem?” The answer, as it turns out, is that, similar to the vulnerabilities in user password changes found with Evil Maid, per-user GP processing did not validate the interactions and communications with the domain controller before processing GPOs. As a result, someone could stand up a rogue DC, and “convince” a user, processing GPOs, that a rogue GPO was valid. This rogue GPO could do anything, including adding a compromised user account to the local Administrators group on the machine, and then, “Bob’s your uncle”, as they say. By forcing per-user GP processing to use the computer account to interact with the DC, as MS16-072 does, that interaction between client and DC is now secured using the machine account’s own credentials, which ensures that the interaction can’t be hijacked by that rogue DC. Now that I understand the *why* of MS16-072, I’m still inclined to ask, “why didn’t they fix the per-user interaction?” but acknowledge that it may have been a more breaking change to do so, than the path they took, as painful as that was to many admins.
As a by-product of MS16-072, we know that one of the “clean-up” tasks we had to perform, was to modify permissions on all GPOs that used per-user security group filtering, to add a Read permission for either Domain Computers or Authenticated Users to those GPOs. Indeed, the PowerShell script in my blog post linked to above, did just that. But that exercise kicked off a discussion amongst my fellow GP MVPs around the value of permissioning GPOs for one account or another, with some arguing for the most restrictive permissions possible (I was in that camp) and some arguing that it didn’t matter, since much of a typical company’s internal network is already discoverable by employees on the network and permissioning GPOs away from users was just so much obfuscation.
But since that conversation and my exploration of BloodHound last week at BSides, I’ve come to the conclusion that a more aggressive stance with respect to Group Policy permissions is required–not to protect against rogue employees discovering something they shouldn’t, but rather hostile intruders, who gain a foothold into your environment and then use a variety of techniques, including Group Policy, to greatly enhance their ability to gain that derivative local admin access I mentioned above. Let’s look at this in more detail.
Using Group Policy Against You
One of the more clever things that the guys who wrote BloodHound and PowerView did, was to leverage Group Policy to provide a quicker way to get information about who was local admin or who had remote desktop access on which machines in your AD network. If you think about a large corporate network–possibly global in reach and scope–the process of searching out which machines have granted local privileged access to which users and groups could take a long time–a long time. If you’re an attacker, you may not be able to go that long undetected. You want to get in and get out quickly, with as much information as possible. What better way to do that than to use Group Policy against you. Group Policy is used by many companies to control local group membership, including which users and groups are local administrators on a box (or have RDP access). And GPOs, by default, are readable by any user in an AD domain. Further, by looking at where GPOs are linked, you can derive what machines in a domain are likely to have those group memberships in place that are mandated by Group Policy. Within Group Policy-land, there are roughly two main areas where local group membership is managed. Either under Restricted Groups policy or within Group Policy Preferences Users and Groups. Within the PowerView module, written by HarmJ0y, and used by Bloodhound, is a function called Find-GPOLocation. The Bloodhound data gathering functions can use this GPO function to cleverly interrogate any GPOs that use these two local group management policy areas and determine which machines they should be applied to. And because most GPOs (and most of AD in a typical deployment) are by default, freely readable by non-privileged users (indeed, Bloodhound’s data gathering facility overall doesn’t require an attacker have any special privileges on the domain other than being a regular domain user) and stored centrally in AD, it becomes a very efficient way to suss out who has admin access across a large environment. And that is exactly what these guys did with Find-GPOLocation, as shown in this screenshot below:
Now, the logic in doing this is pretty basic. It doesn’t take into account security group filtering, GPP Item-Level Targeting or WMI filtering on these GPOs that it searches out, but overall, it’s a pretty clever approach to speeding the discovery of your network and it’s vulnerable hiding places. So, what to do about it?
Protecting Your GPOs From Prying Eyes
We already started going down the path of re-permissioning GPOs in the face of MS16-072. But, that operation was strictly limited to those GPOs that were broken by this patch–those that used per-user security group filtering. What I’m proposing now goes beyond that. What I’m basically saying here is that the approach you take with your GPOs should be the same as any asset that you wish to protect from unwanted attention in your environment. That permission to read a GPO should be on a need-to-know basis only, and especially for those GPOs, like those identified above, which grant privileged access across your environment. It’s only a matter of time before the Bloodhound guys add user rights assignment seeking to the mix, or some other security configuration that makes their hunter tools more effective. So, what does this mean in practice? I try to lay that out here:
Any GPOs that contain per-computer security settings, and especially those that grant privileged access on machines, should be permissioned such that only the intended targets of those GPOs, and GPO administrators, have Read access to them. Let’s take a scenario to illustrate this. You create a GPO, linked at the AppServers OU, that contains Restricted Groups policy that sets local admin access on those App Servers. Only those computers in that OU will process this GPO, therefore only the computers in that OU should be able to read it (have Security Filtering applied). Not Authenticated Users. Ideally, you would have a security group that contains all the computers that will process that GPO, but in the worst case, use Domain Computers instead of a manually maintained computer-based security group. And no others. NONE. Sure, you’ll have GPO admins that have delegated access to read and edit those GPOs. But no other users or computers should be granted Read permission. This looks like the following:
The benefits of this approach are obvious. Once a GPO is permissioned away from read access by a regular user, and only given access to computer accounts or privileged admins, then an attacker must elevate their privileges to successfully read those GPOs. In the case of Bloodhound and the Find-GPOLocation function, it would simply be unable to make the correlation between Restricted Groups or GPP Users and Groups, and specific machines. Now, it has other functions it can use to get that local admin info, but it requires touching every machine in a domain, which takes a lot longer.
The challenges of this approach are, that you need to either maintain security groups for all computers that are targeted by these critical policies, and use those for filtering, or you need to simply use “Domain Computers”. The latter is obviously less secure, because if any one machine is compromised on your network, and an attacker can start a process as LocalSystem, they will be able to read your protected GPOs just fine. But it is still better than having every non-privileged user on your network be able to read your security posture as if it were published on page 1 of the New York Times! I would also say that, you really only need to take this approach for those GPOs that deliver critical information about your network’s security posture. These include pretty much most setting areas under:
Computer Configuration\Policies\Windows Settings\Security Settings and Computer (or User) Configuration\Preferences\Control Panel Settings\Local Users and Groups. So, we’re not talking about all of your GPOs, but just a subset (well, you can do all of them if you really want to). The bottom line is, “HARDEN YOUR GPOs!!!” Don’t assume that information is harmless. In this day and age, giving an attacker a quick and easy roadmap to who has access to what on your network is just dumb.
So, to summarize the guidance from above:
- For any GPOs that deliver security settings under Computer Configuration\Windows Settings\Security Settings, remove read permission for any groups other than the computers that will process those GPOs (or the Domain Computers built-in group, if you can’t use a discretionary security group) and for admins who need to manage those GPOs.
- For any GPOs that deliver local users and groups settings under Computer Configuration (or User Configuration)\Preferences\Control Panel Settings\Local Users and Groups, (LUGS) remove read permission for any groups other than the computers or users that will process those GPOs (for the per-computer LUGS settings, that means the same guidance as #1. For the per-user side, that means granting read to just the user groups who will process those GPOs. Adding a more generic per-user group will not do much for you in this case, since Authenticated Users already has read access by default) and for admins who need to manage those GPOs. Frankly, I would avoid using per-user LUGs altogether, since it’s hard to truly protect those settings from prying unprivileged eyes.
Let me know if you have questions about anything I’ve written in this post. Hopefully this has been helpful. As we continue to rely on Group Policy as a tool for securing our Windows boxes, it’s important that we evolve our approach to keep up with the changing times.