В этой статье познакомимся с перехватом трафика при помощи ARP-спуфинга с практической стороны. Научимся пользоваться утилитой arpspoof и реализуем ее аналог на Python. Также напишем анализатор сетевого трафика для обнаружения ARP-спуфинга.
Автор статьи никого не призывает к правонарушениям и отказывается нести ответственность за ваши действия. Вся информация предоставлена исключительно в ознакомительных целях. Все действия происходят на виртуальных машинах и внутри локальной сети автора. Спасибо!
Сегодня разберемся как выполнить перехват трафика с помощью ARP-спуфинга. Межсетевой экран/маршрутизатор PFSense, две ОС (KaliLinux и Metasploiatable) уже установлены и сконфигурированы в виртуальной машине.
Кстати, если вы столкнулись с проблемой установки PFSense на VirtualBox, например, при загрузке ядра вас обрадовали сообщениями can't find '/boot/entropy', can't find '/etc/hostid' или нечто подобным, то можете пролистать в конец статьи, чтобы узнать, как решить эту проблему.
Уязвимость протокола определения адресов (ARP) может потенциально использовать любой человек, подключившейся к публичному Wi-Fi для просмотра и перехвата незашифрованного трафика.
Готовимся к проведению атаки
Сама атака осуществляется в два этапа. На первом этапе отправляются жертве поддельные ARP-ответ с информацией, что MAC-адрес злоумышленника соответствует IP-адресу маршрутизатора.
Для начала просканируем сеть при помощи инструмента netdiscover. В моем случае это PFSense маршрутизатор (192.168.1.1) и заведомо уязвимая ОС Metasploitable (192.168.1.101)
Теперь необходимо нашей Kali Linux разрешить пересылать пакеты от имени других машин. Для этого установить ip_forward в единицу:
echo 1 > /proc/sys/net/ipv4/ip_forward
Теперь сгенерируем поддельные пакеты, указав интерфейс, IP-адрес жертвы и маршрутизатора, соответственно:
arpspoof -i eth0 -t 192.168.1.101 -r 192.168.1.1
Первый MAC-адрес принадлежит нашему компьютеру, создающему пакет. Второй MAC-адрес принадлежит нашей цели, которая получит ложный пакет. В последнем поле указано, что IP-адрес маршрутизатора соответствует нашему MAC-адресу. Опция —r означает, что обманывать будем оба хоста (цель и маршрутизатор), чтобы перехватывать трафик в обе стороны.
Открываем второй терминал и запускаем urlsnarf для перехвата сайтов, которые будет посещать цель:
urlsnarf -i eth0
Переходим в Metasploitable и обращаемся к любому сайту для примера:
curl http://www.google.com
Переходим в Kali Linux и видим этот запрос. Теперь необходимо все вернуть в исходное состояние. Нажмите Ctrl+C и инструмент arpspoof вернет реальные MAC-адреса.
Реализуем анализатор для обнаружения подобной атаки на Python
Теперь мы можем перейти к написанию простой защиты от ARP-спуфинга. Точнее мы реализуем анализатор, который будет выявлять признаки атаки. Заодно чуть глубже разберемся с работой протоколов.
Познакомимся еще с командой arping, которая посылает ARP-запрос/ответ. Похожа на команду ping, которая посылает ICMP-запрос/ответ. Утилиту arping можно использовать только внутри L2-доменов (группа устройств, которые соединены при помощи оборудования канального уровня). Отвлеклись. Давайте перейдем к коду на Python.
import os
from scapy.all import sniff
def process(packet):
# https://scapy.readthedocs.io/en/latest/api/scapy.layers.l2.html
ip = packet['ARP'].psrc
mac = packet['Ether'].src
# print(f'{ip} {mac}')
if mac in map_ip_mac.keys():
if map_ip_mac[mac] != ip:
try:
old_ip = map_ip_mac[mac]
except:
old_ip = "???"
print(f'Possible ARP-spoofing detected. Changed {old_ip} on {ip}.')
else:
map_ip_mac[mac] = ip
map_ip_mac = {}
sniff(count=0, filter='arp', store=0, prn=process)
Для решения нашей задачи был использован модуль scapy, предназначенный для создания и работы с сетевыми пакетами.
За основу была взята функция sniff(), которая принимает все пакеты. Более подробно можно узнать в документации: help(sniff).
Help on function sniff in module scapy.sendrecv:
sniff(*args, **kwargs)
Sniff packets and return a list of packets.
Args:
count: number of packets to capture. 0 means infinity.
store: whether to store sniffed packets or discard them
prn: function to apply to each packet. If something is returned, it
is displayed.
--Ex: prn = lambda x: x.summary()
session: a session = a flow decoder used to handle stream of packets.
--Ex: session=TCPSession
See below for more details.
filter: BPF filter to apply.
lfilter: Python function applied to each packet to determine if
further action may be done.
--Ex: lfilter = lambda x: x.haslayer(Padding)
offline: PCAP file (or list of PCAP files) to read packets from,
instead of sniffing them
quiet: when set to True, the process stderr is discarded
(default: False).
timeout: stop sniffing after a given time (default: None).
L2socket: use the provided L2socket (default: use conf.L2listen).
opened_socket: provide an object (or a list of objects) ready to use
.recv() on.
stop_filter: Python function applied to each packet to determine if
we have to stop the capture after this packet.
--Ex: stop_filter = lambda x: x.haslayer(TCP)
iface: interface or list of interfaces (default: None for sniffing
on all interfaces).
monitor: use monitor mode. May not be available on all OS
started_callback: called as soon as the sniffer starts sniffing
(default: None).
The iface, offline and opened_socket parameters can be either an
element, a list of elements, or a dict object mapping an element to a
label (see examples below).
For more information about the session argument, see
https://scapy.rtfd.io/en/latest/usage.html#advanced-sniffing-sniffing-sessions
Examples: synchronous
>>> sniff(filter="arp")
>>> sniff(filter="tcp",
... session=IPSession, # defragment on-the-flow
... prn=lambda x: x.summary())
>>> sniff(lfilter=lambda pkt: ARP in pkt)
>>> sniff(iface="eth0", prn=Packet.summary)
>>> sniff(iface=["eth0", "mon0"],
... prn=lambda pkt: "%s: %s" % (pkt.sniffed_on,
... pkt.summary()))
>>> sniff(iface={"eth0": "Ethernet", "mon0": "Wifi"},
... prn=lambda pkt: "%s: %s" % (pkt.sniffed_on,
... pkt.summary()))
Examples: asynchronous
>>> t = AsyncSniffer(iface="enp0s3")
>>> t.start()
>>> time.sleep(1)
>>> print("nice weather today")
>>> t.stop()
Нас интересуют аргументы count (количество захваченный пакетов. Если 0, то без ограничения), filter (фильтр, анализируем только ARP-пакеты), store (хранить ли пакеты или сразу удалять. Нам хранить их не нужно) и prn (функция, которая применяется к каждому пакету).
Как работает наша функция process(), применяемая к каждому пакету? Мы создаем свой словарь, в котором храним в виде ключа MAC-адрес, а виде значения – IP-адрес. В случае изменения первоначального IP-адреса на другой, мы выводим сообщение о возможном ARP-спуфинге.
Давайте запустим нашу программу для анализа трафика с root-правами в одном терминале. Во втором терминале запустим утилиту arping, чтобы просто создать хоть какую-нибудь нагрузку (хотя это и не нужно) и закрепить у себя в сознании наличие этой полезной утилиты. В третьем терминале запустим генерацию поддельных ARP-пакетов для маршрутизатора и целевого компьютера.
Как видите, наш простенький скрипт смог определить ARP-спуфинг. Разумеется, это очень примитивный пример, но он хорошо иллюстрирует работу протокола и как выглядит атака подобного рода.
Продолжаем разбираться с модулем scapy и реализуем свой аналог arpspoof
В начале статьи мы использовали утилиту arpspoof, которая создает поддельные пакеты. Давайте попробуем написать ее аналог с использованием Python и модуля scapy. Главное не забыть реализовать восстановление ARP-таблиц в исходное состояние после завершения атаки.
Более подробно о параметрах функции ARP() вы можете узнать по ссылке выше. Либо можете добавить в анализатор трафика строку print(packet.show()) и проанализировать как выглядит пакет (добавил комментарии, чтобы легче было понять):
###[ ARP ]###
hwtype = 0x1
ptype = IPv4
hwlen = 6
plen = 4
op = is-at
hwsrc = 08:00:27:50:4c:14 # MAC-адрес нашей машины
psrc = 192.168.1.1 # IP-адрес маршрутизатора
hwdst = 08:00:27:43:ff:df # MAC-адрес целевой машины
pdst = 192.168.1.101 # IP-адрес целевой машины
Теперь можете соотнести код функций arp_spoof() (создает поддельный пакет) и arp_restore() (восстанавливает ARP-таблицу) и пример пакета, созданного утилитой arpspoof. Убедились в интуитивности модуля scapy?
Для запуска достаточно запустить наш скрипт с нужными параметрами: IP-адрес целевой машины и маршрутизатора:
# python3 arpspoof.py 192.168.1.101 192.168.1.1
Примечание об установке PFSense на VirualBox
Отличное руководство по установке вы можете найти по этой ссылке. Очень много было потрачено времени на решение этой пустяковой задачи и на поиски ответа в противоположной стороне. Так вот, во многих источниках указано, что нужно выбирать тип операционной системы BSD и версию FreeBSD (64-bit), но у меня при такой раскладке возникала проблема при установке PFSense на VirtualBox. Если вы столкнулись с проблемой загрузки ядра при установке PFSense, измените тип операционной системы на Linux, а версию выберите Debian (64-bit). Вот и все решение проблемы.
Итоги
В этой статье мы бегло научились проводить ARP-спуфинг для перехвата трафика целевой машины при помощи утилиты arpspoof и самостоятельно реализовали ее аналог на языке Python с помощью модуля scapy. Также узнали, как анализировать трафик и обнаруживать возможный ARP-спуфинг.