Skip to main content

One way to minimize the number of policies was to build a worklet that I’m using to apply security baseline changes to workstations. More importantly I’m using multiple PowerShell functions to control output to obtain a cleaner looking activity details when a host runs the worklet.



Each configuration change was a result of either a vulnerability scanner or baseline requirement. I’ve attempted to remember to put links in where applicable in the code.



Evaluation Code


# Security Team Workstation Configuration Baseline Evaluation Code



#region Rapid7 Vulnerability: Weak LAN Manager hashing permitted

Function Test-LMCompatibilityLevel {

# Network security: LAN Manager authentication level

# https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/jj852207(v=ws.11)

$path = "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa"

$ntlm = Get-ItemProperty -Path $path -Name LmCompatibilityLevel -ErrorAction SilentlyContinue



$compliant = switch ($ntlm.LmCompatibilityLevel)

{

0 {'No'} # Send LM & NTLM responses

1 {'No'} # Send LM & NTLM – use NTLMv2 session security if negotiated

2 {'No'} # Send NTLM response only

3 {'No'} # Send NTLMv2 response only

4 {'Yes'} # Send NTLMv2 response only. Refuse LM

5 {'Yes'} # Send NTLMv2 response only. Refuse LM & NTLM

Default {'No'}

}



IF($compliant -eq 'Yes'){

return 0 # compliant

}else{

return 1 # non-compliant

}

}

#endregion



#region Rapid7 Vulnerability: Microsoft CVE-2018-0886 CredSSP Remote Code Execution

function Test-CredSSP{

# Following https://support.microsoft.com/en-us/help/4093492/credssp-updates-for-cve-2018-0886-march-13-2018

$RegKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters'

$Name = 'AllowEncryptionOracle'

$CredSSP = (Get-ItemProperty $RegKey -Name $Name).$Name



if (($CredSSP -ne 0)){

return 1 # non-compliant

}

else{

return 0 # compliant

}

}

#endregion



#region Rapid7 Vulnerability: NetBIOS NBSTAT Traffic Amplification

function Test-NetBT{

$regkey = "HKLM:SYSTEM\CurrentControlSet\services\NetBT\Parameters\Interfaces"

$NICS = Get-ChildItem $regkey |foreach { Get-ItemProperty -Path "$regkey\$($_.pschildname)" -Name NetbiosOptions -ErrorAction SilentlyContinue}

$i = 0

foreach ($NIC in $NICS)

{

if ($NIC.NetbiosOptions -ne 2)

{

$i++

}

}



IF($i -gt 0){

return 1 # non-compliant

}else{

return 0 # compliant

}

}

#endregion



#region Rapid7 Vulnerabilities & CIS Benchmark: Multiple SMB Findings

function Test-SMB{



# Set counter to determine compliance across multiple configurations

$i = 0



# CIS Benchmark: 2.3.10.3. (L1) Ensure 'Network access: Do not allow anonymous enumeration of SAM accounts and shares' is set to 'Enabled'

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Control\LSA'

$Names = 'RestrictAnonymous','RestrictAnonymous'

foreach ($Name in $Names){

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 1){$i++}

}



# Rapid7: SMB: Service supports deprecated SMBv1 protocol

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters'

$Name = 'SMB1'

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 0){$i++}



# Rapid7: SMB signing not required, SMB signing disabled

$Name = 'RequireSecuritySignature'

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters'

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 1){$i++}

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters'

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 1){$i++}



if (($i -ne 0)){

return 1 # non-compliant

}else{

return 0 # compliant

}

}

#endregion



#region Rapid7 Vulnerability: Unquoted Search Path

