Packet Replay With Scapy

From DocWiki

Jump to: navigation, search

Contents


Introduction

This walk through is intended to show how to use scapy with tcpdump and pcaps to replay arbitrary packets towards any device. It includes instructions on using tcpdump to capture packets either simultaneously (knowing when and what to capture) or just letting a capture run and hoping to line up the packets later with an event.

It is non-trivial to add and remove VLAN headers so try and capture the traffic in the same format it's needed.

My packets come from a testing engine, but you could use any pcap.

What is Scapy?

From their site:

Scapy is a powerful interactive packet manipulation program. It 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.

Example Topology

In this example VLAN 610 is where the device under test lives; it's MAC: 001e.bd4f.68ff

I have a linux-client that is using tcpdump to capture packets a testing engine is sending. The linux client sees all vlans.

The switch in this topology is a vSwitch on an ESXi host. This switch is kind enough to toggle uplink ports into promiscuous to flood traffic. Otherwise this would require a technology like SPAN.

+-------------+ L2 Trunk
|linux-client +---------------+
+-------------+               |
                            +-+------+    L2 Trunk +--------------------+
                            | Switch +-------------+ Device Under Test  |
                            +--+-----+             +--------------------+
+-------------+                |
|    tester   +----------------+
+-------------+   VLAN 610

Check Network for Sanity

There is active traffic I want to capture. Since large captures are a hassle, I'm going to set a filter to limit it to a subset of this interfaces traffic.

--xx give hex, include L2 info My filter is for the VLAN_ID, ETHER_TYPE (IPv6) and ETHER_SRC.

I highlighted the dst_mac, vlan tag and ethertype. You can read the hex or use an online packet decoder.

lab@linux-client:~$ sudo tcpdump -i ens192  -xx '(vlan 610 and ip6 and ether src 00:00:10:10:10:80)'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens192, link-type EN10MB (Ethernet), capture size 262144 bytes
11:05:21.884460 IP6 fe80::200:10ff:fe10:1080 > fe80::21e:bdff:fe4f:68ff: HBH HBH ICMP6, echo request, seq 0, length 10
       0x0000:  001e bd4f 68ff 0000 1010 1080 8100 0262
       0x0010:  86dd 6000 0000 001a 00ff fe80 0000 0000
       0x0020:  0000 0200 10ff fe10 1080 fe80 0000 0000
       0x0030:  0000 021e bdff fe4f 68ff 0000 0104 0000
       0x0040:  0000 3a00 0104 0000 0000 8000 39bc 0000
       0x0050:  0000 0000

Capture the Packets, simultaneous

We know what we are looking for, and run the capture at the exact time it's needed.

lab@linux-client:~$ sudo tcpdump -i ens192 '( vlan 610 and ip6 and ether src 00:00:10:10:10:80)' -w test121.pcap
tcpdump: listening on ens192, link-type EN10MB (Ethernet), capture size 262144 bytes
3 packets captured
3 packets received by filter
0 packets dropped by kernel
755 packets dropped by interface

Capture the Packets, asynchronous

Before considering this, make absolutely sure time is synchronized on the device doing the capture, and the device with the crash/logs/event.

Screen is a utility to allow a vty on a linux machine to persist after disconnect. This is necessary if you need a capture to go for a long time.

lab@linux-client:~$ screen
<Press Enter>

This capture uses a rotating buffer making 10 files each 1GB. It will use 10GB total. Avoid files larger than 1GB.

lab@linux-client:~$ sudo tcpdump -i ens192 -W 10 -C 1024 -w capture.pcap
tcpdump: listening on ens192, link-type EN10MB (Ethernet), capture size 262144 bytes

Detach from the screen instance

<Press Ctrl+A then Ctrl+D>

[detached from 27583.pts-1.linux-client]
lab@linux-client:~$

Come back days later, but within the duration of the rotating buffer.

lab@linux-client:~$ screen -list
There is a screen on:
        27583.pts-1.linux-client      (07/25/2018 04:05:26 PM)        (Detached)
1 Socket in /var/run/screen/S-lab.

lab@linux-client:~$ screen -r 
lab@linux-client:~$ sudo tcpdump -i ens192 -W 10 -C 1024 -w capture.pcap
tcpdump: listening on ens192, link-type EN10MB (Ethernet), capture size 262144 bytes

Scapy - Packet Replay and Manipulation

Use Scapy to examine and replay the packets

Run Scapy

Sudo is required

