Using Scapy in RIPE labs

Scapy is a packet manipulation tool and library. It lets you build, send, receive, and decode packets down to the protocol field level. Think of it as ping + tcpdump + Wireshark + a packet foundry — but interactive and scriptable.

1. Starting Scapy

scapy

If you see a >>> Python-like prompt, you’re in. Quit later with exit(), quit(), or Ctrl+D.

2. Building packets

In Scapy, packets are built layer by layer using / to stack protocols:

pkt = IPv6(src="2001:db8:5::5", dst="ff02::1") / ICMPv6ND_NA()
  • IPv6(...) → the IPv6 header

    • src = source IPv6 address

    • dst = destination IPv6 address (ff02::1 = all nodes on the local link)

  • / ICMPv6ND_NA() → attach an ICMPv6 Neighbor Advertisement message on top.

At this point, you have an object called pkt. It’s not sent yet, just sitting in memory.

3. Sending packets

3.1 One-way send

send(pkt)

This just fires it off — no listening for replies. Good for testing or attacks where you don’t care about responses.

4. Probing with Echo Requests

Let’s try an ICMPv6 ping:

f = IPv6(dst="2001:db8:f:1::1") / ICMPv6EchoRequest()
  • The IPv6 layer sets the destination.

  • The ICMPv6EchoRequest() layer is the IPv6 equivalent of ping.

4.1 Send and receive

ans, unans = sr(f)
  • sr() = send packet(s) and receive answers.

  • ans = answered packets (pairs of request + reply).

  • unans = unanswered packets (request sent, but no reply received).

5. Inspecting Results

ans.summary()

This gives a one-line overview of request → reply mapping:

IPv6 / ICMPv6 Echo Request ==> IPv6 / ICMPv6 Echo Reply

For deep inspection:

ans.show()

Which prints full decoded layers, e.g.:

0000 IPv6 / ICMPv6 Echo Request (id: 0x0 seq: 0x0) ==> 
     IPv6 / ICMPv6 Echo Reply (id: 0x0 seq: 0x0)

5.1 Accessing individual results

  • First request/reply pair:

ans[0]

Which is a tuple: (<sent packet>, <received packet>)

  • Just the reply:

ans[0][1]
  • Just the request:

ans[0][0]
  • Show all fields of the request:

ans[0][0].show()

Output example:

###[ IPv6 ]###
  version= 6
  tc= 0
  fl= 0
  plen= None
  nh= ICMPv6
  hlim= 64
  src= 2001:db8:f:1:216:3eff:feee:a
  dst= 2001:db8:f:1::1
###[ ICMPv6 Echo Request ]###
  type= Echo Request
  code= 0
  cksum= None
  id= 0x0
  seq= 0x0

6. Repeated probing with srloop

ans, unans = srloop(f)

This continuously sends requests until you break it (Ctrl+C).

Example output:

RECV 1: IPv6 / ICMPv6 Echo Reply (id: 0x0 seq: 0x0)
RECV 1: IPv6 / ICMPv6 Echo Reply (id: 0x0 seq: 0x0)
RECV 1: IPv6 / ICMPv6 Echo Reply (id: 0x0 seq: 0x0)
^C
Sent 3 packets, received 3 packets. 100.0% hits.

You can then summarise the results:

ans.summary()

7. Capturing packets

To capture packets in Scapy, use the sniff() function. You need to pass the interface where you want to capture packets and define a filtering rule if you do not want to capture all of the packets arriving on that interface.

>>> pkts=sniff(iface="eth0",lfilter = lambda x: x.haslayer(IPv6))
^C

8. Summary

  • Packet composition: Use / to stack headers and protocols.

  • Sending:

    • send() = fire and forget.

    • sr() = send and receive (store replies).

    • srloop() = send repeatedly until you stop it.

  • Inspection:

    • summary() for one-liners.

    • show() for all fields.

    • Index into ans for detailed request/reply tuples.

Scapy does not validate whether fields are “legal” — if you want to set insane values (like Flow Label abuse for covert channels), Scapy will happily craft and send it.

More

Scapy documentation