Статья [ Пишем Hack-Tools ] - многопоточный сканер портов

Приветствую всех читателей!

Начну с того, а зачем изобретать велосипед, если их уже куча написана? Все мы понимаем, что велосипеды разные - чёрные, белые, красные )))

Когда я посмотрел примеры многопоточных сканеров, то понял, что большая часть из них имеет диапазон типа for port in range(1,100): , значит перебор портов будет с 1 по 99. Если мне понадобится порт например 20000, то при попытке записи ]for port in range(1,20001): сканер загнётся от переполнения памяти и невозможности создания нового потока.

Сканеры же, имеющий подобранные порты типа [21, 22, 23, 25, 38, 43, и т.д. были однопоточными, и работали весьма медленно...

horsebike.jpg


В итоге я решил собрать новый велосипед из старых запчастей. Я хотел следующее:

1) Простой короткий код
2) Многопоточность
3) Указания нужных портов

Погнали:

Подключаем модуль threading для работы с потоками. Подключаем модуль socket для работы с сокетами (интерфейс для обеспечения обмена данными между процессами)

Python:
import threading
import socket

Вводим хост для сканирования

Python:
print('-' * 35)
target = input('Enter host:\n\n')
print('-' * 35)

Создаём функцию сканирования портов, в которой создаём сокет, и выставляем таймаут

Python:
def portscan(port): 

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(0.5)

Продолжаем функцию, добавляем в блоке обработки исключений попытку приконнектиться к хосту, и в случае соединения, пишем что порт открыт. Открытое соединение закрываем. Ставим оператор-заглушку pass, в случае отсутствия соединения, ничего не выполняем.

Python:
try:
        connection = s.connect((target, port)) 
        print('Port :', port, "is open.") 
        connection.close()   
    except:
        pass

Пишем список портов (можете добавить любые по желанию).

Python:
ports = [21, 22, 23, 25, 38, 43, 80, 109, 110, 115, 118, 119, 143,  # Список портов
194, 220, 443, 540, 585, 591, 1112, 1433, 1443, 3128, 3197,
3306, 4000, 4333, 5100, 5432, 6669, 8000, 8080, 9014, 9200]

Ну вот и подошли к самому главному и интересному.

Делаем следующую запись, в которой мы запускаем перебор в цикле портов, создаём и запускаем потоки.

Python:
for element in ports: 
    t = threading.Thread(target=portscan, kwargs={'port': element})

    t.start() 

input()

Рассмотрим подробнее, что происходит в этом блоке

Для этого я пошагово запустил скрипт в Pycharm. Хост взял наобум из сети, поэтому я его закрасил. Смотрим внимательнее на скрин - когда у нас шаг прошёл создание потока, появилась надпись, в которой мы видим инициализацию нового потока. Значит всё работает как надо.

scan3.png


На следующем шаге поток запустился.

scan5.png


Если в потоке поставленная задача выполнена, то он останавливается

scan6.png


Результат работы программы наглядно показывает, что потоки закрываются не в том порядке, что открывались. То есть они действительно работают параллельно. На каждый порт запускается отдельный поток. В процессе сканирования, количество потоков разное, взависимости от количества уже отработанных потоков.

scan.png


На моём стареньком компе 2010 года и модемной связи от сотового оператора, скрипт выполняется за мгновенье.
Получилось всё как было задумано.

1457872e557e464.jpg


Исходный код с подробными комментариями

Python:
import threading  # Подключаем модуль threading для работы с потоками
import socket  # Подключаем модуль socket для работы с сокетами (интерфейс для обеспечения обмена данными между процессами)

print('-' * 35)
target = input('Enter host:\n\n')  # Ввод хоста для сканирования
print('-' * 35)


