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
- Scapy
- ScapyTrafficGenerator and old, Python 2 based wrapper
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 asprint(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())