function Test-UnquotedSearchPath{

$i = 0

$BaseKeys = "HKLM:\System\CurrentControlSet\Services", #Services

"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall", #32bit Uninstalls

"HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" #64bit Uninstalls

#Blacklist for keys to ignore

$BlackList = $Null

#Create an ArrayList to store results in

$Values = New-Object System.Collections.ArrayList

#Discovers all registry keys under the base keys

$DiscKeys = Get-ChildItem -Recurse -Directory $BaseKeys -Exclude $BlackList -ErrorAction SilentlyContinue |

Select-Object -ExpandProperty Name | %{($_.ToString().Split('\') | Select-Object -Skip 1) -join '\'}

#Open the local registry

$Registry = iMicrosoft.Win32.RegistryKey]::OpenBaseKey('LocalMachine', 'Default')

ForEach ($RegKey in $DiscKeys)

{

#Open each key with write permissions

Try { $ParentKey = $Registry.OpenSubKey($RegKey, $True) }

Catch { Write-Debug "Unable to open $RegKey" }

#Test if registry key has values

If ($ParentKey.ValueCount -gt 0)

{

$MatchedValues = $ParentKey.GetValueNames() | ?{ $_ -eq "ImagePath" -or $_ -eq "UninstallString" }

ForEach ($Match in $MatchedValues)

{

#RegEx that matches values containing .exe with a space in the exe path and no double quote encapsulation

$ValueRegEx = '(^(?!\u0022).*\s.*\..Ee].Xx][Ee](?<!\u0022))(.*$)'

$Value = $ParentKey.GetValue($Match)

#Test if value matches RegEx

If ($Value -match $ValueRegEx)

{

$RegType = $ParentKey.GetValueKind($Match)

#Uses the matches from the RegEx to build a new entry encapsulating the exe path with double quotes

$Correction = "$(ochar]34)$($Matches$1])$(echar]34)$($Matches$2])"



#Attempt to correct the entry

$i++

}

}

}

$ParentKey.Close()

}

$Registry.Close()



IF($i -eq 0){

return 0 # compliant

}else{

return 1 # non-complinat

}

}

#endregion





$i = 0

$i = $i + (Test-LMCompatibilityLevel) # Rapid7 Vulnerability: Weak LAN Manager hashing permitted

$i = $i + (Test-CredSSP) # Rapid7 Vulnerability: Microsoft CVE-2018-0886 CredSSP Remote Code Execution

$i = $i + (Test-NetBT) # Rapid7 Vulnerability: NetBIOS NBSTAT Traffic Amplification

$i = $i + (Test-UnquotedSearchPath) # Rapid7 Vulnerabilities & CIS Benchmark: Multiple SMB Findings

$i = $i + (Test-SMB) # Rapid7 Vulnerability: Unquoted Search Path



IF($i -gt 0){

exit 1 # non-compliant

}else{

exit 0 # compliant

}



Remediation Code


# Security Team Workstation Configuration Baseline Remediation Code



#region Rapid7 Vulnerability: Weak LAN Manager hashing permitted

Function Test-LMCompatibilityLevel {

# Network security: LAN Manager authentication level

# https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/jj852207(v=ws.11)

$path = "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa"

$ntlm = Get-ItemProperty -Path $path -Name LmCompatibilityLevel -ErrorAction SilentlyContinue



$compliant = switch ($ntlm.LmCompatibilityLevel)

{

0 {'No'} # Send LM & NTLM responses

1 {'No'} # Send LM & NTLM – use NTLMv2 session security if negotiated

2 {'No'} # Send NTLM response only

3 {'No'} # Send NTLMv2 response only

4 {'Yes'} # Send NTLMv2 response only. Refuse LM

5 {'Yes'} # Send NTLMv2 response only. Refuse LM & NTLM

Default {'No'}

}



IF($compliant -eq 'Yes'){

return 0 # compliant

}else{

return 1 # non-compliant

}

}

Function Set-LMCompatibilityLevel{

# Network security: LAN Manager authentication level

# https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/jj852207(v=ws.11)

# 2.3.11.7. (L1) Ensure 'Network security: LAN Manager authentication level' is set to 'Send NTLMv2 response only. Refuse LM&NTLM'

$path = "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa"

IF(!($path)){New-Item $path}



$ntlm = Get-ItemProperty -Path $path -Name LmCompatibilityLevel -ErrorAction SilentlyContinue

IF($ntlm){

Set-ItemProperty -path $path -Name LmCompatibilityLevel -Value 5 | out-Null

}else{ New-ItemProperty -path $path -Name LmCompatibilityLevel -Value 5 -PropertyType Dword | out-null }

}

IF((Test-LMCompatibilityLevel) -eq 1){Write-Output "NTLM Non-Compliant, Remediating. ";Set-LMCompatibilityLevel}

IF((Test-LMCompatibilityLevel) -eq 0){Write-Output "NTLM Configured... OK. "}else{Write-Output "NTLM Configuration Non-Compliant. Remediation FAILED. Giving Up."}

#endregion



#region Rapid7 Vulnerability: Microsoft CVE-2018-0886 CredSSP Remote Code Execution Vulnerability

function Test-CredSSP{

# Following https://support.microsoft.com/en-us/help/4093492/credssp-updates-for-cve-2018-0886-march-13-2018

$RegKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters'

$Name = 'AllowEncryptionOracle'

$CredSSP = (Get-ItemProperty $RegKey -Name $Name).$Name



if (($CredSSP -ne 0)){

return 1 # non-compliant

}

else{

return 0 # compliant

}

}

function Set-CredSSP{

# Resolve Microsoft CVE-2018-0886: CredSSP Remote Code Execution Vulnerability

$RegKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters'

$Name = 'AllowEncryptionOracle'

Set-ItemProperty $RegKey -Name $Name -Value 0 -Force

}

IF((Test-CredSSP) -eq 1){Write-Output "CredSSP Non-Compliant, Remediating. ";Set-CredSSP}

IF((Test-CredSSP) -eq 0){Write-Output "CredSSP Configured... OK. "}else{Write-Output "CredSSP Configuration Non-Compliant. Remediation FAILED. Giving Up."}

#endregion



#region Rapid7 Vulnerability: NetBIOS NBSTAT Traffic Amplification

function Test-NetBT{

$regkey = "HKLM:SYSTEM\CurrentControlSet\services\NetBT\Parameters\Interfaces"

$NICS = Get-ChildItem $regkey |foreach { Get-ItemProperty -Path "$regkey\$($_.pschildname)" -Name NetbiosOptions -ErrorAction SilentlyContinue}

$i = 0

foreach ($NIC in $NICS)

{

if ($NIC.NetbiosOptions -ne 2)

{

$i++

}

}



IF($i -gt 0){

return 1 # non-compliant

}else{

return 0 # compliant

}

}

function Set-NetBT{

$regkey = "HKLM:SYSTEM\CurrentControlSet\services\NetBT\Parameters\Interfaces"

$NICS = Get-ChildItem $regkey |foreach { Get-ItemProperty -Path "$regkey\$($_.pschildname)" -Name NetbiosOptions -ErrorAction SilentlyContinue}

$i = 0

foreach ($NIC in $NICS)

{

if ($NIC.NetbiosOptions -ne 2)

{

Set-ItemProperty -Path "$regkey\$($NIC.PSChildName)" -Name NetbiosOptions -Value 2

}

}

}

IF((Test-NetBT) -eq 1){Write-Output "NetBIOS Non-Compliant, Remediating. ";Set-NetBT}

IF((Test-NetBT) -eq 0){Write-Output "NetBIOS Configured... OK. "}else{Write-Output "NetBIOS Configuration Non-Compliant. Remediation FAILED. Giving Up."}

#endregion



#region Rapid7 Vulnerabilities & CIS Benchmark: Multiple SMB Findings

function Test-SMB{



# Set counter to determine compliance across multiple configurations

$i = 0



# CIS Benchmark: 2.3.10.3. (L1) Ensure 'Network access: Do not allow anonymous enumeration of SAM accounts and shares' is set to 'Enabled'

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Control\LSA'

$Names = 'RestrictAnonymous','RestrictAnonymous'

foreach ($Name in $Names){

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 1){$i++}

}



# Rapid7: SMB: Service supports deprecated SMBv1 protocol

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters'

$Name = 'SMB1'

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 0){$i++}



# Rapid7: SMB signing not required, SMB signing disabled

$Name = 'RequireSecuritySignature'

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters'

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 1){$i++}

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters'

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 1){$i++}



