src/Modules/Discover/Discover.ps1
|
. "$([System.IO.Path]::Combine($PSScriptRoot, 'Private', 'InternetProtocolRange.ps1'))" function discover { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string[]]$targets ) $localIPs = [System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces() | Where-Object { $_.OperationalStatus -eq 'Up' -and $_.NetworkInterfaceType -ne 'Loopback' } | ForEach-Object { $_.GetIPProperties().UnicastAddresses } | Where-Object { $_.Address.AddressFamily -eq 'InterNetwork' } | ForEach-Object { $_.Address.ToString() } $hostResults = [System.Collections.ArrayList]::new() $showMac = $false $runClassification = $false $reachableTargets = [System.Collections.Concurrent.ConcurrentDictionary[string, string]]::new() foreach ($target in $targets) { if ($target -match "/") { $ipRange = internetProtocolRange -subnet $target $ipRange | ForEach-Object -Parallel { $ip = $_ $localResult = $using:reachableTargets $method = "None" Write-Progress -Activity "Checking if $ip is reachable" $pingSender = [System.Net.NetworkInformation.Ping]::new() try { for ($i = 0; $i -lt 2; $i++) { $reply = $pingSender.Send($ip, 1000) if ($reply.Status -eq [System.Net.NetworkInformation.IPStatus]::Success) { $ttl = if ($null -ne $reply.Options) { $reply.Options.Ttl } else { $null } if ($null -eq $ttl) { $pingOut = ping -c 1 -W 1 $ip 2>$null | Out-String if ($pingOut -match 'ttl=(\d+)') { $ttl = $matches[1] } else { $ttl = "?" } } $method = "ICMP (TTL:$ttl)" break } } } catch { } finally { $pingSender.Dispose() } if ($method -eq "None") { foreach ($port in @(443, 80)) { $tcpClient = [System.Net.Sockets.TcpClient]::new() try { $connectResult = $tcpClient.BeginConnect($ip, $port, $null, $null) $success = $connectResult.AsyncWaitHandle.WaitOne(1000, $true) if ($success -and $tcpClient.Connected) { $tcpClient.EndConnect($connectResult) $method = "TCP/$port" break } } catch {} finally { $tcpClient.Close() $tcpClient.Dispose() } } } $localResult[$ip] = $method } @ThrottleCreat $reachableCount = 0 if ($target -match '^(10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.)') { $hasReachable = $false foreach ($ip in $ipRange) { if ($reachableTargets.ContainsKey($ip) -and $reachableTargets[$ip] -ne "None") { $hasReachable = $true; break } } if ($hasReachable) { Write-Host " [*] Internal IP Detected ($target)." @Cha if ((Read-Host " [*] Show MAC Address? (Y/N)") -match '^[Yy]') { $showMac = $true } if ((Read-Host " [*] Discover Switch & Router / Device OS? (Y/N)") -match '^[Yy]') { $runClassification = $true } } } foreach ($ip in $ipRange | Sort-Object) { $detectedMethod = $reachableTargets[$ip] if ($detectedMethod -ne "None") { $dto = [HostResult]::new($ip) $dto.IsReachable = $true if ($detectedMethod -match 'ICMP \(TTL:(\d+)\)') { $dto.Protocol = "ICMP" $dto.TTL = [int]$matches[1] } else { $dto.Protocol = $detectedMethod } if ($showMac -or $runClassification) { $macResult = $null if ($IsWindows -and (Get-Command Get-NetNeighbor -ErrorAction SilentlyContinue)) { $macResult = (Get-NetNeighbor -IPAddress $ip -ErrorAction SilentlyContinue | Select-Object -First 1).LinkLayerAddress } elseif ($IsLinux -and (Get-Command ip -ErrorAction SilentlyContinue)) { $arpLine = ip neigh show $ip 2>$null | Out-String if ($arpLine -match '([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}') { $macResult = $matches[0] } } $dto.MACAddress = if ($macResult) { $macResult } else { "N/A" } } if ($runClassification) { $isLocal = $localIPs -contains $ip $dto.InferClassification($isLocal) } [void]$hostResults.Add($dto) $reachableCount++ } } if ($reachableCount -eq 0) { Write-Host " [*] Layer 3 ICMP Checked." @Dim Write-Host " [*] Layer 4 TCP Checked." @Dim Write-Host " [*] All IPs in subnet $target are not reachable." @Cha } } else { $method = "None" $pingSingle = [System.Net.NetworkInformation.Ping]::new() try { for ($i = 0; $i -lt 2; $i++) { $reply = $pingSingle.Send($target, 1000) if ($reply.Status -eq [System.Net.NetworkInformation.IPStatus]::Success) { $ttl = if ($null -ne $reply.Options) { $reply.Options.Ttl } else { $null } if ($null -eq $ttl) { $pingOut = ping -c 1 -W 1 $target 2>$null | Out-String if ($pingOut -match 'ttl=(\d+)') { $ttl = $matches[1] } else { $ttl = "?" } } $method = "ICMP (TTL:$ttl)" break } } } catch { } finally { $pingSingle.Dispose() } if ($method -eq "None") { Write-Host " [*] Layer ICMP possible blocked for $target." @Cha Write-Host " [*] Attempting Layer 4 (TCP)..." @Inc foreach ($port in @(443, 80)) { $tcpClientSingle = [System.Net.Sockets.TcpClient]::new() try { $connectResult = $tcpClientSingle.BeginConnect($target, $port, $null, $null) $success = $connectResult.AsyncWaitHandle.WaitOne(1000, $true) if ($success -and $tcpClientSingle.Connected) { $tcpClientSingle.EndConnect($connectResult) $method = "TCP/$port" break } } catch {} finally { $tcpClientSingle.Close() $tcpClientSingle.Dispose() } } } if ($method -ne "None") { if ($target -match '^(10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.)') { Write-Host " [*] Internal IP Detected ($target)." @Cha if ((Read-Host " [*] Show MAC Address? (Y/N)") -match '^[Yy]') { $showMac = $true } if ((Read-Host " [*] Discover Switch & Router / Device OS? (Y/N)") -match '^[Yy]') { $runClassification = $true } } $dto = [HostResult]::new($target) $dto.IsReachable = $true if ($method -match 'ICMP \(TTL:(\d+)\)') { $dto.Protocol = "ICMP" $dto.TTL = [int]$matches[1] } else { $dto.Protocol = $method } if ($showMac -or $runClassification) { $macResult = $null if ($IsWindows -and (Get-Command Get-NetNeighbor -ErrorAction SilentlyContinue)) { $macResult = (Get-NetNeighbor -IPAddress $target -ErrorAction SilentlyContinue | Select-Object -First 1).LinkLayerAddress } elseif ($IsLinux -and (Get-Command ip -ErrorAction SilentlyContinue)) { $arpLine = ip neigh show $target 2>$null | Out-String if ($arpLine -match '([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}') { $macResult = $matches[0] } } $dto.MACAddress = if ($macResult) { $macResult } else { "N/A" } } if ($runClassification) { $isLocal = $localIPs -contains $target $dto.InferClassification($isLocal) } [void]$hostResults.Add($dto) $reachableTargets[$target] = $method } else { Write-Host "$target is not reachable" @Cha $reachableTargets[$target] = "None" } } } if ($VerbosePreference -ne 'SilentlyContinue') { Write-Host "`nReachable Hosts:" @Net foreach ($ip in $reachableTargets.Keys | Sort-Object) { if ($reachableTargets[$ip] -ne "None") { Write-Host " - $ip ($($reachableTargets[$ip]))" } } } hostResultTable -Results $hostResults -ShowMac $showMac -ShowClassification $runClassification } |