background image

7/2010

14

OBRONA

Scapy

www.hakin9.org

15

N

a  wszystkie  powyższe  pytania  możemy  odpo-

wiedzieć: tak – mając do dyspozycji darmowe 

oprogramowanie scapy. Jedną możliwości ofe-

rowanych  przez  to  narzędzie  jest  generowanie  pakie-

tów – przy czym, w odróżnieniu od innych znanych ge-

neratorów pakietów (takich jak: sendip, nemesis, netdu-

de, czy hping), scapy:

•   posiada bardzo dużą bazę obsługiwanych protoko-

łów,

•   jest prosty i szybki w obsłudze,

•   zapewnia użytkownikowi wysoką elastyczność pod-

czas korzystania z oferowanej przez siebie funkcjo-

nalności,

•   jest aktywnie rozwijany,

•   oferuje bardzo szerokie możliwości skryptowania,

•   zapewnia  relatywnie  proste  możliwości  implemen-

tacji  obsługi  zupełnie  nowego  rodzaju  pakietów 

i protokołów (wymagana jest przy tym jednak zna-

jomość języka python). 

Sam  autor  narzędzia  twierdzi,  że  jest  ono  w  stanie 

zastąpić  takie  aplikacje  jak:  hping,  85%  funkcjonal-

ności nmap-a, arpspoof, arp-sk, arping, tcpdump, te-

thereal  czy  p0f.  Nie  będziemy  polemizować  z  tym 

twierdzeniem  –  zaprezentujemy  za  to  praktyczne 

przykłady wykorzystania scapy, niech one same bę-

dą komentarzem do możliwości tego oprogramowa-

nia.

ls() – wyświetlenie obsługiwanych pakietów

Scapy  w  wersji  2.1.0  obsługuje  przeszło  300  rodza-

jów pakietów, przy czym pakiet rozumiemy tutaj bardzo 

ogólnie – jako pewien odpowiednio sformatowany zbiór 

danych, który może być przesyłany przez sieć (stosow-

ne  formatowanie  określa  odpowiedni  protokół  siecio-

wy). Na Listingu 1 prezentujemy niewielki fragment li-

sty pakietów zaimplementowanych w scapy, przy czym 

dostępne  są  dodatkowe  pluginy  uzupełniające  tę  listę 

(przykład – protokół OSPF).

ls() – wyświetlenie szczegółów budowy 

pakietu

Przed  utworzeniem  pakietu  w  scapy  warto  zapoznać 

się z jego strukturą (Listing 2).

W pierwszej kolumnie podawana jest nazwa każdego 

pola, w drugiej jego typ, a w trzeciej – wartość domyśl-

na przy tworzeniu nowego pakietu.

Tworzenie nowego pakietu

W scapy jest to prosta operacja:

>>> p = ICMP()

Wyświetlenie szczegółów pakietu

W przykładzie z Listingu 3 jako domyślny typ ICMP został 

ustawiony  echo-request  (znany  z  popularnego  ping-a). 

Jeśli przy budowie pakietu chcielibyśmy podać inny typ, 

możemy zrobić to w sposób przedstawiony na Listingu 4.

Generator Pakietów Scapy

Czy istnieje łatwy sposób na wygenerowanie niemal 

dowolnych pakietów? Czy można bez większych trudności 

zmodyfikować przechwycony pakiet i wysłać go ponownie? 

Czy nieskomplikowanym zadaniem jest przygotowanie 

fuzzera protokołu sieciowego?

Michał Sajdak

Dowiesz się:

•   jak posługiwać się oprogramowaniem scapy,
•   jak generować (niemal) dowolny ruch sieciowy,
•   jak wykonać fuzzing protokołu sieciowego.

Powinieneś wiedzieć:

•   powinieneś  znać  podstawowe  protokoły  wykorzystywane 

w sieci Internet,

•   powinieneś znać dowolny język programowania.

background image

7/2010

14

OBRONA

Scapy

www.hakin9.org

15

Wygenerowanie grupy pakietów

Spróbujmy  tym  razem  wygenerować  nie  jeden  pakiet 

– a całą ich grupę, mianowicie 19 pakietów ICMP o polu 

type, przyjmującym wartości od 0 do 18 (pozostałe po-

la przyjmą wartości domyślne ustalone w scapy). Tym 

razem  skorzystamy  z  funkcji 

sr()

  (jej  nazwa  to  skrót 

od  send-receive),  wysyłającej  w  warstwie  3.  Funkcja 

ta zwraca dwie wartości: pakiety z wysyłanego zbioru, 

które doczekały się odpowiedzi oraz te, na które odpo-

wiedź nie przyszła – patrz Listing 12.

Proste skanowanie portów

Wykorzystując  wiedzę  z  powyższego  przykładu,  wy-

