Skip to main content

Windows Security Worklet - NTLM, SMB, NetBIOS, CredSSP and Unquoted Search Path

  • December 2, 2020
  • 0 replies
  • 642 views

jack.smith
Forum|alt.badge.img+1

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 = [Microsoft.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 = "$([char]34)$($Matches[1])$([char]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 = [Microsoft.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 = "$([char]34)$($Matches[1])$([char]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 = [Microsoft.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 = "$([char]34)$($Matches[1])$([char]34)$($Matches[2])"
                    #Attempt to correct the entry
                    Try { $ParentKey.SetValue("$Match", "$Correction", [Microsoft.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

0 replies

Be the first to reply!

Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings