At its heart, Scapy is a packet manipulation program,
but it's also able to capture, decode, create,
and send a wide range of network protocols.
It's a Python‑based utility and also has a Python library,
meaning it can be used directly from the command line or in Python scripts.
In this and subsequent demos I'll be using Python 3,
but for the most part, the coach should also work in Python 2.
If you don't already have Scapy installed,
then you can use pip install scapy,
or you can git clone it from the secdev GitHub repository.
Packets can be crafted in a number of ways in Scapy,
but this isn't a course about Scapy,
so I'll just show you the way that I learned.
Packets are built up in layers following the OSI model.
We first create the Ethernet layer.
We could specify source and destination MAC addresses,
which could be useful if we wanted to hide our identity,
but we can leave the options blank to defer to the default
values which Scapy grabs from the network.
Next, we build out layer 3, the IP layer.
Here we'll specify the destination IP address as that
of the PLC we identified earlier.
We know the PLC is hosting a basic web server on port 8080,
so let's see if it'll consider a connection from us by initiating a
handshake with a SYN packet at the TCP layer.
For a basic packet, all we need is these three layers,
one of which can be handled by Scapy.
But as we'll see later, we can build a session layer with Modbus,
and if we need to, we can go all the way to the application layer.
We can then build the packet by concatenating delays with a forward slash.
We can see a basic summary of the packet with packet.summary.
This shows the details of the packet structure in
the fields we've specifically set, such as the destination IP address,
an assumed service or protocol based on the port number we specified,
and any flag set, such as the SYN flag, as we have here.
We can see the full details of the packet with packet.show,
which shows the parameters we set and the default
values assumed for the other fields,
such as the source and destination MAC addresses and
the time to live for the packet.
Having created a packet,
we now need to send it either once or multiple times using the count parameter.
We can send a packet at layer 3 with the send command,
and Scapy will take care of routing in layer 2 for us.
Or we can specify layer 2 and send the packet with sendp.
This is particularly helpful if we want to spoof our MAC address to
make the packet appear to have come from another host.
However, if we want to receive a reply to the packet we send,
we need to use sendrecv.
Again, we can send/receive at layer 3, letting Scapy take care of routing,
or at layer 2 by using the sr command.
But if we specify layer 2, as here, we use srp.
Of the packets we send, some may be answered and some may be unanswered,
so the returned value is a Python tuple containing the
answered and unanswered replies to our packet.
We can unpack the reply into separate variables.
In this case, the variables answered and unanswered.
Answered and unanswered are themselves both tuples
containing a probe and its response.
We therefore have a tuple of two tuples,
which we can access using indices enclosed by square brackets.
To view the packet contents of the first probe,
we use ls followed by the answered variable name and 0 in square brackets
indicating the index of the first packet and then again 0 in square
brackets indicating that we want to view the probe.
We can then view the response to the probe by changing the second index to 1.
Here we can see that in response to the SYN packet we sent,
we received a SYN‑ACK in reply.
As well as crafting and injecting packets,
we can also sniff packets on the network.
Using Scapy's sniff command, we can filter on specific types of network traffic,
collect one or many packets, and specify the network interface we want to
capture on. Here we capture the first six ICMP packets seen on network
interface F0, and here we have our response, six ICMP packets.
Let's drop these responses into a variable called ans and
then view a summary of the packets using ans.show. The
first packet shows an error.
Well, okay,
that happens sometimes. Network traffic isn't 100% reliable. But
then we see a series of echo requests and replies.
This looks like a machine at .136 pinging our machine at .140.
Let's take a look at the first answered probe, the
one that errored, using show. Well,
not much here. It shows a server failure and then tries to send DNS error
telemetry to Microsoft via the umwatson.event subdomain.
But let's confirm where it's sending it. By requesting
the destination based just on packet 0,
we get the destination MAC address. But by requesting the
destination based on the response of the first probe,
we see that the destination of the Microsoft telemetry data
is the pfSense firewall at .20, which we can now assume is
also the default network gateway.
The indications were that the ICMP traffic we captured were echo
requests and replies, but how does Scapy know this? That's specified
in the ICMP packet type at the IP layer.
Looking at the second packet,
we see a packet type of 8 which according to RFC 792 is an echo request.
And looking at the third packet, we see a packet type of 0, which
according to the same RFC is an echo reply.