Pass the Hash, I'm Hungry

By Dan Newton August 26, 2016

Recently, I started a GPO cleanup project that also included implementing a host of security recommendations.  One recommendation was listed as “Implement Client-Side Pass-The-Hash Mitigations”.  That’s one big item…as there are multiple things that need to be done in an Active Directory to mitigate against the Pass-the-Hash attack.

What is “Pass-the-Hash” you ask?  Well is a sneaky little attack where by a bad guy that has admin access on a computer is able to grab a hash of credentials of another user (usually they’ll try to get a domain admin account) from memory and then run tools to use that same hash on other systems to impersonate the domain admin user.   This is very simple description….for more details see this nice article: https://nas/content/live/ivisionstaging.blackhat.com/docs/us-15/materials/us-15-Moore-Defeating%20Pass-the-Hash-Separation-Of-Powers-wp.pdf

One of the many recommendations to prevent a “Pass-the-Hash” attack is to isolate/restrict the Domain Admin accounts to only be able to logon to the Domain Controllers.  Great I thought…that seems like a fine idea.  So I went about testing this in the Newton Lab with help from this guide: https://nas/content/live/ivisionstaging.petri.com/how-to-create-a-windows-server-2012-r2-authentication-policy

BUT I missed a key pre-req by not setting up the group policy settings of “Kerberos client support for claims, compound authentication, and Kerberos armoring should be set to Enabled”…which enables claims support for Kerberos clients. BIG FAIL here…as I continued down the path of setting of the Authentication Policy and Authentication Policy Silo.  What’s a Auth Policy and Silo, you ask?  Well it’s a cool feature of Windows Server 2012 R2/Windows 8.1 to be able to support Kerberos claims.  The policy is setup to allow a computer and/or user to “read” the policy and have the policy assigned to the given security principal (user or group).  There’s plenty of good content on this on TechNet.  So I setup the policy and silo and assigned to the DCs and the Domain Admins in the Newton Lab.  Now I’m ready to test…

So the result not following the guided instructions (details…details) was that every Domain Admin account was locked out from logging on to any computer in the domain, that means DCs too! Needless to say that was not good.  So just do an authoritative restore and get you back in business? If I only had a recent backup that would work (2nd lesson learned).  Good thing this was my lab and not on a client’s production AD

So crap I’m locked out of the domain…nothing I tried got things back to normal, so I ended up rebuilding the DCs and rejoining all the members back into the domain.  Now with things back to “normal” I’m ready to try again…this time I know what to do – use PowerShell to make sure I get it all done right (and repeatable for the client).

Here’s what I ended up with…A script that does the following:

  • Create a new GPO named “Kerberos-Claims-Support” and adds the appropriate settings needed (all of them this time)
  • Create a new Authentication Policy
  • Create a new Authentication Policy Silo
  • Grant access to the Policy Silo to the members of “Restricted Admins” (I manually created this group and added a single domain admin to it…fool me once….) and grant access to the Domain Controllers
  • Assign the Policy Silo to the DCs and “Restricted Admins” (I manually created this group and added a single user to it…baby steps you know!)

Here’s the code:

#Set Name Variables:
$AuthPolicyName = "Reduced_Admin_TGT"
$AuthSiloName = "Controlled_Admin_Logon"
$userGroup = "Restricted Admins"


import-module -Name grouppolicy
$GPOName = "Kerberos-Claims-Support"
$RootDSE = Get-ADRootDSE
Write-Host "Creating Group Policy Object with name $GPOName"
New-GPO -Name $GPOName
New-GPLink -Name $GPOName -target $RootDSE.rootDomainNamingContext -LinkEnabled Yes


Write-Host "Enable KDC Support"
Set-GPRegistryValue -Name $GPOName -key "HKLMSoftwareMicrosoftWindowsCurrentVersionPoliciesSystemKDCParameters" -ValueName EnableCbacAndArmor -Type DWord -value 1

