Go каналы, tcp / ip portmap не возвращает все открытые порты - PullRequest
0 голосов
/ 29 апреля 2018

Я учу Голанга, чтобы перенести на него все свои инструменты тестирования на проникновение. Поскольку я люблю писать свои инструменты, это идеальный способ выучить новый язык. В этом конкретном случае я думаю, что что-то не так с тем, как я использую каналы. Я точно знаю, что это не завершение сопоставления портов, потому что другие инструменты, которые я использую, которые я написал на ruby, находят все открытые порты, но мой инструмент golang - нет. Может кто-нибудь, пожалуйста, помогите мне понять, что я делаю неправильно? Являются ли каналы правильным способом сделать это?

package main

import (
    "fmt"
    "log"
    "net"
    "strconv"
    "time"
)

func portScan(TargetToScan string, PortStart int, PortEnd int, openPorts []int) []int {
    activeThreads := 0
    doneChannel := make(chan bool)

    for port := PortStart; port <= PortEnd; port++ {
        go grabBanner(TargetToScan, port, doneChannel)
        activeThreads++
    }

    // Wait for all threads to finish
    for activeThreads > 0 {
        <-doneChannel
        activeThreads--
    }
    return openPorts
}

func grabBanner(ip string, port int, doneChannel chan bool) {
    connection, err := net.DialTimeout(
        "tcp",
        ip+":"+strconv.Itoa(port),
        time.Second*10)
    if err != nil {
        doneChannel <- true
        return
    }
    // append open port to slice
    openPorts = append(openPorts, port)

    fmt.Printf("+ Port %d: Open\n", port)
    // See if server offers anything to read
    buffer := make([]byte, 4096)
    connection.SetReadDeadline(time.Now().Add(time.Second * 5))
    // Set timeout
    numBytesRead, err := connection.Read(buffer)
    if err != nil {
        doneChannel <- true
        return
    }
    log.Printf("+ Banner of port %d\n%s\n", port,
        buffer[0:numBytesRead])
    // here we add to map port and banner
    targetPorts[port] = string(buffer[0:numBytesRead])

    doneChannel <- true
    return
}

Примечание. Кажется, что находят первые пакеты портов, но не те, которые находятся выше высоты, например 8080, но обычно получают 80 и 443 ... Поэтому я подозреваю, что что-то истекло или что-то странное происходит.

Есть много плохих хаков кода, в основном потому, что я много учусь и ищу, как что-то делать, поэтому не стесняйтесь давать советы и даже вносить изменения / тянуть запросы. спасибо

1 Ответ

0 голосов
/ 29 апреля 2018

Ваш код имеет несколько проблем. В grabBanner вы, похоже, ссылаетесь на openPorts, но он нигде не определен. Вы, вероятно, ссылаетесь на глобальную переменную, и эта операция добавления не будет поточно-ориентированной. В дополнение к проблемам безопасности ваших потоков вы, вероятно, исчерпываете ограничения файловых дескрипторов. Возможно, вам следует ограничить количество одновременной работы, выполнив что-то вроде этого:

package main

import (
    "fmt"
    "net"
    "strconv"
    "sync"
    "time"
)

func main() {
    fmt.Println(portScan("127.0.0.1", 1, 65535))
}

// startBanner spins up a handful of async workers
func startBannerGrabbers(num int, target string, portsIn <-chan int) <-chan int {
    portsOut := make(chan int)

    var wg sync.WaitGroup

    wg.Add(num)

    for i := 0; i < num; i++ {
        go func() {
            for p := range portsIn {
                if grabBanner(target, p) {
                    portsOut <- p
                }
            }
            wg.Done()
        }()
    }

    go func() {
        wg.Wait()
        close(portsOut)
    }()

    return portsOut

}

func portScan(targetToScan string, portStart int, portEnd int) []int {
    ports := make(chan int)

    go func() {
        for port := portStart; port <= portEnd; port++ {
            ports <- port
        }
        close(ports)
    }()

    resultChan := startBannerGrabbers(16, targetToScan, ports)

    var openPorts []int
    for port := range resultChan {
        openPorts = append(openPorts, port)
    }

    return openPorts
}

var targetPorts = make(map[int]string)

func grabBanner(ip string, port int) bool {
    connection, err := net.DialTimeout(
        "tcp",
        ip+":"+strconv.Itoa(port),
        time.Second*20)

    if err != nil {
        return false
    }
    defer connection.Close() // you should close this!

    buffer := make([]byte, 4096)
    connection.SetReadDeadline(time.Now().Add(time.Second * 5))
    numBytesRead, err := connection.Read(buffer)

    if err != nil {
        return true
    }

    // here we add to map port and banner
    // ******* MAPS ARE NOT SAFE FOR CONCURRENT WRITERS ******
    // *******************  DO NOT DO THIS *******************
    targetPorts[port] = string(buffer[0:numBytesRead])

    return true
}

Ваше использование var open bool и его постоянная настройка, а затем возврат - и ненужные, и лишенные смысла. Кроме того, проверка if someBoolVar != false не является идиоматическим и многословным способом записи if someBoolVar.

Кроме того, карты не безопасны для одновременного доступа, но ваша функция grabBanner пишет на карту из многих подпрограмм go одновременно. Пожалуйста, прекратите изменять глобальное состояние внутри функций . Вместо этого возвращайте значения.

Вот обновленное объяснение того, что происходит. Сначала мы создаем канал, по которому мы будем выдвигать номера портов для обработки нашими работниками. Затем мы запускаем подпрограмму go, которая записывает порты в диапазоне на этот канал так быстро, как только может. Как только мы записали каждый порт, доступный на этот канал, мы закрываем канал, чтобы наши читатели могли выйти.

Затем мы вызываем метод, который запускает настраиваемое количество bannerGrabber рабочих. Мы передаем IP-адрес и канал для чтения номеров портов-кандидатов. Эта функция порождает num процедуры, каждая из которых проходит по каналу portsIn, который был передан, вызывает функцию grab banner и затем выдвигает порт на исходящий канал, если он был успешным. Наконец, мы запускаем еще одну подпрограмму go, которая ожидает завершения sync.WaitGroup, чтобы мы могли закрыть исходящий (результат) канал, как только все рабочие будут выполнены.

Возвращение в функцию portScan Мы получаем исходящий канал в качестве возвращаемого значения из функции startBannerGrabbers. Затем мы выбираем канал результата, который был возвращен нам, добавляем все открытые порты в список и затем возвращаем результат.

Я также изменил некоторые стилистические вещи, такие как сокращение имен аргументов вашей функции.

Имея риск звучать как испорченная пластинка, я еще раз подчеркну следующее. Прекратить мутировать глобальное состояние . Вместо установки targetPorts вы должны накапливать эти значения безопасным для параллелизма способом и возвращать их вызывающей стороне для использования. Похоже, что использование вами глобальных переменных в этом случае является непродуманным сочетанием удобства и отсутствия размышлений о том, как решить проблему без глобальных значений.

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