Hacking

What Is Scapy?

Interference Security
October 15, 2013 by
Interference Security

Scapy is a Python interpreter that enables you to create, forge, or decode packets on the network, to capture packets and analyze them, to dissect the packets, etc. It also allows you to inject packets into the network. It supports a wide number of network protocols and it can handle and manipulate wireless communication packets.

Scapy can be used to perform the jobs done by many network tools, such as nmap, hping, arpscan, and tshark (the command line of wireshark).

Earn two pentesting certifications at once!

Earn two pentesting certifications at once!

Enroll in one boot camp to earn both your Certified Ethical Hacker (CEH) and CompTIA PenTest+ certifications — backed with an Exam Pass Guarantee.

The concept behind Scapy is that it is cable of sending and receiving packets and it can sniff packets. The packets to be sent can be created easily using the built-in options and the received packets can be dissected. Sniffing of packets helps in understanding what communication is taking place on the network.

Get Scapy

In Backtrack and Kali Linux, it comes pre-installed. You can download and install Scapy from these links:

Download: http://www.secdev.org/projects/scapy/

Installation: http://www.secdev.org/projects/scapy/doc/installation.html

Launch Scapy

After you have installed Scapy, you can launch it easily by typing "scapy" in your terminal or at the command prompt.

Do not worry about the IPv6 warning.

Protocols Supported by Scapy

Scapy supports 356 protocols; we can view the list of supported protocols by typing the command ls() in the Scapy interpreter console.

[Snip…]

Creating a Packet

[plain]

Creating a simple ICMP packet

>>>send(IP(dst="10.0.0.1")/ICMP()/"This is an ICMP packet")

.

Sent 1 packet

[/plain]

We are sending a packet with these contents:

  1. IP() defines that it is an IP packet
  2. Destination of packet : 10.0.0.1
  3. ICMP echo request
  4. Data in ICMP packet : This is an ICMP packet

We can watch the packet sent and its response by using "tcpdump":

[plain]

root@kali:~# tcpdump -nnvvXSs 0 -c2 icmp

tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes

12:15:42.973566 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto ICMP (1), length 50)

10.0.0.2 > 10.0.0.1: ICMP echo request, id 0, seq 0, length 30

0x0000: 4500 0032 0001 0000 4001 66c8 0a00 0002 E..2....@.f.....

0x0010: 0a00 0001 0800 5834 0000 0000 5468 6973 ......X4....This

0x0020: 2069 7320 616e 2049 434d 5020 7061 636b .is.an.ICMP.pack

0x0030: 6574 et

12:15:42.974204 IP (tos 0x0, ttl 64, id 2777, offset 0, flags [none], proto ICMP (1), length 50)

10.0.0.1 > 10.0.0.2: ICMP echo reply, id 0, seq 0, length 30

