Как ускорить работу сканера портов PowerShell - PullRequest
4 голосов
/ 21 июня 2019

По разным причинам я начал писать сканер портов 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] Задумывались об асинхронных соединениях сокетов, так как это может помочь общей скорости соединений - но тогда у вас естьчтобы другой поток / процесс следил за входящим трафиком.Не уверен насчет эффективности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...