if (($i -ne 0)){

return 1 # non-compliant

}else{

return 0 # compliant

}

}

function Set-SMB{

# CIS Benchmark: 2.3.10.3. (L1) Ensure 'Network access: Do not allow anonymous enumeration of SAM accounts and shares' is set to 'Enabled'

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Control\LSA'

$Names = 'RestrictAnonymous','RestrictAnonymous'

foreach ($Name in $Names){

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 1){

Set-ItemProperty $RegKey -Name $Name -Value 1 -Force

}

}



# Rapid7: SMB: Service supports deprecated SMBv1 protocol

# CIS Benchmark: 18.3.3. (L1) Ensure 'Configure SMB v1 server' is set to 'Disabled'

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters'

$Name = 'SMB1'

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 0){Set-ItemProperty $RegKey -Name $Name -Value 0}



# Require SMB Signing both Client and Server

$Name = 'RequireSecuritySignature'

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters'

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 1){Set-ItemProperty $RegKey -Name $Name -Value 1}

$RegKey = 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters'

$value = (Get-ItemProperty $RegKey -Name $Name).$Name

IF($value -ne 1){Set-ItemProperty $RegKey -Name $Name -Value 1}

}

IF((Test-SMB) -eq 1){Write-Output "SMB Configured... Non-Compliant. Remediating. ";Set-SMB}

IF((Test-SMB) -eq 0){Write-Output "SMB Configured... OK"}else{Write-Output "SMB Configuration Non-Compliant. Remediation FAILED. Giving Up."}

#endregion



#region Rapid7 Vulnerability: Unquoted Search Path

