Windows GPO Configuration for Epiphany Collector v2.0
About this Guide
The guide outlines the process for applying a Windows group policy object (GPO) that executes a PowerShell script on select servers and workstations within an organizations' domain for the purpose of allowing Epiphany to make calls to the Windows Security Account Manager (SAM) over RPC and enumerate network sessions to provide better attack path graphing.
Allowing Epiphany to enumerate users and groups in the local SAM database and Active Directory within your organization's domain will provide you with a qualitative risk based on your permission boundaries and privilege use. Allowing network session enumeration will provide “who is logged in from where” information so exposed credentials can be properly triangulated on affected devices. Once the GPO has been created, the servers and workstations will need to be rebooted in order for the changes to take effect.
The group policy change is only one way to execute the PowerShell script, and several other methods are possible such as deployment through SCCM or other software deployment solutions, or manual execution through PowerShell remoting or using remote desktop software.
Overview
To enable the appropriate access, you will perform these tasks:
Identify the Epiphany site collector Active Directory account that will be used.
Edit the GPO deployment PowerShell script to specify the correct Active Directory account.
Copy the PowerShell script to a location readable by Computer Accounts.
Create the group policy in the Group Policy Management Console.
The GPO Powershell script can be obtained from the bottom of this document, Reveald Support, or your Epiphany deployment team.
Version Compatibility
Windows Server 2019 Version 1809
Windows Server
Prerequisite
An Active Directory account that can create group policies.
Instructions
Step 1:
Copy the script provided to a central location reachable by Computer Accounts, such as the scripts directory within the SYSVOL share.
For example: \\EIP.DEMO\SYSVOL\EIP.DEMO\scripts\
Step 2:
Edit the script to specify the user account that will be granted access to NetSession and SAM Access Control Lists in DOMAIN\Username format.
Ensure the last line of the script is uncommented.
Step 3:
Open the Group Policy Management console.
Step 4:
On the organizational unit (OU)where the group policy should be applied, right-click and choose Create a GPO in this domain and Link it here.
Step 5:
Give the new Group Policy a Name.
Step 6:
Right-click on the new Group Policy and choose Edit.
In the directory Computer Configuration → Policies → Windows Settings → Scripts (Startup /Shutdown), right-lick on Shutdown and choose Properties.
Step 7:
On the Powershell Scripts tab in this window, select Add.
Step 8:
Select Browse and navigate to the script location and select Open.
Once the Path is populated, select OK.
Step 9:
Select Apply.
Link this GPO to any other Organizational Units to which it should apply.
Additional Information
Beginning with Windows 10 version 1709 and Server 2019 version 1809, Windows does not allow access to enumerate network sessions via the NetSessionEnum API without administrator permissions. This limits the ability of any collector to infer which accounts are logged on to the operating system putting their identities at risk if the operating system is compromised.
GPO Powershell Script
FunctionInvoke-AddACLs {param( [Parameter(Mandatory =$true)][string]$User ) $usertoadd =New-Object System.Security.Principal.NTAccount($User) $SID = $usertoadd.Translate([System.Security.Principal.SecurityIdentifier])Write-Host $usertoadd has a SID of $SIDAdd-NetSessionEnumACL-SID $SIDWrite-Host"--------------"Add-SAMRACL-SID $SID}FunctionAdd-NetSessionEnumACL {param( [Parameter(Mandatory =$true)][string]$SID )Write-Host"Starting NetSessionEnum ACL" $key ="HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\DefaultSecurity" $subkey ="SrvsvcSessionInfo" $right =0x00000001#Get the current binary value from the registry#This one exists by default, so no real need to check if it doesn't existWrite-Host"Getting current ACL from $key $subkey" $value =Get-ItemPropertyValue-Path $key -Name $subkey#Convert the binary value to a RawSecurityDescriptor object ###$currentacl = New-Object -TypeName System.Security.AccessControl.CommonSecurityDescriptor -ArgumentList $true, $false, $value, 0
$currentacl =New-Object-TypeName System.Security.AccessControl.RawSecurityDescriptor -ArgumentList $value,0#Create a new ACE for our user defined aboveA #$newace = New-Object System.Security.AccessControl.CommonAce([System.Security.AccessControl.AceFlags]::None, [System.Security.AccessControl.AceQualifier]::AccessAllowed, $right, $SID, $false, $null)
$newace = New-Object System.Security.AccessControl.CommonAce -ArgumentList None, AccessAllowed, $right, $SID, $false, $null
#Check if the ACE already existsif ($currentacl.DiscretionaryAcl.GetEnumerator() -notcontains $newAce) {Write-Host"ACE for $SID Not Found in ACL"#If it doesn't exist, Add the new ACE to the ACL ###$currentacl.DiscretionaryAcl.AddAccess([System.Security.AccessControl.AccessControlType]::Allow, $SID, $right, 0, 0)
$currentacl.DiscretionaryAcl.InsertAce($currentacl.DiscretionaryAcl.Count, $newace)Write-Host"Adding ACE for $SID to ACL"#Convert the ACL back to binary $binaryacl =New-Object-TypeName System.Byte[] -ArgumentList $currentacl.BinaryLength $currentacl.GetBinaryForm($binaryacl,0)Write-Host"Converted ACL to binary"#Write the new binary value to the registrytry {Write-Host"Writing $currentacl to $key $name"Set-ItemProperty-Path $key -Name $subkey -Value $binaryacl }catch {Write-Error"Error setting registry key $key $subkey to $binaryacl" } }else {Write-Host"ACE Exists in current ACL" }}FunctionAdd-SAMRACL {param( [Parameter(Mandatory =$true)][string]$SID )Write-Host"Starting SAMR ACL" $key ="HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" $subkey ="RestrictRemoteSam" $right =0x20000#If the RestrictRemoteSam key exists, get the current value, if not, assign an empty valuetry { $value =Get-ItemPropertyValue-Path $key -Name $subkeyif (""-eq $value) {Write-Host"RestrictRemoteSam value is null, creating default ACL" $currentacl = New-Object -TypeName System.Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAG:BAD:(A;;RC;;;BA)"
}else { $currentacl =New-Object-TypeName System.Security.AccessControl.RawSecurityDescriptor -ArgumentList $valueWrite-Host"Getting current ACL from $key $subkey" } }catch { $value ="" $currentacl = New-Object -TypeName System.Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAG:BAD:(A;;RC;;;BA)"
Write-Host"RestrictRemoteSam key not found, creating blank ACL" }#Create a new ACE for our user defined above #$newace = New-Object System.Security.AccessControl.CommonAce([System.Security.AccessControl.AceFlags]::None, [System.Security.AccessControl.AceQualifier]::AccessAllowed, $right, $SID, $false, $null)
$newace = New-Object System.Security.AccessControl.CommonAce -ArgumentList None, AccessAllowed, $right, $SID, $false, $null
if ($currentacl.DiscretionaryAcl.GetEnumerator() -notcontains $newAce) {Write-Host"ACE for $SID Not Found in ACL"#If it doesn't exist, Add the new ACE to the ACL $currentacl.DiscretionaryAcl.InsertAce($currentacl.DiscretionaryAcl.Count, $newace)Write-Host"Adding ACE for $SID to ACL"#Convert the ACL to SDDL $sddl = $currentacl.GetSddlForm([System.Security.AccessControl.AccessControlSections]::All)#Write the new SDDL value to the registrytry {Write-Host"Writing $currentacl to $key $name"Set-ItemProperty-Path $key -Name $subkey -Value $sddl }catch {Write-Error"Error setting registry key $key $subkey to $sddl" } }else {Write-Host"ACE for $SID exists in current ACL" }}FunctionGet-CurrentACLs { $netsessvalue = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\DefaultSecurity" -Name "SrvsvcSessionInfo"
$netsessacl = New-Object -TypeName System.Security.AccessControl.RawSecurityDescriptor -ArgumentList $netsessvalue, 0
Write-Host"Current ACL for NetSessionEnum" $netsessacl.DiscretionaryAcl |Select-Object-Property SecurityIdentifier, AccessMask, AceType |Format-TableWrite-Host"---------------------"try { $samrvalue =Get-ItemPropertyValue-Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa"-Name "RestrictRemoteSam" $samracl =New-Object-TypeName System.Security.AccessControl.RawSecurityDescriptor -ArgumentList $samrvalueWrite-Host"Current ACL for SAMR" $samracl.DiscretionaryAcl |Select-Object-Property SecurityIdentifier, AccessMask, AceType |Format-Table }catch {Write-Host"No ACLs for RestrictRemoteSam found" }}#If this is ran via GPO, uncomment the below line and replace DOMAIN\USER with the user you want to add to the ACLs#Invoke-AddACLs -User DOMAIN\USER%