Загрузка данных


#requires -version 2.0

<#
.SYNOPSIS
    Проверка отключения LLMNR, NetBIOS и WPAD.

.DESCRIPTION
    Совместим с Windows 7 / PowerShell 2.0 и Windows 10.

    Проверяет:
      - LLMNR
      - NetBIOS over TCP/IP
      - WPAD / WinINET AutoDetect
      - WinHTTP DisableWpad
      - PAC AutoConfigURL
      - DNS resolution of wpad.<domain>
      - NetBIOS ports 137/138/139

.NOTES
    HKCU проверки выполняются для текущего пользователя.
    Если запускать скрипт через Computer Startup GPO от SYSTEM,
    HKCU будет у SYSTEM, а не у интерактивного пользователя.
#>

$ErrorActionPreference = "SilentlyContinue"

$script:FailCount = 0
$script:WarnCount = 0


function Write-Result {
    param(
        [string]$Name,
        [string]$Status,
        [string]$Details
    )

    switch ($Status) {
        "PASS" {
            Write-Host ("[PASS] {0}: {1}" -f $Name, $Details) -ForegroundColor Green
        }

        "FAIL" {
            Write-Host ("[FAIL] {0}: {1}" -f $Name, $Details) -ForegroundColor Red
            $script:FailCount++
        }

        "WARN" {
            Write-Host ("[WARN] {0}: {1}" -f $Name, $Details) -ForegroundColor Yellow
            $script:WarnCount++
        }

        default {
            Write-Host ("[INFO] {0}: {1}" -f $Name, $Details)
        }
    }
}


function Get-RegistryValueSafe {
    param(
        [string]$Path,
        [string]$Name
    )

    try {
        return (Get-ItemProperty -Path $Path -Name $Name -ErrorAction Stop).$Name
    }
    catch {
        return $null
    }
}


Write-Host ""
Write-Host "============================================================"
Write-Host "       LLMNR / NETBIOS / WPAD SECURITY CHECK"
Write-Host "============================================================"
Write-Host ""

# ------------------------------------------------------------
# SYSTEM INFORMATION
# ------------------------------------------------------------

$computer = Get-WmiObject Win32_ComputerSystem

$computerName = $env:COMPUTERNAME
$domainName   = $computer.Domain
$os          = Get-WmiObject Win32_OperatingSystem

Write-Host "Computer : $computerName"
Write-Host "Domain   : $domainName"
Write-Host "OS       : $($os.Caption)"
Write-Host "Version  : $($os.Version)"
Write-Host "User     : $env:USERDOMAIN\$env:USERNAME"
Write-Host ""


# ============================================================
# 1. LLMNR
# ============================================================

Write-Host "------------------------------------------------------------"
Write-Host "1. LLMNR"
Write-Host "------------------------------------------------------------"

$llmnrPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient"

$enableMulticast = Get-RegistryValueSafe `
    -Path $llmnrPath `
    -Name "EnableMulticast"