def portscan(port):  # Создаём функцию сканирования портов

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # Создаём сокет
    s.settimeout(0.5)   # Выставляем таймаут

    try:
        connection = s.connect((target, port))  # Пытаемся приконнектиться к хосту
        print('Port :', port, "is open.")   # В случае соединения, пишем что порт открыт
        connection.close()   # Закрываем соединение
    except:
        pass   # Оператор-заглушка, в случае отсутствия соединения, ничего не выполняем


ports = [21, 22, 23, 25, 38, 43, 80, 109, 110, 115, 118, 119, 143,  # Список портов
194, 220, 443, 540, 585, 591, 1112, 1433, 1443, 3128, 3197,
3306, 4000, 4333, 5100, 5432, 6669, 8000, 8080, 9014, 9200]

for element in ports:   # Перебор в цикле портов
    t = threading.Thread(target=portscan, kwargs={'port': element})  # Создаём поток

    t.start()   # Запуск потока

input()
 
P

PenGenKiddy

В любом случае лучше отправлять syn ack через scapy
 

explorer

Platinum
05.08.2018
1 080
2 475
BIT
0
В любом случае лучше отправлять syn ack через scapy
Да, scapy мощный инструмент, однако я сильно сомневаюсь, что скорость будет не хуже. Но вы можете написать свой вариант.
Вот тестовый результат:

sec.png

Для примера взял yahoo.com
Кстати, для тех кто не понял - можно вбивать в сканер как доменное имя yahoo.com так и ip адрес 87.248.98.7

sec.png
 

Anonimyc

Member
25.04.2017
6
0
BIT
0
привет, подскажите пожалуйста как запустить данный код, с-под винды 7? в каком формате файл сохранить?
 

explorer

Platinum
05.08.2018
1 080
2 475
BIT
0
привет, подскажите пожалуйста как запустить данный код, с-под винды 7? в каком формате файл сохранить?
Любой код Python сохраняется с расширением py. Копируете код, вставляете в блокнот и сохраняете, например portscan.py
Для запуска программы должен быть установлен Python3 и поставлены зависимости Пуск --> Выполнить --> cmd.exe:

pip install socket
pip install threading
Потом можно запускать двойным кликом по программе.
 
29.07.2020
41
6
BIT
0
В итоге я решил собрать новый велосипед из старых запчастей. Я хотел следующее:

1) Простой короткий код
2) Многопоточность
3) Указания нужных портов

Этот код - не работает.
Здесь нет многопоточности.
У пользователя нет возможности указать номера портов, а также адрес цели.

Предоставленный автором скрипт - не более чем тест на внимательность, а не сканер портов.
 
  • Не нравится
Реакции: f22
29.07.2020
41
6
BIT
0
pip install socket
pip install threading
Потом можно запускать двойным кликом по программе.
Указанные модули являются стандартными, их установка - не нужна.
По-моему, это основы языка.
 

explorer

Platinum
05.08.2018
1 080
2 475
BIT
0
Указанные модули являются стандартными, их установка - не нужна.
По-моему, это основы языка.
Спасибо за внимательность, странно что никто ранее не заметил. Конечно не нужно, видимо я на автомате написал, много раз в разных темах про установку модулей одно и тоже спрашивали.
 
  • Нравится
Реакции: Сергей Попов
29.07.2020
41
6
BIT
0
explorer, беда вашего кода не в импортировании библиотек, а в отсутствии всего трёх знаков:
строку
connection = s.connect((target, port))
надо заменить:
connection = s.connect_ex((target, port))

Метод - connect_ex

Но и это не всё )
Вы не вложили в него свою душу.
Вы написали его так, как ученик пишет контрольную работу. Написали, сдали и легко вздохнули.
  • Нет "защиты от дурака",
  • Пользователю не предоставлена возможность выбора портов и целей.
  • Где изысканность мышления ?

Я - гастербайтер.
Если-бы гастербайтеры делали свою работу так, как пишут код некоторые пРагРамМысТЫ, то люди жили-бы в руинах.
 

explorer

