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

245 lines
12 KiB
PowerShell

function Disable-RiskyPorts {
<#
.SYNOPSIS
Disable risky firewall ports (LLMNR, NetBIOS, UPnP/SSDP)
.DESCRIPTION
Closes firewall ports that are commonly exploited for MITM attacks,
network enumeration, and credential theft:
- LLMNR (Port 5355) - HIGH RISK: Responder poisoning, credential theft
- NetBIOS (Port 137-139) - MEDIUM RISK: Network enumeration
- UPnP/SSDP (Port 1900, 2869) - MEDIUM RISK: Port forwarding vulnerabilities
Uses language-independent port-based filtering to avoid DisplayName issues.
.PARAMETER SkipUPnP
Skip disabling UPnP/SSDP ports (for users who need DLNA/media streaming)
.EXAMPLE
Disable-RiskyPorts
Disables all risky firewall ports including UPnP
.EXAMPLE
Disable-RiskyPorts -SkipUPnP
Disables LLMNR and NetBIOS but keeps UPnP enabled
.NOTES
Defense in Depth: Security Baseline disables protocols via registry,
but firewall rules may still be active. This function closes the ports
at the firewall level for additional protection.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[switch]$SkipUPnP
)
try {
Write-Log -Level INFO -Message "Disabling risky firewall ports..." -Module "AdvancedSecurity"
$disabledRules = 0
$errors = @()
# PERFORMANCE: Get all firewall rules ONCE and cache port filters
Write-Log -Level INFO -Message "Loading firewall rules for analysis..." -Module "AdvancedSecurity"
$allRules = Get-NetFirewallRule | Where-Object { $_.Direction -eq 'Inbound' -and $_.Enabled -eq $true }
# Pre-fetch port filters to avoid repeated Get-NetFirewallPortFilter calls
# NOTE: We cache both the rule and its ports so we can later filter ONLY
# ALLOW rules for disabling. NoID block rules must remain enabled.
$rulesWithPorts = @()
foreach ($rule in $allRules) {
$portFilter = $rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue
if ($portFilter) {
$rulesWithPorts += [PSCustomObject]@{
Rule = $rule
LocalPort = $portFilter.LocalPort
RemotePort = $portFilter.RemotePort
}
}
}
Write-Log -Level INFO -Message "Analyzed $($rulesWithPorts.Count) firewall rules with port filters" -Module "AdvancedSecurity"
# Backup firewall rules
Write-Log -Level INFO -Message "Backing up firewall rules..." -Module "AdvancedSecurity"
$backupData = @{
FirewallRules = $allRules | Select-Object Name, DisplayName, Enabled, Direction, Action
BackupDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
}
$backupJson = $backupData | ConvertTo-Json -Depth 10
Register-Backup -Type "Firewall_Rules" -Data $backupJson -Name "RiskyPorts_Firewall"
# 1. LLMNR (Port 5355 UDP) - HIGH RISK
Write-Log -Level INFO -Message "Disabling LLMNR firewall rules (Port 5355)..." -Module "AdvancedSecurity"
try {
# Filter from pre-loaded cache (ONLY ALLOW rules - keep NoID block rules enabled)
$llmnrRules = $rulesWithPorts | Where-Object {
($_.LocalPort -eq 5355 -or $_.RemotePort -eq 5355) -and $_.Rule.Action -eq 'Allow'
} | Select-Object -ExpandProperty Rule
foreach ($rule in $llmnrRules) {
Disable-NetFirewallRule -Name $rule.Name -ErrorAction Stop
Write-Log -Level DEBUG -Message "Disabled LLMNR rule: $($rule.DisplayName)" -Module "AdvancedSecurity"
$disabledRules++
}
if ($llmnrRules.Count -eq 0) {
Write-Log -Level INFO -Message "No active LLMNR rules found (already disabled or not present)" -Module "AdvancedSecurity"
}
else {
Write-Log -Level SUCCESS -Message "Disabled $($llmnrRules.Count) LLMNR firewall rules" -Module "AdvancedSecurity"
}
}
catch {
$errors += "LLMNR: $_"
Write-Log -Level WARNING -Message "Failed to disable some LLMNR rules: $_" -Module "AdvancedSecurity"
}
# 2. NetBIOS (Port 137-139) - MEDIUM RISK
Write-Log -Level INFO -Message "Disabling NetBIOS firewall rules (Port 137-139)..." -Module "AdvancedSecurity"
try {
# Filter from pre-loaded cache (ONLY ALLOW rules - keep NoID block rules enabled)
$netbiosRules = $rulesWithPorts | Where-Object {
($_.LocalPort -in @(137, 138, 139)) -or ($_.RemotePort -in @(137, 138, 139))
} | Where-Object { $_.Rule.Action -eq 'Allow' } | Select-Object -ExpandProperty Rule
foreach ($rule in $netbiosRules) {
Disable-NetFirewallRule -Name $rule.Name -ErrorAction Stop
Write-Log -Level DEBUG -Message "Disabled NetBIOS rule: $($rule.DisplayName)" -Module "AdvancedSecurity"
$disabledRules++
}
if ($netbiosRules.Count -eq 0) {
Write-Log -Level INFO -Message "No active NetBIOS rules found (already disabled or not present)" -Module "AdvancedSecurity"
}
else {
Write-Log -Level SUCCESS -Message "Disabled $($netbiosRules.Count) NetBIOS firewall rules" -Module "AdvancedSecurity"
}
}
catch {
$errors += "NetBIOS: $_"
Write-Log -Level WARNING -Message "Failed to disable some NetBIOS rules: $_" -Module "AdvancedSecurity"
}
# Also disable NetBIOS over TCP/IP on all network adapters
Write-Log -Level INFO -Message "Disabling NetBIOS over TCP/IP on all adapters..." -Module "AdvancedSecurity"
try {
$adapters = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "IPEnabled = TRUE"
$adaptedCount = 0
foreach ($adapter in $adapters) {
try {
$result = Invoke-CimMethod -InputObject $adapter -MethodName SetTcpipNetbios -Arguments @{TcpipNetbiosOptions = 2 }
if ($result.ReturnValue -eq 0) {
Write-Log -Level DEBUG -Message "Disabled NetBIOS on adapter: $($adapter.Description)" -Module "AdvancedSecurity"
$adaptedCount++
}
}
catch {
Write-Log -Level WARNING -Message "Could not disable NetBIOS on adapter $($adapter.Description): $_" -Module "AdvancedSecurity"
}
}
Write-Log -Level SUCCESS -Message "Disabled NetBIOS over TCP/IP on $adaptedCount adapters" -Module "AdvancedSecurity"
}
catch {
$errors += "NetBIOS TCP/IP: $_"
Write-Log -Level WARNING -Message "Failed to disable NetBIOS over TCP/IP: $_" -Module "AdvancedSecurity"
}
# 3. UPnP/SSDP (Port 1900, 2869) - MEDIUM RISK (conditional)
if (-not $SkipUPnP) {
Write-Log -Level INFO -Message "Disabling UPnP/SSDP firewall rules (Port 1900, 2869)..." -Module "AdvancedSecurity"
try {
# Filter from pre-loaded cache (ONLY ALLOW rules - keep NoID block rules enabled)
$upnpRules = $rulesWithPorts | Where-Object {
($_.LocalPort -in @(1900, 2869)) -or ($_.RemotePort -in @(1900, 2869))
} | Where-Object { $_.Rule.Action -eq 'Allow' } | Select-Object -ExpandProperty Rule
foreach ($rule in $upnpRules) {
Disable-NetFirewallRule -Name $rule.Name -ErrorAction Stop
Write-Log -Level DEBUG -Message "Disabled UPnP/SSDP rule: $($rule.DisplayName)" -Module "AdvancedSecurity"
$disabledRules++
}
if ($upnpRules.Count -eq 0) {
Write-Log -Level INFO -Message "No active UPnP/SSDP rules found (already disabled or not present)" -Module "AdvancedSecurity"
}
else {
Write-Log -Level SUCCESS -Message "Disabled $($upnpRules.Count) UPnP/SSDP firewall rules" -Module "AdvancedSecurity"
}
}
catch {
$errors += "UPnP/SSDP: $_"
Write-Log -Level WARNING -Message "Failed to disable some UPnP/SSDP rules: $_" -Module "AdvancedSecurity"
}
# Ensure a dedicated inbound block rule exists for SSDP (UDP 1900)
try {
$ssdpRuleName = "NoID Privacy - Block SSDP (UDP 1900)"
$existingSsdpRule = Get-NetFirewallRule -DisplayName $ssdpRuleName -ErrorAction SilentlyContinue
if (-not $existingSsdpRule) {
New-NetFirewallRule -DisplayName $ssdpRuleName `
-Direction Inbound `
-Action Block `
-Enabled True `
-Protocol UDP `
-LocalPort 1900 `
-Profile Any `
-ErrorAction Stop | Out-Null
Write-Log -Level SUCCESS -Message "Created SSDP block rule: $ssdpRuleName" -Module "AdvancedSecurity"
}
else {
Write-Log -Level INFO -Message "SSDP block rule already exists: $ssdpRuleName" -Module "AdvancedSecurity"
}
}
catch {
$errors += "SSDP BlockRule: $_"
Write-Log -Level WARNING -Message "Failed to ensure SSDP block rule: $_" -Module "AdvancedSecurity"
}
}
else {
Write-Log -Level INFO -Message "UPnP/SSDP blocking skipped (user choice for DLNA compatibility)" -Module "AdvancedSecurity"
}
# Summary
if ($errors.Count -eq 0) {
if ($disabledRules -gt 0) {
Write-Log -Level SUCCESS -Message "Disabled $disabledRules risky firewall rules" -Module "AdvancedSecurity"
}
else {
Write-Log -Level SUCCESS -Message "No risky firewall rules required changes (system already protected at firewall level)" -Module "AdvancedSecurity"
}
Write-Host ""
Write-Host "Risky Firewall Ports Disabled: $disabledRules rules" -ForegroundColor Green
if ($disabledRules -eq 0) {
Write-Host " System already protected - no risky ALLOW rules were found for these ports:" -ForegroundColor Gray
}
Write-Host " - LLMNR (5355)" -ForegroundColor Gray
Write-Host " - NetBIOS (137-139)" -ForegroundColor Gray
if (-not $SkipUPnP) {
Write-Host " - UPnP/SSDP (1900, 2869)" -ForegroundColor Gray
}
else {
Write-Host " - UPnP/SSDP (1900, 2869) - SKIPPED" -ForegroundColor Yellow
}
Write-Host ""
return $true
}
else {
Write-Log -Level WARNING -Message "Completed with $($errors.Count) errors. Disabled $disabledRules rules." -Module "AdvancedSecurity"
return $true # Partial success is still success
}
}
catch {
Write-Log -Level ERROR -Message "Failed to disable risky ports: $_" -Module "AdvancedSecurity" -Exception $_.Exception
return $false
}
}