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

Примечание: чтобы прослушивать пакеты в сети, вам нужно быть MITM (Человек посередине), т.е. вы можете сделать это, запустив Arp Spoofer.



Импорт:

import time
from colorama import Fore
from colorama import Style
import scapy.all
from scapy.layers import http
import psutil
from prettytable import PrettyTable
import subprocess
import re

Глобальные переменные:

choice = "Y"

get_current_mac:

def get_current_mac(interface):
 try:
  output = subprocess.check_output(["ifconfig",interface])
  return re.search("\w\w:\w\w:\w\w:\w\w:\w\w:\w\w",str(output)).group(0)
 except:
  pass

Этот код определяет функцию get_current_mac(interface), которая принимает на вход interface (например, «eth0», «wlan0»).

Внутри функции она сначала использует библиотеку subprocess для запуска команды ifconfig [interface] в командной строке и сохранения вывода в переменной output.

Затем он использует библиотеку re (регулярное выражение) для поиска строки, которая соответствует шаблону MAC-адреса в формате xx:xx:xx:xx:xx:xx, где x — шестнадцатеричная цифра. И функция возвращает совпадающую строку.

Функция использует блок try-except, в случае какой-либо ошибки в строке subprocess.check_output([“ifconfig”,interface]) она пропустит исключение и ничего не вернет.

get_current_ip:

def get_current_ip(interface):
 output = subprocess.check_output(["ifconfig",interface])
 pattern = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
 output1 = output.decode()
 ip = pattern.search(output1)[0]
 return ip

Этот код определяет функцию get_current_ip(interface), которая принимает на вход interface (например, «eth0», «wlan0»).

Внутри функции она сначала использует библиотеку subprocess для запуска команды ifconfig [interface] в командной строке и сохранения вывода в переменной «output».

Затем он использует библиотеку re (регулярное выражение) для поиска строки, которая соответствует шаблону IP-адреса в формате xxx.xxx.xxx.xxx, где x — десятичная цифра. Сначала он определяет шаблон, используя re.compile(r’(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})’). Он будет искать строку формата xxx.xxx.xxx.xxx, где x — десятичная цифра.

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

После этого он использует функцию search() объекта pattern для поиска первого вхождения строки, которая соответствует шаблону IP-адреса в строке output1. Он присваивает совпадающую строку переменной ip и возвращает ее.

ip_table:

def ip_table():
    #get all the interface deatils in with psutil in a variable
 addrs = psutil.net_if_addrs()
 t = PrettyTable([f'{Fore.GREEN}Interface','Mac Address',f'IP Address{Style.RESET_ALL}'])
 for k, v  in addrs.items():
  mac = get_current_mac(k)
  ip = get_current_ip(k)
  if ip and mac:
   t.add_row([k,mac,ip])
  elif mac:
   t.add_row([k,mac,f"{Fore.YELLOW}No IP assigned{Style.RESET_ALL}"])
  elif ip:
   t.add_row([k,f"{Fore.YELLOW}No MAC assigned{Style.RESET_ALL}",ip])
 print(t)

Этот код определяет функцию ip_table(), которая используется для печати таблицы сетевых интерфейсов и соответствующих им MAC-адресов и IP-адресов.

Сначала он использует библиотеку psutil, чтобы получить все детали интерфейса и сохранить их в переменной addrs.

Затем он создает таблицу, используя библиотеку PrettyTable, и задает для заголовков таблицы значения Interface, Mac Address и IP Address. Заголовки таблиц также форматируются, чтобы иметь зеленый цвет, используя класс Fore из библиотеки colorama.

Затем он перебирает интерфейсы в переменной addrs, где k — это ключ (т. е. имя интерфейса), а v — значение (т. е. список сведений об интерфейсе).

Для каждого интерфейса он вызывает функции get_current_mac(k) и get_current_ip(k), чтобы получить текущий MAC-адрес и IP-адрес интерфейса.

Затем он проверяет, не пусты ли переменные ip и mac, и добавляет в таблицу строку с именем интерфейса, MAC-адресом и IP-адресом. Если только mac не пусто, добавляет в таблицу строку с именем интерфейса, MAC-адресом и сообщением No IP assigned желтого цвета. Если только ip не пусто, добавляет в таблицу строку с именем интерфейса, сообщением No MAC assigned желтого цвета и IP-адресом.