lab@linux-client:~$ sudo scapy
INFO: Can't import python gnuplot wrapper . Won't be able to plot.
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
Welcome to Scapy (2.2.0)

Import the capture

This creates a PacketList object called test. You can use help(test) to see what you can do to the object.

Scapy does best with old format pcaps.

>>> test = rdpcap("test121.pcap")

See the capture

I'm interested in packet 1.

>>> test.show()
0000 Ether / Dot1Q / fe80::21e:bdff:fe4f:68ff > ff02::d (103) / Raw
0001 Ether / Dot1Q / IPv6 / IPv6ExtHdrHopByHop / IPv6ExtHdrHopByHop / ICMPv6 Echo Request (id: 0x0 seq: 0x0)
0002 Ether / Dot1Q / IPv6 / ICMPv6ND_NA / ICMPv6 Neighbor Discovery Option - Destination Link-Layer Address 00:22:33:44:55:66
0003 Ether / Dot1Q / IPv6 / ICMPv6 Echo Request (id: 0x0 seq: 0x0)
0004 Ether / Dot1Q / IPv6 / ICMPv6ND_NS / ICMPv6 Neighbor Discovery Option - Source Link-Layer Address 00:1e:bd:4f:68:ff
0005 Ether / Dot1Q / IPv6 / ICMPv6ND_RA / ICMPv6NDOptSrcLLAddr / ICMPv6NDOptMTU / ICMPv6NDOptPrefixInfo / ICMPv6 Neighbor Disco:
0006 Ether / Dot1Q / IPv6 / ICMPv6ND_NS / ICMPv6 Neighbor Discovery Option - Source Link-Layer Address 00:1e:bd:4f:68:ff
0007 Ether / Dot1Q / IPv6 / ICMPv6ND_NS / ICMPv6 Neighbor Discovery Option - Source Link-Layer Address 00:1e:bd:4f:68:ff
>>> 

Select the correct packet

Verify the packet you want to send makes sense.

Check the src mac, src dst, and vlan tags. Check the upper layers.

>>> test[1].show()
###[ Ethernet ]###
  dst= 00:1e:bd:4f:68:ff
  src= 00:00:10:10:10:80
  type= 0x8100
###[ 802.1Q ]###
     prio= 0L
     id= 0L
     vlan= 610L
     type= 0x86dd
###[ IPv6 ]###
        version= 6L
        tc= 0L
        fl= 0L
        plen= 26
        nh= Hop-by-Hop Option Header
        hlim= 255
        src= fe80::200:10ff:fe10:1080
        dst= fe80::21e:bdff:fe4f:68ff
###[ IPv6 Extension Header - Hop-by-Hop Options Header ]###
           nh= Hop-by-Hop Option Header
           len= 0
           autopad= On
           \options\
            |###[ PadN ]###
            |  otype= PadN [00: skip, 0: Don't change en-route]
            |  optlen= 4
            |  optdata= '\x00\x00\x00\x00'
###[ IPv6 Extension Header - Hop-by-Hop Options Header ]###
              nh= ICMPv6
              len= 0
              autopad= On
              \options\
               |###[ PadN ]###
               |  otype= PadN [00: skip, 0: Don't change en-route]
               |  optlen= 4
               |  optdata= '\x00\x00\x00\x00'
###[ ICMPv6 Echo Request ]###
                 type= Echo Request
                 code= 0
                 cksum= 0x39bc
                 id= 0x0
                 seq= 0x0
                 data= '\x00\x00'

Change the Ethernet Destination

With a loop

This is a small python loop that sets one attribute on a header, in this example the Ether header.

Notice the space before each on the second line. Python cares about whitespace.

>>> for each in test:
...  each[Ether].dst = "00:00:00:00:00:00"
... 
>>>
Verify
>>> test[Ether][0].dst
'00:00:00:00:00:00'

Or.

Remember the space before "each" on the second line.

>>> for each in test:
...  each[Ether].dst
... 
'00:00:00:00:00:00'
'00:00:00:00:00:00'
'00:00:00:00:00:00'
'00:00:00:00:00:00'
'00:00:00:00:00:00'
'00:00:00:00:00:00'
'00:00:00:00:00:00'
'00:00:00:00:00:00'

Replay a packet, one time

>>> sendp(test[1], iface="ens192")
.
Sent 1 packets.

Replay a packet, multiple times

>>> sendp(test[1], iface="ens192", count=1000)
...............
[output omitted]
Sent 1000 packets.

Rating: 3.0/5 (2 votes cast)

Personal tools