Scapy

Python-Based Interactive Packet Manipulation

@guedou - BHUSA Arsenal - August 7, 2019

Scapy - https://github.com/secdev/scapy

  • packets manipulation in Python

  • developed by Philippe Biondi, since 2003

    • maintained by Gabriel, Guillaume & Pierre, since 2012
  • native support on Linux, macOS & *BSD

    • Solaris & Windows thanks to libpcap & npcap.dll
  • Python3 compatible since 2018

Stats

  • PyPI downloads

    • daily: 15k
    • Python3: 80%
  • GiHub

    • stars: 4200
    • daily clones: 300
  • Python versions

    • 2.7, 3.4, 3.5, 3.6, 3.7, pypy, pypy3

 Installing & Launching Scapy

It is as simple as cloning the git repository:

git clone --depth 1 https://github.com/secdev/scapy
cd scapy
sudo ./run_scapy

                     aSPY//YASa       
             apyyyyCY//////////YCa       |
            sY//////YSpcs  scpCY//Pp     | Welcome to Scapy
 ayp ayyyyyyySCP//Pp           syY//C    | Version 2.4.3
 AYAsAYYYYYYYY///Ps              cY//S   |
         pCCCCY//p          cSSps y//Y   | https://github.com/secdev/scapy
         SPPPP///a          pP///AC//Y   |
              A//A            cyP////C   | Have fun!
              p///Ac            sC///a   |
              P////YCpc           A//A   | We are in France, we say Skappee.
       scccccp///pSP///p          p//Y   | OK? Merci.
      sY/////////y  caa           S//P   |             -- Sebastien Chabal
       cayCyayP//Ya              pY/Ya   |
        sY/PsY////YCc          aC//Yp 
         sc  sccaCY//PCypaapyCP//YSs  
                  spCPY//////YPSps    
                       ccaacs         
                                       using IPython 7.6.1
>>>

 Today Tutorial?

I will escort you in the discovery of most Scapy features:

  • packets manipulation
  • interacting with the network
  • visualization
  • using Scapy as a Python module
  • implementing a new protocol
  • answering machines
  • IPv6 reconnaissance
  • X.509 certificates manipulation
  • TLS tricks

 Slides available at https://guedou.github.io/

Packets Manipulation

  • packets are Python objects
  • the / operator is used to stack packets

In [2]:
packet = IP() / TCP()
Ether() / packet
Out[2]:
<Ether  type=IPv4 |<IP  frag=0 proto=tcp |<TCP  |>>>
  • the ls() function list packets fields

>>> ls(IP, verbose=True)
version    : BitField (4 bits)                   = (4)
ihl        : BitField (4 bits)                   = (None)
tos        : XByteField                          = (0)
len        : ShortField                          = (None)
id         : ShortField                          = (1)
flags      : FlagsField (3 bits)                 = (<Flag 0 ()>)
               MF, DF, evil
frag       : BitField (13 bits)                  = (0)
ttl        : ByteField                           = (64)
proto      : ByteEnumField                       = (0)
chksum     : XShortField                         = (None)
src        : SourceIPField                       = (None)
dst        : DestIPField                         = (None)
options    : PacketListField                     = ([])
  • Scapy selects the correct source IPv4 address, MAC addresses...

In [3]:
p = Ether() / IP(dst="www.secdev.org") / TCP(flags="F")
p.summary()
Out[3]:
"Ether / IP / TCP 192.168.42.18:ftp_data > Net('www.secdev.org'):http F"
  • all fields can be easily accessed

In [4]:
print(p.dst)      # first layer with a dst field, i.e. Ether
print(p[IP].src)  # explicit access to the IP layer src field

# sprintf() supports Scapy own formats strings
print(p.sprintf("%Ether.src% > %Ether.dst%\n%IP.src% > %IP.dst%"))
b8:26:6c:5f:4e:ee
192.168.42.18
b8:e8:56:45:8c:e6 > b8:26:6c:5f:4e:ee
192.168.42.18 > Net('www.secdev.org')
  • a field can store many values

In [5]:
[p for p in IP(ttl=(1, 5)) / ICMP()]  # a sequence of values from 1 to 5
Out[5]:
[<IP  frag=0 ttl=1 proto=icmp |<ICMP  |>>,
 <IP  frag=0 ttl=2 proto=icmp |<ICMP  |>>,
 <IP  frag=0 ttl=3 proto=icmp |<ICMP  |>>,
 <IP  frag=0 ttl=4 proto=icmp |<ICMP  |>>,
 <IP  frag=0 ttl=5 proto=icmp |<ICMP  |>>]
In [6]:
[p for p in IP() / TCP(dport=[22, 80, 443])]  # specific values
Out[6]:
[<IP  frag=0 proto=tcp |<TCP  dport=ssh |>>,
 <IP  frag=0 proto=tcp |<TCP  dport=http |>>,
 <IP  frag=0 proto=tcp |<TCP  dport=https |>>]

Interacting With The Network

  • the sr1() function sends a packet and returns a reply
  • Scapy can match queries and answers

In [7]:
r = sr1(IP(dst="8.8.8.8") / UDP() / DNS(qd=DNSQR()))
r[DNS].an
Begin emission:
Finished sending 1 packets.

Received 2 packets, got 1 answers, remaining 0 packets
Out[7]:
<DNSRR  rrname='www.example.com.' type=A rclass=IN ttl=5868 rdlen=None rdata=93.184.216.34 |>
  • the srp() function sends a list of frames and returns two variables:
    1. r a list of queries and matched answers
    2. u a list of unanswered packets

In [8]:
r, u = srp(Ether() / IP(dst="8.8.8.8", ttl=(5, 10)) / UDP() / DNS(qd=DNSQR(qname="www.example.com")))
r, u
Begin emission:
Finished sending 6 packets.

Received 12 packets, got 6 answers, remaining 0 packets
Out[8]:
(<Results: TCP:0 UDP:2 ICMP:4 Other:0>,
 <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)
In [9]:
# Access the first tuple
print(r[0][0].summary())  # sent packet
print(r[0][1].summary())  # received packet

# Scapy received an ICMP time-exceeded
r[0][1][ICMP]
Ether / IP / UDP / DNS Qry "b'www.example.com'" 
Ether / IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.example.com.'"  / Padding
Out[9]:
<ICMP  type=time-exceeded code=ttl-zero-during-transit chksum=0xeff3 reserved=0 length=17 unused=None |<IPerror  version=4 ihl=5 tos=0x0 len=61 id=1 flags= frag=0 ttl=1 proto=udp chksum=0xbee5 src=192.168.42.18 dst=8.8.8.8 |<UDPerror  sport=domain dport=domain len=41 chksum=0xba0b |<DNS  id=0 qr=0 opcode=QUERY aa=0 tc=0 rd=1 ra=0 z=0 ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=0 qd=<DNSQR  qname='www.example.com.' qtype=A qclass=IN |> an=None ns=None ar=None |<Padding  load='\x00\x00\x00\x00\x00\x00\x00' |>>>>>
  • a list of packets can be written to and read from a PCAP file

In [10]:
wrpcap("scapy.pcap", r)

pcap_p = rdpcap("scapy.pcap")
pcap_p[0]
Out[10]:
<Ether  dst=b8:26:6c:5f:4e:ee src=b8:e8:56:45:8c:e6 type=IPv4 |<IP  version=4 ihl=5 tos=0x0 len=61 id=1 flags= frag=0 ttl=5 proto=udp chksum=0xbae5 src=192.168.42.18 dst=8.8.8.8 |<UDP  sport=domain dport=domain len=41 chksum=0xba0b |<DNS  id=0 qr=0 opcode=QUERY aa=0 tc=0 rd=1 ra=0 z=0 ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=0 qd=<DNSQR  qname='www.example.com.' qtype=A qclass=IN |> an=None ns=None ar=None |>>>>
  • the command() method gives the Python statement that will build the same object

In [11]:
pcap_p[0].command()
Out[11]:
"Ether(dst='b8:26:6c:5f:4e:ee', src='b8:e8:56:45:8c:e6', type=2048)/IP(version=4, ihl=5, tos=0, len=61, id=1, flags=0, frag=0, ttl=5, proto=17, chksum=47845, src='192.168.42.18', dst='8.8.8.8')/UDP(sport=53, dport=53, len=41, chksum=47627)/DNS(length=None, id=0, qr=0, opcode=0, aa=0, tc=0, rd=1, ra=0, z=0, ad=0, cd=0, rcode=0, qdcount=1, ancount=0, nscount=0, arcount=0, qd=DNSQR(qname=b'www.example.com.', qtype=1, qclass=1), an=None, ns=None, ar=None)"
  • the sniff() function captures packets

In [12]:
s = sniff(count=2)
s
Out[12]:
<Sniffed: TCP:2 UDP:0 ICMP:0 Other:0>
In [13]:
sniff(count=2, prn=lambda p: p.summary())
Ether / IPv6 / ICMPv6ND_NS / ICMPv6 Neighbor Discovery Option - Source Link-Layer Address b8:e8:56:45:8c:e6
Ether / IPv6 / ICMPv6 Neighbor Discovery - Neighbor Advertisement (tgt: fe80::ba26:6cff:fe5f:4eee)
Out[13]:
<Sniffed: TCP:0 UDP:0 ICMP:0 Other:2>
In [14]:
sniff(offline=IP(dst="8.8.8.8/24") / UDP(), filter="udp and dst host 8.8.8.8")
Out[14]:
<Sniffed: TCP:0 UDP:1 ICMP:0 Other:0>
  • the lsc() function lists available commands

>>> 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        : Flip a given percentage or number of bits from a string
corrupt_bytes       : Corrupt a given percentage or number of bytes from a string
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
[..]
In [15]:
# Send ARP who-has requests to determine which hosts are up
arping("192.168.42.0/24")
Begin emission:
Finished sending 256 packets.

Received 6 packets, got 5 answers, remaining 251 packets
  b8:26:6c:5f:4e:ee 192.168.42.1
  54:64:d9:79:4e:00 192.168.42.3
  70:ee:50:14:d7:70 192.168.42.29
  24:5e:be:22:47:7f 192.168.42.42
  38:de:ad:1f:b2:38 192.168.42.20
Out[15]:
(<ARPing: TCP:0 UDP:0 ICMP:0 Other:5>,
 <Unanswered: TCP:0 UDP:0 ICMP:0 Other:251>)
  • the help() function describes commands behaviors and arguments

>>> help(traceroute)
Help on function traceroute in module scapy.layers.inet:

traceroute(target, dport=80, minttl=1, maxttl=30, sport=<RandShort>, l4=None, filter=None, timeout=2, verbose=None, **kargs)
    Instant TCP traceroute

    :param target:  hostnames or IP addresses
    :param dport:   TCP destination port (default is 80)
    :param minttl:  minimum TTL (default is 1)
    :param maxttl:  maximum TTL (default is 30)
    :param sport:   TCP source port (default is random)
    :param l4:      use a Scapy packet instead of TCP
    :param filter:  BPF filter applied to received packets
    :param timeout: time to wait for answers (default is 2s)
    :param verbose: detailed output
    :return: an TracerouteResult, and a list of unanswered packets

Visualization

  • with srloop(), send 100 packets to 8.8.8.8 and 8.8.4.4
  • the multiplot() method can be used to display IP ID values

In [20]:
ans, unans = srloop(IP(dst=["8.8.8.8", "1.1.1.1"]) / ICMP(), inter=.1, timeout=.1, count=80, verbose=False)
In [21]:
%matplotlib inline
ans.multiplot(lambda x, y: (y[IP].src, (y.time, y[IP].id)), plot_xy=True)
Out[21]:
[[<matplotlib.lines.Line2D at 0x11ab19a50>],
 [<matplotlib.lines.Line2D at 0x11ab0ff50>]]
  • the raw() function builds a packet, as sent on the network
In [22]:
pkt = IP() / UDP() / DNS(qd=DNSQR())
repr(raw(pkt))
Out[22]:
"b'E\\x00\\x00=\\x00\\x01\\x00\\x00@\\x11|\\xad\\x7f\\x00\\x00\\x01\\x7f\\x00\\x00\\x01\\x005\\x005\\x00)\\xb6\\xd3\\x00\\x00\\x01\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x03www\\x07example\\x03com\\x00\\x00\\x01\\x00\\x01'"

This representation being complicated, Scapy can:

  • do a hexdump of the content
In [23]:
hexdump(pkt)
0000  45 00 00 3D 00 01 00 00 40 11 7C AD 7F 00 00 01  E..=....@.|.....
0010  7F 00 00 01 00 35 00 35 00 29 B6 D3 00 00 01 00  .....5.5.)......
0020  00 01 00 00 00 00 00 00 03 77 77 77 07 65 78 61  .........www.exa
0030  6D 70 6C 65 03 63 6F 6D 00 00 01 00 01           mple.com.....
  • dump fields content layer by layer
In [24]:
pkt.show()
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = udp
  chksum    = None
  src       = 127.0.0.1
  dst       = 127.0.0.1
  \options   \
###[ UDP ]### 
     sport     = domain
     dport     = domain
     len       = None
     chksum    = None
###[ DNS ]### 
        id        = 0
        qr        = 0
        opcode    = QUERY
        aa        = 0
        tc        = 0
        rd        = 1
        ra        = 0
        z         = 0
        ad        = 0
        cd        = 0
        rcode     = ok
        qdcount   = 1
        ancount   = 0
        nscount   = 0
        arcount   = 0
        \qd        \
         |###[ DNS Question Record ]### 
         |  qname     = 'www.example.com'
         |  qtype     = A
         |  qclass    = IN
        an        = None
        ns        = None
        ar        = None

  • display a pretty representation
In [14]:
pkt.canvas_dump()
Out[14]:

The traceroute() functions calls sr(IP(ttl=(1,15)) and create the TracerouteResult object


In [25]:
ans, unans = traceroute('www.secdev.org', maxttl=15)
Begin emission:
Finished sending 15 packets.

Received 20 packets, got 14 answers, remaining 1 packets
   217.25.178.5:tcp80 
1  192.168.42.1    11 
3  193.253.82.102  11 
4  193.252.159.153 11 
5  193.252.137.78  11 
6  130.117.15.233  11 
7  154.25.7.150    11 
8  154.25.4.254    11 
9  149.6.166.166   11 
10 217.25.178.5    SA 
11 217.25.178.5    SA 
12 217.25.178.5    SA 
13 217.25.178.5    SA 
14 217.25.178.5    SA 
15 217.25.178.5    SA 

Different methods can be used to display the results, like world_trace() that uses the GeoIP module from MaxMind, and cartopy


In [22]:
%matplotlib inline
ans.world_trace()
Out[22]:
[[<matplotlib.lines.Line2D at 0x7fb432ee41d0>]]

The make_table() method provides a compact results representation, useful for a basic port scanner


In [27]:
targets = ["scanme.nmap.org", "nmap.org"]

ans = sr(IP(dst=targets) / TCP(dport=[22, 80, 443, 31337]), timeout=3, verbose=False)[0]

ans.extend(sr(IP(dst=targets) / UDP() / DNS(qd=DNSQR()), timeout=3, verbose=False)[0])

ans.make_table(lambda x, y: (x[IP].dst,
                             x.sprintf('%IP.proto%/{TCP:%r,TCP.dport%}{UDP:%r,UDP.dport%}'),
                             y.sprintf('{TCP:%TCP.flags%}{ICMP:%ICMP.type%}')))
          45.33.32.156 45.33.49.119 
tcp/22    SA           SA           
tcp/31337 SA           RA           
tcp/443   RA           SA           
tcp/80    SA           SA           
udp/53    dest-unreach -            

Scapy As a Python Module

Scapy can be used to build your own tools like ping6.py:


In [35]:
import argparse                                                                 
                                                                                
from scapy.all import *                                                         
                                                                                
parser = argparse.ArgumentParser(description="A simple ping6")                  
parser.add_argument("ipv6_host", help="An IPv6 address")
args = parser.parse_args()                                                      
                                                                                
print(sr1(IPv6(dst=args.ipv6_host) / ICMPv6EchoRequest(), verbose=0).summary())
sudo python ping6.py www.kame.net
IPv6 / ICMPv6 Echo Reply (id: 0x0 seq: 0x0)

Implementing a New Protocol

To add new protocols, create an object:

  • that inherits from Packet
  • defines fields in the fields_desc variable

In [36]:
class DNSTCP(Packet):
    name = "DNS over TCP"
    
    fields_desc = [ FieldLenField("len", None, fmt="!H", length_of="dns"),
                    PacketLenField("dns", 0, DNS, length_from=lambda p: p.len)]
    
    # This method tells Scapy to decode the payload with DNSTCP
    def guess_payload_class(self, payload):
        return DNSTCP

This new protocol can be directly used to build and parse a packet


In [37]:
DNSTCP(raw(DNSTCP(dns=DNS())))
Out[37]:
<DNSTCP  len=12 dns=<DNS  id=0 qr=0 opcode=QUERY aa=0 tc=0 rd=1 ra=0 z=0 ad=0 cd=0 rcode=ok qdcount=0 ancount=0 nscount=0 arcount=0 |> |>

The StreamSocket object allows Scapy to use a TCP socket


In [38]:
import socket

from scapy.all import *

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # create a TCP socket
sck.connect(("8.8.8.8", 53))  # connect to 8.8.8.8 on 53/TCP

# Create a StreamSocket and define the default class
ssck = StreamSocket(sck)
ssck.basecls = DNSTCP

# Send the DNS query
ssck.sr1(DNSTCP(dns=DNS(qd=DNSQR(qname="www.example.com"))))
Begin emission:
Finished sending 1 packets.

Received 1 packets, got 1 answers, remaining 0 packets
Out[38]:
<DNSTCP  len=49 dns=<DNS  id=0 qr=1 opcode=QUERY aa=0 tc=0 rd=1 ra=1 z=0 ad=0 cd=0 rcode=ok qdcount=1 ancount=1 nscount=0 arcount=0 qd=<DNSQR  qname='www.example.com.' qtype=A qclass=IN |> an=<DNSRR  rrname='www.example.com.' type=A rclass=IN ttl=5713 rdlen=None rdata=93.184.216.34 |> ns=None ar=None |> |>

Answering Machines

Scapy can wait for a query, then send an answer with the AnsweringMachine object.

Two methods are mandatory:

  1. is_request(): returns True if the packet is the expected query
  2. make_reply(): returns the packet that will be sent by Scapy

Note: in the following example, the Wi-Fi interface must be put in monitor mode

In [ ]:
from scapy.all import *

# Specify the Wi-Fi interface
conf.iface = "mon0"

# Create the Answering Machine
class ProbeRequest_am(AnsweringMachine):
  function_name = "pram"

  mac = "00:11:22:33:44:55"

  def is_request(self, pkt):
    return Dot11ProbeReq in pkt

  def make_reply(self, req):

    rep = RadioTap()
    # Note: depending on your Wi-Fi card, you might need something else than RadioTap()
    rep /= Dot11(addr1=req.addr2, addr2=self.mac, addr3=self.mac, ID=RandShort(), SC=RandShort())
    rep /= Dot11ProbeResp(cap="ESS", timestamp=int(time.time())
    rep /= Dot11Elt(ID="SSID", info="Scapy !")
    rep /= Dot11Elt(ID="Rates", info='\x82\x84\x0b\x16\x96')
    rep /= Dot11Elt(ID="DSset", info=orb(10))

    return rep

# Start the answering machine
#ProbeRequest_am()()  # uncomment to test

IPv6 Reconnaissance

  • discover the link IPv6 router using the Router Solicitation message

In [39]:
sr1(IPv6() / ICMPv6ND_RS())
Begin emission:
Finished sending 1 packets.

Received 2 packets, got 1 answers, remaining 0 packets
Out[39]:
<IPv6  version=6 tc=192 fl=0 plen=104 nh=ICMPv6 hlim=255 src=fe80::ba26:6cff:fe5f:4eee dst=ff02::1 |<ICMPv6ND_RA  type=Router Advertisement code=0 cksum=0x4199 chlim=64 M=0 O=1 H=0 prf=High P=0 res=0 routerlifetime=600 reachabletime=0 retranstimer=0 |<ICMPv6NDOptPrefixInfo  type=3 len=4 prefixlen=64 L=1 A=1 R=0 res1=0 validlifetime=0x708 preferredlifetime=0x258 res2=0x0 prefix=2a01:cb08:229:3700:: |<ICMPv6NDOptRDNSS  type=25 len=3 res=0 lifetime=600 dns=[ fe80::ba26:6cff:fe5f:4eee ] |<ICMPv6NDOptDNSSL  type=31 len=2 res=0 lifetime=600 searchlist=['home.'] |<ICMPv6NDOptMTU  type=5 len=1 res=0x0 mtu=1500 |<ICMPv6NDOptSrcLLAddr  type=1 len=1 lladdr=b8:26:6c:5f:4e:ee |>>>>>>>
  • probe local nodes and list manufacturers

In [40]:
a,u = sr(IPv6(dst="ff02::1") / ICMPv6EchoRequest(), multi=1, timeout=1)
a.make_table(lambda t: (t[0][IPv6].dst, t[1][IPv6].src, in6_addrtovendor(t[1][IPv6].src)))
Begin emission:
Finished sending 1 packets.

Received 6 packets, got 0 answers, remaining 1 packets
 

 X.509 Certificates Manipulation

  • Scapy can easily parse certificates, and display their contents

In [1]:
load_layer("tls")
cert_blackhat = Cert(pem2der(open("files/blackhat.com.pem", "rb").read()))  # assuming you d/l the certificate
cert_blackhat
Out[1]:
[X.509 Cert. Subject:/OU=PositiveSSL Multi-Domain/CN=ssl764995.cloudflaressl.com, Issuer:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO ECC Domain Validation Secure Server CA 2]
  • several useful methods help exploring them

In [2]:
print(cert_blackhat.isSelfSigned())  # check if it is self signed
print(cert_blackhat.subject)  # display the subject
print(cert_blackhat.remainingDays()) # compute the number of days until expiration
False
{'organizationUnitName': 'PositiveSSL Multi-Domain', 'commonName': 'ssl764995.cloudflaressl.com'}
156.39600694444445
  • look for the Subject Alternative Name extension

In [3]:
[e  for e in cert_blackhat.tbsCertificate.extensions if e.extnID == "2.5.29.17"]
Out[3]:
[<X509_Extension  extnID=<ASN1_OID['subjectAltName']> critical=None extnValue=<X509_ExtSubjectAltName  subjectAltName=[<X509_GeneralName  generalName=<X509_DNSName  dNSName=<ASN1_IA5_STRING[b'ssl764995.cloudflaressl.com']> |> |>, <X509_GeneralName  generalName=<X509_DNSName  dNSName=<ASN1_IA5_STRING[b'*.blackhat.com']> |> |>, <X509_GeneralName  generalName=<X509_DNSName  dNSName=<ASN1_IA5_STRING[b'blackhat.com']> |> |>] |> |>]
  • moreover, some cryptographic tricks are also included, like verifying signatures

In [4]:
# Verify issuers signatures
cert_comodo = Cert(pem2der(open("files/comodo.pem", "rb").read())) # assuming you d/l the certificate        
print(cert_blackhat.isIssuerCert(cert_comodo))  # check the signature
True
  • or, change the certificate signature

In [5]:
cert_blackhat.tbsCertificate.serialNumber.val = 0x42  # Change a value

private_key = PrivKeyRSA("files/private_key.pem")  # Load a private key
new_cert_blackhat = private_key.resignCert(cert_blackhat)  # Do a new signature

print(hex(new_cert_blackhat.tbsCertificate.serialNumber.val))  # Print the value
print(private_key.verifyCert(new_cert_blackhat))  # Verify the signature
0x42
True

 HTTP & TLS tricks

  • since Scapy v2.4.3, it is possible to perform HTTP queries

In [6]:
load_layer("http")
req = HTTP() / HTTPRequest(
    Accept_Encoding=b'gzip, deflate',
    Cache_Control=b'no-cache',
    Pragma=b'no-cache',
    Connection=b'keep-alive',
    Host=b'www.secdev.org',
)
t = TCP_client.tcplink(HTTP, "www.secdev.org", 80)
r = t.sr1(req, timeout=3)
Begin emission:
Finished sending 1 packets.

Received 1 packets, got 1 answers, remaining 0 packets
In [66]:
r[HTTPResponse].show()
###[ HTTP Response ]### 
  Http_Version= 'HTTP/1.1'
  Status_Code= '200'
  Reason_Phrase= 'OK'
  Accept_Patch= None
  Accept_Ranges= 'bytes'
  Access_Control_Allow_Credentials= None
  Access_Control_Allow_Headers= None
  Access_Control_Allow_Methods= None
  Access_Control_Allow_Origin= None
  Access_Control_Expose_Headers= None
  Access_Control_Max_Age= None
  Age       = None
  Allow     = None
  Alt_Svc   = None
  Cache_Control= None
  Connection= 'Keep-Alive'
  Content_Disposition= None
  Content_Encoding= 'gzip'
  Content_Language= None
  Content_Length= '5351'
  Content_Location= None
  Content_MD5= None
  Content_Range= None
  Content_Security_Policy= None
  Content_Type= 'text/html'
  Date      = 'Thu, 25 Jul 2019 13:00:35 GMT'
  Delta_Base= None
  ETag      = '"300a-56be3867f3785-gzip"'
  Expires   = None
  IM        = None
  Keep_Alive= 'timeout=5, max=100'
  Last_Modified= 'Fri, 11 May 2018 00:50:41 GMT'
  Link      = None
  Location  = None
  P3P       = None
  Permanent = None
  Permanent = None
  Pragma    = None
  Proxy_Authenticate= None
  Public_Key_Pins= None
  Refresh   = None
  Retry_After= None
  Server    = 'Apache'
  Set_Cookie= None
  Status    = None
  Strict_Transport_Security= None
  Timing_Allow_Origin= None
  Tk        = None
  Trailer   = None
  Transfer_Encoding= None
  Upgrade   = None
  Vary      = 'Accept-Encoding'
  Via       = '1.1 www.secdev.org'
  WWW_Authenticate= None
  Warning   = None
  X_Content_Duration= None
  X_Content_Security_Policy= None
  X_Content_Type_Options= None
  X_Correlation_ID= None
  X_Frame_Options= None
  X_Powered_By= None
  X_Request_ID= None
  X_UA_Compatible= None
  X_WebKit_CSP= None
  X_XSS_Protection= None
  Unknown_Headers= None
###[ Raw ]### 
     load      = '<html>\n<head>\n<title>SecDev.org</title>\n</head>\n<body>\n<!--\n<a href="http://www.miscmag.com"><img border=0 height="100" src="misc_noir.png"></a>\n-->\n<H1>secdev</H1>\n\n\n\n\n<H4>Me</H4>\n<ul>\n<li> mail: phil<b></b>@<i></i>secdev<i></i>.<b></b>org</li>\n<li> <a href="phil.asc">PGP Key</a></li>\n<li> <a href="http://www.oreilly.com/catalog/9780596009632/"><img style="vertical-align:middle" height="30" border=0 alt="[Security Power Tools cover]" src="images/security_power_tools-cover.gif">&nbsp;Security Power Tools</a> was out in August 2007.\n     I wrote a complete chapter on <a href="projects/scapy/">Scapy</a> and one on shellcodes.</li>\n<form action="https://www.paypal.com/cgi-bin/webscr" method="post">\n<li> If you like what I do, you can \n<input type="hidden" name="cmd" value="_s-xclick">\n<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----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-----END PKCS7-----\n">\n<input style="vertical-align:middle" type="image" src="https://www.paypal.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">\n<img alt="" border="0" src="https://www.paypal.com/fr_FR/i/scr/pixel.gif" width="1" height="1">\n</form></li>\n</ul>\n\n\n\n<H4>Conferences</H4>\n<ul>\n<li><a href="http://www.osdem.org">OSDEM</a> : <a href="conf/osdem.pdf">Kernel security (Slides for OSDEM, Feb 2001)</a></li>\n<li><a href="http://www.fosdem.org">FOSDEM</a> : <a href="conf/ksecurity_en.pdf">Kernel security (Slides for FOSDEM, Feb 2002)</a></li>\n<li><a href="http://www.openweekend.cz/">OpenWeekend</a> : <a href="conf/ksec_openweekend.pdf">Slides</a> \n<li><a href="http://lsm.abul.org">LSM (RMLL)</a> : <a href="conf/ksec_lsm.pdf">Kernel security (Slides for LSM, July 2002)</a></li>\n<li><a href="http://www.defcon.org">DefCon X</a> : <a href="conf/ksec_defcon.pdf">Kernel security (Slides for DefCon 10, August 2002)</a></li>\n<li><a href="http://www.fosdem.org">FOSDEM 2003</a> : <a href="conf/libqsearch.pdf">presentation of libqsearch (Slides for FOSDEM, Feb 2003)</a></li>\n<li><a href="http://www.rencontresmondiales.org">LSM 2003</a> : <a href="conf/scapy_lsm2003.pdf">presentation of Scapy</a> and <a href="conf/shellforge_lsm2003.pdf">presentation of shellforge</a></li>\n<li><a href="http://www.linux-kongress.org">10th Linux Kongress</a> : <a href="conf/ksec_kongress03.pdf">presentation of Kernel Level Security (again)</a> (<a href="conf/ksec_article_kongress03.pdf">article for proceedings</a>)</li>\n<li><a href="http://www.cansecwest.com">CanSecWest/core04</a> : <a href="conf/shellforgeG2_csw04.pdf">Shellforge G2: shellcodes for everybody and every platform</a></li>\n<li><a href="http://www.syscan.org">SyScAN 04</a> : <a href="conf/shellcodes_syscan04.pdf">About UNIX Shellcodes</a></li>\n<li><a href="http://www.cansecwest.com">CanSecWest/core05</a> : <a href="conf/scapy_csw05.pdf">Packet generation and network based attacks with Scapy</a></li>\n<li><a href="http://lsm.abul.org">LSM (RMLL) 2005</a> : <a href="conf/shellforge_lsm2005.pdf">ShellForge</a></li>\n<li><a href="http://www.t2.fi/english/">T2\'2005</a> : <a href="conf/scapy_T2.pdf">Scapy: explore the net with new eyes</a> (<a href="conf/scapy_T2.handout.pdf">printable version</a>)</li>\n<li><a href="http://lufgi4.informatik.rwth-aachen.de/courses/show/1">Summerschool Applied IT Security 2005</a> : <a href="conf/scapy_Aachen.pdf">Network packet manipulation with Scapy</a></li>\n<li><a href="http://hack.lu">Hack.lu 2005</a> conference and workshop : <a href="conf/scapy_hack.lu.pdf">Network packet manipulation with Scapy</a> (<a href="conf/scapy_hack.lu.handout.pdf">printable version</a>)</li>\n<li><a href="http://pacsec.jp">PacSec/core05</a> : <a href="conf/scapy_pacsec05.pdf">Network packet forgery with Scapy</a> (<a href="conf/scapy_pacsec05.handout.pdf">printable version</a>)</li>\n<li><a href="http://www.blackhat.com">BlackHat Europe 06</a> : <a href="conf/skype_BHEU06.pdf">Silver Needle in the Skype</a> (<a href="conf/skype_BHEU06.handout.pdf">printable version</a>)</li>\n<li><a href="http://www.hackinthebox.org">Hack In The Box 2006</a> : <a href="conf/scapy-IPv6_HITB06.pdf">Scapy and IPv6 networking</a> <!--(<a href="conf/scapy-IPv6_HITB06.handout.pdf">printable version</a>)--></li>\n<li><a href="http://www.cansecwest.com">CanSecWest/core07</a> : <a href="conf/IPv6_RH_security-csw07.pdf">Ipv6 Routing Headers Security</a> (tools demonstrated: <a href="/projects/rtgraph3d">RT Graph 3D</a> and <a href="/projects/ipv6world">IPv6World</a>) (<a href="http://www.natisbad.org">summary of issues and fixes triggered</a>)</li>\n</ul>\n\n<H4>Projects/programs</H4>\n<ul>\n<li><a href="https://scapy.net/">Scapy</a>: a powerful network discovery tool.\n<li><a href="projects/rtgraph3d/">RTGraph3D</a>: make 3D graphs in realtime\n<li><a href="projects/ipv6world/">IPv6 world</a>: 3D IPv6 backbone explorer\n<li><a href="projects/etherpuppet/">EtherPuppet</a> : clone an Ethernet interface through TCP (even work on my Linksys WRT54G)\n<li><a href="projects/net2pcap/">net2pcap</a> : auditable daemon (less than 300 lines) to dump traffic to a pcap file.\n<li><a href="projects/pcapdispatcher/">PCAPdispatcher</a>: small program to dispatch a big pcap file into many others by their type or connection.\n<li><a href="projects/shellforge/">ShellForge</a>: write your shellcodes in C, ShellForge will convert them. (Inspired from Stealth\'s <a href="http://www.team-teso.net/releases/hellkit-1.2.tar.gz">Hellkit</a>).\n<li><a href="projects/tuntap_udp/">tunproxy</a> : a demonstration tunneling program over UDP using tun/tap (and his C clone)\n<li><a href="python/eapy.py">eapy</a>: a simplistic 802.1X EAP authentication client (MD5 challenges only, use PF_PACKET --&gt; Linux only)\n<li><a href="python/bfi.py">bfy</a>: a little BrainFuck interpreter (BrainFuck <em>Hello world</em> program <a href="python/hello.bf">included!</a>)\n<li><a href="python/asm2graph.py">asm2graph</a> and <a href="python/bin2graph.py">bin2graph</a> : 2 small experiments to convert a binary program to a graph. (Use GraphViz). <br>\nTechnical solutions are very close to Silvio\'s <a href="http://www.big.net.au/~silvio/coding/graphing/">flowgraph</a>, which I did not know at this time.\n<li><a href="python/arpyspoof.py">arpyspoof</a>: a clone of <a href="http://monkey.org/~dugsong/dsniff/">arpspoof</a>. See links on <a href="http://sid.rstack.org/arp-sk/">arp-sk page</a> for more informations or tools about ARP cache poisonning.\n<li><a href="python/etherleak.py">etherleak.py</a> : a simple etherleak tester.\n<li><a href="python/">All python scripts</a>\n<li><a href="projects/experiments/">experiments</a>\n</ul>\n\n<H4>Linux Kernel Patches</H4>\n<ul>\n<li><a href="projects/sfswap/">SYN/FIN swap patch</a> : swap SYN and FIN flags in TCP headers to/from a given peer\n<li><a href="patches/icmpleak.patch">ICMP Leak patch for 2.0.39</a> to fix <a href="adv/CARTSA-20030314-icmpleak.txt">ICMP Leak bug</a>\n<li><a href="http://www.lids.org">LIDS homepage</a>\n<li><a href="lids_specifs/index.html">LIDS 0.0 specif. rev0.2</a>\n    (<a href="lids_specifs.ps.gz">lids_specif.ps.gz</a>)\n<li><a href="patches/">all patches</a>\n</ul>\n\n\n<H4>Intrusion detection</H4>\n<ul>\n<li><a href="ids.ps.gz">Rapport</a> (et aussi en <a href="ids.pdf">PDF</a>)</li>\n<li><a href="idsbiblio">La biblio</a></li>\n</ul>\n\n<H4>Nmap</H4>\n<ul>\n<li><a href="nmap/">Some nmap hacks</a></li>\n</ul>\n\n<H4>Quick search experiments</H4>\n<ul>\n<li><a href="quicksearch/essai.ps">A postscript</a></li>\n<li><a href="python/">Implementations in python</a></li>\n<li><a href="libqsearch.html">libqsearch project</a></li>\n</ul>\n\n<H4>World domination</H4>\n<ul>\n<li><a href="python/searchbot">Search bot, sketch 1</a></li>\n</ul>\n\n<H4>Sharp Zaurus</H4>\n<ul>\n<li><a href=zaurus/zethereal.html>Ethereal on a Sharp Zaurus</a></li>\n<li><a href=zaurus/crosscompile.html>Example for setting up a cross compilation tool chain</a>\n</ul>\n\n<h3>If you trust me, you can trust my website</h3>\n<pre>\n-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA1\n\nIssuer: C=FR, ST=IdF, L=Paris, O=secdev.org, OU=secdev.org, CN=*.secdev.org\nSHA1 Fingerprint=EA:EE:C0:3F:53:B8:C8:AD:6A:05:24:32:85:F4:54:8D:87:21:34:7D\nMD5 Fingerprint=0D:07:6B:00:E7:86:C6:3C:B8:55:EB:02:6A:FC:E0:9C\n-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v1.4.6 (GNU/Linux)\n\niD8DBQFIMfI3Xuj/Xz2aQ+IRAmKbAKC25LEoT753HUqMfqNLyh0/LikftwCfbDlv\nJu6Rwb59JxlZIR+J6TKwE78=\n=wexP\n-----END PGP SIGNATURE-----\n</pre>\n\n<center><small>\n<!--Creative Commons License--><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.5/"><img alt="Creative Commons License" style="border-width: 0" src="images/by-nc-sa.png"/></a><br/>Except where explicitely said otherwise, work on this site is licensed under GPLv2 for code and under a<br><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.5/">Creative Commons Attribution-NonCommercial-ShareAlike 2.5  License</a> for the remaining.\n<!--/Creative Commons License-->\n<!-- <rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n\t<Work rdf:about="">\n\t\t<license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.5/" />\n\t</Work>\n\t<License rdf:about="http://creativecommons.org/licenses/by-nc-sa/2.5/"><permits rdf:resource="http://web.resource.org/cc/Reproduction"/><permits rdf:resource="http://web.resource.org/cc/Distribution"/><requires rdf:resource="http://web.resource.org/cc/Notice"/><requires rdf:resource="http://web.resource.org/cc/Attribution"/><prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/><permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/><requires rdf:resource="http://web.resource.org/cc/ShareAlike"/></License></rdf:RDF> -->\n</small></center>\n\n\n<a href="totoyoyo.html"><font color=#ffffff>SP4N\\TR4P, d0n`t f01l0\\N!</font></a>\n</body>\n</html>\n'

  • sniff TLS traffic

In [11]:
load_layer("tls")
s = sniff(filter="port 443", count=100)  # sniff packets on port 443
ch_list = [p for p in s if TLSClientHello in p]  # filter Client Hello messages
ch_list[0][TLSClientHello].show()  # display the first message
###[ TLS Handshake - Client Hello ]### 
  msgtype   = client_hello
  msglen    = 508
  version   = TLS 1.2
  gmt_unix_time= Sat, 10 Oct 2026 00:01:56 +0100 (1791590516)
  random_bytes= f8f3159aa9f5bde32af8db592a160d3100fbee52581db2579fde7767
  sidlen    = 32
  sid       = '\xc4\x8d\r\x81yl\x81\x1b\xc4\xb9vY\x83{V\xaf\xd9\xef\xfc--(\x16h\xc0\xdd\x8f\xe6\x85c\xdaA'
  cipherslen= 36
  ciphers   = [TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256, TLS_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA]
  complen   = 1
  comp      = null
  extlen    = 399
  \ext       \
   |###[ TLS Extension - Server Name ]### 
   |  type      = server_name
   |  len       = 21
   |  servernameslen= 19
   |  servernames= [b'my.geekstory.net']
   |###[ TLS Extension - Extended Master Secret ]### 
   |  type      = extended_master_secret
   |  len       = 0
   |###[ TLS Extension - Renegotiation Indication ]### 
   |  type      = renegotiation_info
   |  len       = 1
   |  reneg_conn_len= 0
   |  renegotiated_connection= ''
   |###[ TLS Extension - Supported Groups ]### 
   |  type      = supported_groups
   |  len       = 14
   |  groupslen = 12
   |  groups    = [x25519, secp256r1, secp384r1, secp521r1, ffdhe2048, ffdhe3072]
   |###[ TLS Extension - Supported Point Format ]### 
   |  type      = ec_point_formats
   |  len       = 2
   |  ecpllen   = 1
   |  ecpl      = [uncompressed]
   |###[ TLS Extension - Session Ticket ]### 
   |  type      = session_ticket
   |  len       = 0
   |  ticket    = ''
   |###[ TLS Extension - Application Layer Protocol Negotiation ]### 
   |  type      = alpn
   |  len       = 14
   |  protocolslen= 12
   |  protocols = [b'h2, http/1.1']
   |###[ TLS Extension - Certificate Status Request ]### 
   |  type      = status_request
   |  len       = 5
   |  stype     = ocsp
   |  \req       \
   |   |###[ OCSPStatusRequest structure ]### 
   |   |  respidlen = 0
   |   |  \respid    \
   |   |  reqextlen = 0
   |   |  reqext    = ''
   |###[ TLS Extension - Key Share (for ClientHello) ]### 
   |  type      = key_share
   |  len       = 107
   |  client_shares_len= 105
   |  \client_shares\
   |   |###[ Key Share Entry ]### 
   |   |  group     = x25519
   |   |  kxlen     = 32
   |   |  key_exchange= '\xa8~\xa6\xe91\xd3\x86\xccV\x7fb\xf9\xca\xc4R\xd7\x7f\xc7\xf1E8\x06\x9c\xc7Q\x08D\xe4\xa4\xe0\x1b*'
   |   |###[ Key Share Entry ]### 
   |   |  group     = secp256r1
   |   |  kxlen     = 65
   |   |  key_exchange= '\x04\xfa\x91Y$\x9e\x06\xa36cZ\xd3\xaf\xbd\x94b\xee-JF>\x13\x9d\xd9\xef\x8f\xbc\x13\x00+\xc7,k\xe1\xee\xd0\x15(\xe5\xdf\x97\xdc\xc5\x80\x1crh\xfc}\x1e\xeeL\xd9pQ\xff\xf2\x11J\x0b\xddf_wq'
   |###[ TLS Extension - Supported Versions (for ClientHello) ]### 
   |  type      = supported_versions
   |  len       = 9
   |  versionslen= 8
   |  versions  = [TLS 1.3, TLS 1.2, TLS 1.1, TLS 1.0]
   |###[ TLS Extension - Signature Algorithms ]### 
   |  type      = signature_algorithms
   |  len       = 24
   |  sig_algs_len= 22
   |  sig_algs  = [sha256+ecdsa, sha384+ecdsa, sha512+ecdsa, sha256+rsaepss, sha384+rsaepss, sha512+rsaepss, sha256+rsa, sha384+rsa, sha512+rsa, sha1+ecdsa, sha1+rsa]
   |###[ TLS Extension - PSK Key Exchange Modes ]### 
   |  type      = psk_key_exchange_modes
   |  len       = 2
   |  kxmodeslen= 1
   |  kxmodes   = [psk_dhe_ke]
   |###[ TLS Extension - Record Size Limit ]### 
   |  type      = record_size_limit
   |  len       = 2
   |  record_size_limit= 16385
   |###[ TLS Extension - Padding ]### 
   |  type      = padding
   |  len       = 142
   |  padding   = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

Projects That Uses Scapy

Questions?

Issues?

Pull Requests?

Beers?