noid-privacy/Modules/AdvancedSecurity/Private/Test-RiskyPorts.ps1

134 lines
5.2 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function Test-RiskyPorts {
<#
.SYNOPSIS
Test risky firewall ports compliance
.DESCRIPTION
Checks if risky firewall ports (LLMNR, NetBIOS, UPnP/SSDP) are closed
.EXAMPLE
Test-RiskyPorts
#>
[CmdletBinding()]
param()
try {
$result = [PSCustomObject]@{
Feature = "Risky Firewall Ports"
Status = "Unknown"
Details = @()
OpenPorts = @()
DisabledRules = 0
EnabledRules = 0
Compliant = $false
}
$riskyPorts = @(5355, 137, 138, 139, 1900, 2869)
# Detect NoID SSDP firewall block rule for UDP 1900
$ssdpRuleName = "NoID Privacy - Block SSDP (UDP 1900)"
$ssdpBlockRule = Get-NetFirewallRule -DisplayName $ssdpRuleName -ErrorAction SilentlyContinue
$ssdpBlockActive = $false
if ($ssdpBlockRule -and $ssdpBlockRule.Enabled -eq 'True' -and $ssdpBlockRule.Action -eq 'Block') {
$ssdpBlockActive = $true
}
# PERFORMANCE FIX: Batch query instead of per-rule queries
# Old approach: Get-NetFirewallRule | ForEach { Get-NetFirewallPortFilter } = 300 queries × 200ms = 60s!
# New approach: Get all port filters once, then filter = 2-3s total
# Get all inbound firewall rules (pre-filter by direction)
$inboundRules = Get-NetFirewallRule -Direction Inbound -ErrorAction SilentlyContinue
# Get all port filters in one batch query
$allPortFilters = @{}
Get-NetFirewallPortFilter -ErrorAction SilentlyContinue | ForEach-Object {
$allPortFilters[$_.InstanceID] = $_
}
# Now filter rules by risky ports (fast lookup)
$riskyRules = $inboundRules | Where-Object {
$portFilter = $allPortFilters[$_.InstanceID]
if ($portFilter) {
($portFilter.LocalPort -in $riskyPorts) -or ($portFilter.RemotePort -in $riskyPorts)
}
else {
$false
}
}
foreach ($rule in $riskyRules) {
if ($rule.Enabled -eq $true) {
$portFilter = $allPortFilters[$rule.InstanceID]
if ($rule.Action -eq 'Allow') {
$result.EnabledRules++
$result.Details += "WARNING: Allow rule '$($rule.DisplayName)' is ENABLED (Port: $($portFilter.LocalPort))"
}
else {
$result.Details += "INFO: Block rule '$($rule.DisplayName)' is ENABLED (Port: $($portFilter.LocalPort))"
}
}
else {
$result.DisabledRules++
}
}
# Check actual port listeners
foreach ($port in $riskyPorts) {
if ($port -in @(137, 138, 139, 2869)) {
# TCP ports
$listener = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
if ($listener) {
$result.OpenPorts += "TCP $port"
$result.Details += "OPEN: TCP port $port is LISTENING!"
}
}
else {
# UDP ports (5355, 1900)
$listener = Get-NetUDPEndpoint -LocalPort $port -ErrorAction SilentlyContinue
if ($listener) {
$result.OpenPorts += "UDP $port"
$result.Details += "OPEN: UDP port $port is LISTENING!"
}
}
}
# Determine compliance
$udp1900Open = $result.OpenPorts -contains "UDP 1900"
$otherOpenPorts = $result.OpenPorts | Where-Object { $_ -ne "UDP 1900" }
if ($result.OpenPorts.Count -eq 0 -and $result.EnabledRules -eq 0) {
# Ideal case: no listeners and no allow rules
$result.Status = "Secure"
$result.Compliant = $true
$result.Details += "All risky ports closed and firewall rules disabled"
}
elseif ($udp1900Open -and -not $otherOpenPorts -and $result.EnabledRules -eq 0 -and $ssdpBlockActive) {
# Only open endpoint is UDP 1900, but protected by NoID block rule (inbound)
$result.Status = "Secure (blocked by firewall)"
$result.Compliant = $true
$result.Details += "UDP 1900 is listening locally but inbound traffic is blocked by '$ssdpRuleName'"
}
elseif ($result.OpenPorts.Count -eq 0 -and $result.EnabledRules -gt 0) {
$result.Status = "Partially Secure"
$result.Compliant = $false
$result.Details += "Ports closed but $($result.EnabledRules) firewall rules still enabled"
}
else {
$result.Status = "Insecure"
$result.Compliant = $false
}
return $result
}
catch {
Write-Log -Level ERROR -Message "Failed to test risky ports: $_" -Module "AdvancedSecurity" -Exception $_.Exception
return [PSCustomObject]@{
Feature = "Risky Firewall Ports"
Status = "Error"
Details = @("Failed to test: $_")
Compliant = $false
}
}
}