Platinum
05.08.2018
1 080
2 475
BIT
0
Моя_ПреЛесТь никакой ошибки в коде нет, метод connect_ex там совершенно не нужен. То что отсутствует блок try/exect вас смущает, ну так я его не писал, это очевидно. Что касается портов, гораздо проще перечислить порты в коде, чем их постоянно вводить для каждого таргета.

Как это пользователю не предоставлен выбор таргета? Похоже не такой уж вы и внимательный. А это в коде тогда что?
target = input('Enter host:\n\n') # Ввод хоста для сканирования
Да код не идеальный, я могу как угодно его написать и с ООП, и со всеми обработками ошибок, и с более грамотной многопоточностью через классы а не с Thread и т.д. Это старая статья, цель не стояла написать идеальный код, я писал очень много кода "на все случаи жизни", просто учился.
 
29.07.2020
41
6
BIT
0
Ага, выбор цели я не заметил - каюсь ) Приношу извинения .

explorer, нисколько не сомневаюсь в уровне Ваших знаний, Вы напрасно объясняетесь). Они (знания) неоднократно подтверждены Вами в различных статьях. Вероятно, впреть мне нужно подбирать более мягкие выражения в своих комментариях ))
Насчёт метода - я с Вами буду спорить.
Самоё интересное, что на форуме имеется ещё одна аналогичная статья, посвящённая многопоточному сканеру портов.
Простой многопоточный сканер портов

Cenzor воплотил в коде аналогичную Вашему коду многопоточность, использовал ООП и тот-же метод ( я считаю - не совсем корректный метод ), а также использовал модули:
  • argparse - для ввода аргументов , как в nmap
  • tqdm - для вывода работы скрипта в виде прогресс-бара.

метод connect_ex там совершенно не нужен
Нужен, нужен .
Попробуйте в Linux просканировать локальную сеть.
Ваши скрипты не обнаружат открытые порты.
 

f22

Codeby Academy
Gold Team
05.05.2019
1 940
228
BIT
1 772
Почему вы используете утверждение "надо"?
Смотрим доки
socket.connect_ex(address)
Like connect(address), but return an error indicator instead of raising an exception for errors returned by the C-level connect() call (other problems, such as “host not found,” can still raise exceptions). The error indicator is 0 if the operation succeeded, otherwise the value of the errno variable. This is useful to support, for example, asynchronous connects.
Главное отличие - вместо исключения при неудачном подключении, мы получаем обычный int.
Какого-то иного смысла в код программы это изменение не вносит.
Исключение обрабатывалось изначально.
Python:
try:
    connection = s.connect((target, port))
    print('Port :', port, "is open.")
    connection.close()
except:
    pass

Cenzor воплотил в коде аналогичную Вашему коду многопоточность, использовал ООП и тот-же метод ( я считаю - не совсем корректный метод ), а также использовал модули:
  • argparse - для ввода аргументов , как в nmap
  • tqdm - для вывода работы скрипта в виде прогресс-бара.
А с чего вы решили, что любая программа должна писаться в ООП стиле?
При чём тут необходимость ввода аргумента, если код автора может быть использован в каком-то ином скрипте/программе, где аргументы могут передаваться иными способами.

Но и это не всё )
Вы не вложили в него свою душу.
Вы написали его так, как ученик пишет контрольную работу. Написали, сдали и легко вздохнули.
  • Нет "защиты от дурака",
  • Пользователю не предоставлена возможность выбора портов и целей.
  • Где изысканность мышления ?
Ну что за ересь? В названии статьи где-то есть упоминание о финальном коммерческом продукте для конечного пользователя?
Автор предложил своё видение реализации, вот и всё.
Требовать от него чего-то ещё, как минимум неприлично.
Хочется - реализуйте сами, не знаете как - задайте вопрос.

Попробуйте в Linux просканировать локальную сеть.
Ваши скрипты не обнаружат открытые порты.
Что за бред?
Вы скрипт-то хоть запускали?
 