konajmy prosty skaner portów (Listing 13). W naszym 

przypadku będzie to wysłanie 4 pakietów TCP z usta-

wioną flagą Syn, na cztery różne porty.

W  pętli  powyżej  przeglądamy  całą  zwróconą  tabli-

cę o nazwie a. Każdy element tej tablicy posiada dwa 

kolejne elementy – pakiet wysłany oraz otrzymana na 

niego odpowiedź (w pętli odpowiadają tym elementom 

zmienne 

req 

oraz 

resp

). Jeśli odpowiedź jest pakietem 

TCP z flagą SA, oznacza to że badany port jest otwarty 

(otrzymaliśmy segment TCP z flagami SA w odpowiedzi 

na segment z flagą S).

Podsłuchiwanie ruchu oraz modyfikacja 

komunikacji sieciowej

Aby podsłuchać ruch, możemy skorzystać z wbudowa-

nej w scapy funkcji 

sniff()

, możemy również wczytać 

zbiór pakietów w formacie libpcap – funkcja 

rdpcap()

.

Na  Listingu  14  zauważmy,  że  przechwycony  przez 

nas pakiet IP zawiera początkowo poprawną sumę kon-

trolną, jednak po zmianie docelowego adresu IP, suma 

kontrolna  będzie  błędna!  Dlatego,  aby  wysłać  pakiet 

bez błędów, poprosiliśmy scapy o automatyczne wyge-

nerowanie prawidłowej sumy za nas, podstawiając jej 

wartość na pustą:

i[IP].chksum=None

Odczytanie  podsłuchanych  pakietów  ze  zrzutu  w  for-

macie libpcap jest równie proste (Listing 15.)

Przy  okazji  warto  również  wspomnieć  o  funkcji 

wrpcap()

 – zapisującej pakiety w formacie libpcap. Ta-

ka możliwość może okazać się przydatna, jeśli chcie-

libyśmy wybrane pakiety poddać obróbce lub analizie 

w innym,  zewnętrznym  narzędziu.  Dalej  (Listing  16) 

prezentujemy  przykład  sfragmentowania  komunikacji 

IP,  z  wykorzystaniem  narzędzia  tcprewrite,  które  po-

siada wkompilowaną obsługę mechanizmu fragroute.

Fuzzing protokołów sieciowych

W  skrócie,  fuzzing  protokołów  sieciowych,  polega  na 

wygenerowaniu  pakietów  niekoniecznie  zgodnych  ze 

specyfikacją protokołu oraz sprawdzeniu w jaki sposób 

W  przykładzie  na  Listingu  4  skorzystaliśmy  z  poda-

nia typu bezpośrednio lub za pośrednictwem mnemoni-

ka. Mnemoniki dla pól typu enum możemy wyświetlić za 

pomocą składni: pakiet.nazwa_pola.i2s

Łączenie pakietów

Jak  wiemy,  pełen  prawidłowy  pakiet  ICMP,  składa  się 

z kilku warstw: ramka (na potrzebny artykułu nazywamy 

 pakietem) warstwy drugiej modelu OSI, pakiet IP oraz 

pakiet ICMP. Złóżmy dwa pakiety – IP oraz wcześniej 

stworzony ICMP (Listing 4, Listing 5). Ramka etherne-

towa zostanie dodana później – już przez scapy.

Zauważmy,  że  wszystkie  pola  zostały  wypełnione 

zgodnie  z  wartościami  domyślnymi  (polecenie 

ls(typ_

pakietu)

) – a dodatkowo pole IP.proto zostało wypełnio-

ne poprawnie – tj. pakiet protokołu IP w powyższym pa-

kiecie transportuje pakiet protokółu ICMP. Zwróćmy rów-

nież uwagę na pola chksum – przyjęły one wartość None

W tym przypadku oznacza to, że sumy kontrolne zosta-

ną wyliczone na podstawie tego jak zbudujemy pakiet – 

a wykona to za nas scapy. Aktualną sumę kontrolną moż-

na zobaczyć wykorzystując metodę 

show2 

(Listing 6).

Przy  okazji  wspomnijmy,  że  dostępne  w  danej  kla-

sie zmienne i metody możemy uzyskać poleceniem 

dir 

(wynik  tego  polecania,  widoczny  na  Listingu  7,  został 

skrócony w celu ułatwienia prezentacji wyników).

Z  kolei  pomoc  dotyczącą  interesującej  nas  metody 

możemy uzyskać poleceniem 

help()

 – Listing 8.

Modyfikacja zawartości pakietu 

Aby zmodyfikować pole w interesującej nas warstwie, 

stosujemy  notację: 

pakiet[warstwa].pole  =  wartość

Na przykład:

