"Сканер Портов" на Python. 4 часть.
BLACK CODEПишем свой аналог NMAP на Python. Часть 4.

Предупреждение! Я не профессионал, так что в теории могу ошибиться!
Всем привет! Это канал BLACK CODE. Сегодня мы продолжим серию статьей по созданию своего сканера портов на Python.
Прошлый части:
Прошлая часть
В прошлой части мы в разы ускорили программу, а добились мы этого многопоточностью библиотеки threading.
Полный код программы из прошлой части - Полный код программы.
До завершения программы осталось уже совсем немного. И я решил посвятить эту часть визуальному оформлению. Сегодня мы будем использовать 2 новых библиотеки - colorama и os.
С помощью colorama мы добьёмся цветного текста в программе, а с помощью системной библиотеки os сделаем кое-что другое.
Colorama и os
Colorama
Colorama является сторонней библиотекой, так что придётся её установить через терминал.
Открываете терминал/cmd и пишем следующее:
Windows
pip install colorama
Linux/Mac OS
pip3 install colorama
Ждём установки и двигаемся дальше.
Давайте разберём только лишь тот функционал библиотеки, который мы будем сегодня использовать.
Импортируем 3 модуля в программу:
from colorama import Fore, Style, init
И за одно импортируем name из os:
from os import name
Она нам пригодится в модуле colorama
Так вот, Fore служит для того, чтобы делать цветной текст, вам нужно добавить название цвета на англ. к 'Fore.', чтобы получить какой-либо цвет, пример: Fore.YELLOW, а вот как это должно примерно выглядеть в питоне:
print(Fore.GREEN + 'Hello') # Вывод зелёным цетом надпись "Hello"
В библиотеке colorama существует всего 8 цветом, вот их список:

Но! Просто так на windows colorama не работает, поэтому мы еще импортируем функцию init из colorama и за одно name из os:
from colorama import Fore, init # импорт Fore и init из colorama
from os import name # импорт name из os
if name == 'nt': # Если система - Windows, то...
init() # Выполнение функции init
print(Fore.CYAN + 'Hello') # Вывод цветного текста
Объясняю, мы проверяем систему, если система называется nt(это windows), то выполняем функцию init(), без которой colorama на windows работать не будет
Вот так всё просто.
Теперь разбёрем еще и Style из colorama
Его мы будем использовать только для сброса цветов, при выходе из программы:
# импорт библиотек
from colorama import Fore, Style, init
from os import name
if name == 'nt': # если windows, то выполняем функцию init
init()
print(Fore.RED + 'BLACK CODE') # Вывод текста красным цветом
print(Style.RESET_ALL) # Сброс цветов
Если кто-то не понял, то это нужно, чтобы цвет не оставался при выходе программы.
Os
Библиотека os является стандартной в python, так что устанавливать её не придётся.
Перейдем сразу к модулям, который мы будем использовать - name, system.
Думаю вы уже поняли, что name - выдает кодовое название вашей системы.
Вот, что он может выдавать - 'posix', 'nt', 'mac', 'os2', 'ce', 'java'.
from os import name
print(name)
У меня выдаёт 'posix'(Mac OS).
Так, name разобрали, теперь очередь за system. system выполняет системные команды(cls, clear, ls, echo и тд...)
К примеру, у нас есть файл hello.txt, в котором есть одна строчка - "Hello from BLACK CODE'
И мы хотим прочитать содержание этого файла в программе(следующий пример не работает на windows, так как там не команды 'cat')
cat - выводит содержание файла
from os import system
system('cat hello.txt')
Всё, теперь в нашей программе произойдет вывод содержания 'hello.txt', а то есть - Hello from BLACK CODE.
С библиотеками разобрались, теперь приступим к написанию нашей новой функции.
Функция clear
Сегодня мы напишем новую функцию в нашей программе, её задача будет в очистке нашего экрана.
Надеюсь, что вы знаете команду, которая очищает экран вашей операционной системы. Если нет, то вот, держите:
clear - Команда для unix-like систем(linux, mac os и тд)
cls - Команда очистка для Windows
И так как мы пишем мультиплатформенную программу, то нам нужно что-то делать. Думаю вы догадались, что мы сейчас будем делать условие исходя из системы пользователя.
Давайте напишем данную функцию:
def clear(): # создание функции очитски экрана
if name == 'nt': # Если у пользователя windows, то...
system('cls') # Выполнение системной команды 'cls' для очистки экрана
else: # В противном случае...
system('clear') # Выполнение системной команды 'clear' для очистки экрана
Всё очень просто, мы смотрим систему, а потом выполняем нужную команду.
В принципе, на этом новаторство закончилось, далее я просто подставлял цвета под каждый print и input, а в конце их сбросил, еще вставил 2 раза функцию clear, но не вижу смысла это подробно рассматривать, там везде есть комментарии.
Полный код программы
# -*- coding: utf-8 -*-
import socket # импорт библиотеки socket
import threading # импорт библиотеки для многопоточности
from colorama import Fore, Style, init # импорт модулей Fore, Init и Style из библиотеки colorama
from os import name, system # импорт модуля name для определения системы, импорт system для выполнения системных команд
if name == 'nt': # Если у пользователя windows, то...
init() # Выполнение функции init из библиотеки colorama
def clear(): # создание функции очитски экрана
if name == 'nt': # Если у пользователя windows, то...
system('cls') # Выполнение системной команды 'cls' для очистки экрана
else: # В противном случае...
system('clear') # Выполнение системной команды 'clear' для очистки экрана
# Слоаврь с портами и их обозначениями
ports = {
20: 'FTP-DATA', 21: 'FTP', 22: 'SSH', 23: 'Telnet', 25: 'SMTP', 42: 'NAMESERVER',
43: 'WHOIS', 53: 'DOMAIN (DNS)', 67: 'BOOTPS', 69: 'TFTP', 80: 'HTTP', 110: 'POP3', 139: 'NETBIOS-SSN', 443: 'TCP - HTTPS',
1080: 'SOCKS', 3128: 'HTTP used by Web caches', 3389: 'RAdmin', 5900: 'Virtual Network Computing (VNC)',
8000: 'iRDMI', 8008: 'HTTP_ALT', 8080: 'WEBCACHE', 8888: 'NewsEDGE server'}
def single_scanning(host, port): # функцию сканирования одного порта
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # создание сокета
s.settimeout(0.5) # Ставим таймаут для сканирования
try: # пробуем сделать следующее
connection = s.connect((host, port)) # пробуем подключиться к порту
except socket.error: # если ошибка, то...
print(Fore.RED + '[-] Port: ' + str(port) + ' - CLOSED') # вывод о том, что порт закрыт (красный цвет)
else: # если ошибки не было, то...
try: # пробем получить ключ из словаря
print(Fore.GREEN + '[+] Port: ' + str(port) + '(' + ports[port] + ')' + ' - OPEN') # пробуем вытянуть порт из словаря(такого порта может не быть в словаре) (зеленый цвет)
except: # если ошибка, то...
print(Fore.GREEN + '[+] Port: ' + str(port) + ' - OPEN') # Выводим, что порт открыт, не берём значение из словаря (зеленый цвет)
def all_scanning(host, port): # сканирование всех портов в словаре
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # создание сокета
s.settimeout(0.5) # Ставим таймаут для сканирования
try: # пробуем сделать следующее...
connection = s.connect((host, port)) # пробуем подключиться к порту
print(Fore.GREEN + '[+] ' + ' Port: ' + str(port) + '(' + ports[port] + ') - OPEN') # если все прошло успешно, то вывод о том, что порт открыт (зеленый цвет)
except socket.error: # если ошибка socket'а, то...
pass # заглушка(ничего не делаем)
def main(): # главная функция
clear() # Вызов функции очистки экрана
print(Fore.GREEN + '''
|-------------------|
| PortScanner |
| |
| |
| BLACK CODE |
|-------------------|
''') # Вывод зеленым цветом приветсвенное сообщение
print(Fore.YELLOW + '''
1 - Single Port Scanning
2 - All Ports Scanning
''') # Вывод желтым цветом о выборе режима
mode = input(Fore.YELLOW + '\n[*] Enter Mode (1/2): ') # пользователь выбирает режим(желтый цвет)
clear() # Вызов функции очистки экрана
if mode == '1': # если пользователь ввёл 1, то...
host = input(Fore.YELLOW + '[*] Enter Host: ') # запрос цели у пользователя(желтый цвет)
port = int(input(Fore.YELLOW + '\n[*] Enter Port: ')) # запрос порта у пользователя(желтый цвет)
print(Fore.YELLOW + '\n[*] Scanning...\n') # (желтый цвет)
single_scanning(host, port) # запуск функции сканирования одного порта
elif mode == '2': # если пользователь ввёл 2, то...
host = input(Fore.YELLOW + '[*] Enter Host: ') # запрос цели у пользователя(жетый цввет)
print(Fore.YELLOW + '\n[*] Scanning...') # (желтый цвет)
print(Fore.GREEN + '\n[*] Open Ports:\n') # (зеленый цвет)
for port in ports: # перебор всех портов из словаря
thread = threading.Thread(target=all_scanning, kwargs={'host': host, 'port': port}) # создание потока, цель которого - функция "all_scanning", с аргументами - host, port
thread.start() # запускем поток
thread.join() # подсоединени потока к основному(чтобы программа дальше работала)
else: # если пользователь ввёл что-то другое, то...
print(Fore.RED + '[!] ERROR: Wrong Mode!') # Вывод сообщения о ошибке (красный цвет)
print(Style.RESET_ALL) # Сброс цветов
exit(1) # Выход из программы
print(Style.RESET_ALL) # Сброс цветов
main() # Вызов главной функции
Полный код программы(кликабельно)
Тестируем программу
Функционал остался почти тот же, изменилось лишь оформление:
Первый режим:



Второй режим:


Неправильный режим:


Всё отлично работает, можно было бы добавить аргументы, чтобы можно было запускать программу так:
python3 port_scanner4.py -t google.com -p 20
И так далее, но я вообще их не люблю, мне почему-то комфортнее запускать программы так.
На этом всё, думаю, что это предпоследняя часть, а следующая часть будет финальной, потому что больше придумать дополнение для программы, так как этот функционал уже довольно достойный. Подписывайтесь на BLACK CODE, чтобы не пропустить следующие статьи.
Надеюсь, что вы узнали что-то новое для себя.

Канал: BLACK CODE
Литература Хакера: @archivehacker
Админ: @blackcode_admin