はじめに
前回作成したネットワークスキャナーに、ネットワークセキュリティ評価レポート作成機能を追加しました。同一ネットワーク上の全デバイスのMACアドレスを収集し、各デバイスのベンダー(製造元)情報を自動で取得できるだけでなく、ポートスキャン機能も備えているため、デバイスのセキュリティ状態も確認できます。さらに今回は、スキャン結果から分かりやすいHTMLレポートを自動生成し、サービスバージョン情報も詳細に取得できるようになりました。
「知らないデバイスが接続されていないか」のチェック、「デバイスが不要なポートを開放していないか」のチェック、そして「使用中のサービスのバージョン情報」の可視化に活用するためのスクリプトです。
<ネットワークセキュリティ評価レポートのサンプル>
<検出されたデバイス一覧>
このスクリプトで出来ること
- ローカルネットワーク内の全IPアドレスに対してPingを実行
- 応答があったデバイスのMACアドレスを取得
- IEEE OUIデータベースを使用して、MACアドレスからベンダー情報を特定
- 各デバイスに対してポートスキャンを実行し、オープンポートを検出
- オープンポートからサービスバナー情報を取得し、サービスのバージョンを特定(新)
- 詳細なサービス分析(SMB, RDP, VNC, MySQLなど)を実行(新)
- 検出したデバイス情報とポート情報をCSVファイルに出力
- スキャン結果を包括的なHTMLセキュリティレポートとして自動生成(新)
- 将来的にはサービスの脆弱性スキャンも実施予定(実装中)(新)
- 結果をコンソール上にも分かりやすく表示
全スクリプトのダウンロード
<ダウンロードファイルの構成>
C:.
│ networkscanner.ps1
│
├─Data
└─Modules
Banner-Analyzer.ps1
Banner-Grabber.ps1
Enhanced-Scanner.ps1
MAC-Vendor.ps1
MySQL-Detailed-Scanner.ps1
Port-Scanner.ps1
RDP-Detailed-Scanner.ps1
Report-Generator.ps1
SMB-Detailed-Scanner.ps1
VNC-Detailed-Scanner.ps1
Vulnerability-Scanner.ps1
スクリプトの解説
主要機能
ネットワークスキャナーは、複数のPowerShellモジュールから構成されており、各モジュールが特定の機能を担当しています。
- Port-Scanner.ps1: TCP接続を使ったポートスキャン機能を提供
- Banner-Grabber.ps1: オープンポートからサービスバナーを取得
- Banner-Analyzer.ps1: 取得したバナーからソフトウェア情報を解析
- MAC-Vendor.ps1: MACアドレスからベンダー情報を識別
- Enhanced-Scanner.ps1: Nmapを活用した高度なスキャン機能
- [サービス名]-Detailed-Scanner.ps1: 各種サービス(SMB, RDP, VNC, MySQL)の詳細分析
- Report-Generator.ps1: 包括的なHTMLセキュリティレポート生成機能
- Vulnerability-Scanner.ps1: バナー情報と脆弱性データベースを照合(開発中)
パラメータ設定
ネットワークスキャナーは、豊富なパラメータを持ち、ニーズに合わせたカスタマイズが可能です。これらのパラメータを組み合わせることで、軽量なスキャンから詳細な脆弱性診断まで、様々なレベルのスキャンを実行できます。
オプション | 説明 |
–StartIP “192.168.1.1” | スキャン開始IPアドレス |
–EndIP “192.168.1.254” | スキャン終了IPアドレス |
–Subnet “192.168.1.0/24” | サブネット指定(代替方法) |
–PortsToScan @(22, 80, 443, 3389) | スキャン対象ポート指定 |
–EnablePortScan | ポートスキャンを有効化 |
–EnableBannerGrabbing | バナー取得を有効化 |
–EnableDetailedBannerAnalysis | バナー詳細解析を有効化 |
–EnableVulnScan | 脆弱性スキャンを有効化(開発中) |
–UpdateVulnDatabase | 脆弱性DBを更新 |
–SuppressVulnDetails | 脆弱性の詳細表示を抑制 |
–EnableDetailedSMBScan | SMB詳細スキャン |
–EnableDetailedRDPScan | RDP詳細スキャン |
–EnableDetailedVNCScan | VNC詳細スキャン |
–EnableDetailedMySQLScan | MySQL詳細スキャン |
–MySQLUsername “user” | MySQL認証用ユーザー名 |
–MySQLPassword “pass” | MySQL認証用パスワード |
–EnableEnhancedScanning | Nmapを使用した拡張スキャン |
–NoConsoleOutput | コンソール出力を抑制 |
–OutputPath “C:\Scan\Results” | 出力先ディレクトリ |
使用方法
基本的な実行方法
- スクリプトをダウンロードして任意の場所に保存します(例:networkscanner.ps1)
- PowerShellを管理者権限で起動
- スクリプトのあるディレクトリに移動
- 以下のコマンドを実行
.\networkscanner.ps1
実行時のオプション例
基本的なポートスキャン(軽量版)
.\networkscanner.ps1 -EnablePortScan -PortsToScan @(22, 80, 443, 3389)
バナー情報取得とバージョン解析
.\networkscanner.ps1 -EnablePortScan -EnableBannerGrabbing -EnableDetailedBannerAnalysis
セキュリティレポート付きの詳細スキャン
.\networkscanner.ps1 -EnablePortScan -EnableBannerGrabbing -EnableDetailedBannerAnalysis
RDPとSMBに特化した詳細スキャン
.\networkscanner.ps1 -Subnet "192.168.1.0/24" -EnablePortScan -EnableDetailedSMBScan -EnableDetailedRDPScan
完全な詳細スキャン(すべての機能を有効化)
.\networkscanner.ps1 -EnablePortScan -EnableBannerGrabbing -EnableDetailedBannerAnalysis -EnableEnhancedScanning -EnableDetailedSMBScan -EnableDetailedRDPScan -EnableDetailedVNCScan -EnableDetailedMySQLScan
実行結果
スクリプトを実行すると、以下のような出力が表示されます。
拡張ネットワークデバイス検出ツール(脆弱性スキャン・バナー詳細解析機能付き)
-----------------------------------------------------
ポートスキャンが有効: 20, 21, 22, 23, 25, 53, 67, 68, 69, 80, 110...
バナー取得が有効: オープンポートのサービス情報を取得します
バナー詳細解析が有効: ソフトウェアバージョン情報を抽出します
スキャンを開始: 192.168.1.1 から 192.168.1.254
192.168.1.1 は応答中...
MAC: 00-11-22-33-44-55 ベンダー: Cisco Systems
ポートスキャン中... 完了
オープンポート: 22(SSH), 80(HTTP), 443(HTTPS)
バナー詳細解析結果:
ポート 22(SSH): openssh:openssh バージョン: 8.2p1
ポート 80(HTTP): nginx:nginx バージョン: 1.18.0
ポート 443(HTTPS): nginx:nginx バージョン: 1.18.0
192.168.1.25 は応答中...
MAC: AA-BB-CC-DD-EE-FF ベンダー: Microsoft
詳細SMBスキャンを実行中...
SMB詳細情報: OS=Windows 10 or Server 2016+, Version=SMB 3.1.1
ポートスキャン中... 完了
オープンポート: 135(EPMAP), 139(NetBIOS), 445(SMB), 3389(RDP)
詳細RDPスキャンを実行中... 完了
RDP詳細情報: OS=Windows 10, Version=RDP 10.0 (Windows 10/11/Server 2016+), Security=CredSSP
バナー詳細解析結果:
ポート 445(SMB): microsoft:smb バージョン: SMB 3.1.1
ポート 3389(RDP): microsoft:rdp バージョン: 10.0
...
検出結果: 25台
IPAddress MACAddress Vendor HostName OpenPorts
--------- ---------- ------ -------- ---------
192.168.1.1 00-11-22-33-44-55 Cisco Systems router1.local 22(SSH), 80(HTTP), 443(HTTPS)
192.168.1.25 AA-BB-CC-DD-EE-FF Microsoft win10-pc.local 135(EPMAP), 139(NetBIOS), 445(SMB), 3389(RDP)
...
バナー詳細解析結果:
192.168.1.1 (router1.local):
ポート 22(SSH): openssh:openssh バージョン: 8.2p1 [SSH Authentication]
ポート 80(HTTP): nginx:nginx バージョン: 1.18.0 [HTTP Header]
ポート 443(HTTPS): nginx:nginx バージョン: 1.18.0 [HTTP Header]
...
CSVファイル出力完了: C:\Path\To\Results\network_devices.csv
セキュリティレポート出力完了: C:\Path\To\Results\security_report.html
レポートをブラウザで確認するには、以下のコマンドを実行してください:
Start-Process C:\Path\To\Results\security_report.html
ネットワークセキュリティ評価レポート(実装中)
本スクリプトの最大の特長の一つが、自動生成される「ネットワークセキュリティ評価レポート」です。このレポートはHTML形式で出力され、以下のような情報が視覚的に整理されています。
レポートの主な内容
- スキャン概要:
- 検出されたデバイス数
- スキャン実施日時
- 検出された脆弱性の総数と重要度別の内訳(脆弱性スキャンが有効な場合)
- ホスト別セキュリティ評価:
- IPアドレス、ホスト名、MACアドレス、ベンダー情報
- オープンポートとサービス情報のリスト
- バナー解析で特定されたサービス識別情報
- ポート番号
- サービスタイプ
- 製品名とベンダー
- バージョン情報
- 脆弱性情報 (脆弱性スキャン機能実装後):
- 重要度別に分類された脆弱性リスト
- 重要(Critical)
- 高リスク(High)
- 中リスク(Medium)
- 低リスク(Low)
- 各脆弱性の詳細情報
- CVE ID
- CVSSスコア
- 影響を受けるバージョン
- 脆弱性の説明
- 重要度別に分類された脆弱性リスト
<ネットワークセキュリティ評価レポートのサンプル>
各スクリプトの解説
networkscanner.ps1:メインスクリプト
すべてのモジュールを統合して実行するメインスクリプトです。
<ポイント>
- IP範囲の柔軟な指定方法(開始-終了IP、サブネット表記)
- アクティブなホストのみを詳細スキャンして効率化
- 結果をCSVファイルとHTMLレポートの両方で出力
- スキャンの実行順序を最適化(ポートスキャン→バナー取得→詳細スキャン)
# NetworkScanner.ps1
# パラメータ定義
param (
[string]$StartIP = "192.168.1.1",
[string]$EndIP = "192.168.1.254",
[string]$Subnet = "",
[int[]]$PortsToScan = @(20, 21, 22, 23, 25, 53, 80, 443, 445, 3306, 3389, 5900, 8080),
[switch]$EnablePortScan = $false,
[switch]$EnableBannerGrabbing = $false,
[switch]$EnableDetailedBannerAnalysis = $false,
[switch]$EnableEnhancedScanning = $false,
[switch]$EnableVulnScan = $false,
[switch]$EnableDetailedSMBScan = $false,
[switch]$EnableDetailedRDPScan = $false
# その他のパラメータ...
)
# 必要なモジュールの読み込み
$modulesDir = Join-Path $PSScriptRoot "Modules"
$modulesToLoad = @(
"$modulesDir\Port-Scanner.ps1",
"$modulesDir\Banner-Grabber.ps1",
# その他のモジュール...
)
# モジュールのロード
foreach ($module in $modulesToLoad) {
if (Test-Path $module) {
. $module
} else {
Write-Host "モジュールファイルが見つかりません: $module" -ForegroundColor Red
exit
}
}
# IPアドレス範囲の設定
$IPRange = @()
if ($Subnet) {
# サブネット表記の場合
if ($Subnet -match "^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/(\d{1,2})$") {
# サブネット処理...
}
} elseif ($StartIP -and $EndIP) {
# 開始IPと終了IPが指定されている場合
# IPレンジ処理...
}
# スキャン結果を格納する配列
$scanResults = @()
# 各IPをスキャン
foreach ($ip in $IPRange) {
# pingでホストの存在を確認
$ping = Test-Connection -ComputerName $ip -Count 1 -Quiet
if ($ping) {
# MACアドレスの取得
$arpResult = arp -a $ip | Out-String
$macPattern = "([0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2})"
$macAddress = if ($arpResult -match $macPattern) { $matches[1] } else { "不明" }
# ベンダー情報の取得
$vendorInfo = if ($macAddress -ne "不明") {
Get-MACVendor -MACAddress $macAddress -OuiDatabasePath $OuiDatabasePath
} else {
"不明"
}
# オープンポートのスキャン
$openPorts = @()
$bannerDetails = @()
if ($EnablePortScan) {
$openPorts = Get-OpenPorts -IPAddress $ip -Ports $PortsToScan -GetBanners:$EnableBannerGrabbing
if ($EnableDetailedBannerAnalysis -and $EnableBannerGrabbing -and $openPorts) {
# バナー解析処理...
}
}
# SMB詳細スキャン
$smbDetailedResults = $null
if ($EnableDetailedSMBScan -and ($openPorts | Where-Object { $_.Port -eq 139 -or $_.Port -eq 445 })) {
$smbDetailedResults = Get-SMBDetailedInfo -IPAddress $ip
}
# RDP詳細スキャン
$rdpDetailedResults = $null
if ($EnableDetailedRDPScan -and ($openPorts | Where-Object { $_.Port -eq 3389 })) {
$rdpDetailedResults = Get-RDPDetailedInfo -IPAddress $ip
}
# その他の詳細スキャン...
# スキャン結果オブジェクトの作成
$scanResult = [PSCustomObject]@{
IPAddress = $ip
HostName = $hostName
MACAddress = $macNormalized
Vendor = $vendorInfo
OpenPorts = $openPortsStr
BannerDetails = $bannerDetails
Vulnerabilities = $vulnerabilities
DetectedTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss"
}
# 結果を配列に追加
$scanResults += $scanResult
}
}
# CSVファイルに出力
$csvPath = Join-Path -Path $OutputPath -ChildPath "network_devices.csv"
$scanResults | Select-Object IPAddress, HostName, MACAddress, Vendor, OpenPorts, DetectedTime |
Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8
# セキュリティレポートの生成
$reportPath = Join-Path -Path $OutputPath -ChildPath "security_report.html"
Generate-VulnerabilityReport -ScanResults $scanResults -ReportPath $reportPath
Port-Scanner.ps1:ポートスキャン機能
TCP接続を使って指定したIPアドレスのポート開放状況を確認します。
<ポイント>
- 非同期TCP接続を使用してタイムアウト処理を効率的に実装
- よく知られたポートとサービスのマッピングを提供
- オプションでバナー情報の取得も可能(Get-ServiceBanner関数を呼び出し)
# 指定したIPアドレスとポートの接続テスト
function Test-Port {
param(
[string]$IPAddress,
[int]$Port,
[int]$Timeout = 100
)
$tcpClient = New-Object System.Net.Sockets.TcpClient
try {
$connectionResult = $tcpClient.BeginConnect($IPAddress, $Port, $null, $null)
$waitResult = $connectionResult.AsyncWaitHandle.WaitOne($Timeout, $false)
if ($waitResult) {
try {
$tcpClient.EndConnect($connectionResult)
return $true
} catch {
return $false
}
}
} catch {
return $false
} finally {
$tcpClient.Close()
}
return $false
}
# IPアドレスに対してポートスキャンを実行し、オープンポートのリストを返す関数
function Get-OpenPorts {
param(
[string]$IPAddress,
[int[]]$Ports,
[switch]$GetBanners = $false,
[int]$BannerTimeout = 2000
)
$openPorts = @()
foreach ($port in $Ports) {
if (Test-Port -IPAddress $IPAddress -Port $port) {
$serviceName = if ($portServices.ContainsKey($port)) { $portServices[$port] } else { "不明" }
# バナー情報
$bannerInfo = "取得なし"
if ($GetBanners) {
$bannerResult = Get-ServiceBanner -IPAddress $IPAddress -Port $port -Timeout $BannerTimeout
$bannerInfo = $bannerResult.Banner
}
$openPorts += [PSCustomObject]@{
Port = $port
Service = $serviceName
Banner = $bannerInfo
Protocol = if ($portServices.ContainsKey($port)) { $portServices[$port] } else { "不明" }
}
}
}
return $openPorts
}
Banner-Grabber.ps1:バナー取得機能
オープンポートから返されるバナー情報(サービス識別情報)を取得します。
<ポイント>
- サービスタイプに応じた専用の処理方法を実装
- HTTP/HTTPSではHEADリクエストを使用して効率的にヘッダー情報を取得
- SSHやFTPなど各種プロトコルに応じたハンドシェイクを実装
- タイムアウト処理を実装してハングを防止
# バナー情報を取得する関数
function Get-ServiceBanner {
param(
[string]$IPAddress,
[int]$Port,
[int]$Timeout = 2000
)
# バナーを初期化
$banner = "バナー取得失敗"
# ポートに応じてバナー取得ロジックを変更
switch ($Port) {
# HTTP/HTTPSの場合は、HTTP GETリクエストを送信
{ $_ -in 80, 8000, 8080, 443, 8443 } {
try {
# HTTPSの場合、証明書検証を無効化
if ($_ -in 443, 8443) {
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
}
$protocol = if ($_ -in 443, 8443) { "https" } else { "http" }
$uri = "$protocol`://$IPAddress`:$Port"
$request = [System.Net.WebRequest]::Create($uri)
$request.Timeout = $Timeout
$request.Method = "HEAD" # HEADリクエストでヘッダーのみを取得
try {
$response = $request.GetResponse()
$banner = "$($response.ProtocolVersion) $([int]$response.StatusCode) $($response.StatusDescription)"
# サーバー情報が存在する場合
if ($response.Headers["Server"]) {
$banner += " | Server: $($response.Headers["Server"])"
}
$response.Close()
} catch [System.Net.WebException] {
# エラーレスポンスからも情報を取得
if ($_.Exception.Response) {
$banner = "接続エラー: $($_.Exception.Message)"
}
}
} catch {
$banner = "バナー取得エラー: $($_.Exception.Message)"
}
}
# SSHの場合
22 {
try {
$client = New-Object System.Net.Sockets.TcpClient
if ($client.ConnectAsync($IPAddress, $Port).Wait($Timeout)) {
$stream = $client.GetStream()
$buffer = New-Object byte[] 1024
$read = $stream.Read($buffer, 0, 1024)
if ($read -gt 0) {
$banner = [System.Text.Encoding]::ASCII.GetString($buffer, 0, $read).Trim()
}
$stream.Close()
}
$client.Close()
} catch {
$banner = "バナー取得エラー: $($_.Exception.Message)"
}
}
# その他多数のプロトコル処理(省略)...
}
return [PSCustomObject]@{
Port = $Port
Protocol = $protocol
Banner = $banner
}
}
Banner-Analyzer.ps1:バナー解析機能
バナー文字列から製品名とバージョン情報を抽出するエンジンです。
<ポイント>
- サービスタイプごとに正規表現パターンのライブラリを構築
- バージョン文字列の標準化によりバージョン比較が容易に
- ベンダーと製品の区別を明確にするデータ構造設計
- HTTP/SSHなど各種プロトコルに対応したパターンを用意
# バナーシグネチャファイルの初期化
function Initialize-BannerSignatures {
param (
[string]$BannerSignaturesPath
)
# 基本的なシグネチャを作成
$bannerSignatures = @(
@{
ServiceType = "HTTP"
Patterns = @(
@{
RegEx = "Server: Apache/(\d+\.\d+\.\d+)"
VendorProduct = "apache:http_server"
},
@{
RegEx = "Server: nginx/(\d+\.\d+\.\d+)"
VendorProduct = "nginx:nginx"
},
# 他多数のパターン...
)
},
@{
ServiceType = "SSH"
Patterns = @(
@{
RegEx = "SSH-\d+\.\d+-OpenSSH[_-](\d+\.\d+[p\d]*)"
VendorProduct = "openssh:openssh"
},
# 他のSSHパターン...
)
},
# 他のサービスタイプ...
)
return $bannerSignatures
}
# バージョン文字列を標準形式に変換する関数
function Convert-VersionString {
param (
[string]$Version
)
# 空または無効なバージョン文字列の場合
if ([string]::IsNullOrEmpty($Version)) {
return $null
}
# バージョン文字列を分割して標準化
if ($Version -match "(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?") {
$major = if ($matches[1]) { [int]$matches[1] } else { 0 }
$minor = if ($matches[2]) { [int]$matches[2] } else { 0 }
$patch = if ($matches[3]) { [int]$matches[3] } else { 0 }
$build = if ($matches[4]) { [int]$matches[4] } else { 0 }
return [PSCustomObject]@{
Major = $major
Minor = $minor
Patch = $patch
Build = $build
FullString = "$major.$minor.$patch.$build"
OriginalString = $Version
}
}
return $null
}
# バナー情報から製品・バージョン情報を抽出する関数
function Extract-BannerInfo {
param (
[string]$Banner,
[string]$ServiceType,
[array]$BannerSignatures
)
# サービスタイプに対応するシグネチャパターンを検索
$signatureSet = $BannerSignatures | Where-Object { $_.ServiceType -eq $ServiceType }
if ($null -eq $signatureSet) {
return $null
}
# 各パターンに対して正規表現マッチングを実行
foreach ($pattern in $signatureSet.Patterns) {
if ($Banner -match $pattern.RegEx) {
# バージョン文字列を抽出(正規表現の最初のキャプチャリンググループ)
$versionString = if ($matches.Count -gt 1) { $matches[1] } else { "unknown" }
# ベンダー:製品を分析
$vendorProductParts = $pattern.VendorProduct -split ":"
$vendor = $vendorProductParts[0]
$product = $vendorProductParts[1]
# 結果を返す
return [PSCustomObject]@{
Vendor = $vendor
Product = $product
Version = $versionString
ParsedVersion = Convert-VersionString -Version $versionString
FullBanner = $Banner
MatchPattern = $pattern.RegEx
ServiceType = $ServiceType
}
}
}
return $null
}
MAC-Vendor.ps1:MACベンダー解決
MACアドレスからベンダー(製造元)情報を特定するモジュールです。
<ポイント>
- IEEE OUIデータベースを自動的にダウンロードして最新状態を維持
- ダウンロード失敗時には最小限のデータベースをフォールバックとして提供
- MACアドレスの形式正規化(ハイフンやコロンを除去)
- 大文字・小文字を問わず検索できるよう正規化
- MACベンダー情報はCSVファイルとして保存
# OUIデータベースの初期化と作成 function Initialize-OUIDatabase { param ( [string]$OuiDatabasePath ) # IEEE OUIデータベースをダウンロード $ouiUrl = "http://standards-oui.ieee.org/oui/oui.txt" $tempFile = "$env:TEMP\oui_temp.txt" try { Invoke-WebRequest -Uri $ouiUrl -OutFile $tempFile Write-Host "ダウンロード完了" -ForegroundColor Green # OUIデータを解析してCSVに変換 $ouiData = @() Get-Content -Path $tempFile | ForEach-Object { # 新しい形式に対応した正規表現 if ($_ -match "([0-9A-F]{2})-([0-9A-F]{2})-([0-9A-F]{2})\s+\(hex\)\s+(.+?)(\s{2,}|$)") { $oui = "$($matches[1])$($matches[2])$($matches[3])" $vendor = $matches[4].Trim() $ouiData += [PSCustomObject]@{ OUI = $oui Vendor = $vendor } } } # CSVとして保存 $ouiData | Export-Csv -Path $OuiDatabasePath -NoTypeInformation Remove-Item -Path $tempFile -ErrorAction SilentlyContinue return $OuiDatabasePath } catch { Write-Host "ダウンロード失敗: $($_.Exception.Message)" -ForegroundColor Red Write-Host "代替データベースの作成を試みます..." -ForegroundColor Yellow # 最小限のベンダーリストを作成(省略) $minimalOuiData = @( [PSCustomObject]@{OUI = "000000"; Vendor = "Xerox Corporation"}, [PSCustomObject]@{OUI = "00000C"; Vendor = "Cisco Systems"}, # 他の主要ベンダー... ) $minimalOuiData | Export-Csv -Path $OuiDatabasePath -NoTypeInformation return $OuiDatabasePath } } # MACアドレスからベンダー情報を取得する関数 function Get-MACVendor { param ( [string]$MACAddress, [string]$OuiDatabasePath ) $oui = ($MACAddress -replace '[-:]', '').Substring(0, 6).ToUpper() $vendor = Import-Csv -Path $OuiDatabasePath | Where-Object { $_.OUI -eq $oui } | Select-Object -ExpandProperty Vendor -First 1 if ($vendor) { return $vendor } else { return "不明" } }
Report-Generator.ps1:HTMLレポート生成
スキャン結果からHTMLレポートを生成するモジュールです。
- HTML/CSSを使用してレポートを生成
- 脆弱性を重要度別に色分けして直感的に把握できるデザイン
- ホスト情報、ポート情報、脆弱性情報などを階層的に整理
- セキュアなHTML生成(特殊文字のエスケープ処理)
# HTML特殊文字をエスケープする関数
function Escape-HtmlSpecialChars {
param (
[string]$text
)
if ([string]::IsNullOrEmpty($text)) {
return ""
}
return $text.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace('"', """).Replace("'", "'")
}
# ポートスキャン結果から脆弱性レポートを生成する関数
function Generate-VulnerabilityReport {
param (
[array]$ScanResults,
[string]$ReportPath
)
# レポートのHTMLヘッダー(CSSスタイルは省略)
$htmlHeader = @"
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ネットワークセキュリティ評価レポート</title>
<style>
/* スタイル定義(省略) */
</style>
</head>
<body>
<div class="container">
<h1>ネットワークセキュリティ評価レポート</h1>
<p>生成日時: $(Get-Date -Format "yyyy年MM月dd日 HH:mm:ss")</p>
"@
# 脆弱性集計情報の追加
$totalVulns = 0
$vulnerableHosts = 0
# 脆弱性の集計処理...
# サマリーセクションの生成
$htmlSummary = @"
<div class="summary">
<h2>スキャン概要</h2>
<p><strong>検出されたデバイス数:</strong> $($ScanResults.Count) 台</p>
<p><strong>検出された脆弱性数:</strong> $totalVulnerabilities 件</p>
<p>
<span class="severity critical">重要的: $criticalVulnerabilities</span>
<span class="severity high">高: $highVulnerabilities</span>
<span class="severity medium">中: $mediumVulnerabilities</span>
<span class="severity low">低: $lowVulnerabilities</span>
</p>
</div>
"@
# 各ホストの詳細情報セクション
$htmlHosts = ""
foreach ($hostItem in $ScanResults) {
$hostVulnCount = if ($hostItem.Vulnerabilities) { $hostItem.Vulnerabilities.Count } else { 0 }
$htmlHosts += @"
<div class="host-section">
<div class="host-header">
<h3>$($hostItem.IPAddress) $(if ($hostItem.HostName -ne "不明") { "($($hostItem.HostName))" })</h3>
<div>
<span class="severity $(if ($hostVulnCount -gt 0) { "high" } else { "low" })">
脆弱性: $hostVulnCount 件
</span>
</div>
</div>
<div class="host-info">
<p><strong>MACアドレス:</strong> $($hostItem.MACAddress)</p>
<p><strong>ベンダー:</strong> $($hostItem.Vendor)</p>
<p><strong>検出時刻:</strong> $($hostItem.DetectedTime)</p>
</div>
<h4>オープンポート情報</h4>
<!-- ポート情報の表示 -->
<!-- バナー情報の表示 -->
<!-- 脆弱性情報の表示 -->
<!-- 脆弱性がない場合のメッセージ -->
<div class="security-ok">
<strong>セキュリティ評価:</strong> このホストでは既知の脆弱性は検出されませんでした。
最新のパッチが適用されているか、このサービスは現在の脆弱性データベースに登録されている脆弱性の影響を受けません。
</div>
</div>
"@
}
# レポートのフッター
$htmlFooter = @"
<div class="footer">
<p>このレポートはセキュリティ診断ツールによって自動生成されました</p>
<p>スキャン日時: $(Get-Date -Format "yyyy年MM月dd日 HH:mm:ss")</p>
</div>
</div>
</body>
</html>
"@
# HTML全体を組み立てて保存
$reportHtml = $htmlHeader + $htmlSummary + $htmlHosts + $htmlFooter
$reportHtml | Out-File -FilePath $ReportPath -Encoding UTF8 -Force
Write-Host "セキュリティレポートを作成しました: $ReportPath" -ForegroundColor Green
}
SMB-Detailed-Scanner.ps1:SMB詳細スキャン
SMBサービスの詳細情報を取得するモジュールです。
<ポイント>
- Nmapを活用してSMBプロトコルの詳細情報を取得
- SMBバージョン(方言)情報を解析して標準化
- バージョン情報からOSバージョンを推定
- 複数のNmapスクリプト(smb-os-discovery, smb-protocols等)を組み合わせて詳細情報を収集
function Get-SMBDetailedInfo {
param(
[string]$IPAddress
)
# nmapが利用可能か確認
$nmapPath = Get-Command nmap -ErrorAction SilentlyContinue
if ($null -eq $nmapPath) {
Write-Host " SMB詳細スキャンエラー: nmapが見つかりません" -ForegroundColor Red
return $fallbackResult
}
try {
# nmapコマンドを実行
$nmapCommand = "nmap -p 139,445 --script=smb-os-discovery,smb-protocols,smb-security-mode,smb-enum-shares $IPAddress"
$nmapResult = & nmap -p 139,445 --script=smb-os-discovery,smb-protocols,smb-security-mode,smb-enum-shares $IPAddress 2>&1
# OS情報を抽出
$osLine = $nmapResult | Where-Object { $_ -match "OS:" }
$sambaVersion = "不明"
$osInfo = "不明"
if ($osLine -match "OS: (.+)") {
$osInfo = $matches[1].Trim()
if ($osLine -match "Samba ([\d\.]+)") {
$sambaVersion = $matches[1].Trim()
}
}
# プロトコル情報を抽出(SMBバージョン対応)
[System.Collections.ArrayList]$dialectsList = @()
$resultText = $nmapResult -join "`n"
# SMB方言(バージョン)情報の抽出と標準化
if ($resultText -match "\|\s+dialects:[^\|]+((?:\|\s+[^\|]+)+)") {
$dialectsSection = $matches[1]
foreach ($line in ($dialectsSection -split "`n")) {
if ($line -match "\|\s+(\d+:\d+:\d+)") {
$dialectsList.Add($matches[1]) | Out-Null
} elseif ($line -match "\|\s+(NT LM 0\.12)") {
if (-not ($dialectsList -contains "1:0:0")) {
$dialectsList.Add("1:0:0") | Out-Null # SMB 1.0を標準表記に変換
}
}
}
}
# 方言リストを値でソート
$sortedDialects = @()
# ソート処理...
# バージョン判定ロジック - フェイルセーフ付き
$dialectsStr = "不明"
$dialectValue = 0
if ($sortedDialects.Count -gt 0) {
$highestDialect = $sortedDialects[0]
$dialectsStr = $sortedDialects -join ", "
# 方言に基づいてSMBバージョンとWindowsバージョンを判定
if ($dialectValue -ge 30101) { # 3:1:1
$sambaVersion = "SMB 3.1.1"
$osInfo = "Windows 10/11 or Server 2016+"
} elseif ($dialectValue -ge 30000) { # 3:0:0 または 3:0:2
$sambaVersion = "SMB 3.0"
$osInfo = "Windows 8/8.1 or Server 2012/R2"
}
# その他のバージョン判定...
}
# ポート139用と445用の結果オブジェクトを作成
$port139Result = [PSCustomObject]@{
Port = 139
Vendor = $vendor
Product = "netbios-ssn"
Version = $sambaVersion
OSInfo = $osInfo
ComputerName = $computerName
DomainName = $domainName
Dialects = $dialectsStr
FullInfo = "OS: $osInfo, SMB Version: $sambaVersion" + $(if ($dialectsStr -ne "不明") { ", Dialects: $dialectsStr" } else { "" })
}
$port445Result = [PSCustomObject]@{
Port = 445
Vendor = $vendor
Product = "smb"
Version = $sambaVersion
OSInfo = $osInfo
ComputerName = $computerName
DomainName = $domainName
Dialects = $dialectsStr
FullInfo = "OS: $osInfo, SMB Version: $sambaVersion" + $(if ($dialectsStr -ne "不明") { ", Dialects: $dialectsStr" } else { "" })
}
return @($port139Result, $port445Result)
}
catch {
Write-Host " SMB詳細スキャンエラー: $($_.Exception.Message)" -ForegroundColor Red
return $fallbackResult
}
}
以上です。
コメント