p1[IP].dst = '192.168.0.1'

Wysłanie pakietu oraz odebranie odpowiedzi

Istnieje  kilka  funkcji  wysyłających  oraz  odbierających 

pakiety  –  można  je  poznać  wydając  polecenie

  lsc()

 

oraz 

help

(nazwa_funkcji).  W  przykładzie  poniżej  wy-

korzystamy funkcję 

sr1()

, która wysyła pakiety w war-

stwie 3 modelu OSI (tj. ramka warstwy drugiej zostanie 

za nas uzupełniona) oraz odbiera pierwszy pakiet odpo-

wiedzi (Listing 9).

Zauważmy,  że  nie  musieliśmy  uzupełniać  pakietu 

o ramkę ethernetową, tę pracę wykonała za nas funk-

cja 

sr1()

. Jeśli chcielibyśmy jednak kontrolować dane 

również w warstwie 2, musielibyśmy skorzystać z funk-

cji 

srp1()

 oraz uzupełnić pakiet o ramkę Ethernet. Przy 

założeniu, że w zmiennej i zdefiniowany mamy pakiet 

IP()/ICMP(), dołożenie ramki ethernetowej wygląda tak 

jak na Listingu 10.

Dla dalszego zobrazowania możliwości oferowanych 

przez scapy, prezentujemy wynik wspomnianego wyżej 

polecenia 

lsc()

 – widoczny na Listingu 11.

background image

7/2010

16

OBRONA

Scapy

www.hakin9.org

17

na taką komunikację zareaguje docelowy system. Przy-

kładowo, niepoprawnym pakietem może być pakiet IP 

z ustaloną nietypową wartością w polu IP.version. Czę-

sto w ten sposób wykryta może być błędna obsługa da-

nego pakietu przez docelowy system, co niekiedy koń-

czy się jego kompromitacją (patrz np. pracę Wifi Advan-

ced Fuzzing @ Blackhat EU 07, pokazującą podatno-

ści  umożliwiające  wykonanie  wrogiego  kodu  na  bez-

przewodowym  punkcie  dostępowym  z  uprawnieniami 

jądra systemu operacyjnego – potencjalnie nawet bez 

konieczności uwierzytelnienia się w urządzeniu access 

point!). Najprostsza postać realizacji fuzzingu w scapy 

wygląda tak jak na Listingu 17.

Odpowiadający  takiej  komunikacji,  zrzut  wykonany 

przy pomocy tcpdump-a wygląda z kolei tak jak na Li-

stingu 18.

Analogicznie  do  przykładu  pokazanego  na  Listingu 

18, istnieje możliwość ręcznego podstawienia danego 

pola, nie wartością, a funkcją, zwracającą wartość loso-

wą (Listing 19).

Prosty program w pythonie

Jako ilustrację do możliwości skryptowania z wykorzy-

staniem  scapy,  przedstawiamy  szkic  bardzo  prostego 

skanera portów napisanego w pythonie. Komentarzem 

do skryptu niech będzie sam kod źródłowy, jak na Li-

stingu 20.

Podsumowanie

Dociekliwych  Czytelników  zachęcamy  do  własnego 

eksperymentowania z oprogramowaniem scapy. Mamy 

nadzieję, że pokazaliśmy moc tego narzędzia, którego 

rozmaite zastosowania są ograniczone niemal tylko po-

mysłowością użytkownika.

Listing 1. Typy pakietów dostępne w scapy

securitum-t1:~# scapy
Welcome to Scapy (2.1.0)
>>> ls()

ARP        : ARP
ASN1_Packet : None
BOOTP      : BOOTP
CookedLinux : cooked linux
DHCP       : DHCP options
DHCP6      : DHCPv6 Generic Message)
...
DNS        : DNS
DNSQR      : DNS Question Record
DNSRR      : DNS Resource Record
DUID_EN    : DUID - Assigned by Vendor Based on 

Enterprise Number

Dot11      : 802.11
Dot11ATIM  : 802.11 ATIM
Dot11AssoReq : 802.11 Association Request
Dot11AssoResp : 802.11 Association Response
...
Dot1Q      : 802.1Q
Dot3       : 802.3
EAP        : EAP
EAPOL      : EAPOL
Ether      : Ethernet
GPRS       : GPRSdummy
GRE        : GRE
...
IP         : IP
IPOption   : None
IPOption_Address_Extension : IP Option Address 

Extension

...
PPP        : PPP Link Layer
PPP_ECP    : None
PPP_ECP_Option : PPP ECP Option
PPP_ECP_Option_OUI : PPP ECP Option
...
RIP        : RIP header
RIPEntry   : RIP entry
RTP        : RTP
RadioTap   : RadioTap dummy
Radius     : Radius
Raw        : Raw
RouterAlert : Router Alert
STP        : Spanning Tree Protocol
SebekHead  : Sebek header
TCP        : TCP
TCPerror   : TCP in ICMP
TFTP       : TFTP opcode
...