0x0000: 4500 0032 0ad9 0000 4001 5bf0 0a00 0001 E..2....@.[.....

0x0010: 0a00 0002 0000 6034 0000 0000 5468 6973 ......`4....This

0x0020: 2069 7320 616e 2049 434d 5020 7061 636b .is.an.ICMP.pack

0x0030: 6574 et

2 packets captured

2 packets received by filter

0 packets dropped by kernel

[/plain]

Using the tcpdump output, we can see that the packet originated from 10.0.0.2 and was destined for 10.0.0.2. It is an ICMP echo request packet with the data "This is an ICMP packet."

Sending and Receiving Packets

Scapy has the capability to send packets and to receive packets. It provides three functions to send and receive packets on the network:

  1. sr()
  2. sr1()
  3. srp()

sr() : This function sends the packet and returns all received answered and unanswered packets. It works on layer 3 packets

sr1() : This function sends the packet and returns only the first packet that answered the packet we sent. It does not return the unanswered packets. It works on layer 3 packets.

srp() : This function works on layer 2 packets. It cannot be used for layer 3.

sr1() example:

TCP a packet to the port 80.

[plain]

>>> resp1 = sr1(IP(dst="10.0.0.1")/TCP(dport=80))

Begin emission:

.Finished to send 1 packets.

*

Received 2 packets, got 1 answers, remaining 0 packets

[/plain]

  1. This sends an IP packet to destination 10.0.0.1.
  2. It is a TCP packet for the destination's port 80.
  3. We got one answer in response.

Looking at the response packet we receive:

[plain]

>>> resp1.show()

###[ IP ]###

version= 4L

ihl= 5L

tos= 0x0

len= 44

id= 0

flags= DF

frag= 0L

ttl= 64

proto= tcp

chksum= 0x26ca

src= 10.0.0.1

dst= 10.0.0.2

options

###[ TCP ]###

sport= http

dport= ftp_data

seq= 3817102999

ack= 1

dataofs= 6L

reserved= 0L

flags= SA

window= 5840

chksum= 0x2ac3

urgptr= 0

options= [('MSS', 1460)]

###[ Padding ]###

load= 'x00x02'

[/plain]

The show() function on the "resp1" variable shows the structure of the packet we received in response from the destination host.

As we can see, it is an IP packet with source 10.0.0.1 and destination 10.0.0.2.

The destination replied using port 80 (http_data) and the source received the response on port 20 (ftp_data). Since we had not specified the source port in the TCP(), Scapy set it to a default value of 21 for us.

We can also see that the flags SYN(S) and ACK(A) are set in the response packet (flags= SA). This means that the port 80 is open on 10.0.0.1

sr() example:

TCP packet to the port 80.

[plain]

>>> ans,unans = sr(IP(dst="10.0.0.1")/TCP(dport=80))

Begin emission:

.Finished to send 1 packets.

*

Received 2 packets, got 1 answers, remaining 0 packets

[/plain]

Since the sr() function returns both the answered and unanswered packets, we can receive them in the two variables "ans" and "unans," respectively.

We have got one answer so, looking at the answer:

[plain]

>>> ans

<Results: TCP:1 UDP:0 ICMP:0 Other:0>

>>> ans.summary()

IP / TCP 10.0.0.2:ftp_data > 10.0.0.1:http S ==> IP / TCP 10.0.0.1:http > 10.0.0.2:ftp_data SA / Padding

[/plain]

Simply typing "ans" gives us the results for the received answered packets, which shows that one TCP packet has been received. Further details of the answered packet can be shown using the summary() function.

Note: The show() function is not available for sr().

SA (S=SYN and A=ACK) in the answered packet means that the port is open.

Now we send a packet to the closed port 8081:

[plain]

>>> ans,unans = sr(IP(dst="10.0.0.1")/TCP(dport=8081))

Begin emission:

.Finished to send 1 packets.

*

Received 2 packets, got 1 answers, remaining 0 packets

>>> ans.summary()

IP / TCP 10.0.0.2:ftp_data > 10.0.0.1:tproxy S ==> IP / TCP 10.0.0.1:tproxy > 10.0.0.2:ftp_data RA / Padding

[/plain]

RA (R=RST and A=ACK) in the answered packet means that reset has been received and the port is closed on the destination 10.0.0.1

Setting Timeout for a Packet

Timeout value is used to define the number of seconds to wait for the response. Think of a scenario in which we sent a TCP packet for port 80 to a host that is not reachable and we have not specified the timeout value. In that case it will keep waiting for the response. To avoid this, we specify the timeout value.

Send TCP packet to port 80 of unreachable host 10.0.0.99 without a timeout value:

[plain]

>>> ans,unans = sr(IP(dst="10.0.0.99")/TCP(dport=80))

Begin emission:

WARNING: Mac address to reach destination not found. Using broadcast.

Finished to send 1 packets.

...........................................................^C

Received 6 packets, got 0 answers, remaining 1 packets

[/plain]

Send TCP packet to port 80 of unreachable host 10.0.0.99 without timeout value:

[plain]

>>> ans,unans = sr(IP(dst="10.0.0.99")/TCP(dport=80),timeout=10)

Begin emission:

.....WARNING: Mac address to reach destination not found. Using broadcast.

Finished to send 1 packets.

...

Received 8 packets, got 0 answers, remaining 1 packets

[/plain]

Setting Flags in a Packet

Every packet we send on the network may contain some set flags. The flags set in a packet help in handling and identifying the packet and in generating suitable response for that packet.

Some of the flags of a TCP packet are:

  1. PSH
  2. SYN
  3. ACK
  4. URG
  5. FIN
  6. RST

Every flag has a specific meaning associated with it:

PSH The sending application informs TCP that data should be sent immediately and the data should be pushed up to the receiving application immediately.

SYN It initiates a connection with the destination host.

ACK It acknowledges the received data from the host.

URG This flags marks that the data is of higher priority than the other data.

FIN This flag, when, set marks the closing of the connection.

RST The RST or reset flag is sent in response to an error and aborts the connection.

To set a particular flag in a TCP packet, the "flag" attribute is used.

Example: sr1(IP(dst="10.0.0.1")/TCP(dport=80,flags="S"),timeout=10).

In this example, we set the SYN flag inside the TCP packet using flag="S." We can also set multiple flags inside a TCP packet by simply appending the flag's first character to the flag attribute.

Example: sr1(IP(dst="10.0.0.1")/TCP(dport=80,flags="SU"),timeout=10)

In the above example, we set the SYN and URG flags.

Use Scapy inside a Python program

Scapy can be utilized not only through its interpreter console but can also be used inside a Python program by importing the Scapy module.

Example:

[c]
#! /usr/bin/python

from scapy.all import *

ans,unans = sr(IP(dst="10.0.0.1")/TCP(dport=80))

ans.summary()

[/c]

Response:

[plain]

WARNING: No route found for IPv6 destination :: (no default route?)

Begin emission:

.Finished to send 1 packets.

*

Received 2 packets, got 1 answers, remaining 0 packets

IP / TCP 10.0.0.2:ftp_data > 10.0.0.1:http S ==> IP / TCP 10.0.0.1:http > 10.0.0.2:ftp_data SA / Padding

[/plain]

Scapy Configuration

There are many settings that can be tweaked and configurations that can be created to make the use of Scapy much easier and more convenient. Since most computers also have a wireless card, we can use the wireless interface to send our data.

Example:

[c]
#! /usr/bin/python

from scapy.all import *

conf.iface='wlan0'

ans,unans = sr(IP(dst="10.0.0.1")/TCP(dport=23))

ans.summary()

[/c]

Response:

[plain]

WARNING: No route found for IPv6 destination :: (no default route?)

Begin emission:

..Finished to send 1 packets.

*

Received 3 packets, got 1 answers, remaining 0 packets

IP / TCP 10.0.0.5:ftp_data > 10.0.0.1:telnet S ==> IP / TCP 10.0.0.1:telnet > 10.0.0.5:ftp_data SA

[/plain]

We can see that there is too much output on screen. This configuration is called verbosity and by default is set to 1. It can be disabled by using the configuration option: conf.verb=0.

[c]
#! /usr/bin/python

from scapy.all import *

conf.iface='wlan0'

conf.verb=0

ans,unans = sr(IP(dst="10.0.0.1")/TCP(dport=23))

ans.summary()

[/c]

Response:

[plain]

WARNING: No route found for IPv6 destination :: (no default route?)

IP / TCP 10.0.0.5:ftp_data > 10.0.0.1:telnet S ==> IP / TCP 10.0.0.1:telnet > 10.0.0.5:ftp_data SA

[/plain]

We see a warning at the start of the program run:

[plain]

WARNING: No route found for IPv6 destination :: (no default route?)

[/plain]

This warning can be disabled by using the "logging" module of Python.

Example:

[c]
#! /usr/bin/python

import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

from scapy.all import *

conf.iface='wlan0'

conf.verb=0

ans,unans = sr(IP(dst="10.0.0.1")/TCP(dport=23))

ans.summary()

[/c]

Response:

[plain]

IP / TCP 10.0.0.5:ftp_data > 10.0.0.1:telnet S ==> IP / TCP 10.0.0.1:telnet > 10.0.0.5:ftp_data SA

[/plain]

"logging.getLogger("scapy.runtime").setLevel(logging.ERROR)" sets logging only for errors that occur during the program execution and not the warnings. Do note that the logging setting should be used before importing the Scapy module inside the Python program.

Port Scanning

Nmap is a very popular network tool that is widely used for port scanning. But is not just limited to scanning ports; it is also capable of detecting the operating system, service version detection, banner grabbing, and much more. It also supports the Nmap scripting engine(NSE).

Nmap is implemented using C programming language and, if we look at the port scanning module, we will find that it has lots of lines of code to read and understand.

But, using Scapy, we can easily implement port scanning techniques because port scanning is nothing but sending packets to the target, reading the responses, and making suitable decisions.

Some of the port scanning techniques implemented by Nmap are:

  1. TCP SYN scan
  2. TCP connect scan
  3. SCTP INIT scan
  4. NULL scan
  5. FIN scan
  6. XMAS scan
  7. UDP scan
  8. TCP ACK scan
  9. TCP window scan

These different port scanning techniques are used to find the current status of the port(s) on the host. The result of one scan might not result in telling the correct status of the port being scanned, so we cannot tell for sure what the status of the port is. That's why we utilize a number of scanning techniques to conclude with the most probable status of the port on the host.

There could be three states of a port on a host:

  1. Open
  2. Closed
  3. Filtered

Open The port is open and we are able to establish communication with it.

Closed The port is closed and communication cannot be established.

Filtered The status of the port (open or closed) cannot be detected. The result is unsure.

The filtered state of a port means there is some doubt about the state of the port. It could be open or closed. But we are not sure what the state is. There might be a firewall and there are also other possibilities.

Become a Certified Ethical Hacker, guaranteed!

Become a Certified Ethical Hacker, guaranteed!

Get training from anywhere to earn your Certified Ethical Hacker (CEH) Certification — backed with an Exam Pass Guarantee.

References

Interference Security
Interference Security

Interference Security is a freelance information security researcher. Experience gained by learning, practicing and reporting bugs to application vendors. CEH certified but believes in practical knowledge and out of the box thinking rather than collecting certificates. Always open to learning more to enhance his knowledge. Information security is a hobby rather a job for him. Builds tools to automate testing and make things easier.