Наконец, он печатает таблицу, используя оператор print(t).

нюхать:

def sniff(interface):
    #scapy.all.sniff(iface=interface, store=False, prn=process_sniffed_packet,filter="port 80")
    scapy.all.sniff(iface=interface, store=False, prn=process_sniffed_packet)

Этот код использует библиотеку Scapy для перехвата пакетов на указанном сетевом интерфейсе. Функция принимает один параметр, «интерфейс», который является сетевым интерфейсом, на котором перехватываются пакеты.

Функция использует метод Scapy sniff() для захвата пакетов на указанном интерфейсе с параметром store, установленным на False, что означает, что пакеты не будут храниться в памяти.

Вместо этого пакеты передаются функции process_sniffed_packet, указанной в параметре prn, каждый раз при захвате пакета.

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

process_sniffed_packet:

def process_sniffed_packet(packet):
    #funtion to monitor the packets
    #we check that the packet hac the layer httprequest
    if packet.haslayer(http.HTTPRequest):
        #if the packet has the http request then we check that it contain the RAW fied of the packet
        print("[+] HTTP REQUEST >>>>>")
        url_extractor(packet)
        test = get_login_info(packet)
        #if get_login_info found some then print those
        if test:
            print(f"{Fore.GREEN}[+] Username OR password is Send >>>> ", test ,f"{Style.RESET_ALL}")
        #To Print the raw Packet
        if (choice=="Y" or choice == "y"):
            raw_http_request(packet)

Этот код определяет функцию «process_sniffed_packet(packet)», которая принимает на вход «пакет», захваченный функцией «sniff()» библиотеки Scapy.

Функция сначала проверяет, имеет ли пакет уровень HTTPRequest, используя функцию haslayer() пакета и класс http.HTTPRequest из импорта scapy.layers.

Если пакет имеет уровень HTTPRequest, он печатает сообщение [+] HTTP REQUEST >>>>>, а затем вызывает две другие функции: url_extractor(packet) и get_login_info(packet). Функция url_extractor(packet) извлекает URL-адрес из пакета в удобочитаемом формате. Функция get_login_info(packet) используется для извлечения информации для входа в систему из пакета.

После этого, если функция get_login_info(packet) возвращает какое-либо значение, она печатает сообщение [+] Username OR password is Send >>>> и возвращаемое значение, которое предположительно представляет собой извлеченную информацию для входа.

Затем он проверяет глобальную переменную choice, чтобы узнать, является ли она Y или y, и если да, то вызывает функцию raw_http_request(packet), которая печатает необработанный HTTP-запрос пакета.

get_login_info:

def get_login_info(packet):
    if packet.haslayer(scapy.all.Raw):
            #if it contain the raw fild then print that field post request 
            load = packet[scapy.all.Raw].load
            load_decode = load.decode()
            keywords = ["username","user","email","pass","login","password","UserName","Password"]
            for i in keywords:
                if i in load_decode:
                    return load_decode

Этот код определяет функцию get_login_info(packet), которая принимает на вход packet, захваченную функцией sniff() библиотеки Scapy.

Функция сначала проверяет, имеет ли пакет уровень Raw, используя функцию haslayer() пакета и импорт scapy.all.Raw из библиотеки Scapy.

Если пакет имеет уровень Raw, он извлекает поле load из пакета, используя package[scapy.all.Raw].load. Затем он декодирует поле загрузки в строку, чтобы его можно было искать по ключевым словам.

Затем он создает список ключевых слов, который включает такие слова, как “username”, “user”, “email”, “pass”, “login”, “password”, “UserName”, “Password”, которые обычно используются в формах входа.

Затем он перебирает ключевые слова, проверяя, присутствуют ли какие-либо из них в переменной load_decode. Если какое-либо из ключевых слов присутствует в переменной load_decode, возвращается переменная load_decode.

url_extractor:

def url_extractor(packet):
    #get the http layer of the packet
    #packet.show() or packet.summary()
    http_layer= packet.getlayer('HTTPRequest').fields
    #get the ip layer of the packet 
    ip_layer = packet.getlayer('IP').fields
    #Print them in a readable form 
    print(ip_layer["src"] , "just requested \n" ,http_layer["Method"].decode()," ",http_layer["Host"].decode(), " " ,http_layer["Path"].decode() )
    return

Этот код определяет функцию url_extractor(packet), которая принимает на вход packet, захваченный функцией sniff() библиотеки Scapy.

Функция сначала использует функцию getlayer() пакета для извлечения слоя HTTPRequest и присвоения полей этого слоя переменной http_layer. Затем он снова использует функцию getlayer() для извлечения слоя IP и присваивает поля этого слоя переменной ip_layer.

Затем он печатает исходный IP-адрес из переменной ip_layer, сообщение just requested и метод, хост и путь из переменной http_layer. Он использует метод .decode() для преобразования строки байтов в строку.

raw_http_request:

def raw_http_request(packet):
    httplayer = packet[http.HTTPRequest].fields
    print("-----------------***Raw HTTP Packet***-------------------")
    print("{:<8} {:<15}".format('Key','Label'))
    try:
        for k, v in httplayer.items():
            try:
                label = v.decode()
            except:
                pass
            print("{:<40} {:<15}".format(k,label))  
    except KeyboardInterrupt:
        print("\n[+] Quitting Program...")  
    print("---------------------------------------------------------")
    # TO PRINT A SOLE RAW PACKET UNCOMMENT THE BELOW LINE
    # print(httplayer)

Этот код определяет функцию raw_http_request(packet) , которая принимает на вход packet, захваченную функцией sniff() библиотеки Scapy.

Сначала функция использует нотацию с квадратными скобками для извлечения слоя HTTPRequest пакета и присваивает поля этого слоя переменной httplayer.

Затем он печатает message — — — — — — — — -Raw HTTP Packet — — — — — — — — — - и создает таблицу с двумя столбцами Key и Label, используя формат {:<8} {:<15}.

Затем он использует блок try-except для перебора пар ключ-значение переменной httplayer. Для каждой пары ключ-значение он пытается декодировать значение и присваивает его переменной label. Затем он печатает ключ и метку в таблице.

У него также есть возможность распечатать весь необработанный пакет, но это прокомментировано в коде.

main_sniff:

def main_sniff():
    print(f"{Fore.BLUE}Welcome To Packet Sniffer{Style.RESET_ALL}")
    print(f"{Fore.YELLOW}[***] Please Start Arp Spoofer Before Using this Module [***] {Style.RESET_ALL}")
    try:
        global choice
        choice = input("[*] Do you want to to print the raw Packet : Y?N : ")
        ip_table()
        interface = input("[*] Please enter the interface name : ")
        print("[*] Sniffing Packets...")
        sniff(interface)
        print(f"{Fore.YELLOW}\n[*] Redirecting to Main Menu...{Style.RESET_ALL}")
        time.sleep(3)
    except KeyboardInterrupt:
        print(f"{Fore.RED}\n[!] Redirecting to Main Menu...{Style.RESET_ALL}")
        time.sleep(3)

Этот код определяет функцию main_sniff(), которая является основной функцией программы.

Сначала функция печатает сообщение Welcome To Packet Sniffer синим цветом и предупреждающее сообщение Please Start Arp Spoofer Before Using this Module желтым цветом.

Затем он использует блок try-except для обработки исключения KeyboardInterrupt. Внутри блока try он объявляет глобальную переменную choice и присваивает значение, введенное пользователем при запросе Do you want to to print the raw Packet : Y?N : . Затем он вызывает функцию ip_table(), которая выводит сведения о сетевых интерфейсах компьютера.

Затем он предлагает пользователю ввести имя интерфейса и присваивает его переменной interface. Затем он печатает сообщение Sniffing Packets… и вызывает функцию sniff(interface), которая перехватывает пакеты на введенном интерфейсе.

Наконец, он печатает сообщение Exiting… и ждет 3 секунды перед выходом из функции.

Если пользователь нажимает Ctrl+C (KeyboardInterrupt), блок try прерывается и выполняется блок exclude, где он печатает сообщение Exiting… и ждет 3 секунды перед выходом из функции.

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