Создание сканера портов на Python

PythonBeginner
Практиковаться сейчас

Введение

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

Сканирование портов — это процесс отправки запросов на ряд портов сервера для определения того, какие из них открыты. Этот этап критически важен для обеспечения безопасности и поиска уязвимых служб. Мы начнем с изучения основ сканирования портов и его значения.

Ключевые концепции:

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

👀 Предварительный просмотр

Вот как будет выглядеть работа создаваемого нами инструмента:

python port_scanner.py 127.0.0.1 5000-9000

Вывод:

Opened Port: 8081
Scanning completed.

🎯 Задачи

В этом проекте вы научитесь:

  • Использовать возможности сетевого программирования Python (библиотека socket) для взаимодействия с сетевыми портами.
  • Реализовывать многопоточный подход в Python для повышения эффективности задач сетевого сканирования.
  • Разрабатывать консольный инструмент на Python, принимающий пользовательские данные для гибкой настройки сканирования.

🏆 Достижения

После завершения этого проекта вы сможете:

  • Использовать библиотеку socket для создания сетевых соединений, проверки доступности портов и обработки сетевых исключений.
  • Понимать и применять многопоточность в Python для выполнения параллельных задач, что значительно ускоряет операции, интенсивно использующие сеть.
  • Создавать практичные консольные скрипты, улучшив свои навыки программирования на Python и понимание парсинга аргументов командной строки.

Проверка TCP-соединения

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

Откройте файл с именем port_scanner.py в директории /home/labex/project и добавьте следующую функцию:

import argparse
from queue import Queue
from socket import AF_INET, gethostbyname, socket, SOCK_STREAM
import threading

def tcp_test(port: int, target_ip: str) -> None:
    with socket(AF_INET, SOCK_STREAM) as sock:
        sock.settimeout(1)
        result = sock.connect_ex((target_ip, port))
        if result == 0:
            print(f"Opened Port: {port}")

Этот код определяет функцию tcp_test, которая пытается установить TCP-соединение с конкретным портом по целевому IP-адресу. Мы устанавливаем таймаут, чтобы избежать длительного ожидания на каждом порту, и используем метод connect_ex для попытки подключения.

Если connect_ex возвращает 0, это означает, что соединение прошло успешно, порт открыт, и функция выводит соответствующее сообщение.

Настройка параллельной проверки портов

Далее мы создадим функцию-обработчик worker, которую будет использовать каждый поток для извлечения портов из очереди и вызова функции tcp_test.

Добавьте следующий код в ваш файл port_scanner.py:

def worker(target_ip: str, queue: Queue) -> None:
    while not queue.empty():
        port = queue.get()
        tcp_test(port, target_ip)
        queue.task_done()

Функция worker предназначена для запуска в нескольких потоках. Она непрерывно извлекает номера портов из очереди и использует ранее определенную функцию tcp_test для проверки их состояния.

После проверки порта она помечает задачу в очереди как выполненную. Такой подход позволяет сканировать порты одновременно, что значительно ускоряет процесс.

Организация процесса сканирования

Функция main координирует весь процесс: настраивает очередь, инициализирует рабочие потоки и управляет операцией сканирования в заданном диапазоне.

Добавьте функцию main в port_scanner.py:

def main(host: str, start_port: int, end_port: int) -> None:
    target_ip = gethostbyname(host)
    queue = Queue()
    for port in range(start_port, end_port + 1):
        queue.put(port)
    for _ in range(100):  ## При необходимости количество потоков можно изменить
        t = threading.Thread(target=worker, args=(target_ip, queue,))
        t.daemon = True
        t.start()
    queue.join()
    print("Scanning completed.")

Функция main управляет всем циклом работы сканера.

Сначала она преобразует имя хоста в IP-адрес, затем создает очередь для портов. Очередь заполняется всеми портами из указанного диапазона, после чего запускается несколько рабочих потоков (в данном примере 100), которые параллельно обрабатывают очередь. Функция ожидает завершения обработки всех портов (queue.join()) и выводит сообщение об окончании сканирования.

Запуск сканера портов

Наконец, пришло время запустить наш сканер. Мы просканируем диапазон портов на локальном хосте (localhost), чтобы протестировать инструмент.

Добавьте следующие строки в конец файла port_scanner.py, чтобы сделать скрипт исполняемым:

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='TCP Port Scanner')
    parser.add_argument('host', help='Host to scan')
    parser.add_argument('ports', help='Port range to scan, formatted as start-end')
    args = parser.parse_args()

    start_port, end_port = map(int, args.ports.split('-'))
    main(args.host, start_port, end_port)

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

С помощью библиотеки argparse определяются два обязательных аргумента: host и ports.

  • Аргумент host служит для указания адреса или имени целевого хоста.
  • Аргумент ports ожидает строку с диапазоном портов в формате "начало-конец" (например, "5000-8000"). Скрипт разделяет эту строку по символу -, преобразует значения в целые числа и передает их в функцию main.

Теперь запустите сканер, выполнив следующую команду в терминале:

python port_scanner.py 127.0.0.1 5000-9000

Вывод:

Opened Port: 8081
Scanning completed.

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

Для этого сначала нажмите кнопку добавления и выберите опцию "Web Service".

Выбор опции Web Service

Затем введите порт 8081 и нажмите кнопку "Access".

Ввод порта и доступ к веб-серверу

Вы увидите веб-сервер, работающий в вашей системе и ожидающий соединений на порту 8081.

Веб-сервер запущен на порту 8081

Резюме

В ходе этого проекта мы создали базовый сканер портов на Python, пройдя путь от простейшей функции tcp_test до полноценного многопоточного приложения. Мы разбили процесс на понятные этапы, в результате чего получили функциональный инструмент для идентификации открытых портов. Благодаря этой практике мы не только углубили знания в области сетевой безопасности, но и закрепили навыки программирования на Python и управления параллельными процессами.

✨ Проверить решение и практиковаться✨ Проверить решение и практиковаться✨ Проверить решение и практиковаться✨ Проверить решение и практиковаться