Introduction to Scapy 🤘
This article intends to make a brief introduction about what is Scapy and its functionalities, showing a couple of basic examples and integrating them in Python programs, so that any kind of action can be automated.
Scapy is considered by many to be one of the most important package handling tools. It allows for many possibilities and is a great opportunity to expand your network knowledge.
If you want to improve your networking skills, now is your chance, read on 🙂
Firstly I will explain you the use and operation of the command line interface and then I will demostrate you how to import and use these libraries in a program written in Python.
- What is Scapy?
- What is it for?
- First steps with Scapy
- Practical cases of use with Python
What is Scapy? 🙄
Scapy is a library made in Python, with its own command line interpreter (CLI), which allows to create, modify, send and capture network packets.
It can be used interactively through the command line interface or as a library by importing it into Python programs. It can also run on Linux, Mac OS X and Windows systems.
What is it for? 😮
Applied to the field of computer security, this tool allows us to perform scans and/or network attacks.
The main advantage of Scapy is that, unlike other tools, it provides us with the ability to modify network packages at a low level, allowing us to use existing network protocols and parameterize them based on our needs.
And in case we decide to use your libraries in Python, we will be able to develop our own tools, and in this way, we could make other higher level developments and integrate them all together according to our needs.
First steps with Scapy 👣
Using the Command Line Interpreter (CLI) ⚙️
To start using this tool we must:
- Download and install the Scapy software
- Run it directly from the command line (with administrator permissions):
Basic Functions via Command Line (CLI) 🔧
The main basic functions we should know are:
- ls() : list of available layers
- explore() : graphical interface to display existing layers
- lsc() : available functions
- help() : help menu.
And within the function group, the most common are:
- send(): send packets to level 2.
- sendp(): send packets to level 3.
- sr(): send and receive packets at level 3.
- srp(): send and receive packets at level 2.
- sr1(): send and receive only the first packet at level 3.
- srp1(): sends and receives only the first packet to level 2.
- sniff(): packet sniffing.
- traceroute(): command trace route.
- arping(): Send who-has ARP requests to determine which machines are up in the network.
Example of use through Command Line Interpreter (CLI) 💻
The simplest construction could be to create an ICMP-type package. In this case we will build a packet whose value we will store in a variable (P), and which we will parameterize using the IP layer (destination ip), a second ICMP layer and later a payload (“hello SanExperts”).
Then we will send it using the command: sr1(p)
If we execute the ‘show()’ command it will layer the contents of the package:
In this case we have used the IP of the equipment itself, but we could modify the parameters of the package to do so using other ip or MAC addresses. Based on our needs, we could do the sending at level 3 (sr) or level 2 (srp) of the TCP model.
For example, to make a scan of the hosts in our subnet, it would be enough to execute the following command (srp) and show the values of what if they have responded (ans):
If we need help on any of the commands, we can show it by using the ‘help()’ command:
Practical cases of use with Python ⌨️
Below are a couple of examples of use cases.
Use Case 1: Port Scanning 🖨️
Perform a program for port scanning at both TCP and UDP level using Scapy. This will allow us to make our own personalized tool for reviewing services to listen in our network.
To do this example of use, we start by creating a program in Python that will support command line parameters. To do this we start developing a program that allows us to indicate the target to be scanned, as well as the ports, both in a unitary way and in a range (1-n), indicating if the scan is going to be done from the TCP or UDP protocol.
As a requirement, we must import Scapy’s libraries.
Within the program, in the main() function we validate the correct syntax and start the function that will perform the scan.
Later, we defined the class that will perform the scan, making a difference between TCP and UDP:
To build our package we define the different layers with the shipping data, as well as the appropriate parameters:
- ip destination (dst)
- random port of origin (sport)
- destination port (dport)
- flags: S, SA, FPU.
And we perform the sending by (sr1) storing the result in a variable (result).
We will then review the flags obtained to discern whether the port is open or closed based on the response.
** Before continuing, it is important to know how the TCP protocol works and how the conversations and the flags used are established, so that we can know the state of the port according to each type of response.
As a summary, these will be the flags we are going to use for the example:
NULL = 0x00
END = 0x01
SYN = 0x02
RST = 0x04
PSH = 0x08
ACK = 0x10
SYN + ACK = 0x12
RST + ACK = 0x14
PSH + ACK = 0x18
Based on the flags obtained, the status of the ports can be summarized as follows:
- Open port: The port is not blocked by an FW and there is a service listening on it.
Flags are received: SYN and ACK (0x12)
- Closed port: The port is not blocked and there is no service listening to it.
Flags are received: RST and ACK (0x14).
- Filtered port: An FW blocks access to the port.
Nothing is received.
So, going back to the example code, this is how the response would be evaluated.
In the example, the response is examined for the “SYN, ACK” flag and if found, it is determined that communication has been established and the port is open.
For UDP, we will use a similar process. Since it is an offline protocol, we will send the packet and wait some time to see if the data is received. Later, and depending on the type of response, we will have to determine if the port is open or closed.
If we would like to have a higher level of detail and know if the ports are “filtered”, we should include that information as part of the output in the following testers, for both TCP and UDP:
And finally, the normal result of the script after running it would be this:
Use Case 2: ARP Spoofing 🖱️
Performing a poisoning of our victim’s ARP cache tables (ARP spoofing).
This attack consists of sending fake ARP messages. The purpose is to associate the attacker’s MAC address with the IP address of another node, such as the default gateway.
This would allow us to carry out attacks of the following types: MiTM (Man In The Middle), DoS (Denial of Service) or Session Hijacking.
We started by creating our program in Python and importing the Scapy libraries, as shown above. We defined functions and requested at the beginning of the execution the ips of the gateway and the victim computer and started the execution:
The first thing we have to do is get the MACs of both IPs. To do this we execute the following function:
Already knowing the MAC address, we can manipulate the packages through Scapy.
To do this, the packages are sent using the following parameters:
- Source IP address (psrc): IP gateway
- Destination IP address (pdst): target IP
- Source MAC address (hwsrc): the MAC address of the sending device is omitted by default.
- Target MAC address (hwdst): target mac
With this shipment we intend to send a package to the victim computer (referenced by ip and mac) by associating the ip of the Gateway with our MAC address (attacking computer).
As a result, the victim team’s ARP tables go from containing this value:
To this one:
To undo it, we will have to send all the correct data back to the computer:
- Source IP address (psrc)
- Destination IP address (pdst)
- Source MAC address (hwsrc)
- Destination MAC address (hwdst)