1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Function Multi-TCP {
Param(
[String] $ip=$(throw "Parameter missing: -ip 192.168.0"),
[Int] $port = 80,
[Int] $timeout = 1000,
[Int] $thread = 20
)
$throttleLimit = $thread
$SessionState = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$Pool = [runspacefactory]::CreateRunspacePool(1, $throttleLimit, $SessionState, $Host)
$Pool.Open()
$ScriptBlock = {
Param(
[String] $_ip,
[Int] $_port,
[Int] $_timeout
)
try {
$tcpclient = New-Object -TypeName system.Net.Sockets.TcpClient
$iar = $tcpclient.BeginConnect($_ip,$_port,$null,$null)
$wait = $iar.AsyncWaitHandle.WaitOne($_timeout,$false)
if(!$wait) {
$tcpclient.Close()
Write-Host $_ip, $_port, $false
} else {
$null = $tcpclient.EndConnect($iar)
$tcpclient.Close()
Write-Host $_ip, $_port, $true
}
} catch {
$tcpclient.Close()
Write-Host $_ip, $_port, $false
}
}
$threads = @()
$handles = for ($x = 1; $x -le 255; $x++) {
$powershell = [powershell]::Create().AddScript($ScriptBlock).AddArgument("$ip.$x").AddArgument($port).AddArgument($timeout)
$powershell.RunspacePool = $Pool
$powershell.BeginInvoke()
$threads += $powershell
}
do {
$i = 0
$done = $true
foreach ($handle in $handles) {
if ($handle -ne $null) {
if ($handle.IsCompleted) {
$threads[$i].EndInvoke($handle)
$threads[$i].Dispose()
$handles[$i] = $null
} else {
$done = $false
}
}
$i++
}
if (-not $done) { Start-Sleep -Milliseconds 200 }
} until ($done)
}

代码只测试扫描C段IP,用法:

1
Multi-TCP -ip 192.168.0 [-port 80] [-timeout 1000] [-thread 50]

如果想支持批量VLSM格式的IP地址段,可参考Powersploit的部分代码, 代码顺便贴一下,防止忘记:
https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/Invoke-Portscan.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Function IP-Parse {
Param(
[String] $iHost
)
$hostList = New-Object System.Collections.ArrayList
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.Insert($hostList.Count, $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.Insert($hostList.Count, $address.IPAddressToString)
}
}
return $hostList
}