Python Многопоточность Обучение Сканер портов

Python в ИБ. Часть 10. Многопоточный сканер портов

Python в ИБ. Часть 10. Многопоточный сканер портов

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

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

Теперь мы добавим мультипоточность, то есть наш сканер будет работать не в одном основном потоке, сканирую один порт за другим, а сразу в нескольких потоках (как будто мы запускаем сканирование для каждого порта отдельно в другой консоли). Конечно, если спускаться на уровень ниже, то будет ясно, что многопоточность – это лишь абстракция, но нам это не особо нужно сейчас.

Для добавления многопоточности нам потребуется:

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

TCP_TIMEOUT – обозначает максимальное количество секунд, которое сокет будет пытаться установить соединение с портом на целевом сервере.

hostPort_queue – очередь состоящая из кортежей вида (host, port), из неё будут браться данные для запуска функции сканирования.

Идём дальше. Вынесем код сканирования в отдельную функцию.

По сути тот-же самый код, только теперь в функции, которая принимает в качестве аргументов ip-адрес и порт.

Теперь нам нужно сделать функцию, которая будет запускаться в отдельном потоке, брать не отсканированную пару хост-порт из очереди и запускать их сканирования. Назовём такую функцию runner, можно и по другому, обычно такие функции принято называть worker.

Эта функция забирает значения из очереди, после чего запускает их сканирование. После завершения сканирования, поток посылает сигнал, что он был завершён с помощью метода task_done.

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

Тут всё достаточно просто, создаётся 50 потоков, которые будут принимать значения из создаваемой очереди. Метод join() блокирует ход основного выполнения программы (то есть основной поток), пока не будут завершены все задачи которые есть в очереди, то есть пока не отработает сканирование.

Вот, что получилось в результате:

import socket
import argparse
import threading
from queue import Queue

cheks = {}
TCP_TIMEOUT = 5
hostPort_queue = None

def parsePorts( buf ):
	res = []

	if "-" in buf:
		res = [int(i) for i in range( int( buf.split( '-' )[ 0 ] ), int( buf.split( '-' )[ 1 ] ) + 1 ) ]
	else:
		res = [ int( buf ) ]

	return res

def init_parser():
	parser = argparse.ArgumentParser()
	parser.add_argument( "ip", type = str,
                    help = "target ip-addr" )
	parser.add_argument( "-p", type=str,
                    help="set port or range	with separator '-'" )

	return parser

def scanPort( host, port ):
	sock = socket.socket()
	sock.settimeout( TCP_TIMEOUT )

	try:
		sock.connect( ( host, port ) )
		cheks[ host + ":" + str( port ) ] = 'up'
	except:
		cheks[ host + ":" + str( port ) ] = 'down'

	sock.close()

def runner():
    while 1:
        host, port = hostPort_queue.get()
        scanPort( host, port )
        hostPort_queue.task_done()


if __name__ == "__main__":

	args = init_parser().parse_args()

	target_ip = args.ip
	ports = parsePorts( args.p )

	hostPort_queue = Queue()

	for _ in range( 50 ):
		thread = threading.Thread( target = runner )
		thread.daemon = True
		thread.start()

	for port in ports:
		hostPort_queue.put( (target_ip, port) )

	hostPort_queue.join()

	for i in cheks:
		if cheks[ i ] == 'up':
			print i, cheks[ i ]

Протестируем.

Запустим сканирование 5000 портов на старом сканере, который делал это в 1 поток и на новом, который делает это в 50 потоков.

Новый сканер справился за 1.6 секунды.

А у старого сканера это заняло бы 19 секунд.

Разница очевидна.

Очень злой админ
Очень злой админ Автор статьи

Админ сайта. Публикует интересные статьи с других ресурсов, либо их переводы. Если есть настроение, бывает, что пишет и что-то своё.

Leave a Reply

Your email address will not be published. Required fields are marked *