Write-Host "Set KDC Claims Armor Level"
Set-GPRegistryValue -Name $GPOName -key "HKLMSoftwareMicrosoftWindowsCurrentVersionPoliciesSystemKDCParameters" -ValueName CbacAndArmorLevel -Type Dword -value 1

Write-Host "Enable Kerberos client support for claims"
Set-GPRegistryValue -Name $GPOName -key "HKLMSoftwareMicrosoftWindowsCurrentVersionPoliciesSystemKerberosParameters" -ValueName EnableCbacAndArmor -Type Dword -value 1



# Create New Auth Policy
New-ADAuthenticationPolicy -Name $AuthPolicyName `
                           -Description "Authentication policy to set 2 hour Ticket Granting Ticket for administrators" `
                           -UserTGTLifetimeMins 120 `
                           -Enforce `
                           -ProtectedFromAccidentalDeletion $True

#Set Access Control Condition to Silo $AuthSiloName
Set-ADAuthenticationPolicy -Identity $AuthPolicyName `
                           -UserAllowedToAuthenticateFrom "O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == `"Controlled_Admin_Logon`"))"


#Create New Silo and assign $AuthPolicyName Policy
New-ADAuthenticationPolicySilo -Name $AuthSiloName `
                               -Description "Authentication policy silo to control the scope of logon for administrators" `
                               -UserAuthenticationPolicy $AuthPolicyName `
                               -ComputerAuthenticationPolicy $AuthPolicyName `
                               -ServiceAuthenticationPolicy $AuthPolicyName `
                               -Enforce `
                               -ProtectedFromAccidentalDeletion $True


#Grant DCs access to new Silo
#Add members
Get-ADGroupMember -Identity $userGroup |ForEach-Object {Grant-ADAuthenticationPolicySiloAccess -Identity $AuthSiloName -Account $_.DistinguishedName}

#Add DCs
Get-ADDomainController -Filter {IsReadOnly -eq $False} |ForEach-Object {Grant-ADAuthenticationPolicySiloAccess -Identity $AuthSiloName -Account $_.ComputerObjectDN}


#Associate the Read/Write DCs:
Get-ADComputer -LDAPFilter "(&(&(&(samAccountType=805306369)(useraccountcontrol:1.2.840.113556.1.4.803:=8192))))" |Set-ADAccountAuthenticationPolicySilo ñAuthenticationPolicySilo $AuthSiloName

#Associate the group members:
Get-ADGroupMember -Identity $userGroup |Set-ADAccountAuthenticationPolicySilo ñAuthenticationPolicySilo $AuthSiloName

 

Once the above code is run the Kerberos tickets on the Domain Controllers need to reboot all the DCs to force the policy update and clear out Kerberos.  Now you’ll have the members of the “Restricted Admins” group locked out restricted to just the domain controllers.  Try to logon to a member server or member workstation and you’ll get this:

Domain Controllers need to reboot all DCs to force policy update and clear out Kerberos

NOTE:  You’ll get this same message on any DC that has not been rebooted…once you reboot you’ll have access again.  Also if you add more users to the “Restricted Admins” group (and assign the silo to that user) no further reboots of DCs will be required.

Also if you set this up with the code above and need to quickly roll back use the following:

#Set Name Variables:
$AuthPolicyName = "Reduced_Admin_TGT"
$AuthSiloName = "Controlled_Admin_Logon"
$userGroup = "Restricted Admins"

#get group members and revoke Policy Silo for each
$Group = Get-ADGroupMember -Identity $userGroup -Recursive
foreach($member in $Group){
Revoke-ADAuthenticationPolicySiloAccess -Identity $AuthSiloName -Account $member -Confirm:$false
}

 

Please Note: I used the code from this “Hey, Scripting Guy” blog to help with the Auth Policy and Silo portion….and to setup the GPO I found this handy write up.

 

I hope that this painful lesson that I went through will serve others well.

All this talk of hash makes me hungry for some Who Hash:

Hungry for Who Hash because of Pass the Hash

Happy scripting.

D