if ($null -eq $enableMulticast) {

    Write-Result `
        -Name "LLMNR policy" `
        -Status "FAIL" `
        -Details "EnableMulticast отсутствует. LLMNR не считается принудительно отключённым."

}
elseif ([int]$enableMulticast -eq 0) {

    Write-Result `
        -Name "LLMNR policy" `
        -Status "PASS" `
        -Details "EnableMulticast = 0"

}
else {

    Write-Result `
        -Name "LLMNR policy" `
        -Status "FAIL" `
        -Details "EnableMulticast = $enableMulticast"

}


# ============================================================
# 2. NETBIOS
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------"
Write-Host "2. NETBIOS over TCP/IP"
Write-Host "------------------------------------------------------------"

$adapters = Get-WmiObject Win32_NetworkAdapterConfiguration `
    -Filter "IPEnabled=True"

if ($null -eq $adapters) {

    Write-Result `
        -Name "NetBIOS adapters" `
        -Status "WARN" `
        -Details "IP-enabled сетевые адаптеры не найдены."

}
else {

    $netbiosFail = $false

    foreach ($adapter in $adapters) {

        $description = $adapter.Description
        $index       = $adapter.Index

        # TcpipNetbiosOptions:
        # 0 = DHCP
        # 1 = Enable NetBIOS
        # 2 = Disable NetBIOS

        $nbt = $adapter.TcpipNetbiosOptions

        if ($nbt -eq 2) {

            Write-Result `
                -Name "NetBIOS adapter $index" `
                -Status "PASS" `
                -Details "$description -> TcpipNetbiosOptions = 2"

        }
        elseif ($nbt -eq 1) {

            Write-Result `
                -Name "NetBIOS adapter $index" `
                -Status "FAIL" `
                -Details "$description -> NetBIOS ENABLED (TcpipNetbiosOptions = 1)"

            $netbiosFail = $true

        }
        elseif ($nbt -eq 0) {

            Write-Result `
                -Name "NetBIOS adapter $index" `
                -Status "FAIL" `
                -Details "$description -> DHCP-controlled (TcpipNetbiosOptions = 0)"

            $netbiosFail = $true

        }
        else {

            Write-Result `
                -Name "NetBIOS adapter $index" `
                -Status "WARN" `
                -Details "$description -> неизвестное значение: $nbt"

        }
    }

    if ($netbiosFail) {
        Write-Result `
            -Name "NetBIOS overall" `
            -Status "FAIL" `
            -Details "Как минимум один IP-enabled адаптер не имеет принудительного Disable NetBIOS."
    }
    else {
        Write-Result `
            -Name "NetBIOS overall" `
            -Status "PASS" `
            -Details "Все IP-enabled адаптеры имеют TcpipNetbiosOptions = 2."
    }
}


# ============================================================
# 3. WPAD - WININET
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------"
Write-Host "3. WPAD / WinINET"
Write-Host "------------------------------------------------------------"

$internetSettings = `
    "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"

$autoDetect = Get-RegistryValueSafe `
    -Path $internetSettings `
    -Name "AutoDetect"

$autoConfigURL = Get-RegistryValueSafe `
    -Path $internetSettings `
    -Name "AutoConfigURL"


# AutoDetect
if ($null -eq $autoDetect) {

    Write-Result `
        -Name "WinINET AutoDetect" `
        -Status "FAIL" `
        -Details "AutoDetect отсутствует. Автоматическое обнаружение WPAD не считается отключённым."

}
elseif ([int]$autoDetect -eq 0) {

    Write-Result `
        -Name "WinINET AutoDetect" `
        -Status "PASS" `
        -Details "AutoDetect = 0"

}
else {

    Write-Result `
        -Name "WinINET AutoDetect" `
        -Status "FAIL" `
        -Details "AutoDetect = $autoDetect"

}


# PAC URL
if ([string]::IsNullOrEmpty($autoConfigURL)) {

    Write-Result `
        -Name "Explicit PAC URL" `
        -Status "PASS" `
        -Details "AutoConfigURL отсутствует."

}
else {

    Write-Result `
        -Name "Explicit PAC URL" `
        -Status "WARN" `
        -Details "Найден AutoConfigURL: $autoConfigURL"

}


# ============================================================
# 4. WPAD - WINHTTP
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------"
Write-Host "4. WPAD / WinHTTP"
Write-Host "------------------------------------------------------------"

$winhttpPath = `
    "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp"

$disableWpad = Get-RegistryValueSafe `
    -Path $winhttpPath `
    -Name "DisableWpad"


if ($null -eq $disableWpad) {

    # На Windows 7 этого параметра может вообще не быть.
    Write-Result `
        -Name "WinHTTP DisableWpad" `
        -Status "WARN" `
        -Details "DisableWpad отсутствует. Для Windows 7 это ожидаемо; для современных Windows 10 желательно наличие DisableWpad = 1."

}
elseif ([int]$disableWpad -eq 1) {

    Write-Result `
        -Name "WinHTTP DisableWpad" `
        -Status "PASS" `
        -Details "DisableWpad = 1"

}
else {

    Write-Result `
        -Name "WinHTTP DisableWpad" `
        -Status "FAIL" `
        -Details "DisableWpad = $disableWpad"

}


# ============================================================
# 5. WINHTTP CURRENT CONFIGURATION
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------"
Write-Host "5. WinHTTP proxy configuration"
Write-Host "------------------------------------------------------------"

$winhttp = netsh winhttp show proxy 2>&1

$winhttpText = $winhttp -join " "

Write-Host $winhttpText

if ($winhttpText -match "Direct access") {

    Write-Result `
        -Name "WinHTTP proxy" `
        -Status "PASS" `
        -Details "WinHTTP настроен на Direct access."

}
else {

    Write-Result `
        -Name "WinHTTP proxy" `
        -Status "WARN" `
        -Details "WinHTTP имеет proxy configuration. Это не обязательно WPAD."

}


# ============================================================
# 6. DNS WPAD
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------"
Write-Host "6. DNS WPAD"
Write-Host "------------------------------------------------------------"

if ([string]::IsNullOrEmpty($domainName)) {

    Write-Result `
        -Name "WPAD DNS" `
        -Status "WARN" `
        -Details "Не удалось определить домен."

}
else {

    $wpadName = "wpad.$domainName"

    Write-Host "Проверяем: $wpadName"

    try {

        $addresses = [System.Net.Dns]::GetHostAddresses($wpadName)

        if ($addresses.Count -gt 0) {

            $ips = @()

            foreach ($address in $addresses) {
                $ips += $address.IPAddressToString
            }

            Write-Result `
                -Name "WPAD DNS" `
                -Status "WARN" `
                -Details "$wpadName разрешается: $($ips -join ', '). Наличие DNS-записи не доказывает использование WPAD."

        }
        else {

            Write-Result `
                -Name "WPAD DNS" `
                -Status "PASS" `
                -Details "$wpadName не разрешается."

        }

    }
    catch {

        Write-Result `
            -Name "WPAD DNS" `
            -Status "PASS" `
            -Details "$wpadName не разрешается."

    }
}


# ============================================================
# 7. NETBIOS PORTS
# ============================================================

Write-Host ""
Write-Host "------------------------------------------------------------"
Write-Host "7. NetBIOS ports"
Write-Host "------------------------------------------------------------"

# Проверяем LISTENING TCP ports 139
$tcp139 = netstat -ano -p tcp 2>$null |
    Select-String "LISTENING" |
    Select-String ":139"

if ($tcp139) {

    Write-Result `
        -Name "TCP/139" `
        -Status "FAIL" `
        -Details "Обнаружен listening TCP/139."

}
else {

    Write-Result `
        -Name "TCP/139" `
        -Status "PASS" `
        -Details "Listening TCP/139 не обнаружен."

}


# UDP 137/138
$udpNetbios = netstat -ano -p udp 2>$null |
    Select-String ":(137|138)\s"

if ($udpNetbios) {

    Write-Host $udpNetbios

    Write-Result `
        -Name "UDP/137-138" `
        -Status "FAIL" `
        -Details "Обнаружен UDP listener на NetBIOS ports."

}
else {

    Write-Result `
        -Name "UDP/137-138" `
        -Status "PASS" `
        -Details "UDP/137-138 listeners не обнаружены."

}


# ============================================================
# FINAL RESULT
# ============================================================

Write-Host ""
Write-Host "============================================================"
Write-Host "                     FINAL RESULT"
Write-Host "============================================================"

Write-Host ""

Write-Host "FAIL : $script:FailCount" -ForegroundColor Red
Write-Host "WARN : $script:WarnCount" -ForegroundColor Yellow

Write-Host ""

if ($script:FailCount -eq 0 -and $script:WarnCount -eq 0) {

    Write-Host "RESULT: PASS" -ForegroundColor Green
    Write-Host "LLMNR / NetBIOS / WPAD выглядят полностью отключенными."

}
elseif ($script:FailCount -eq 0) {

    Write-Host "RESULT: PASS WITH WARNINGS" -ForegroundColor Yellow
    Write-Host "Критических нарушений не обнаружено, но есть предупреждения."

}
else {

    Write-Host "RESULT: FAIL" -ForegroundColor Red
    Write-Host "Обнаружены настройки, которые необходимо исправить."

}

Write-Host ""