Sunday, July 10, 2011

Introduction to Scapy

 Scapy is a powerful tool that can be used to manipulate and generate network traffic.
It can be either run interactively from the command line or used as a library in a Python script.

Scapy could be installed either through APT in Ubuntu:
$ sudo apt-get install python-scapy
Or the distutils way:
$ cd /tmp
$ wget http://www.secdev.org/projects/scapy/files/scapy-latest.zip
$ unzip scapy-latest.zip
$ cd scapy-2.*
$ sudo python setup.py install
To launch Scapy:
$ scapy
>>>
There is pretty much everything that could be done with Python interpreter plus
the goodies brought by Scapy.
>>> new_packet = IP()
>>> new_packet
<IP  |>
The ls() command is used either without arguments to list supported protocols or
with a packet as an argument to list a protocol (or an instance of it) fields, types, actual values and default values.
>>> ls(new_packet)
version    : BitField             = 4               (4)
ihl        : BitField             = None            (None)
tos        : XByteField           = 0               (0)
len        : ShortField           = None            (None)
id         : ShortField           = 1               (1)
flags      : FlagsField           = 0               (0)
frag       : BitField             = 0               (0)
ttl        : ByteField            = 64              (64)
proto      : ByteEnumField        = 0               (0)
chksum     : XShortField          = None            (None)
src        : Emph                 = '127.0.0.1'     (None)
dst        : Emph                 = '127.0.0.1'     ('127.0.0.1')
options    : PacketListField      = []              ([]) 
>>> new_packet.dst
'127.0.0.1'
>>> new_packet.dst = '192.168.1.1'
>>> new_packet
<IP  dst=192.168.1.1 |>
del() is used to revert field values back to default.
>>> del(new_packet.dst)
>>> new_packet.dst
'127.0.0.1'
lsc() is used to list available commands.
to encapsulate protocols, the / operator is used.
>>> Ether()
<Ether  |>
>>> Ether()/IP()
<Ether  type=0x800 |<IP  |>>

>>> Ether()/IP()/TCP()
<Ether  type=0x800 |<IP  frag=0 proto=tcp |<TCP  |>>>
Notice that default fields values are changed accordingly.
a raw string of data can also be used as a layer.
>>> IP()/TCP()/"Payload !"
<IP  frag=0 proto=tcp |<TCP  |<Raw  load='Payload !' |>>>
str() function is used to get raw representation of a packet.
>>> a = IP()
>>> str(a)
'E\x00\x00\x14\x00\x01\x00\x00@\x00|\xe7\x7f\x00\x00\x01\x7f\x00\x00\x01'
>>> IP(str(a))
<IP  version=4L ihl=5L tos=0x0 len=20 id=1 flags= frag=0L ttl=64 proto=ip chksum=0x7ce7 src=127.0.0.1 dst=127.0.0.1 |>
the hide_defaults() method could be used to delete the default values.
>>> b = IP(str(a))
>>> b
<IP  version=4L ihl=5L tos=0x0 len=20 id=1 flags= frag=0L ttl=64 proto=ip chksum=0x7ce7 src=127.0.0.1 dst=127.0.0.1 |>
>>> b.hide_defaults()
>>> b
<IP  ihl=5L len=20 chksum=0x7ce7 src=127.0.0.1 |>
hexdump() is used to show hexadecimal representation of the packet, like in wireshark.

The real deal:
What are packets useful for if not sent and received ?
To be able to send traffic, Scapy should be run as root.
$sudo scapy
>>>
To send packets, there are two commands available: send() which sends packets at layer 3 and sendp() which sends packets at layer 2.
>>> send(IP(dst='192.168.1.1')/ICMP())
.
Sent 1 packets.

>>> sendp(Ether()/IP(dst='192.168.1.1')/ICMP(), iface="wlan0")
.
Sent 1 packets.
Multiple packets could be sent with varying fields values, for example:

>>> group =IP(dst='192.168.1.1-3')/ICMP()
>>> group
<IP  frag=0 proto=icmp dst=Net('192.168.1.1-3') |<ICMP  |>>
>>> [p for p in group]
[<IP  frag=0 proto=icmp dst=192.168.1.1 |<ICMP  |>>,
 <IP  frag=0 proto=icmp dst=192.168.1.2 |<ICMP  |>>,
 <IP  frag=0 proto=icmp dst=192.168.1.3 |<ICMP  |>>]

>>> send(IP(dst='192.168.1.1-3')/ICMP())
.
Sent 3 packets.

>>> destinations = ['192.168.1.1', '192.168.1.5', '192.168.1.20']

>>> send(IP(dst=destinations, ttl=(1,4))/ICMP())
.
Sent 12 packets.

To send and receive packets sr() and srp() are used (at layer 2 and 3).
sr1() and srp1() are variants that return only the first replied packet.

>>> response = sr1(IP(dst='192.168.1.1')/ICMP())
Begin emission:
..Finished to send 1 packets.
*
Received 3 packets, got 1 answers, remaining 0 packets
>>> response
<IP  version=4L ihl=5L tos=0x0 len=28 id=31732 flags= frag=0L ttl=64 proto=icmp chksum=0x7b69 src=192.168.1.1 dst=192.168.1.50 options=[] |<ICMP  type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |>>
>>> response.summary()
'IP / ICMP 192.168.1.1 > 192.168.1.50 echo-reply 0'
>>> response.show()
###[ IP ]###
  version= 4L
  ihl= 5L
  tos= 0x0
  len= 28
  id= 31732
  flags=
  frag= 0L
  ttl= 64
  proto= icmp
  chksum= 0x7b69
  src= 192.168.1.1
  dst= 192.168.1.50
  \options\
###[ ICMP ]###
     type= echo-reply
     code= 0
     chksum= 0xffff
     id= 0x0
     seq= 0x0

This is practically all that's needed to begin using Scapy. Coupled with TCP/IP knowledge, a lot of traditional tools and more could be replaced with Scapy. In future articles, we will try to make useful scripts with Scapy.
The project's website http://www.secdev.org/projects/scapy/ contains complete documentation, demos, mailing lists and all about Scapy.

No comments:

Post a Comment