Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Python Scapy

Scapy

Virtualenv for root

Some of the commands of Scapy can be executed as a regular user, others require the elevated rights of the root user on Linux.

Therefore we create a Python virtual environment for the root user in the /opt/venv3 directory, we'll install scapy in this virtual environment and will use it when necessary.

sudo virtualenv /opt/venv3

Install Scapy

This is how we install it to the virtual environment of the root user.

sudo /opt/venv3/bin/pip install scapy

Tcpdump

For some of the examples we are going to use tcpdump to capture what's going on the network so we can see the traffic generated by scapy.

When running tcpdump it will display a banner like this, we'll disregard this in the following ouput files.

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes

Scapy ping an IP using ICMP

  • In one window use ifconfig to get the name of the interface or use "any"
tcpdump -nn host 8.8.8.8 -i any
tcpdump -nn host 8.8.8.8
  • In another window run
ping -c 1 8.8.8.8
10:15:40.705266 IP 192.168.1.204 > 8.8.8.8: ICMP echo request, id 17, seq 1, length 64
10:15:40.761960 IP 8.8.8.8 > 192.168.1.204: ICMP echo reply, id 17, seq 1, length 64
import scapy.all as scapy
scapy.send(scapy.IP(dst="8.8.8.8")/scapy.ICMP())
sudo /opt/venv3/bin/python ping_other.py
10:18:18.497851 IP 192.168.1.204 > 8.8.8.8: ICMP echo request, id 0, seq 0, length 8
10:18:18.554260 IP 8.8.8.8 > 192.168.1.204: ICMP echo reply, id 0, seq 0, length 8

Scapy ping ICMP

  • In one window we run tcpdump listening to traffic from localhost to localhost
sudo tcpdump -nn src 127.0.0.1 and dst 127.0.0.1 -i lo

In another terminal we send a single ping:

ping -c 1 localhost

This is what tcpdump captured:

10:42:23.016599 IP 127.0.0.1 > 127.0.0.1: ICMP echo request, id 11, seq 1, length 64
10:42:23.016608 IP 127.0.0.1 > 127.0.0.1: ICMP echo reply, id 11, seq 1, length 64

Then we run our scapy script:

import scapy.all as scapy
scapy.send(scapy.IP()/scapy.ICMP(id=1, seq=1))
sudo /opt/venv3/bin/python ping.py
  • We must run it as user root but we need to use he python 3 that has scapy installed which is probably in some virtualenv.
10:43:48.081774 IP 127.0.0.1 > 127.0.0.1: ICMP echo request, id 0, seq 0, length 8
  • TODO why is there no response?

Scapy display (show)

  • thing.show() is the same as print(thing.display())
import scapy.all as scapy

ip = scapy.IP()
ip.display()

tcp = scapy.TCP()
tcp.display()

icmp = scapy.ICMP()
icmp.display()
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = hopopt
  chksum    = None
  src       = 127.0.0.1
  dst       = 127.0.0.1
  \options   \

None
###[ TCP ]### 
  sport     = ftp_data
  dport     = http
  seq       = 0
  ack       = 0
  dataofs   = None
  reserved  = 0
  flags     = S
  window    = 8192
  chksum    = None
  urgptr    = 0
  options   = []

None
###[ ICMP ]### 
  type      = echo-request
  code      = 0
  chksum    = None
  id        = 0x0
  seq       = 0x0

None

Scapy ip

import scapy.all as scapy

ip = scapy.IP()

print(repr(ip))
print(ip.display())


ip = scapy.IP(dst="8.8.8.8")
print(ip.display())


ip = scapy.IP(dst="8.8.8.8", src="7.7.7.7")
print(ip.display())
<IP  |>
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = hopopt
  chksum    = None
  src       = 127.0.0.1
  dst       = 127.0.0.1
  \options   \

None
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = hopopt
  chksum    = None
  src       = 192.168.1.204
  dst       = 8.8.8.8
  \options   \

None
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = hopopt
  chksum    = None
  src       = 7.7.7.7
  dst       = 8.8.8.8
  \options   \

None

Scapy Configuration