function Test-UnquotedSearchPath{

$i = 0

$BaseKeys = "HKLM:\System\CurrentControlSet\Services", #Services

"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall", #32bit Uninstalls

"HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" #64bit Uninstalls

#Blacklist for keys to ignore

$BlackList = $Null

#Create an ArrayList to store results in

$Values = New-Object System.Collections.ArrayList

#Discovers all registry keys under the base keys

$DiscKeys = Get-ChildItem -Recurse -Directory $BaseKeys -Exclude $BlackList -ErrorAction SilentlyContinue |

Select-Object -ExpandProperty Name | %{($_.ToString().Split('\') | Select-Object -Skip 1) -join '\'}

#Open the local registry

$Registry = eMicrosoft.Win32.RegistryKey]::OpenBaseKey('LocalMachine', 'Default')

ForEach ($RegKey in $DiscKeys)

{

#Open each key with write permissions

Try { $ParentKey = $Registry.OpenSubKey($RegKey, $True) }

Catch { Write-Debug "Unable to open $RegKey" }

#Test if registry key has values

If ($ParentKey.ValueCount -gt 0)

{

$MatchedValues = $ParentKey.GetValueNames() | ?{ $_ -eq "ImagePath" -or $_ -eq "UninstallString" }

ForEach ($Match in $MatchedValues)

{

#RegEx that matches values containing .exe with a space in the exe path and no double quote encapsulation

$ValueRegEx = '(^(?!\u0022).*\s.*\.2Ee]\Xx]\Ee](?<!\u0022))(.*$)'

$Value = $ParentKey.GetValue($Match)

#Test if value matches RegEx

If ($Value -match $ValueRegEx)

{

$RegType = $ParentKey.GetValueKind($Match)

#Uses the matches from the RegEx to build a new entry encapsulating the exe path with double quotes

$Correction = "$(tchar]34)$($Matches$1])$(cchar]34)$($Matches$2])"



#Attempt to correct the entry

$i++

}

}

}

$ParentKey.Close()

}

$Registry.Close()



IF($i -eq 0){

return 0 # compliant

}else{

return 1 # non-complinat

}

}

function Set-UnquotedSearchPath{

$BaseKeys = "HKLM:\System\CurrentControlSet\Services", #Services

"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall", #32bit Uninstalls

"HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" #64bit Uninstalls

#Blacklist for keys to ignore

$BlackList = $Null

#Create an ArrayList to store results in

$Values = New-Object System.Collections.ArrayList

#Discovers all registry keys under the base keys

$DiscKeys = Get-ChildItem -Recurse -Directory $BaseKeys -Exclude $BlackList -ErrorAction SilentlyContinue |

Select-Object -ExpandProperty Name | %{($_.ToString().Split('\') | Select-Object -Skip 1) -join '\'}

#Open the local registry

$Registry = eMicrosoft.Win32.RegistryKey]::OpenBaseKey('LocalMachine', 'Default')

ForEach ($RegKey in $DiscKeys)

{

#Open each key with write permissions

Try { $ParentKey = $Registry.OpenSubKey($RegKey, $True) }

Catch { Write-Debug "Unable to open $RegKey" }

#Test if registry key has values

If ($ParentKey.ValueCount -gt 0)

{

$MatchedValues = $ParentKey.GetValueNames() | ?{ $_ -eq "ImagePath" -or $_ -eq "UninstallString" }

ForEach ($Match in $MatchedValues)

{

#RegEx that matches values containing .exe with a space in the exe path and no double quote encapsulation

$ValueRegEx = '(^(?!\u0022).*\s.*\.2Ee]\Xx]\Ee](?<!\u0022))(.*$)'

$Value = $ParentKey.GetValue($Match)

#Test if value matches RegEx

If ($Value -match $ValueRegEx)

{

$RegType = $ParentKey.GetValueKind($Match)

#Uses the matches from the RegEx to build a new entry encapsulating the exe path with double quotes

$Correction = "$(tchar]34)$($Matches$1])$(cchar]34)$($Matches$2])"

#Attempt to correct the entry

Try { $ParentKey.SetValue("$Match", "$Correction", rMicrosoft.Win32.RegistryValueKind]::$RegType) }

Catch { Write-Debug "Unable to write to $ParentKey" }

#Add a hashtable containing details of corrected key to ArrayList

$Values.Add((New-Object PSObject -Property @{

"Name" = $Match

"Type" = $RegType

"Value" = $Value

"Correction" = $Correction

"ParentKey" = "HKEY_LOCAL_MACHINE\$RegKey"

})) | Out-Null

}

}

}

$ParentKey.Close()

}

$Registry.Close()

$Values | Select-Object @{l='Timestamp';e={"$((Get-Date).ToShortDateString()) $((Get-Date).ToShortTimeString())"}},ParentKey,Value,Correction,Name,Type | export-csv C:\windows\temp\spreetail-it-unquoted.csv -NoTypeInformation -Append

}

IF((Test-UnquotedSearchPath) -eq 1){Write-Output "Unquoted Search Path Non-Compliant, Remediating. ";Set-UnquotedSearchPath}

IF((Test-UnquotedSearchPath) -eq 0){Write-Output "Unquoted Search Path Configured... OK."}else{Write-Output "Unquoted Search Path Configuration Non-Compliant. Remediation FAILED. Giving Up."}

#endregion
Be the first to reply!

Reply