ANTICHAT

ANTICHAT (https://forum.antichat.xyz/index.php)
-   PHP (https://forum.antichat.xyz/forumdisplay.php?f=37)
-   -   Разработка многопоточного сканера ip-диапазонов: от основ до оптимизации (https://forum.antichat.xyz/showthread.php?t=565543)

explorer 05.11.2018 17:38

Приветствую тебя читатель!

Сегодня мы окунёмся в настоящую эволюцию, и напишем целых три программы, от простого к более сложному.

https://forum.antichat.xyz/attachmen...c25b99c902.png

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

У разных портов бывает разное назначение. Приведу буквально несколько примеров:

21 — FTP (File Transfer Protocol) Протокол передачи файлов. FTP позволяет подключаться к серверам, просматривать содержимое каталогов и загружать файлы с сервера или на сервер.
23 — TELNET (TELecommunication NETwork) Позволяет управлять Операционной Системой удаленно.
53 – DNS (Domain Name System) Показывает установлен ли DNS. Может использоваться для так называемого DNS Spoofing, то есть подменой объекта DNS.

Первая ступень – черепаха

Приступим:

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

Python:


Код:

import
socket
from
netaddr
import
*

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

Python:


Код:

def
port_scan
(
port
,
host
)
:
s
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
s
.
settimeout
(
0.5
)
try
:
connection
=
s
.
connect
(
(
host
,
port
)
)
print
(
host
,
'Port :'
,
port
,
"is open."
)
connection
.
close
(
)
except
:
pass

Потом делаем ввод диапазонов IP-адресов, с помощью split определяем разделитель, в данном случае дефис. То есть ввод осуществляется так 87.248.98.0-87.248.98.255 Также назначаем начало и конец диапазона. Делаем ввод нужного порта.

Python:


Код:

ipStart
,
ipEnd
=
input
(
"Enter IP-IP: "
)
.
split
(
"-"
)
iprange
=
IPRange
(
ipStart
,
ipEnd
)
port
=
int
(
input
(
'Enter port: '
)
)

Ну и напоследок накидаем цикл перебора IP-адресов.

Python:


Код:

for
ip
in
iprange
:
host
=
str
(
ip
)
port_scan
(
port
,
host
)
input
(
)

Скрипт готов. Давайте его протестируем. Вводим диапазон87.248.98.0-87.248.98.255 и порт 443.

https://forum.antichat.xyz/attachmen...86cd3b3b1e.png

Сканер работает, но посмотрите на скорость – 127 секунд понадобилось, чтобы просканировать 256 позиций. Это ужасно медленно – настоящая черепаха! И немудрено, ведь он однопоточный.

https://forum.antichat.xyz/attachmen...47fc371121.png

Вторая ступень – арабский скакун

Если предыдущую программу сравнивать с лошадью, то у нас получилась жалкая кляча с заплетающимися копытами. Так давайте её пришпорим, и придадим прыти арабского скакуна!

Поскакали!

Для этого мы дополнительно импортируем модуль threading, необходимый для создания многопоточности.

Python:


Код:

import
threading
import
socket
from
netaddr
import
*

Теперь изменим цикл, и добавим туда создание и запуск потока.

Python:


Код:

for
ip
in
iprange
:
host
=
str
(
ip
)
t
=
threading
.
Thread
(
target
=
port_scan
,
args
=
(
port
,
host
)
)
t
.
start
(
)

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

https://forum.antichat.xyz/attachmen...206dfa76ca.png

https://forum.antichat.xyz/attachmen...59276f6aa0.png

Й-я-х-у-у!!! Фантастика!!! Всего три строчки добавлены в код, и программу просто не узнать. Скорость отличная, 8-9 сотых секунды на 256 хостов. Настоящий жеребец!

https://forum.antichat.xyz/attachmen...2c4571a3a4.png

Ну а теперь ложка дёгтя. Выставим-ка диапазон побольше 87.248.95.0-87.248.98.255 Здесь уже 1024 адреса. Запускаем программу, и … получаем ошибку – не удаётся запустить новый поток. Похоже наш арабский скакун подвернул себе ногу

https://forum.antichat.xyz/attachmen...0ada498759.png

А так всё хорошо начиналось… Программа получилась очень шустрая, но больше двух диапазонов(512 адресов), у неё не получается осилить. Произошёл конфликт потоков. Почему так произошло? Программа запускает потоки быстрее, чем они успевают завершаться.

На самом деле этот вопрос решается использованием замков или семафоров для блокировки потоков. Но мы на этот раз воспользуемся совершенно другой возможностью, которая есть в python – это мультипроцессинг.

Третья ступень – зверь

Ну что же друзья, вот мы и добрались до самого интересного. Начнём с того, чем же отличается мультипроцессинг от потоков. Потоки создаются в одном главном потоке GIL (Global Interpreter Lock). То есть все потоки работают внутри одного главного потока.

А модуль multiprocessing позволяет нам запускать множество процессов – сколько процессов, столько GIL'ов. Круто, да? Кроме того, имеется замечательный класс Pool умеющий выполнять функции параллельно. То есть исключается ситуация, когда несколько потоков пытаются обратиться одновременно к одному объекту. Для модуля multiprocessing также можно применять semaphore и lock, как и в threading. Но у нас будет чистый эксперимент без использования замков.

Возьмёмся за дело – вместо threading импортируем Pool. И немного изменим функцию port_scan.

Python:


Код:

import
socket
from
multiprocessing
import
Pool
from
netaddr
import
*
def
port_scan
(
arg
)
:
host
,
port
=
arg

    s
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
s
.
settimeout
(
0.5
)
try
:
s
.
connect
(
(
host
,
port
)
)
print
(
host
,
'Port :'
,
port
,
"is open."
)
s
.
close
(
)
return
port
,
True
except
(
socket
.
timeout
,
socket
.
error
)
:
return
port
,
False

Добавим вместо ввода порта количество процессов. А портов нарисуем целый список, чего уж тут вошкаться с одним портом

Python:


Код:

if
__name__
==
'__main__'
:
print
(
'-'
*
38
)
ipStart
,
ipEnd
=
input
(
"Enter IP-IP: "
)
.
split
(
"-"
)
iprange
=
IPRange
(
ipStart
,
ipEnd
)
number
=
int
(
input
(
'Number of processes: '
)
)
print
(
'-'
*
38
)
ports
=
[
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, вложив их в друг друга. Первый цикл останется без изменений, в нём мы прокрутим ip. Второй цикл создаёт пул процессов с аргументами порт и хост.

Python:


Код:

pool
=
Pool
(
processes
=
number
)
for
ip
in
iprange
:
host
=
str
(
ip
)
pool
.
imap_unordered
(
port_scan
,
[
(
host
,
port
)
for
port
in
ports
]
)

Так, уже чешутся руки потестить Не будем мелочиться, и забубеним вот такенный диапазон 87.248.85.0-87.248.98.255, но сколько же потоков сделать? Пусть будет 400! Ну вот, выставил от балды, а сколько же там операций понадобится провернуть программе? Немного математики не помешает.
14*256*34 = 121 856

Расшифрую – 14 диапазонов по 256 хостов и 34 порта.
Ну ничего себе!!! А не подавится?! Нечего гадать, старт! Первые секунды ничего не происходило, оно и понятно, в это время программа запускала 400 процессов. А потом понеслось…

https://forum.antichat.xyz/attachmen...ac3584547f.png

Ё-оу!!! Программа даже не поморщилась, проглотила и пережевала в своей пасти 121 856 операций. Настоящий зверь!!! Ушло времени 30.5 минут (1834.28 секунд).

https://forum.antichat.xyz/attachmen...99124ab94b.png

Давайте сделаем синтетический подсчёт - производительность операций в секунду:

1] Черепаха

256/127.28 = 2.01

2] Арабский скакун

256/0.09 =2844.44

3] Зверь

121 856/1834.28 = 66.43

Что мы видим – черепаха самая медленная, но она стабильная, и её скорость всегда будет примерно одинаковой.
Арабский скакун – просто огонь, лучшее решение для проверки 256 хостов.
Зверь – всеядный и бесстрашный, работает с огромными диапазонами ip, и большим количеством процессов, одновременно тестируя множество портов.

Ну а теперь ещё о звере. Мои наблюдения следующие:

- Если выставить 1 порт и маленький диапазон на 256 хостов, то скорость идентична черепахе. Меньше задач – меньше производительность.
- Пропуски открытых портов замечены не были.
- Разумеется при разном количестве процессов, результаты могут отличаться в разы.
- Количество процессов ограничено исключительно производительностью машины. Даже на моём древнем компе, 1000 запущенных процессов прекрасно переваривалось.

Однако не стоит думать, что чем больше процессов, тем лучше. После любого пика идёт падение, так что нужно выбирать золотую середину. Часто 90-100 процессов давали лучшие результаты. В общем нужно подбирать оптимальный параметр под своё железо.

Условия тестирования вкратце:

Windows 7, оперативной памяти 4 Гб, процессор Dual-Core E5400, видеокарта GeForce GT 630, скорость интернета очень низкая.

https://forum.antichat.xyz/attachmen...3a80394041.png

Послесловие:

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

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

P.P.S Сначала было интересно наблюдать как появляются всё новые списки закрытых портов. Но нет смысла выводить ненужную информацию в консоль, поэтому выводятся только гуды.
После запуска зверя тестирование портов идёт до тех пор, пока не появится надпись Enter to exit

explorer 06.11.2018 21:30

Тут у меня спрашивали про оконный интерфейс. Решил накидать оболочку.

https://forum.antichat.xyz/attachmen...a4297b0021.png

https://forum.antichat.xyz/attachmen...9839f2c91e.png

Только это черепаха То есть один диапазон сканирует две минуты. Ну и здесь ещё результаты выводятся после окончания сканирования, а не сразу. Короче учебный материал для тех, кто хочет GUI освоить.

Sharky 10.11.2018 23:29

Дальше - больше. Можно и запись в файл вести, а не в консоль. Жалко, что я не на питоне пишу, хотя даже я разобрался в исходном коде.

explorer 11.11.2018 12:47

Цитата:


shArky сказал(а):

Дальше - больше. Можно и запись в файл вести, а не в консоль. Жалко, что я не на питоне пишу, хотя даже я разобрался в исходном коде.


Я уже неспешно начал писать Pro-версию, запись в файл будет. Одной из главных фишек будет охват большого количества вариантов сканирования - типа:

* Диапазон IP - лист портов
* Диапазон IP - диапазон портов
* Лист IP - лист портов
и так далее всего 12 вариантов. Не нашёл в сети ничего похожего, 3-4 варианта максимум.

А чтобы пользователь не путался, всё будет вложено в друг друга, в общем для самого неподготовленного юзера будет простота использования.

lmike 22.11.2018 21:58

писал на java с nio по оракловому примеру, многопоточная прога...
на линухах упевала максимум открытых сокетов забить...
цель - поиск хостов в сетках, к которым комп подключен (автоматом определяет маски и интерфейсы с IPV4), с таймаутом по установлению соединения на сокет и общий таймаут по ожиданию всех потоков, запись в лог файл
CIDR ограничивал на 20
код для java 1.8
НО основным будет, в любом случае, детальное прощупывание хоста, т.е. ответ хоста c адресом/портом, по сокету - это ниочем

explorer 22.11.2018 22:06

Цитата:


lmike сказал(а):

писал на java с nio по оракловому примеру, многопоточная прога...
на линухах упевала максимум открытых сокетов забить...
цель - поиск хостов в сетках, к которым комп подключен (автоматом определяет маски и интерфейсы с IPV4), с таймаутом по установлению соединения на сокет и общий таймаут по ожиданию всех потоков, запись в лог файл
CIDR ограничивал на 20
код для java 1.8
НО основным будет, в любом случае, детальное прощупывание хоста, т.е. ответ хоста c адресом/портом, по сокету - это ниочем


Мясо всегда наращивается на скилет ) Сначала стулья...


Время: 17:44