MICHAŁ SAJDAK

Dyrektor  ds.  Rozwoju  w  �rmie  Securi-
tum.  Prowadzi  szkolenia  o  tematyce 
związanej  z  bezpieczeństwem  IT  oraz 
realizuje  testy  penetracyjne  systemów 
IT. Posiadacz certy�katu CISSP. 
Kontakt z autorem: 
michal.sajdak@securitum.pl

W Sieci

•   http://www.secdev.org/projects/scapy/,

•   http://www.dirk-loss.de/scapy-doc/,

•   http://trac.secdev.org/scapy/wiki/OSPF,

•   http://freshmeat.net/projects/sendip/,

•   http://nemesis.sourceforge.net/,

•   http://netdude.sourceforge.net/,

•   http://www.hping.org/,

•   http://www.blackhat.com/presentations/bh-europe-07/

Butti/Presentation/bh-eu-07-Butti.pdf.

background image

7/2010

16

OBRONA

Scapy

www.hakin9.org

17

Listing 2. Struktura pakietu w scapy

>>> ls(ICMP)
type       : ByteEnumField        = (8)
code       : MultiEnumField       = (0)
chksum     : XShortField          = (None)
id         : ConditionalField     = (0)
seq        : ConditionalField     = (0)
ts_ori     : ConditionalField     = (50705671)
ts_rx      : ConditionalField     = (50705671)
ts_tx      : ConditionalField     = (50705671)
gw         : ConditionalField     = ('0.0.0.0')
ptr        : ConditionalField     = (0)
reserved   : ConditionalField     = (0)
addr_mask  : ConditionalField     = ('0.0.0.0')
unused     : ConditionalField     = (0)

Listing 3. Wyświetlenie zawartości pakietu

>>> p.show()
###[ ICMP ]###
  type= echo-request
  code= 0
  chksum= None
  id= 0x0
  seq= 0x0

Listing 4. Stworzenie pakietu ICMP

>>> p = ICMP(type=0)
>>> ICMP.type.i2s
{0: 'echo-reply', 3: 'dest-unreach', 4: 'source-

quench', 

5: 'redirect', 8: 'echo-request', 9: 'router-

advertisement', 

10: 'router-solicitation', 11: 'time-exceeded', 
12: 'parameter-problem', 13: 'timestamp-request', 
14: 'timestamp-reply', 15: 'information-request', 
16: 'information-response', 17: 'address-mask-

request', 

18: 'address-mask-reply'}
>>> p = ICMP(type='information-request')

Listing 5. Łączenie pakietów

>>> p1 = IP()/p
>>> p1.show()
###[ IP ]###
  version= 4
  ihl= None
  tos= 0x0
  len= None
  id= 1
  flags=
  frag= 0
  ttl= 64
  proto= icmp
  chksum= None
  src= 127.0.0.1
  dst= 127.0.0.1
  \options\
###[ ICMP ]###
     type= echo-request
     code= 0
     chksum= None
     id= 0x0
     seq= 0x0

Listing 6. Wynik metody show2()

>>> i.show2()
###[ IP ]###
  version= 4L
  ...
  chksum= 0x7cde
  ...
  \options\
###[ ICMP ]###
     ...
     chksum= 0xf7ff
>>>

Listing 7. Wyświetlenie zmiennych i metod dostępnych w 

danej klasie