import scapy.config as config
print(config.conf)
ASN1_default_codec = None
AS_resolver = None
BTsocket   = None
L2listen   = None
L2socket   = None
L3socket   = None
L3socket6  = None
USBsocket  = None
auto_crop_tables = True
auto_fragment = True
bufsize    = 65536
cache_iflist = {}
checkIPID  = False
checkIPaddr = True
checkIPinIP = True
checkIPsrc = True
check_TCPerror_seqack = False
color_theme = <NoTheme>
commands   = 
contribs   = {}
crypto_valid = True
crypto_valid_advanced = True
debug_dissector = False
debug_match = False
debug_tls  = False
default_l2 = None
dot15d4_protocol = None
emph       = <Emphasize []>
except_filter = ''
extensions_paths = '.'
fancy_prompt = True
filter     = ''
geoip_city = None
histfile   = '/home/gabor/.scapy_history'
iface      = None
interactive = False
interactive_shell = ''
ipv6_enabled = True
l2types    = 
l3types    = 
layers     = 
load_layers = ['bluetooth', 'bluetooth4LE', 'dhcp', 'dhcp6', 'dns', 'dot11',...
logLevel   = 30
loopback_name = 'lo'
mib        = None
min_pkt_size = 60
netcache   = 
noenum     = <Resolve []>
padding    = 1
prog       = display = 'display' dot = 'dot' hexedit = 'hexer' ifconfig = 'i...
promisc    = True
prompt     = '>>> '
raise_no_dst_mac = False
raw_layer  = None
raw_summary = False
recv_poll_rate = 0.05
resolve    = <Resolve []>
route      = None
route6     = None
session    = ''
sniff_promisc = 1
stats_classic_protocols = []
stats_dot11_protocols = []
stealth    = 'not implemented'
temp_files = []
use_bpf    = False
use_npcap  = False
use_pcap   = False
use_pypy   = False
verb       = 2
version    = '2.4.4'
warning_threshold = 5
wepkey     = ''

Scapy List interfaces

import scapy.all as scapy

interfaces = scapy.get_if_list()
print(interfaces)


['lo', 'enp0s31f6', 'wlp3s0', 'enx0050b6e59f0e']

Scapy ping-pong

import scapy.all as scapy
reply = scapy.sr1(scapy.IP()/scapy.ICMP(id=1, seq=1, length=64), timeout=3)
if reply is not None:
    print('reply')
    print(reply.src)
    print(reply.dst)
  • TODO

Scapy sniffing - capturing packets

import scapy.all as scapy

snf = scapy.sniff(filter="src 127.0.0.1 and dst 127.0.0.1", count=2, iface='lo')

print("done")
print(snf)
snf.summary()
print('-------')
print(snf[0])
snf[0].display
print('-------')
#print(snf[0].icmp.display)
icmp = snf[0].getlayer('ICMP')
icmp.display()
sudo /opt/venv3/bin/python sniff.py

Scapy ping between two IPs that do not belong to my server

tcpdump -nn host 8.8.8.8 -i any
tcpdump -nn host 8.8.8.8
import scapy.all as scapy

scapy.send(scapy.IP(dst="8.8.8.8", src="7.7.7.7")/scapy.ICMP())
10:25:42.357691 IP 7.7.7.7 > 8.8.8.8: ICMP echo request, id 0, seq 0, length 8

Scapy Traceroute

import sys
import scapy.all as scapy

target = '8.8.8.8'
if len(sys.argv) == 2:
    target = sys.argv[1]

ans, unans = scapy.sr(scapy.IP(dst=target, ttl=(1,22),id=scapy.RandShort())/scapy.TCP(flags=0x2), timeout=10)
for snd,rcv in ans:
    print(snd.ttl, rcv.src, isinstance(rcv.payload, scapy.TCP))

Scapy TCP port 80

import random
import scapy.all as scapy

ip = scapy.IP(dst="8.8.8.8", src="7.7.7.7")

source_port = random.randint(1024, 65535)
dest_port = 80
tcp = scapy.TCP(sport=source_port, dport=dest_port)
tcp.display()

pkg = ip/tcp
pkg.display()

scapy.send(pkg)

Scapy Layers

import scapy.all as scapy
import scapy.layers as layers
print(scapy.LayersList().layers()) # []

import scapy.config as config
print(config.LayersList().layers()) # []

print(dir(layers))
  • TODO: why are the lists empty?
  • TODO: how to get the list of available layers?

Scapy HTTP

sudo tcpdump -nn host 8.8.8.8 and port 80 -i any
curl --max-time 1 http://8.8.8.8
#print(dir(scapy))
#import random
import scapy.all as scapy
import scapy.layers as layers
scapy.load_layer("http")  # does not complain even if we supply an incorrect name
#print(dir(layers))

#host = '8.8.8.8'
#host = 'https://httpbin.org/get'
host = '54.164.234.192'

ip = scapy.IP(dst=host)
print(dir(layers.http))

#scapy.explore(layers.http)
http = layers.http.HTTP()
#http.show()
request = layers.http.HTTPRequest(
    Accept_Encoding = b'gzip, deflate',
    Cache_Control = b'no-cache',
    Connection = b'keep-alive',
    Host = host,
    Pragma = b'no-cache'
)
#request.show()

req = http/request
a = scapy.TCP_client.tcplink(layers.http.HTTP, host, 80) # needs root?
#answser = a.sr1(ip/req)
scapy.send(ip/req)


#scapy.send(scapy.IP(dst="8.8.8.8")/scapy.HTTPRequest())