29.07.2020
41
6
BIT
0
f22, при всём уважении к тебе, ты чё злой такой ?
Когда глаза отойдут от злобной красноты, попробуй адекватно перечитать мои посты.
Я нигде не давал повода тому, что любая программа должна писаться в ООП.
Я ни от кого ничего не требую.
К конструкции try-except нигде претензий не высказывал.
С чего Вы решили, что я должен с вами соглашаться, почему я не имею права на критику ?

Что за бред?
Вы скрипт-то хоть запускали?

Сам бред несёшь.
Запусти и протестируй, вместо того, чтобы аргументировать выдержками из доков.
 

f22

Codeby Academy
Gold Team
05.05.2019
1 940
228
BIT
1 772
Я нигде не давал повода тому, что любая программа должна писаться в ООП.
Тогда к чему вы написали это?
Cenzor воплотил в коде аналогичную Вашему коду многопоточность, использовал ООП


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

К конструкции try-except нигде претензий не высказывал.
Тогда на каком основании вы утверждаете, что


С чего Вы решили, что я должен с вами соглашаться, почему я не имею права на критику ?
А где я утверждаю, что вы должны со мной соглашаться?
Вы критикуете чужой код с позиции "мне такой код не нравится, в нём изысканности мышления нет!" - а это абсолютно нелепый аргумент.

Запусти и протестируй, вместо того, чтобы аргументировать выдержками из доков.
Пожалуйста
21_15-26_putty_f230J5sXXW.png
 
29.07.2020
41
6
BIT
0
f22, я не буду реагировать на Ваши портянки высказывания.
Представьте только, что сейчас начнётся. если мы с Вами начнём учить друг друга правилам хорошего тона.
В конце концов, я не ставлю перед собою задачу понравиться Вам.
Оставайтесь со своими чертиками в своей голове своми мыслями.
Оставляю за вами право оставаться мелочным и злым.
Я не желаю втягиваться в эти разборки.


Насчёт работы скрипта.
Я наблюдаю совсем иную картину у себя.
screen.png

Скрипт запускался вчера и породил мои негативные комменты, а также сейчас, после ваших комментариев.
192.168.27.1 - роутер с OpenWRT на борту
192.168.27.109 - ноутбук под управлением Debian.

К обоим машинам ручное подключение происходит успешно.
Метод connect_ex меняет картину на противоположную.

Всё ёще с уважением к Вам )
 

f22

Codeby Academy
Gold Team
05.05.2019
1 940
228
BIT
1 772
Я наблюдаю совсем иную картину у себя.
Я не знаю, какой скрипт вы запускаете, но скрипт автора лежит здесь
21_16-16_chrome_5uAilrhI8T.png

Вот результат его работы
21_16-20_putty_I1jW4rjUXJ.png

А вот результат использования метода connect_ex(), на котором вы так настаиваете
21_16-23_putty_C4o6yi3T08.png

При том, что nmap выдаёт
21_16-24_putty_q2rn7NBJZH.png
 
29.07.2020
41
6
BIT
0
В любом случае лучше отправлять syn ack через scapy
Сканер портов, написанный на основе модуля scapy будет требовать привилегий суперпользователя. Невозможно создать и отравить пакет без root -привилегий.
Скорость сканирования по сравнению со сканером, написанным на основе модуля socket - не увеличится.
Не думаю, что это "лучше".
Или я что-то недопонимаю ?
 

Lisenok

Green Team
02.04.2016
133
75
BIT
1
Благодарствую! Как раз понадобился портсканер.
Кстати, если кто то захочет писать под себя, немного заглупил со строкой ports = [21... , там если один порт нужен Вам, то без кавычек пишите его, ports = 80 , к примеру.
А то я чуть ли не все там переписал из того что можно переписать, не понимал почему не сканирует, а вон оно как вышло)
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!