1085 lines
41 KiB
PowerShell
1085 lines
41 KiB
PowerShell
function Invoke-Portscan
|
|
{
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
Simple portscan module
|
|
|
|
PowerSploit Function: Invoke-Portscan
|
|
Author: Rich Lundeen (http://webstersProdigy.net)
|
|
License: BSD 3-Clause
|
|
Required Dependencies: None
|
|
Optional Dependencies: None
|
|
|
|
.DESCRIPTION
|
|
|
|
Does a simple port scan using regular sockets, based (pretty) loosely on nmap
|
|
|
|
.PARAMETER Hosts
|
|
|
|
Include these comma seperated hosts (supports IPv4 CIDR notation) or pipe them in
|
|
|
|
.PARAMETER HostFile
|
|
|
|
Input hosts from file rather than commandline
|
|
|
|
.PARAMETER ExcludeHosts
|
|
|
|
Exclude these comma seperated hosts
|
|
|
|
.PARAMETER Ports
|
|
|
|
Include these comma seperated ports (can also be a range like 80-90)
|
|
|
|
.PARAMETER PortFile
|
|
|
|
Input ports from a file
|
|
|
|
.PARAMETER TopPorts
|
|
|
|
Include the x top ports - only goes to 1000, default is top 50
|
|
|
|
.PARAMETER ExcludedPorts
|
|
|
|
Exclude these comma seperated ports
|
|
|
|
.PARAMETER SkipDiscovery
|
|
|
|
Treat all hosts as online, skip host discovery
|
|
|
|
.PARAMETER PingOnly
|
|
|
|
Ping scan only (disable port scan)
|
|
|
|
.PARAMETER DiscoveryPorts
|
|
|
|
Comma separated ports used for host discovery. -1 is a ping
|
|
|
|
.PARAMETER Threads
|
|
|
|
number of max threads for the thread pool (per host)
|
|
|
|
.PARAMETER nHosts
|
|
|
|
number of hosts to concurrently scan
|
|
|
|
.PARAMETER Timeout
|
|
|
|
Timeout time on a connection in miliseconds before port is declared filtered
|
|
|
|
.PARAMETER SleepTimer
|
|
|
|
Wait before thread checking, in miliseconds
|
|
|
|
.PARAMETER SyncFreq
|
|
|
|
How often (in terms of hosts) to sync threads and flush output
|
|
|
|
.PARAMETER T
|
|
|
|
[0-5] shortcut performance options. Default is 3. higher is more aggressive. Sets (nhosts, threads,timeout)
|
|
5 {$nHosts=30; $Threads = 1000; $Timeout = 750 }
|
|
4 {$nHosts=25; $Threads = 1000; $Timeout = 1200 }
|
|
3 {$nHosts=20; $Threads = 100; $Timeout = 2500 }
|
|
2 {$nHosts=15; $Threads = 32; $Timeout = 3000 }
|
|
1 {$nHosts=10; $Threads = 32; $Timeout = 5000 }
|
|
|
|
.PARAMETER GrepOut
|
|
|
|
Greppable output file
|
|
|
|
.PARAMETER XmlOut
|
|
|
|
output XML file
|
|
|
|
.PARAMETER ReadableOut
|
|
|
|
output file in 'readable' format
|
|
|
|
.PARAMETER AllformatsOut
|
|
|
|
output in readable (.nmap), xml (.xml), and greppable (.gnmap) formats
|
|
|
|
.PARAMETER noProgressMeter
|
|
|
|
Suppresses the progress meter
|
|
|
|
.PARAMETER quiet
|
|
|
|
supresses returned output and don't store hosts in memory - useful for very large scans
|
|
|
|
.PARAMETER ForceOverwrite
|
|
|
|
Force Overwrite if output Files exist. Otherwise it throws exception
|
|
|
|
.EXAMPLE
|
|
|
|
C:\PS> Invoke-Portscan -Hosts "webstersprodigy.net,google.com,microsoft.com" -TopPorts 50
|
|
|
|
Description
|
|
-----------
|
|
Scans the top 50 ports for hosts found for webstersprodigy.net,google.com, and microsoft.com
|
|
|
|
.EXAMPLE
|
|
|
|
C:\PS> echo webstersprodigy.net | Invoke-Portscan -oG test.gnmap -f -ports "80,443,8080"
|
|
|
|
Description
|
|
-----------
|
|
Does a portscan of "webstersprodigy.net", and writes a greppable output file
|
|
|
|
.EXAMPLE
|
|
|
|
C:\PS> Invoke-Portscan -Hosts 192.168.1.1/24 -T 4 -TopPorts 25 -oA localnet
|
|
|
|
Description
|
|
-----------
|
|
Scans the top 20 ports for hosts found in the 192.168.1.1/24 range, outputs all file formats
|
|
|
|
.LINK
|
|
|
|
http://webstersprodigy.net
|
|
#>
|
|
|
|
[CmdletBinding()]Param (
|
|
#Host, Ports
|
|
[Parameter(ParameterSetName="cmdHosts",
|
|
|
|
ValueFromPipeline=$True,
|
|
Mandatory = $True)]
|
|
[String[]] $Hosts,
|
|
|
|
[Parameter(ParameterSetName="fHosts",
|
|
Mandatory = $True)]
|
|
[Alias("iL")]
|
|
[String] $HostFile,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("exclude")]
|
|
[String] $ExcludeHosts,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("p")]
|
|
[String] $Ports,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("iP")]
|
|
[String] $PortFile,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[String] $TopPorts,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("xPorts")]
|
|
[String] $ExcludedPorts,
|
|
|
|
#Host Discovery
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("Pn")]
|
|
[Switch] $SkipDiscovery,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("sn")]
|
|
[Switch] $PingOnly,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("PS")]
|
|
[string] $DiscoveryPorts = "-1,445,80,443",
|
|
|
|
#Timing and Performance
|
|
[Parameter(Mandatory = $False)]
|
|
[int] $Threads = 100,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[int] $nHosts = 25,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[int] $Timeout = 2000,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[int] $SleepTimer = 500,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[int] $SyncFreq = 1024,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[int] $T,
|
|
|
|
#Output
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("oG")]
|
|
[String] $GrepOut,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("oX")]
|
|
[String] $XmlOut,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("oN")]
|
|
[String] $ReadableOut,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("oA")]
|
|
[String] $AllformatsOut,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Switch] $noProgressMeter,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("q")]
|
|
[Switch] $quiet,
|
|
|
|
[Parameter(Mandatory = $False)]
|
|
[Alias("F")]
|
|
[Switch] $ForceOverwrite
|
|
|
|
#TODO add script parameter
|
|
#TODO add resume parameter
|
|
)
|
|
|
|
PROCESS {
|
|
|
|
Set-StrictMode -Version 2.0
|
|
|
|
$version = .13
|
|
$hostList = New-Object System.Collections.ArrayList
|
|
$portList = New-Object System.Collections.ArrayList
|
|
$hostPortList = New-Object System.Collections.ArrayList
|
|
|
|
$scannedHostList = @()
|
|
|
|
function Parse-Hosts
|
|
{
|
|
Param (
|
|
[Parameter(Mandatory = $True)] [String] $Hosts
|
|
)
|
|
|
|
[String[]] $iHosts = $Hosts.Split(",")
|
|
|
|
foreach($iHost in $iHosts)
|
|
{
|
|
$iHost = $iHost.Replace(" ", "")
|
|
|
|
if(!$iHost)
|
|
{
|
|
continue
|
|
}
|
|
|
|
if($iHost.contains("/"))
|
|
{
|
|
$netPart = $iHost.split("/")[0]
|
|
[uint32]$maskPart = $iHost.split("/")[1]
|
|
|
|
$address = [System.Net.IPAddress]::Parse($netPart)
|
|
|
|
if ($maskPart -ge $address.GetAddressBytes().Length * 8)
|
|
{
|
|
throw "Bad host mask"
|
|
}
|
|
|
|
$numhosts = [System.math]::Pow(2,(($address.GetAddressBytes().Length *8) - $maskPart))
|
|
|
|
$startaddress = $address.GetAddressBytes()
|
|
[array]::Reverse($startaddress)
|
|
|
|
$startaddress = [System.BitConverter]::ToUInt32($startaddress, 0)
|
|
[uint32]$startMask = ([System.math]::Pow(2, $maskPart)-1) * ([System.Math]::Pow(2,(32 - $maskPart)))
|
|
$startAddress = $startAddress -band $startMask
|
|
|
|
#in powershell 2.0 there are 4 0 bytes padded, so the [0..3] is necessary
|
|
$startAddress = [System.BitConverter]::GetBytes($startaddress)[0..3]
|
|
[array]::Reverse($startaddress)
|
|
|
|
$address = [System.Net.IPAddress] [byte[]] $startAddress
|
|
|
|
$hostList.Add($address.IPAddressToString)
|
|
|
|
for ($i=0; $i -lt $numhosts-1; $i++)
|
|
{
|
|
|
|
$nextAddress = $address.GetAddressBytes()
|
|
[array]::Reverse($nextAddress)
|
|
$nextAddress = [System.BitConverter]::ToUInt32($nextAddress, 0)
|
|
$nextAddress ++
|
|
$nextAddress = [System.BitConverter]::GetBytes($nextAddress)[0..3]
|
|
[array]::Reverse($nextAddress)
|
|
|
|
$address = [System.Net.IPAddress] [byte[]] $nextAddress
|
|
$hostList.Add($address.IPAddressToString)
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
$hostList.Add($iHost)
|
|
}
|
|
}
|
|
}
|
|
|
|
function Parse-ILHosts
|
|
{
|
|
Param (
|
|
[Parameter(Mandatory = $True)] [String] $HostFile
|
|
)
|
|
|
|
Get-Content $HostFile | ForEach-Object {
|
|
Parse-Hosts $_
|
|
}
|
|
}
|
|
|
|
function Exclude-Hosts
|
|
{
|
|
Param (
|
|
[Parameter(Mandatory = $True)] [String] $excludeHosts
|
|
)
|
|
|
|
[String[]] $iHosts = $excludeHosts.Split(",")
|
|
|
|
foreach($iHost in $iHosts)
|
|
{
|
|
$iHost = $iHost.Replace(" ", "")
|
|
$hostList.Remove($iHost)
|
|
}
|
|
}
|
|
|
|
function Get-TopPort
|
|
{
|
|
Param (
|
|
[Parameter(Mandatory = $True)]
|
|
[ValidateRange(1,1000)]
|
|
[int] $numPorts
|
|
)
|
|
|
|
#list of top 1000 ports from nmap from Jun 2013
|
|
[int[]] $topPortList = @(80,23,443,21,3389,110,445,139,143,53,135,3306,8080,22
|
|
1723,111,995,993,5900,1025,1720,548,113,81,6001,179,1026,2000,8443,
|
|
8000,32768,554,26,1433,49152,2001,515,8008,49154,1027,5666,646,5000,
|
|
5631,631,49153,8081,2049,88,79,5800,106,2121,1110,49155,6000,513,
|
|
990,5357,49156,543,544,5101,144,7,389,8009,9999,5009,7070,5190,3000,
|
|
5432,1900,3986,13,1029,9,5051,6646,49157,1028,873,1755,2717,4899,9100,
|
|
119,37,1000,3001,5001,82,10010,1030,9090,2107,1024,2103,6004,1801,
|
|
5050,19,8031,1041,255,1048,1049,1053,1054,1056,1064,3703,17,808,3689,
|
|
1031,1044,1071,5901,100,9102,2869,4001,5120,8010,9000,2105,636,1038,
|
|
2601,1,7000,1066,1069,625,311,280,254,4000,1761,5003,2002,1998,2005,
|
|
1032,1050,6112,1521,2161,6002,2401,902,4045,787,7937,1058,2383,1033,
|
|
1040,1059,50000,5555,1494,3,593,2301,3268,7938,1022,1234,1035,1036,1037,
|
|
1074,8002,9001,464,497,1935,2003,6666,6543,24,1352,3269,1111,407,500,
|
|
20,2006,1034,1218,3260,15000,4444,264,33,2004,1042,42510,999,3052,1023,
|
|
222,1068,888,7100,1717,992,2008,7001,2007,8082,512,1043,2009,5801,1700,
|
|
7019,50001,4662,2065,42,2602,3333,9535,5100,2604,4002,5002,1047,1051,1052,
|
|
1055,1060,1062,1311,3283,4443,5225,5226,6059,6789,8089,8651,8652,8701,9415,
|
|
9593,9594,9595,16992,16993,20828,23502,32769,33354,35500,52869,55555,55600,
|
|
64623,64680,65000,65389,1067,13782,366,5902,9050,85,1002,5500,1863,1864,
|
|
5431,8085,10243,45100,49999,51103,49,90,6667,1503,6881,27000,340,1500,8021,
|
|
2222,5566,8088,8899,9071,5102,6005,9101,163,5679,146,648,1666,83,3476,5004,
|
|
5214,8001,8083,8084,9207,14238,30,912,12345,2030,2605,6,541,4,1248,3005,8007,
|
|
306,880,2500,1086,1088,2525,4242,8291,9009,52822,900,6101,2809,7200,211,800,
|
|
987,1083,12000,705,711,20005,6969,13783,1045,1046,1061,1063,1070,1072,1073,
|
|
1075,1077,1078,1079,1081,1082,1085,1093,1094,1096,1098,1099,1100,1104,1106,
|
|
1107,1108,1148,1169,1272,1310,1687,1718,1783,1840,2100,2119,2135,2144,2160,
|
|
2190,2260,2381,2399,2492,2607,2718,2811,2875,3017,3031,3071,3211,3300,3301,
|
|
3323,3325,3351,3404,3551,3580,3659,3766,3784,3801,3827,3998,4003,4126,4129,
|
|
4449,5222,5269,5633,5718,5810,5825,5877,5910,5911,5925,5959,5960,5961,5962,
|
|
5987,5988,5989,6123,6129,6156,6389,6580,6901,7106,7625,7777,7778,7911,8086,
|
|
8181,8222,8333,8400,8402,8600,8649,8873,8994,9002,9011,9080,9220,9290,9485,
|
|
9500,9502,9503,9618,9900,9968,10002,10012,10024,10025,10566,10616,10617,10621,
|
|
10626,10628,10629,11110,13456,14442,15002,15003,15660,16001,16016,16018,17988,
|
|
19101,19801,19842,20000,20031,20221,20222,21571,22939,24800,25734,27715,28201,
|
|
30000,30718,31038,32781,32782,33899,34571,34572,34573,40193,48080,49158,49159,
|
|
49160,50003,50006,50800,57294,58080,60020,63331,65129,691,212,1001,1999,2020,
|
|
2998,6003,7002,50002,32,2033,3372,99,425,749,5903,43,458,5405,6106,6502,7007,
|
|
13722,1087,1089,1124,1152,1183,1186,1247,1296,1334,1580,1782,2126,2179,2191,2251,
|
|
2522,3011,3030,3077,3261,3493,3546,3737,3828,3871,3880,3918,3995,4006,4111,4446,
|
|
5054,5200,5280,5298,5822,5859,5904,5915,5922,5963,7103,7402,7435,7443,7512,8011,
|
|
8090,8100,8180,8254,8500,8654,9091,9110,9666,9877,9943,9944,9998,10004,10778,15742,
|
|
16012,18988,19283,19315,19780,24444,27352,27353,27355,32784,49163,49165,49175,
|
|
50389,50636,51493,55055,56738,61532,61900,62078,1021,9040,666,700,84,545,1112,
|
|
1524,2040,4321,5802,38292,49400,1084,1600,2048,2111,3006,6547,6699,9111,16080,
|
|
555,667,720,801,1443,1533,2106,5560,6007,1090,1091,1114,1117,1119,1122,1131,1138,
|
|
1151,1175,1199,1201,1271,1862,2323,2393,2394,2608,2725,2909,3003,3168,3221,3322,
|
|
3324,3390,3517,3527,3800,3809,3814,3826,3869,3878,3889,3905,3914,3920,3945,3971,
|
|
4004,4005,4279,4445,4550,4567,4848,4900,5033,5080,5087,5221,5440,5544,5678,5730,
|
|
5811,5815,5850,5862,5906,5907,5950,5952,6025,6510,6565,6567,6689,6692,6779,6792,
|
|
6839,7025,7496,7676,7800,7920,7921,7999,8022,8042,8045,8093,8099,8200,8290,8292,
|
|
8300,8383,9003,9081,9099,9200,9418,9575,9878,9898,9917,10003,10180,10215,11111,
|
|
12174,12265,14441,15004,16000,16113,17877,18040,18101,19350,25735,26214,27356,
|
|
30951,32783,32785,40911,41511,44176,44501,49161,49167,49176,50300,50500,52673,
|
|
52848,54045,54328,55056,56737,57797,60443,70,417,714,722,777,981,1009,2022,4224,
|
|
4998,6346,301,524,668,765,2041,5999,10082,259,1007,1417,1434,1984,2038,2068,4343,
|
|
6009,7004,44443,109,687,726,911,1461,2035,4125,6006,7201,9103,125,481,683,903,
|
|
1011,1455,2013,2043,2047,6668,6669,256,406,843,2042,2045,5998,9929,31337,44442,
|
|
1092,1095,1102,1105,1113,1121,1123,1126,1130,1132,1137,1141,1145,1147,1149,1154,
|
|
1164,1165,1166,1174,1185,1187,1192,1198,1213,1216,1217,1233,1236,1244,1259,1277,
|
|
1287,1300,1301,1309,1322,1328,1556,1641,1688,1719,1721,1805,1812,1839,1875,1914,
|
|
1971,1972,1974,2099,2170,2196,2200,2288,2366,2382,2557,2800,2910,2920,2968,3007,
|
|
3013,3050,3119,3304,3307,3376,3400,3410,3514,3684,3697,3700,3824,3846,3848,3859,
|
|
3863,3870,3872,3888,3907,3916,3931,3941,3957,3963,3968,3969,3972,3990,3993,3994,
|
|
4009,4040,4080,4096,4143,4147,4200,4252,4430,4555,4600,4658,4875,4949,5040,5063,
|
|
5074,5151,5212,5223,5242,5279,5339,5353,5501,5807,5812,5818,5823,5868,5869,5899,
|
|
5905,5909,5914,5918,5938,5940,5968,5981,6051,6060,6068,6203,6247,6500,6504,6520,
|
|
6550,6600)
|
|
$numPorts--
|
|
$portList.AddRange($topPortList[0..$numPorts])
|
|
}
|
|
|
|
function Parse-Ports
|
|
{
|
|
Param (
|
|
[Parameter(Mandatory = $True)] [String] $Ports,
|
|
[Parameter(Mandatory = $True)] $pList
|
|
)
|
|
|
|
foreach ($pRange in $Ports.Split(","))
|
|
{
|
|
|
|
#-1 is a special case for ping
|
|
if ($pRange -eq "-1")
|
|
{
|
|
$pList.Add([int]$pRange)
|
|
}
|
|
elseif ($pRange.Contains("-"))
|
|
{
|
|
[int[]] $range = $pRange.Split("-")
|
|
if ($range.Count -ne 2 -or $pRange.Split("-")[0] -eq "" -or $pRange.split("-")[1] -eq "")
|
|
{
|
|
throw "Invalid port range"
|
|
}
|
|
|
|
$pList.AddRange($range[0]..$range[1])
|
|
}
|
|
else
|
|
{
|
|
$pList.Add([int]$pRange)
|
|
}
|
|
|
|
}
|
|
foreach ($p in $pList)
|
|
{
|
|
if ($p -lt -1 -or $p -gt 65535)
|
|
{
|
|
throw "Port $p out of range"
|
|
}
|
|
}
|
|
}
|
|
|
|
function Parse-IpPorts
|
|
{
|
|
Param (
|
|
[Parameter(Mandatory = $True)] [String] $PortFile
|
|
)
|
|
|
|
Get-Content $PortFile | ForEach-Object {
|
|
Parse-Ports -Ports $_ -pList $portList
|
|
}
|
|
}
|
|
|
|
function Remove-Ports
|
|
{
|
|
Param (
|
|
[Parameter(Mandatory = $True)] [string] $ExcludedPorts
|
|
)
|
|
|
|
[int[]] $ExcludedPorts = $ExcludedPorts.Split(",")
|
|
|
|
foreach ($x in $ExcludedPorts)
|
|
{
|
|
$portList.Remove($x)
|
|
}
|
|
}
|
|
|
|
function Write-PortscanOut
|
|
{
|
|
Param (
|
|
[Parameter(Mandatory = $True, ParameterSetName="Comment")] [string] $comment,
|
|
[Parameter(Mandatory = $True, ParameterSetName="HostOut")] [string] $outhost,
|
|
[Parameter(Mandatory = $True, ParameterSetName="HostOut")] [bool] $isUp,
|
|
[Parameter(Mandatory = $True, ParameterSetName="HostOut")] $openPorts,
|
|
[Parameter(Mandatory = $True, ParameterSetName="HostOut")] $closedPorts,
|
|
[Parameter(Mandatory = $True, ParameterSetName="HostOut")] $filteredPorts,
|
|
[Parameter()] [bool] $SkipDiscovery,
|
|
[Parameter()] [System.IO.StreamWriter] $grepStream,
|
|
[Parameter()] [System.Xml.XmlWriter] $xmlStream,
|
|
[Parameter()] [System.IO.StreamWriter] $readableStream
|
|
|
|
)
|
|
switch ($PSCmdlet.ParameterSetName)
|
|
{
|
|
"Comment"
|
|
{
|
|
|
|
Write-Verbose $comment
|
|
|
|
if ($grepStream) {
|
|
$grepStream.WriteLine("# " + $comment)
|
|
}
|
|
if ($xmlStream) {
|
|
$xmlStream.WriteComment($comment)
|
|
}
|
|
if ($readableStream) {
|
|
$readableStream.WriteLine($comment)
|
|
}
|
|
}
|
|
"HostOut"
|
|
{
|
|
$oPort = [string]::join(",", $openPorts.ToArray())
|
|
$cPort = [string]::join(",", $closedPorts.ToArray())
|
|
$fPort = [string]::join(",", $filteredPorts.ToArray())
|
|
|
|
if ($grepStream) {
|
|
#for grepstream use tabs - can be ugly, but easier for regex
|
|
if ($isUp -and !$SkipDiscovery) {
|
|
$grepStream.writeline("Host: $outhost`tStatus: Up")
|
|
}
|
|
if ($isUp -or $SkipDiscovery) {
|
|
if ($oPort -ne "") {
|
|
$grepStream.writeline("Host: $outhost`tOpen Ports: $oPort")
|
|
}
|
|
if ($cPort -ne "") {
|
|
$grepStream.writeline("Host: $outhost`tClosed Ports: $cPort")
|
|
}
|
|
if ($fPort -ne "") {
|
|
$grepStream.writeline("Host: $outhost`tFiltered Ports: $fPort")
|
|
}
|
|
}
|
|
elseif (!$SkipDiscovery) {
|
|
$grepStream.writeline("Host: $outhost`tStatus: Down")
|
|
}
|
|
}
|
|
if ($xmlStream) {
|
|
$xmlStream.WriteStartElement("Host")
|
|
|
|
$xmlStream.WriteAttributeString("id", $outhost)
|
|
if (!$SkipDiscovery) {
|
|
if ($isUp) {
|
|
$xmlStream.WriteAttributeString("Status", "Up")
|
|
}
|
|
else {
|
|
$xmlStream.WriteAttributeString("Status", "Downs")
|
|
}
|
|
}
|
|
|
|
$xmlStream.WriteStartElement("Ports")
|
|
foreach($p in $openPorts) {
|
|
$xmlStream.writestartElement("Port")
|
|
$xmlStream.WriteAttributeString("id", [string]$p)
|
|
$xmlStream.WriteAttributeString("state", "open")
|
|
$xmlStream.WriteEndElement()
|
|
|
|
}
|
|
foreach ($p in $closedPorts) {
|
|
$xmlStream.writestartElement("Port")
|
|
$xmlStream.WriteAttributeString("id", [string]$p)
|
|
$xmlStream.WriteAttributeString("state", "closed")
|
|
$xmlStream.WriteEndElement()
|
|
}
|
|
foreach ($p in $filteredPorts) {
|
|
$xmlStream.writestartElement("Port")
|
|
$xmlStream.WriteAttributeString("id", [string]$p)
|
|
$xmlStream.WriteAttributeString("state", "filtered")
|
|
$xmlStream.WriteEndElement()
|
|
}
|
|
|
|
$xmlStream.WriteEndElement()
|
|
$xmlStream.WriteEndElement()
|
|
}
|
|
if ($readableStream) {
|
|
$readableStream.writeline("Porscan.ps1 scan report for $outhost")
|
|
if ($isUp) {
|
|
$readableStream.writeline("Host is up")
|
|
}
|
|
|
|
if ($isUp -or $SkipDiscovery) {
|
|
|
|
$readableStream.writeline(("{0,-10}{1,0}" -f "PORT", "STATE"))
|
|
|
|
[int[]]$allports = $openPorts + $closedPorts + $filteredPorts
|
|
foreach($p in ($allports| Sort-Object))
|
|
{
|
|
if ($openPorts.Contains($p)) {
|
|
$readableStream.writeline(("{0,-10}{1,0}" -f $p, "open"))
|
|
}
|
|
elseif ($closedPorts.Contains($p)) {
|
|
$readableStream.writeline(("{0,-10}{1,0}" -f $p, "closed"))
|
|
}
|
|
elseif ($filteredPorts.Contains($p)) {
|
|
$readableStream.writeline(("{0,-10}{1,0}" -f $p, "filtered"))
|
|
}
|
|
}
|
|
|
|
}
|
|
elseif(!$SkipDiscovery) {
|
|
$readableStream.writeline("Host is Down")
|
|
}
|
|
$readableStream.writeline("")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#function for Powershell v2.0 to work
|
|
function Convert-SwitchtoBool
|
|
{
|
|
Param (
|
|
[Parameter(Mandatory = $True)] $switchValue
|
|
)
|
|
If ($switchValue) {
|
|
return $True
|
|
}
|
|
return $False
|
|
}
|
|
|
|
try
|
|
{
|
|
|
|
[bool] $SkipDiscovery = Convert-SwitchtoBool ($SkipDiscovery)
|
|
[bool] $PingOnly = Convert-SwitchtoBool ($PingOnly)
|
|
[bool] $quiet = Convert-SwitchtoBool ($quiet)
|
|
[bool] $ForceOverwrite = Convert-SwitchtoBool ($ForceOverwrite)
|
|
|
|
#########
|
|
#parse arguments
|
|
#########
|
|
|
|
[Environment]::CurrentDirectory=(Get-Location -PSProvider FileSystem).ProviderPath
|
|
|
|
if ($PsCmdlet.ParameterSetName -eq "cmdHosts")
|
|
{
|
|
foreach($h in $Hosts)
|
|
{
|
|
Parse-Hosts($h) | Out-Null
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Parse-ILHosts($HostFile) | Out-Null
|
|
}
|
|
if($ExcludeHosts)
|
|
{
|
|
Exclude-Hosts($ExcludeHosts)
|
|
}
|
|
if (($TopPorts -and $Ports) -or ($TopPorts -and $PortFile))
|
|
{
|
|
throw "Cannot set topPorts with other specific ports"
|
|
}
|
|
if($Ports)
|
|
{
|
|
Parse-Ports -Ports $Ports -pList $portList | Out-Null
|
|
}
|
|
if($PortFile)
|
|
{
|
|
Parse-IpPorts($PortFile) | Out-Null
|
|
}
|
|
if($portList.Count -eq 0)
|
|
{
|
|
if ($TopPorts)
|
|
{
|
|
Get-TopPort($TopPorts) | Out-Null
|
|
}
|
|
else
|
|
{
|
|
#if the ports still aren't set, give the deftault, top 50 ports
|
|
Get-TopPort(50) | Out-Null
|
|
}
|
|
}
|
|
if ($ExcludedPorts)
|
|
{
|
|
Remove-Ports -ExcludedPorts $ExcludedPorts | Out-Null
|
|
}
|
|
|
|
if($T)
|
|
{
|
|
switch ($T)
|
|
{
|
|
5 {$nHosts=30; $Threads = 1000; $Timeout = 750 }
|
|
4 {$nHosts=25; $Threads = 1000; $Timeout = 1200 }
|
|
3 {$nHosts=20; $Threads = 100; $Timeout = 2500 }
|
|
2 {$nHosts=15; $Threads = 32; $Timeout = 3000 }
|
|
1 {$nHosts=10; $Threads = 32; $Timeout = 5000 }
|
|
default {
|
|
throw "Invalid T parameter"
|
|
}
|
|
}
|
|
}
|
|
|
|
$grepStream = $null
|
|
$xmlStream = $null
|
|
$readableStream = $null
|
|
|
|
if($AllformatsOut)
|
|
{
|
|
if ($GrepOut -or $XmlOut -or $ReadableOut) {
|
|
Write-Warning "Both -oA specified with other output... going to ignore -oG/-oN/-oX"
|
|
}
|
|
$GrepOut = $AllformatsOut + ".gnmap"
|
|
$XmlOut = $AllformatsOut + ".xml"
|
|
$ReadableOut = $AllformatsOut + ".nmap"
|
|
}
|
|
if ($GrepOut) {
|
|
if (!$ForceOverwrite -and (Test-Path $GrepOut)) {
|
|
throw "Error: $AllformatsOut already exists. Either delete the file or specify the -f flag"
|
|
}
|
|
$grepStream = [System.IO.StreamWriter] $GrepOut
|
|
}
|
|
if ($ReadableOut) {
|
|
if (!$ForceOverwrite -and (Test-Path $ReadableOut)) {
|
|
throw "Error: $ReadableOut already exists. Either delete the file or specify the -f flag"
|
|
}
|
|
$readableStream = [System.IO.StreamWriter] $ReadableOut
|
|
}
|
|
if ($XmlOut) {
|
|
if (!$ForceOverwrite -and (Test-Path $XmlOut)) {
|
|
throw "Error: $XmlOut already exists. Either delete the file or specify the -f flag"
|
|
}
|
|
|
|
$xmlStream = [System.xml.xmlwriter]::Create([string]$XmlOut)
|
|
$xmlStream.WriteStartDocument()
|
|
$xmlStream.WriteStartElement("Portscanrun")
|
|
$xmlStream.WriteAttributeString("version", $version)
|
|
|
|
}
|
|
|
|
Parse-Ports -Ports $DiscoveryPorts -pList $hostPortList | Out-Null
|
|
|
|
$startdate = Get-Date
|
|
$myInvocationLine = $PSCmdlet.MyInvocation.Line
|
|
$startMsg = "Invoke-Portscan.ps1 v$version scan initiated $startdate as: $myInvocationLine"
|
|
|
|
#TODO deal with output
|
|
Write-PortscanOut -comment $startMsg -grepStream $grepStream -xmlStream $xmlStream -readableStream $readableStream
|
|
|
|
#converting back from int array gives some argument error checking
|
|
$sPortList = [string]::join(",", $portList)
|
|
$sHostPortList = [string]::join(",", $hostPortList)
|
|
|
|
########
|
|
#Port Scan Code - run on a per host basis
|
|
########
|
|
$portScanCode = {
|
|
param (
|
|
[Parameter( Mandatory = $True)] [string] $thost,
|
|
[Parameter( Mandatory = $True)][bool] $SkipDiscovery,
|
|
[Parameter( Mandatory = $True)][bool] $PingOnly,
|
|
[Parameter( Mandatory = $True)][int] $Timeout,
|
|
[Parameter( Mandatory = $True)] $PortList,
|
|
[Parameter( Mandatory = $True)] $hostPortList,
|
|
[Parameter( Mandatory = $True)][int] $maxthreads)
|
|
Process
|
|
{
|
|
$openPorts = New-Object System.Collections.ArrayList
|
|
$closedPorts = New-Object System.Collections.ArrayList
|
|
$filteredPorts = New-Object System.Collections.ArrayList
|
|
|
|
$sockets = @{}
|
|
$timeouts = New-Object Hashtable
|
|
|
|
#set maximum $async threads
|
|
$fThreads = New-Object int
|
|
$aThreads = New-Object int
|
|
[System.Threading.ThreadPool]::GetMaxThreads([ref]$fThreads, [ref]$aThreads) | Out-Null
|
|
[System.Threading.ThreadPool]::SetMaxThreads($fthreads,$maxthreads) | Out-Null
|
|
|
|
function New-ScriptBlockCallback {
|
|
param(
|
|
[parameter(Mandatory=$true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[scriptblock]$Callback
|
|
)
|
|
|
|
#taken from http://www.nivot.org/blog/post/2009/10/09/PowerShell20AsynchronousCallbacksFromNET
|
|
if (-not ("CallbackEventBridge" -as [type])) {
|
|
Add-Type @"
|
|
using System;
|
|
|
|
public sealed class CallbackEventBridge
|
|
{
|
|
public event AsyncCallback CallbackComplete = delegate { };
|
|
|
|
private CallbackEventBridge() {}
|
|
|
|
private void CallbackInternal(IAsyncResult result)
|
|
{
|
|
CallbackComplete(result);
|
|
}
|
|
|
|
public AsyncCallback Callback
|
|
{
|
|
get { return new AsyncCallback(CallbackInternal); }
|
|
}
|
|
|
|
public static CallbackEventBridge Create()
|
|
{
|
|
return new CallbackEventBridge();
|
|
}
|
|
}
|
|
"@
|
|
}
|
|
|
|
$bridge = [CallbackEventBridge]::Create()
|
|
Register-ObjectEvent -InputObject $bridge -EventName CallbackComplete -Action $Callback | Out-Null
|
|
|
|
$bridge.Callback
|
|
|
|
}
|
|
|
|
function Test-Port {
|
|
|
|
Param (
|
|
[Parameter(Mandatory = $True)] [String] $h,
|
|
[Parameter(Mandatory = $True)] [int] $p,
|
|
[Parameter(Mandatory = $True)] [int] $timeout
|
|
)
|
|
|
|
try {
|
|
$pAddress = [System.Net.IPAddress]::Parse($h)
|
|
$sockets[$p] = new-object System.Net.Sockets.TcpClient $pAddress.AddressFamily
|
|
|
|
}
|
|
catch {
|
|
#we're assuming this is a host name
|
|
$sockets[$p] = new-object System.Net.Sockets.TcpClient
|
|
}
|
|
|
|
|
|
$scriptBlockAsString = @"
|
|
|
|
#somewhat of a race condition with the timeout, but I don't think it matters
|
|
if ( `$sockets[$p] -ne `$NULL)
|
|
{
|
|
if (!`$timeouts[$p].Disposed) {
|
|
`$timeouts[$p].Dispose()
|
|
}
|
|
|
|
`$status = `$sockets[$p].Connected;
|
|
if (`$status -eq `$True)
|
|
{
|
|
#Write-Output "$p is open"
|
|
`$openPorts.Add($p)
|
|
}
|
|
else
|
|
{
|
|
#Write-Output "$p is closed"
|
|
`$closedPorts.Add($p)
|
|
|
|
}
|
|
`$sockets[$p].Close();
|
|
|
|
`$sockets.Remove($p)
|
|
}
|
|
"@
|
|
$timeoutCallback = @"
|
|
#Write-Output "$p is filtered"
|
|
`$sockets[$p].Close()
|
|
if (!`$timeouts[$p].Disposed) {
|
|
`$timeouts[$p].Dispose()
|
|
`$filteredPorts.Add($p)
|
|
}
|
|
`$sockets.Remove($p)
|
|
"@
|
|
|
|
$timeoutCallback = [scriptblock]::Create($timeoutCallback)
|
|
|
|
$timeouts[$p] = New-Object System.Timers.Timer
|
|
Register-ObjectEvent -InputObject $timeouts[$p] -EventName Elapsed -Action $timeoutCallback | Out-Null
|
|
$timeouts[$p].Interval = $timeout
|
|
$timeouts[$p].Enabled = $true
|
|
|
|
$myscriptblock = [scriptblock]::Create($scriptBlockAsString)
|
|
$x = $sockets[$p].beginConnect($h, $p,(New-ScriptBlockCallback($myscriptblock)) , $null)
|
|
|
|
}
|
|
|
|
function PortScan-Alive
|
|
{
|
|
Param (
|
|
[Parameter(Mandatory = $True)] [String] $h
|
|
)
|
|
|
|
Try
|
|
{
|
|
|
|
#ping
|
|
if ($hostPortList.Contains(-1))
|
|
{
|
|
$ping = new-object System.Net.NetworkInformation.Ping
|
|
$pResult = $ping.send($h)
|
|
if ($pResult.Status -eq "Success")
|
|
{
|
|
return $True
|
|
}
|
|
}
|
|
foreach($Port in $hostPortList)
|
|
{
|
|
if ($Port -ne -1)
|
|
{
|
|
Test-Port -h $h -p $Port -timeout $Timeout
|
|
}
|
|
}
|
|
|
|
do {
|
|
Start-Sleep -Milli 100
|
|
if (($openPorts.Count -gt 0) -or ($closedPorts.Count -gt 0)) {
|
|
return $True
|
|
}
|
|
}
|
|
While ($sockets.Count -gt 0)
|
|
|
|
}
|
|
Catch
|
|
{
|
|
Write-Error "Exception trying to host scan $h"
|
|
Write-Error $_.Exception.Message;
|
|
}
|
|
|
|
return $False
|
|
}
|
|
|
|
function Portscan-Port
|
|
{
|
|
Param (
|
|
[Parameter(Mandatory = $True)] [String] $h
|
|
)
|
|
|
|
[string[]]$Ports = @()
|
|
|
|
foreach($Port in $Portlist)
|
|
{
|
|
Try
|
|
{
|
|
Test-Port -h $h -p $Port -timeout $Timeout
|
|
}
|
|
Catch
|
|
{
|
|
Write-Error "Exception trying to scan $h port $Port"
|
|
Write-Error $_.Exception.Message;
|
|
}
|
|
}
|
|
}
|
|
[bool] $hostResult = $False
|
|
|
|
if(!$SkipDiscovery)
|
|
{
|
|
[bool] $hostResult = PortScan-Alive $thost
|
|
$openPorts.clear()
|
|
$closedPorts.clear()
|
|
$filteredPorts.Clear()
|
|
}
|
|
if((!$PingOnly) -and ($hostResult -or $SkipDiscovery))
|
|
{
|
|
Portscan-Port $thost
|
|
}
|
|
while ($sockets.Count -gt 0) {
|
|
Start-Sleep -Milli 500
|
|
}
|
|
|
|
return @($hostResult, $openPorts, $closedPorts, $filteredPorts)
|
|
}
|
|
}
|
|
|
|
# the outer loop is to flush the loop.
|
|
# Otherwise Get-Job | Wait-Job could clog, etc
|
|
|
|
[int]$saveIteration = 0
|
|
[int]$computersDone=0
|
|
[int]$upHosts=0
|
|
while (($saveIteration * $SyncFreq) -lt $hostList.Count)
|
|
{
|
|
|
|
Get-Job | Remove-Job -Force
|
|
$sIndex = ($saveIteration*$SyncFreq)
|
|
$eIndex = (($saveIteration+1)*$SyncFreq)-1
|
|
|
|
foreach ($iHost in $hostList[$sIndex..$eIndex])
|
|
{
|
|
$ctr = @(Get-Job -state Running)
|
|
while ($ctr.Count -ge $nHosts)
|
|
{
|
|
Start-Sleep -Milliseconds $SleepTimer
|
|
$ctr = @(Get-Job -state Running)
|
|
}
|
|
|
|
$computersDone++
|
|
if(!$noProgressMeter)
|
|
{
|
|
Write-Progress -status "Port Scanning" -Activity $startMsg -CurrentOperation "starting computer $computersDone" -PercentComplete ($computersDone / $hostList.Count * 100)
|
|
}
|
|
|
|
Start-Job -ScriptBlock $portScanCode -Name $iHost -ArgumentList @($iHost, $SkipDiscovery, $PingOnly, $Timeout, $portList, $hostPortList, $Threads) | Out-Null
|
|
}
|
|
|
|
Get-Job | Wait-Job | Out-Null
|
|
|
|
foreach ($job in Get-Job)
|
|
{
|
|
$jobOut = @(Receive-Job $job)
|
|
[bool]$hostUp = $jobOut[0]
|
|
$jobName = $job.Name
|
|
|
|
$openPorts = $jobOut[1]
|
|
$closedPorts = $jobOut[2]
|
|
$filteredPorts = $jobOut[3]
|
|
|
|
if($hostUp) {
|
|
$upHosts ++
|
|
}
|
|
|
|
if (!$quiet)
|
|
{
|
|
$hostDate = Get-Date
|
|
$hostObj = New-Object System.Object
|
|
$hostObj | Add-Member -MemberType Noteproperty -Name Hostname -Value $jobName
|
|
|
|
$hostObj | Add-Member -MemberType Noteproperty -Name alive -Value $hostUp
|
|
$hostObj | Add-Member -MemberType Noteproperty -Name openPorts -Value $openPorts
|
|
$hostObj | Add-Member -MemberType Noteproperty -Name closedPorts -Value $closedPorts
|
|
$hostObj | Add-Member -MemberType Noteproperty -Name filteredPorts -Value $filteredPorts
|
|
$hostObj | Add-Member -MemberType NoteProperty -Name finishTime -Value $hostDate
|
|
|
|
$scannedHostList += $hostobj
|
|
}
|
|
|
|
Write-PortscanOut -outhost $jobName -isUp $hostUp -openPorts $openPorts -closedPorts $closedPorts -filteredPorts $filteredPorts -grepStream $grepStream -xmlStream $xmlStream -readableStream $readableStream -SkipDiscovery $SkipDiscovery
|
|
}
|
|
|
|
if ($grepStream) {
|
|
$grepStream.flush()
|
|
}
|
|
if ($xmlStream) {
|
|
$xmlStream.flush()
|
|
}
|
|
if($readableStream) {
|
|
$readableStream.flush()
|
|
}
|
|
|
|
$saveIteration ++
|
|
}
|
|
|
|
$enddate = Get-Date
|
|
$totaltime = ($enddate - $startdate).TotalSeconds
|
|
$endMsg = "Port scan complete at $enddate ($totaltime seconds)"
|
|
if (!$SkipDiscovery) {
|
|
$endMsg += ", $upHosts hosts are up"
|
|
}
|
|
|
|
Write-PortscanOut -comment $endMsg -grepStream $grepStream -xmlStream $xmlStream -readableStream $readableStream
|
|
|
|
if($grepStream) {
|
|
$grepStream.Close()
|
|
}
|
|
if ($xmlStream) {
|
|
$xmlStream.Close()
|
|
}
|
|
if($readableStream) {
|
|
$readableStream.Close()
|
|
}
|
|
|
|
return $scannedHostList
|
|
|
|
}
|
|
Catch
|
|
{
|
|
Write-Error $_.Exception.Message;
|
|
}
|
|
}
|
|
}
|