>>> dir(p)
['__class__', '__contains__', '__delattr__', '__

delitem__', '__dict__', [...]

'add_payload', 'add_underlayer', 'aliastypes', 

'answers', 'build', [...]

'show', 'show2', 'show_indent', 'sprintf', 

'summary', 'time', [...]

background image

7/2010

18

OBRONA

Scapy

www.hakin9.org

19

Listing 8. Wyświetlenie pomocy dla wybranej metody

>>> 
help(p.show2)
Help on method show2 in module scapy.packet:

show2(self) method of scapy.layers.inet.ICMP instance
    Prints a hierarchical view of an assembled version of the packet, 
    so that automatic fields are calculated (checksums, etc.)

Listing 9. Podstawowa metoda wysłania pakietu oraz 

odebrania odpowiedzi – sr1()

>>> r = sr1(p1)
Begin emission:
Finished to send 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 

packets

>>> r.show()
###[ IP ]###
  version= 4L
  ihl= 5L
  tos= 0x0
  len= 28
  id= 30733
  flags=
  frag= 0L
  ttl= 64
  proto= icmp
  chksum= 0x8106
  src= 192.168.0.1
  dst= 192.168.0.124
  \options\
###[ ICMP ]###
     type= echo-reply
     code= 0
     chksum= 0xffff
     id= 0x0
     seq= 0x0
###[ Padding ]###
        load= '\x00\x00\x00\x00\x00\x00\x00\x00\x00\

x00\x00\x00\x00\x00\x00\x00\x00\
x00'

Listing 10. Podstawowa metoda wysłania pakietu oraz 

odebrania odpowiedzi - srp1()

>>> i2 = Ether(dst='00:19:5b:dc:b7:ec')/i
>>> i2.show()
###[ Ethernet ]###
  dst= 00:19:5b:dc:b7:ec
  src= 00:0c:29:7f:48:3f
  type= 0x800
###[ IP ]###
     version= 4
     ihl= None
     tos= 0x0
     len= None
     id= 1
     flags=
     frag= 0
     ttl= 64
     proto= icmp
     chksum= None
     src= 192.168.0.124
     dst= 192.168.0.1
     \options\
###[ ICMP ]###
        type= echo-request
        code= 0
        chksum= None
        id= 0x0
        seq= 0x0
>>> r2 = srp1(i2)
Begin emission:
Finished to send 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 

packets

background image

7/2010

18

OBRONA

Scapy

www.hakin9.org

19

Listing 11. Wynik polecenia lsc()

arpcachepoison: Poison target's cache with (your MAC,victim's IP) couple
arping        : Send ARP who-has requests to determine which hosts are up
defrag        : defrag(plist) -> ([not fragmented], [defragmented],
defragment    : defrag(plist) -> plist defragmented as much as possible
dyndns_del    : Send a DNS delete message to a nameserver for "name"
etherleak     : Exploit Etherleak flaw
fragment      : Fragment a big IP datagram
fuzz          : Transform a layer into a fuzzy layer by replacing some 
                default values by random objects
getmacbyip    : Return MAC address corresponding to a given IP address
hexdiff       : Show differences between 2 binary strings
ls            : List  available layers, or infos on a given layer
rdpcap        : Read a pcap file and return a packet list
send          : Send packets at layer 3
sendp         : Send packets at layer 2
sendpfast     : Send packets at layer 2 using tcpreplay for performance
sniff         : Sniff packets
split_layers  : Split 2 layers previously bound
sr            : Send and receive packets at layer 3
sr1           : Send packets at layer 3 and return only the first answer
srflood       : Flood and receive packets at layer 3
srloop        : Send a packet at layer 3 in loop and print 
                the answer each time
srp           : Send and receive packets at layer 2
srp1          : Send and receive packets at layer 2 and return only 
                the first answer
srpflood      : Flood and receive packets at layer 2
srploop       : Send a packet at layer 2 in loop and print the answer 
                each time
traceroute    : Instant TCP traceroute
tshark        : Sniff packets and print them calling pkt.show(), 
                a bit like text wireshark
wireshark     : Run wireshark on a list of packets
wrpcap        : Write a list of packets to a pcap file

Listing 12. Generowanie grupy pakietów

>>> pi = IP(dst='192.168.0.1')/ICMP(type=(0,18))
>>> answered,uanswered = sr(pi)
Begin emission:
...*.Finished to send 19 packets.
.......^C
Received 12 packets, got 1 answers, remaining 18 packets
>>> answered.show()
0000 IP / ICMP 192.168.0.124 > 192.168.0.1 echo-request 0 
==> IP / ICMP 192.168.0.1 > 192.168.0.124 echo-reply 0 / Padding
>>> uanswered.show()
0000 IP / ICMP 192.168.0.124 > 192.168.0.1 dest-unreach network-unreachable
0001 IP / ICMP 192.168.0.124 > 192.168.0.1 source-quench 0
0002 IP / ICMP 192.168.0.124 > 192.168.0.1 redirect network-redirect
0003 IP / ICMP 192.168.0.124 > 192.168.0.1 time-exceeded ttl-zero-during-transit
0004 IP / ICMP 192.168.0.124 > 192.168.0.1 parameter-problem ip-header-bad
0005 IP / ICMP 192.168.0.124 > 192.168.0.1 1 0

background image

7/2010

20

OBRONA

Scapy

www.hakin9.org

21

0006 IP / ICMP 192.168.0.124 > 192.168.0.1 2 0
0007 IP / ICMP 192.168.0.124 > 192.168.0.1 6 0
0008 IP / ICMP 192.168.0.124 > 192.168.0.1 7 0
0009 IP / ICMP 192.168.0.124 > 192.168.0.1 router-advertisement 0
0010 IP / ICMP 192.168.0.124 > 192.168.0.1 router-solicitation 0
0011 IP / ICMP 192.168.0.124 > 192.168.0.1 echo-reply 0
0012 IP / ICMP 192.168.0.124 > 192.168.0.1 timestamp-request 0
0013 IP / ICMP 192.168.0.124 > 192.168.0.1 timestamp-reply 0
0014 IP / ICMP 192.168.0.124 > 192.168.0.1 information-request 0
0015 IP / ICMP 192.168.0.124 > 192.168.0.1 information-response 0
0016 IP / ICMP 192.168.0.124 > 192.168.0.1 address-mask-request 0
0017 IP / ICMP 192.168.0.124 > 192.168.0.1 address-mask-reply 0

Listing 13. Proste skanowanie portów

>>> packets = IP(dst='192.168.0.1')/TCP(flags='S',dport=[22,23,80,515])
>>> a,ua=sr(packets)
Begin emission:
**..Finished to send 4 packets.
*.*
Received 7 packets, got 4 answers, remaining 0 packets
>>> a.show()
0000 IP / TCP 192.168.0.124:ftp_data > 192.168.0.1:ssh S 
==> IP / TCP 192.168.0.1:ssh > 192.168.0.124:ftp_data RA / Padding
0001 IP / TCP 192.168.0.124:ftp_data > 192.168.0.1:telnet S 
==> IP / TCP 192.168.0.1:telnet > 192.168.0.124:ftp_data RA / Padding
0002 IP / TCP 192.168.0.124:ftp_data > 192.168.0.1:www S 
==> IP / TCP 192.168.0.1:www > 192.168.0.124:ftp_data SA / Padding
0003 IP / TCP 192.168.0.124:ftp_data > 192.168.0.1:printer S 
==> IP / TCP 192.168.0.1:printer > 192.168.0.124:ftp_data SA / Padding

>>> for req,resp in a:
...     print "port = "+str(req.dport)
...     resp.sprintf('%TCP.flags%')
...
port = 22
'RA'
port = 23
'RA'
port = 80
'SA'
port = 515
'SA'

Listing 14. Podsłuchiwanie ruchu oraz mody�kacja komunikacji sieciowej

>>> res = sniff()
^C>>> res.show()
0000 Ether / IP / TCP 192.168.0.124:ssh > 192.168.0.107:3242 PA / Raw
0001 Ether / IP / TCP 192.168.0.107:3242 > 192.168.0.124:ssh A
0002 Ether / ARP who has 192.168.0.1 says 192.168.0.124
0003 Ether / ARP is at 00:19:5b:dc:b7:ec says 192.168.0.1 / Padding
0004 Ether / IP / UDP / DNS Qry "www.onet.pl."
0005 Ether / IP / UDP / DNS Ans "213.180.146.27"
0006 Ether / IP / ICMP 192.168.0.124 > 213.180.146.27 echo-request 0 / Raw

background image

7/2010

20

OBRONA

Scapy

www.hakin9.org

21

0007 Ether / IP / ICMP 213.180.146.27 > 192.168.0.124 echo-reply 0 / Raw
0008 Ether / IP / UDP / DNS Qry "27.146.180.213.in-addr.arpa."
0009 Ether / IP / UDP / DNS Ans "s4.m1r2.onet.pl."
0010 Ether / IP / ICMP 192.168.0.124 > 213.180.146.27 echo-request 0 / Raw
0011 Ether / IP / ICMP 213.180.146.27 > 192.168.0.124 echo-reply 0 / Raw
0012 Ether / IP / UDP / DNS Qry "27.146.180.213.in-addr.arpa."
0013 Ether / IP / UDP / DNS Ans "s4.m1r2.onet.pl."
0014 Ether / IP / ICMP 192.168.0.124 > 213.180.146.27 echo-request 0 / Raw
0015 Ether / IP / ICMP 213.180.146.27 > 192.168.0.124 echo-reply 0 / Raw
0016 Ether / IP / UDP / DNS Qry "27.146.180.213.in-addr.arpa."
0017 Ether / IP / UDP / DNS Ans "s4.m1r2.onet.pl."
>>> i = res[6]
>>> i.show()
###[ Ethernet ]###
  dst= 00:19:5b:dc:b7:ec
  src= 00:0c:29:7f:48:3f
  type= 0x800
###[ IP ]###
     version= 4L
     ihl= 5L
     tos= 0x0
     len= 84
     id= 0
     flags= DF
     frag= 0L
     ttl= 64
     proto= icmp
     chksum= 0x11b5
     src= 192.168.0.124
     dst= 213.180.146.27
     \options\
###[ ICMP ]###
        type= echo-request
        code= 0
        chksum= 0x1dbc
        id= 0xa30d
        seq= 0x1
###[ Raw ]###
           load= '\xf3R\xd8K~\x93\x02\x00\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\

x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'

>>> i[IP].dst='87.98.189.148'
>>> i[IP].chksum=None
>>> r = srp1(i)
Begin emission:
Finished to send 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
>>> r.show()
###[ Ethernet ]###
  dst= 00:0c:29:7f:48:3f
  src= 00:19:5b:dc:b7:ec
  type= 0x800
###[ IP ]###
     version= 4L

background image

7/2010

22

OBRONA

Scapy

www.hakin9.org

23

     ihl= 5L
     tos= 0x0
     len= 84
     id= 40889
     flags=
     frag= 0L
     ttl= 0
     proto= icmp
     chksum= 0x44d5
     src= 87.98.189.148
     dst= 192.168.0.124
     \options\
###[ ICMP ]###
        type= echo-reply
        code= 0
        chksum= 0x25bc
        id= 0xa30d
        seq= 0x1
###[ Raw ]###
           load= '\xf3R\xd8K~\x93\x02\x00\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\

x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567'

Listing 15. Odczytanie ruchu z pliki w formacie libpcap

securitum-t1:~# tcpdump -n -s 0 -i eth0 -U -w out.pcap
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
^C20 packets captured
21 packets received by filter

securitum-t1:~# scapy
Welcome to Scapy (2.1.0)
>>> packets = rdpcap('out.pcap')
>>> packets.show()
0000 Ether / IP / TCP 192.168.0.124:ssh > 192.168.0.107:3242 PA / Raw
0001 Ether / IP / TCP 192.168.0.124:ssh > 192.168.0.107:3242 PA / Raw
0002 Ether / IP / TCP 192.168.0.107:3242 > 192.168.0.124:ssh A / Padding
0003 Ether / IP / UDP / DNS Qry "www.onet.pl."
0004 Ether / IP / UDP / DNS Ans "213.180.146.27"
0005 Ether / IP / ICMP 192.168.0.124 > 213.180.146.27 echo-request 0 / Raw
0006 Ether / IP / ICMP 213.180.146.27 > 192.168.0.124 echo-reply 0 / Raw
0007 Ether / IP / UDP / DNS Qry "27.146.180.213.in-addr.arpa."
0008 Ether / IP / UDP / DNS Ans "s4.m1r2.onet.pl."
0009 Ether / ARP who has 192.168.0.124 says 192.168.0.107 / Padding
0010 Ether / ARP is at 00:0c:29:7f:48:3f says 192.168.0.124
0011 Ether / IP / ICMP 192.168.0.124 > 213.180.146.27 echo-request 0 / Raw
0012 Ether / IP / ICMP 213.180.146.27 > 192.168.0.124 echo-reply 0 / Raw
0013 Ether / IP / UDP / DNS Qry "27.146.180.213.in-addr.arpa."
0014 Ether / IP / UDP / DNS Ans "s4.m1r2.onet.pl."
0015 Ether / IP / ICMP 192.168.0.124 > 213.180.146.27 echo-request 0 / Raw
0016 Ether / IP / ICMP 213.180.146.27 > 192.168.0.124 echo-reply 0 / Raw
0017 Ether / IP / UDP / DNS Qry "27.146.180.213.in-addr.arpa."
0018 Ether / IP / UDP / DNS Ans "s4.m1r2.onet.pl."
0019 Ether / IP / TCP 192.168.0.107:3242 > 192.168.0.124:ssh PA / Raw

background image

7/2010

22

OBRONA

Scapy

www.hakin9.org

23

Listing 16. Wykorzystanie funkcji wrpcap()

>>> pkt = Ether()/IP(dst='192.168.0.1')/ICMP()/("X"*100)
>>> wrpcap('to_fragment.pcap', pkt)

securitum-t2:~# tcprewrite --infile=to_fragment.pcap 
--outfile=fragmented.pcap --fragroute=/usr/local/etc/fragroute.conf
192.168.0.104 > 192.168.0.1: icmp: type 8 code 0 (frag 1:24@0+)
192.168.0.104 > 192.168.0.1: (frag 1:24@24+)
192.168.0.104 > 192.168.0.1: (frag 1:24@48+) [delay 0.001 ms]
192.168.0.104 > 192.168.0.1: (frag 1:12@96) [delay 0.001 ms]
192.168.0.104 > 192.168.0.1: (frag 1:24@72+) [delay 0.001 ms]
192.168.0.104 > 192.168.0.1: (frag 1:24@72+)
192.168.0.104 > 192.168.0.1: icmp: type 65 code 71 (frag 1:24@0+) [delay 0.001 ms]
192.168.0.104 > 192.168.0.1: (frag 1:12@96)
192.168.0.104 > 192.168.0.1: (frag 1:24@24+) [delay 0.001 ms]
192.168.0.104 > 192.168.0.1: (frag 1:24@48+)
securitum-t2:~# scapy
>>> f = rdpcap('fragmented.pcap')
>>> f.show()
0000 Ether / IP / ICMP 192.168.0.104 > 192.168.0.1 echo-request 0 / Raw
0001 Ether / 192.168.0.104 > 192.168.0.1 icmp frag:3 / Raw
0002 Ether / 192.168.0.104 > 192.168.0.1 icmp frag:6 / Raw
0003 Ether / 192.168.0.104 > 192.168.0.1 icmp frag:12 / Raw
0004 Ether / 192.168.0.104 > 192.168.0.1 icmp frag:9 / Raw
0005 Ether / 192.168.0.104 > 192.168.0.1 icmp frag:9 / Raw
0006 Ether / IP / ICMP 192.168.0.104 > 192.168.0.1 65 71 / Raw
0007 Ether / 192.168.0.104 > 192.168.0.1 icmp frag:12 / Raw
0008 Ether / 192.168.0.104 > 192.168.0.1 icmp frag:3 / Raw
0009 Ether / 192.168.0.104 > 192.168.0.1 icmp frag:6 / Raw

Listing 17. Podstawowa metoda fuzzingu protokołu sieciowego

>>> p = IP(dst='192.168.0.1')/ICMP()
>>> p = fuzz(p)
>>> p.show()
###[ IP ]###
  version= 

<

RandNum

>

  ihl= None
  tos= 31
  len= None
  id= 

<

RandShort

>

  flags=
  frag= 0
  ttl= 

<

RandByte

>

  proto= icmp
  chksum= None
  src= 192.168.0.124
  dst= 192.168.0.1
  \options\
###[ ICMP ]###
     type= 

<

RandByte

>

     code= 207
     chksum= None
     unused= 

<

RandInt

>

background image

7/2010

24

OBRONA

>>> send(p,loop=1)
................................................................................................................

Listing 18. Fuzzing protokołu sieciowego widziany w tcpdump()

securitum-t1:~# tcpdump -v -n -i eth0 icmp
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes

18:37:00.152656 IP7 (tos 0x8b,CE, ttl 63, id 19269, offset 0, flags [+, rsvd], proto ICMP (1), length 28) 

192.168.0.124 > 192.168.0.1: ICMP type-#170, length 8

        IP5 [|ip]
18:37:00.156424 IP14 (tos 0x99,ECT(1), ttl 128, id 46969, offset 0, flags [+, DF, rsvd], proto ICMP (1), length 

28) 192.168.0.124 > 192.168.0.1: ICMP type-#180, length 8

        IP5 [|ip]
18:37:00.159799 IP9 (tos 0x7a,ECT(0), ttl 114, id 53503, offset 0, flags [DF], proto ICMP (1), length 28) 

192.168.0.124 > 192.168.0.1: ICMP type-#105, length 8

        IP5 [|ip]
18:37:00.163474 IP14 (tos 0x18, ttl 163, id 24203, offset 0, flags [+, rsvd], proto ICMP (1), length 28) 

192.168.0.124 > 192.168.0.1: ICMP type-#61, length 8

        IP5 [|ip]
18:37:00.167175 IP5 (tos 0x1,ECT(1), ttl 13, id 59219, offset 0, flags [none], proto ICMP (1), length 28) 

192.168.0.124 > 192.168.0.1: ICMP type-#180, length 8

        IP5 [|ip]
...

Listing 19. Ustawienie pola w pakiecie funkcją zwracającą 

wartość losową 

>>> i = IP()/ICMP()
>>> i[IP].version = RandShort()
>>> i.show()
###[ IP ]###
  version= 

<

RandShort

>

  ihl= None
  tos= 0x0
  len= None
  id= 1
  flags=
  frag= 0
  ttl= 64
  proto= icmp
  chksum= None
  src= 127.0.0.1
  dst= 127.0.0.1
  \options\
###[ ICMP ]###
     type= echo-request
     code= 0
     chksum= None
     id= 0x0
     seq= 0x0

Listing 20. Prosty skaner portów napisany w pythonie, z 

wykorzystaniem scapy. scapy-scanner.py (uruchomienie: 

python scapy-scanner.py)

from scapy.all import *

# zakres portow do skanowania
ports = (1,1024)
# cel skanowania
dst_ip = '192.168.0.1'

# definicja pakietow
syn_packets = IP(dst=dst_ip)/TCP(flags='S',dport=po

rts)

# wyslanie pakietow oraz odebranie odpowiedzi
answered, uanaswered = sr(syn_packets, verbose=0)

# analiza odpowiedzi
for request, response in answered:
        response_flags = response.sprintf('%TCP.flag

s%')

        if response_flags == 'SA':
                print "Port TCP: " + 

str(request.dport) + " otwarty"