По разным причинам я начал писать сканер портов PowerShell, не в последнюю очередь, чтобы начать его изучать.
Первая использованная итерация Test-Netconnection
.Казалось, что это будет слишком медленно;поэтому я спустился на один уровень вниз, чтобы использовать сокеты, в частности System.Net.Sockets.TcpClient
.(Начали смотреть на System.Net.Sockets.Socket
, поскольку в документах MS упоминается Socket.BeginConnect()
метод , который может начать асинхронный запрос на удаленное соединение, но пока не уверен, поможет ли это.)
Это все еще казалось слишком медленным, поэтому я посмотрел на работу.Все, что было сделано, это потребляло больше ресурсов для небольшого увеличения скорости, поэтому после большого поиска в Google мне удалось заставить многопоточность (или то, что PowerShell называет многопоточность) работать с помощью RunSpacePools
.Я думал, что это в значительной степени сделано, и производительность в порядке, если вы просматриваете входной файл с 5 IP-адресами.Тем не менее, попробовал это с CIDR / 24 этим утром, и это заняло около 20-30 минут.
[Редактировать] Я должен добавить, что этот скрипт будет принимать значение 'thread', но если ничего не указано, используется значение потока по умолчанию number of cores + 1
, чтобы воспользоваться преимуществами многопоточности RunSpacePool.
Итак, я начал смотреть на то, как Федор увеличил свою скорость, и в The Art of Scanning
в PHRACK, статья 11 , он заявляет (пока говорит о сканировании TCP Connect ()):
При выполнении отдельного вызова connect () для каждого целевого порта в линейном режиме могут потребоваться несколько лет.при медленном соединении вы можете ускорить сканирование, используя множество сокетов параллельно.
Ясно, что здесь возможна некоторая оптимизация.
Итак, любой может указать мне направлениео том, как я это включаю - как я уже говорил, все еще довольно плохо знаком с PoSH, поэтому я расширяю границы моего понимания с помощью RunSpacePools
.В частности, я хотел бы получить совет: а) если мои инстинкты правы, чтобы увеличить скорость сканирования для увеличения параллелизма сокетов, б) как это сделать и в) если System.Net.Sockets.Socket
более уместно.
function doConnect {
$ipLoopCount = 0
$portLoopCount = 0
# check for randomise switch
if ($randomise) {
$ipArray = makeRange | Sort-Object {Get-Random}
$portArray = makePortRange | Sort-Object {Get-Random}
} else {
# Connects to IPs in order
$ipArray = makeRange
$portArray = makePortRange
}
# initialise runspaces
if ($threads) {
$useThreads = $threads
} else {
$useThreads = ([int]$env:NUMBER_OF_PROCESSORS + 1)
}
$pool = [RunspaceFactory]::CreateRunspacePool(1, $useThreads)
$pool.ApartmentState = "MTA"
$pool.Open()
$runspaces = @()
# set higher priority for powershell process
if ($priority) {
$proc = Get-Process -Id $pid;
$proc.PriorityClass = 'High'
} else{
$proc = Get-Process -Id $pid;
$proc.PriorityClass = 'Normal'
}
# info object
$infoDisplay = @{
InputFile = $inFile
Target_IPs = $ipArray
Target_Ports = $portArray
Process_Priority = $proc.PriorityClass
Threads = $useThreads
}
[PSCustomObject]$infoDisplay
# set up scriptblock to pass to runspaces
$scriptblock = {
Param (
[IPAddress]$sb_ip,
[int]$sb_port
)
# This progress bar doesn't work yet
Write-Progress -Activity "Scan range $StartIPaddress - $EndIPAddress" -Status "% Complete:" -PercentComplete((($portLoopCount)/($ipArray.Length*$portArray.Length))*100)
if ($delay) {
$delay = Get-Random -Maximum 1000 -Minimum 1;
Start-Sleep -m $delay
}
$socket = New-Object System.Net.Sockets.TcpClient
$socket.Connect($sb_ip, $sb_Port)
if ($socket.Connected) {
Write-Output "Connected to $sb_port on $sb_ip"
#} else {
# Write-Output "Failed to connect to port $sb_port on $sb_ip"
}
$socket.Close()
}
foreach ($nIP in $ipArray) {
$ipLoopCount++
foreach ($nPort in $portArray) {
$portLoopCount++
$runspace = [PowerShell]::Create()
$null = $runspace.AddScript($scriptblock)
$null = $runspace.AddArgument($nIP)
$null = $runspace.AddArgument($nPort)
$runspace.RunspacePool = $pool
$runspaces += [PSCustomObject]@{
Pipe = $runspace;
Status = $runspace.BeginInvoke()
}
}
}
while ($runspaces.Status -ne $null) {
$completed = $runspaces | Where-Object { $_.Status.IsCompleted -eq $true }
foreach ($runspace in $completed) {
$runspace.Pipe.EndInvoke($runspace.Status)
$runspace.Status = $null
}
}
$pool.Close()
$pool.Dispose()
}
Может случиться так, что PowerShell - совершенно неправильная попытка сделать это, но это полезное упражнение, поскольку среда достаточно закрыта, и установка «правильного» сканера портов - т.е. nmap - невозможна.
[Редактировать 2] Я не думаю, что сокращение тайм-аута и включение этого в логику - это решение, к которому я стремлюсь.
[Редактировать3] Параллельный коммутатор не помог.
[Редактировать 4] Задумывались об асинхронных соединениях сокетов, так как это может помочь общей скорости соединений - но тогда у вас естьчтобы другой поток / процесс следил за входящим трафиком.Не уверен насчет эффективности.