Packet Sniffing and Spoofing Lab
Packet Sniffing and Spoofing Lab
Packet Sniffing and Spoofing Lab
1 Overview
Packet sniffing and spoofing are two important concepts in network security; they are two major threats
in network communication. Being able to understand these two threats is essential for understanding se-
curity measures in networking. There are many packet sniffing and spoofing tools, such as Wireshark,
Tcpdump, Netwox, Scapy, etc. Some of these tools are widely used by security experts, as well as by
attackers. Being able to use these tools is important for students, but what is more important for students in
a network security course is to understand how these tools work, i.e., how packet sniffing and spoofing are
implemented in software.
The objective of this lab is two-fold: learning to use the tools and understanding the technologies under-
lying these tools. For the second object, students will write simple sniffer and spoofing programs, and gain
an in-depth understanding of the technical aspects of these programs. This lab covers the following topics:
Readings and Videos. Detailed coverage of sniffing and spoofing can be found in the following:
• Chapter 15 of the SEED Book, Computer & Internet Security: A Hands-on Approach, 2nd Edition,
by Wenliang Du. See details at https://www.handsonsecurity.net.
• Section 2 of the SEED Lecture, Internet Security: A Hands-on Approach, by Wenliang Du. See details
at https://www.handsonsecurity.net/video.html.
Lab environment. This lab has been tested on the SEED Ubuntu 20.04 VM. You can download a pre-built
image from the SEED website, and run the SEED VM on your own computer. However, most of the SEED
labs can be conducted on the cloud, and you can follow our instruction to create a SEED VM on the cloud.
Note for Instructors. There are two sets of tasks in this lab. The first set focuses on using tools to conduct
packet sniffing and spoofing. It only requires a little bit of Python programming (usually a few lines of
code); students do not need to have a prior Python programming background.
The second set of tasks is designed primarily for Computer Science/Engineering students. Students need
to write their own C programs from the scratch to do sniffing and spoofing. This way, they can gain a deeper
understanding on how sniffing and spoofing tools actually work. Students need to have a solid programming
background for these tasks. The two sets of tasks are independent; instructors can choose to assign one set
or both sets to their students, depending on their students’ programming background.
SEED Labs – Packet Sniffing and Spoofing Lab 2
Network: 10.9.0.0/24
Attacker User
10.9.0.1 10.9.0.5
All the containers will be running in the background. To run commands on a container, we often need
to get a shell on that container. We first need to use the "docker ps" command to find out the ID of
the container, and then use "docker exec" to start a shell on that container. We have created aliases for
them in the .bashrc file.
$ dockps // Alias for: docker ps --format "{{.ID}} {{.Names}}"
$ docksh <id> // Alias for: docker exec -it <id> /bin/bash
SEED Labs – Packet Sniffing and Spoofing Lab 3
$ docksh 96
root@9652715c8e0a:/#
If you encounter problems when setting up the lab environment, please read the “Common Problems”
section of the manual for potential solutions.
• Shared folder. When we use the attacker container to launch attacks, we need to put the attacking
code inside the attacker container. Code editing is more convenient inside the VM than in containers,
because we can use our favorite editors. In order for the VM and container to share files, we have
created a shared folder between the VM and the container using the Docker volumes. If you look
at the Docker Compose file, you will find out that we have added the following entry to some of the
containers. It indicates mounting the ./volumes folder on the host machine (i.e., the VM) to the
/volumes folder inside the container. We will write our code in the ./volumes folder (on the
VM), so they can be used inside the containers.
volumes:
- ./volumes:/volumes
• Host mode. In this lab, the attacker needs to be able to sniff packets, but running sniffer programs
inside a container has problems, because a container is effectively attached to a virtual switch, so it
can only see its own traffic, and it is never going to see the packets among other containers. To solve
this problem, we use the host mode for the attacker container. This allows the attacker container to
see all the traffics. The following entry used on the attacker container:
network_mode: host
When a container is in the host mode, it sees all the host’s network interfaces, and it even has the
same IP addresses as the host. Basically, it is put in the same network namespace as the host VM.
However, the container is still a separate machine, because its other namespaces are still different
from the host.
Getting the network interface name. When we use the provided Compose file to create containers for
this lab, a new network is created to connect the VM and the containers. The IP prefix for this network is
10.9.0.0/24, which is specified in the docker-compose.yml file. The IP address assigned to our
SEED Labs – Packet Sniffing and Spoofing Lab 4
VM is 10.9.0.1. We need to find the name of the corresponding network interface on our VM, because
we need to use it in our programs. The interface name is the concatenation of br- and the ID of the network
created by Docker. When we use ifconfig to list network interfaces, we will see quite a few. Look for
the IP address 10.9.0.1.
$ ifconfig
br-c93733e9f913: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.9.0.1 netmask 255.255.255.0 broadcast 10.9.0.255
...
Another way to get the interface name is to use the "docker network" command to find out the
network ID ourselves (the name of the network is seed-net:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
a82477ae4e6b bridge bridge local
e99b370eb525 host host local
df62c6635eae none null local
c93733e9f913 seed-net bridge local
a = IP()
a.show()
# python3 mycode.py
###[ IP ]###
version = 4
ihl = None
...
We can also get into the interactive mode of Python and then run our program one line at a time at the
Python prompt. This is more convenient if we need to change our code frequently in an experiment.
SEED Labs – Packet Sniffing and Spoofing Lab 5
# python3
>>> from scapy.all import *
>>> a = IP()
>>> a.show()
###[ IP ]###
version = 4
ihl = None
...
def print_pkt(pkt):
pkt.show()
The code above will sniff the packets on the br-c93733e9f913 interface. Please read the instruction
in the lab setup section regarding how to get the interface name. If we want to sniff on multiple interfaces,
we can put all the interfaces in a list, and assign it to iface. See the following example:
iface=[’br-c93733e9f913’, ’enp0s3’]
Task 1.1A. In the above program, for each captured packet, the callback function print pkt() will be
invoked; this function will print out some of the information about the packet. Run the program with the
root privilege and demonstrate that you can indeed capture packets. After that, run the program again, but
without using the root privilege; describe and explain your observations.
// Make the program executable
# chmod a+x sniffer.py
Task 1.1B. Usually, when we sniff packets, we are only interested certain types of packets. We can do
that by setting filters in sniffing. Scapy’s filter use the BPF (Berkeley Packet Filter) syntax; you can find the
BPF manual from the Internet. Please set the following filters and demonstrate your sniffer program again
(each filter should be set separately):
SEED Labs – Packet Sniffing and Spoofing Lab 6
• Capture any TCP packet that comes from a particular IP and with a destination port number 23.
• Capture packets comes from or to go to a particular subnet. You can pick any subnet, such as
128.230.0.0/16; you should not pick the subnet that your VM is attached to.
In the code above, Line À creates an IP object from the IP class; a class attribute is defined for each IP
header field. We can use ls(a) or ls(IP) to see all the attribute names/values. We can also use a.show()
and IP.show() to do the same. Line Á shows how to set the destination IP address field. If a field is not set,
a default value will be used.
>>> ls(a)
version : BitField (4 bits) = 4 (4)
ihl : BitField (4 bits) = None (None)
tos : XByteField = 0 (0)
len : ShortField = None (None)
id : ShortField = 1 (1)
flags : FlagsField (3 bits) = <Flag 0 ()> (<Flag 0 ()>)
frag : BitField (13 bits) = 0 (0)
ttl : ByteField = 64 (64)
proto : ByteEnumField = 0 (0)
chksum : XShortField = None (None)
src : SourceIPField = ’127.0.0.1’ (None)
dst : DestIPField = ’127.0.0.1’ (None)
options : PacketListField = [] ([])
Line  creates an ICMP object. The default type is echo request. In Line Ã, we stack a and b together
to form a new object. The / operator is overloaded by the IP class, so it no longer represents division;
instead, it means adding b as the payload field of a and modifying the fields of a accordingly. As a result,
we get a new object that represent an ICMP packet. We can now send out this packet using send() in
Line Ä. Please make any necessary change to the sample code, and then demonstrate that you can spoof an
ICMP echo request packet with an arbitrary source IP address.
SEED Labs – Packet Sniffing and Spoofing Lab 7
If you are an experienced Python programmer, you can write your tool to perform the entire procedure
automatically. If you are new to Python programming, you can do it by manually changing the TTL field in
each round, and record the IP address based on your observation from Wireshark. Either way is acceptable,
as long as you get the result.
Hint: You need to understand how the ARP protocol works in order to correctly explain your observation.
You also need to know a little bit about routing. The following command help you find the router for a
specified destination:
ip route get 1.2.3.4
SEED Labs – Packet Sniffing and Spoofing Lab 8
int main()
{
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
char filter_exp[] = "ip proto icmp";
bpf_u_int32 net;
Tim Carstens has also written a tutorial on how to use pcap library to write a sniffer program. The
tutorial is available at http://www.tcpdump.org/pcap.htm.
Task 2.1A: Understanding How a Sniffer Works In this task, students need to write a sniffer program to
print out the source and destination IP addresses of each captured packet. Students can type in the above code
or download the sample code from the SEED book’s website (https://www.handsonsecurity.
net/figurecode.html). Students should provide screenshots as evidences to show that their snif-
fer program can run successfully and produces expected results. In addition, please answer the following
questions:
• Question 1. Please use your own words to describe the sequence of the library calls that are essential
for sniffer programs. This is meant to be a summary, not detailed explanation like the one in the
tutorial or book.
• Question 2. Why do you need the root privilege to run a sniffer program? Where does the program
fail if it is executed without the root privilege?
• Quesiton 3. Please turn on and turn off the promiscuous mode in your sniffer program. Can you
demonstrate the difference when this mode is on and off? Please describe how you can demonstrate
this.
Task 2.1B: Writing Filters. Please write filter expressions for your sniffer program to capture each of
the followings. You can find online manuals for pcap filters. In your lab reports, you need to include
screenshots to show the results after applying each of these filters.
• Capture the TCP packets with a destination port number in the range from 10 to 100.
Task 2.1C: Sniffing Passwords. Please show how you can use your sniffer program to capture the pass-
word when somebody is using telnet on the network that you are monitoring. You may need to modify
your sniffer code to print out the data part of a captured TCP packet (telnet uses TCP). It is acceptable if
you print out the entire data part, and then manually mark where the password (or part of it) is.
int sd;
struct sockaddr_in sin;
char buffer[1024]; // You can change the buffer size
Task 2.2A: Write a spoofing program. Please write your own packet spoofing program in C. You need to
provide evidences (e.g., Wireshark packet trace) to show that your program successfully sends out spoofed
IP packets.
Task 2.2B: Spoof an ICMP Echo Request. Spoof an ICMP echo request packet on behalf of another
machine (i.e., using another machine’s IP address as its source IP address). This packet should be sent to a
remote machine on the Internet (the machine must be alive). You should turn on your Wireshark, so if your
spoofing is successful, you can see the echo reply coming back from the remote machine.
• Question 4. Can you set the IP packet length field to an arbitrary value, regardless of how big the
actual packet is?
• Question 5. Using the raw socket programming, do you have to calculate the checksum for the IP
header?
• Question 6. Why do you need the root privilege to run the programs that use raw sockets? Where
does the program fail if executed without the root privilege?
SEED Labs – Packet Sniffing and Spoofing Lab 11
5 Guidelines
5.1 Filling in Data in Raw Packets
When you send out a packet using raw sockets, you basically construct the packet inside a buffer, so when
you need to send it out, you simply give the operating system the buffer and the size of the packet. Working
directly on the buffer is not easy, so a common way is to typecast the buffer (or part of the buffer) into
structures, such as IP header structure, so you can refer to the elements of the buffer using the fields of
those structures. You can define the IP, ICMP, TCP, UDP and other header structures in your program. The
following example show how you can construct an UDP packet:
struct ipheader {
type field;
.....
}
struct udpheader {
type field;
......
}
You may also need to use inet addr(), inet network(), inet ntoa(), inet aton() to
convert IP addresses from the dotted decimal form (a string) to a 32-bit integer of network/host byte order.
You can get their manuals from the Internet.
6 Submission
You need to submit a detailed lab report, with screenshots, to describe what you have done and what you
have observed. You also need to provide explanation to the observations that are interesting or surprising.
Please also list the important code snippets followed by explanation. Simply attaching code without any
explanation will not receive credits.