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.
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
ją 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.
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.
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', [...]
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
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
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
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
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
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
>
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"