A powerful interactive packet-crafting and manipulation library that lets you build, send, sniff, and dissect network packets layer by layer.
Scapy treats packets as stackable Python objects (Ether()/IP()/TCP()), giving you total control over every field. It can forge arbitrary packets, replay traffic, sniff the wire, and decode dozens of protocols — replacing a fistful of tools (hping, tcpdump, arpspoof) with one scriptable library. It is a staple for network reconnaissance, custom scanners, and protocol testing on authorized networks.
pip install scapyWarning
Sending/sniffing raw packets requires root/administrator privileges (sudo). Only run against networks and hosts you own or are authorized to test.
from scapy.all import IP, TCP, sr1
# Craft a TCP SYN to an authorized target and wait for one reply
packet = IP(dst="127.0.0.1") / TCP(dport=80, flags="S")
reply = sr1(packet, timeout=2, verbose=0)
if reply is None:
print("no response (filtered)")
elif reply.haslayer(TCP) and reply[TCP].flags == "SA":
print("open - SYN/ACK received")
else:
print("closed")Packets are built by stacking layers with /. Most send and sniff operations require root.
| API | Purpose |
|---|---|
IP(), TCP(), UDP(), ICMP(), Ether(), ARP(), DNS() |
Protocol layers |
a / b |
Stack layers into a packet |
send(pkt) |
Send at layer 3, no reply expected |
sendp(pkt) |
Send at layer 2 |
sr1(pkt, timeout=) |
Send and return the first reply |
sr(pkts, timeout=) |
Send and return (answered, unanswered) |
srp(pkt) |
Layer-2 send and receive |
sniff(filter=, count=, prn=, timeout=) |
Capture packets (BPF filter syntax) |
pkt.show() / pkt.summary() |
Inspect a packet |
wrpcap(path, pkts) / rdpcap(path) |
Write and read pcap files |
pkt.haslayer(L) / pkt[L] |
Test for and access a layer |
Note
Scapy layer and field names vary between versions and protocol modules. Verify against pkt.show() and the version you have installed rather than assuming.
Craft and send an ICMP echo (ping) and read the reply:
from scapy.all import IP, ICMP, sr1
pkt = IP(dst="8.8.8.8") / ICMP()
reply = sr1(pkt, timeout=2, verbose=0)
if reply:
print(f"Reply from {reply.src} ttl={reply.ttl}")
else:
print("No reply")Reply from 8.8.8.8 ttl=118
A minimal TCP SYN port scanner for an authorized host:
from scapy.all import IP, TCP, sr1
target = "192.168.56.101" # authorized lab host
for port in (22, 80, 443, 8080):
pkt = IP(dst=target) / TCP(dport=port, flags="S")
resp = sr1(pkt, timeout=1, verbose=0)
if resp and resp.haslayer(TCP) and resp[TCP].flags == 0x12: # SYN-ACK
print(f"{port}/tcp open")
else:
print(f"{port}/tcp closed/filtered")22/tcp open
80/tcp open
443/tcp closed/filtered
8080/tcp closed/filtered
Sniff packets and summarize traffic (passive analysis):
from scapy.all import sniff
def show(pkt):
if pkt.haslayer("IP"):
print(pkt["IP"].src, "->", pkt["IP"].dst, pkt.summary())
sniff(filter="tcp port 80", prn=show, count=3, timeout=10)192.168.56.10 -> 93.184.216.34 Ether / IP / TCP 192.168.56.10:54321 > 93.184.216.34:http S
93.184.216.34 -> 192.168.56.10 Ether / IP / TCP 93.184.216.34:http > 192.168.56.10:54321 SA
192.168.56.10 -> 93.184.216.34 Ether / IP / TCP 192.168.56.10:54321 > 93.184.216.34:http A
- Custom port/host scanning — build SYN, ACK, or FIN scanners tuned to your engagement instead of relying on a single tool.
- Packet crafting & protocol testing — forge malformed or edge-case packets to test firewall rules, IDS/IPS behavior, and stack robustness.
- Network sniffing & analysis — capture and dissect traffic to find cleartext credentials or misconfigurations on an authorized segment.
- ARP / discovery tooling — send ARP requests to map live hosts on a local network.
- Traffic replay — resend captured packets to reproduce and analyze protocol behavior.
- Running without root — crafting and sniffing raw packets needs elevated privileges; you will get a
PermissionErroror silent failure. - Forgetting
timeout=onsr1(), which blocks indefinitely when there is no reply. - Not checking for
None—sr1()returnsNoneon timeout, and indexing it raisesTypeError. - Assuming a reply layer exists — always guard with
haslayer()beforepkt[TCP]. - Leaving
verbose=1in a script, flooding stdout. - Testing loopback with layer-2 functions —
srp()and Ether-based sends do not work as expected onlo. - Reaching for Scapy when a plain [[Socket-Module|socket]] would do; Scapy is for crafting and inspecting, not ordinary connections.
[!warning] Authorized use only Scapy sends arbitrary packets onto a real network. Use it only on networks you own or are explicitly authorized to test, ideally an isolated lab.
- Packet crafting is high impact. Malformed or high-rate packets can crash network devices, disrupt services, and take down a segment. This is not a low-risk tool.
- Never spoof source addresses outside an isolated lab. Address spoofing enables reflection and amplification attacks against third parties and is unlawful in most jurisdictions.
- Sniffing captures other people's traffic. On a shared network that may include credentials and personal data, and interception is illegal in many jurisdictions without explicit authorization.
- Root is required, so the blast radius is large. Run in a VM or container dedicated to lab work.
- Rate-limit deliberately. A tight
send()loop is a denial-of-service generator. - Store pcap files securely — they frequently contain credentials and personal data.
- Always set
verbose=0in scripts and a sensibletimeout=so scans don't hang. - Use
sr1()for a single expected reply,srp()at layer 2, andsend()when you don't need answers. - Run inside a scoped lab/VLAN; document authorization before crafting traffic.
- Prefer BPF
filter=strings onsniff()to reduce noise and CPU load. - Be aware raw sockets are OS-privileged; drop privileges promptly after binding where possible.
- [[dnspython]] — higher-level DNS queries without hand-crafting packets
- [[pwntools]] — pairs with Scapy for network-facing exploit work
- [[Readme|Python for Security Professionals]] — course home