Packet Crafting and Network Exploration with Scapy

According to its main page,

Scapy is a powerful interactive packet manipulation library written in Python. Scapy is able to forge or decode packets of a wide number of protocols, send them on the wire, capture them, match requests and replies, and much more.

https://scapy.net/

Install

Depending on your OS and the installation method you want to use there are several options to install Scapy.

pip install scapy

sudo apt install python3-scapy

git clone https://github.com/secdev/scapy

yay -S scapy

sudo scapy

INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
                                      
                     aSPY//YASa       
             apyyyyCY//////////YCa       |
            sY//////YSpcs  scpCY//Pp     | Welcome to Scapy
 ayp ayyyyyyySCP//Pp           syY//C    | Version 2.5.0
 AYAsAYYYYYYYY///Ps              cY//S   |
         pCCCCY//p          cSSps y//Y   | https://github.com/secdev/scapy
         SPPPP///a          pP///AC//Y   |
              A//A            cyP////C   | Have fun!
              p///Ac            sC///a   |
              P////YCpc           A//A   | Craft packets before they craft
       scccccp///pSP///p          p//Y   | you.
      sY/////////y  caa           S//P   |                      -- Socrate
       cayCyayP//Ya              pY/Ya   |
        sY/PsY////YCc          aC//Yp 
         sc  sccaCY//PCypaapyCP//YSs  
                  spCPY//////YPSps    
                       ccaacs         
                                       using IPython 8.20.0

In my case, the first time I ran Scapy I got that INFO message about PyX that disappeared after installing python-pyx.

Usage

Scapy can be used either in interactive mode or in python code.

Sending ICMP Ping Request:

sr1(IP(dst="8.8.8.8")/ICMP())

Begin emission:
WARNING: Incompatible L3 types detected using <class 'scapy.layers.inet.IP'> instead of <class 'scapy.layers.inet6.IPv46'> !
Finished sending 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets
<IP  version=4 ihl=5 tos=0x0 len=28 id=0 flags= frag=0 ttl=120 proto=icmp chksum=0xfece src=8.8.8.8 dst=xxx.xxx.xxx.xxx |<ICMP  type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |

Craft and Send Custom TCP Packet:

# Import Scapy
from scapy.all import *

# Craft and send a TCP packet to port 80 on google.com, and capture the response
response = sr1(IP(dst="google.com")/TCP(dport=80), timeout=2)

# Check if a response was received
if response:
    # Display the response details
    response.show()
else:
    print("No response received.")

❯ sudo python send_tcp_packet.py

Begin emission:
WARNING: Incompatible L3 types detected using <class 'scapy.layers.inet.IP'> instead of <class 'scapy.layers.inet6.IPv46'> !
Finished sending 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets
###[ IP ]### 
  version   = 4
  ihl       = 5
  tos       = 0x0
  len       = 44
  id        = 0
  flags     = DF
  frag      = 0
  ttl       = 123
  proto     = tcp
  chksum    = 0x8900
  src       = 142.250.179.206
  dst       = xxx.xxx.xxx.xxx
  \options   \
###[ TCP ]### 
     sport     = www_http
     dport     = ftp_data
     seq       = 309367137
     ack       = 1
     dataofs   = 6
     reserved  = 0
     flags     = SA
     window    = 65535
     chksum    = 0x7dbf
     urgptr    = 0
     options   = [('MSS', 1289)]

Capture and Display Packets:

pks = sniff(count=5)
pks.show

<bound method _PacketList.show of <Sniffed: TCP:5 UDP:0 ICMP:0 Other:0>>

pks[0].show

<bound method Packet.show of <IP version=4 ihl=5 tos=0x0 len=83 id=60692 flags=DF frag=0 ttl=63 proto=tcp chksum=0x47c7 src=xxx.xxx.xxx.xxx dst=yyy.yyy.yyy.yyy |<TCP sport=https dport=50686 seq=182204631 ack=2416855860 dataofs=8 reserved=0 flags=PA window=252 chksum=0x941c urgptr=0 options=[('NOP', None), ('NOP', None), ('Timestamp', (2129392428, 1421923492))] |<Raw load='\x14\x07\x06\x00\xaa\\xa5\\xdf\\xe0\\x23-Y\\xbc.\x0d\\xc7\\x9e<\\xc2\\xc0\\x8f}\\xd3\\xa0\x0c\\xcbdZ"\x15\\x8b\\xff' |

pks[1].show

<bound method Packet.show of <IP version=4 ihl=5 tos=0x0 len=52 id=53224 flags=DF frag=0 ttl=64 proto=tcp chksum=0x6412 src=yyy.yyy.yyy.yyy dst=xxx.xxx.xxx.xxx |<TCP sport=50686 dport=https seq=2416855860 ack=182204662 dataofs=8 reserved=0 flags=A window=249 chksum=0xd949 urgptr=0 options=[('NOP', None), ('NOP', None), ('Timestamp', (1421928457, 2129392428))] |

pks[2].show

<bound method Packet.show of <IP version=4 ihl=5 tos=0x0 len=52 id=60693 flags=DF frag=0 ttl=63 proto=tcp chksum=0x47e5 src=185.175.25.23 dst=10.0.42.3 |<TCP sport=https dport=50686 seq=182204662 ack=2416855860 dataofs=8 reserved=0 flags=FA window=252 chksum=0xeca9 urgptr=0 options=[('NOP', None), ('NOP', None), ('Timestamp', (2129392429, 1421923492))] |

pks[3].show

<bound method Packet.show of <IP version=4 ihl=5 tos=0x0 len=52 id=53225 flags=DF frag=0 ttl=64 proto=tcp chksum=0x6411 src=10.0.42.3 dst=185.175.25.23 |<TCP sport=50686 dport=https seq=2416855860 ack=182204663 dataofs=8 reserved=0 flags=FA window=249 chksum=0xd946 urgptr=0 options=[('NOP', None), ('NOP', None), ('Timestamp', (1421928457, 2129392429))] |

pks[4].show

<bound method Packet.show of <IP version=4 ihl=5 tos=0x0 len=52 id=60694 flags=DF frag=0 ttl=63 proto=tcp chksum=0x47e4 src=185.175.25.23 dst=10.0.42.3 |<TCP sport=https dport=50686 seq=182204663 ack=2416855861 dataofs=8 reserved=0 flags=A window=252 chksum=0xd926 urgptr=0 options=[('NOP', None), ('NOP', None), ('Timestamp', (2129392458, 1421928457))] |

And if we ask for another package, it gives an error because we just got 5 packages.

pks[5].show

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In[19], line 1
----> 1 pks[5].show

File /usr/lib/python3.11/site-packages/scapy/plist.py:176, in _PacketList.__getitem__(self, item)
    173 if isinstance(item, slice):
    174     return self.__class__(self.res.__getitem__(item),
    175                           name="mod %s" % self.listname)
--> 176 return self.res.__getitem__(item)

IndexError: list index out of range