packets, pcap’s & python
BSides London 2014 Scapy Workshop
By Adam Maxwell / @catalyst256
Pre-requites for workshop
1. Have a laptop.
2. Have Scapy installed (VM is fine).
• Kali or BackTrack
• Linux
• Mac OSX
• Windows (you’re on your own)
3. If possible clone this GitHub repo:
• https://github.com/catalyst256/ScapyWrkShop
4. A BSides London Scapy Cheat Card
What are we going to learn today
• Who am I
• Scapy - brief intro
• Write some packets
• Read some packets
• Some cool Scapy features
• Using Scapy with Python
Who am I – The bad stuff
• I don’t work in InfoSec.
• I’m not a network engineer.
• I am VMware Certified (that impressed you
right??).
• I work for an insurance company (someone
has to).
• This is my first EVER workshop (sorry).
Who am I – The slightly better stuff
• I’m the author of “The Very Unofficial Dummies
Guide to Scapy”.
• I hold an OSCP & OSWP and I’ve sat the SANS
SEC503 course.
• Spend far too much time with the 3 P’s:
• Packets
• pcaps
• Python
• I wrote a Maltego Transform set for analyzing
pcap files called sniffMyPackets.
Scapy - A Brief Intro
• Written by Philippe Biondi.
• Based on Python
• Some of the cool stuff it can do:
• Forge packets
• Decode packets
• Send & Receive packets
• ARP Poisoning
• Sniff packets
• Current version: 2.2.0-dev
• Check out: http://bb.secdev.org/scapy/overview
Packets – Vanilla Packet
• Lets create the 3 layers for a TCP packet.
• Now lets view it.
>>> a = Ether()
>>> b = IP()
>>> c = TCP()
>>> a.show()
>>> b.show()
>>> c.show()
Packets – Tweak it a bit
• Lets change the IP destination port
• Lets change the TCP destination port
>>> b.dst = ’1.1.1.1'
>>> c.dport = 80
Packets – The Humble ICMP
• One liner ICMP Packet (Request)
• But wait we didn’t set a ICMP Type.
• The Scapy default for an ICMP packet is type 8
(or echo-request).
>>> i = IP(dst='127.0.0.1')/ICMP()/"HelloWorld"
>>> i
<IP frag=0 proto=icmp dst=127.0.0.1 |<ICMP |<Raw load='HelloWorld' |>>>
>>> ls(ICMP)
type : ByteEnumField = (8)
…
Packets – The Humble ICMP
• Time to release your packet..
• Oh did you want to see the response??
• Change your src IP & dst IP to something
“valid” eg.
>>> sendp(i)
.
Sent 1 packets.
>>>
>>> i[IP].src = '10.1.99.28'
>>> i[IP].dst = '10.1.99.1'
Packets – The Humble ICMP
• Now lets send it and collect the response.
>>> x = sr1(i)
Begin emission:
..Finished to send 1 packets.
.*
Received 4 packets, got 1 answers, remaining 0 packets
>>> x
<IP version=4L ihl=5L tos=0x0 len=38 id=22514 flags=
frag=0L ttl=64 proto=icmp chksum=0x48c6
src=10.1.99.1 dst=10.1.99.28 options=[] |
<ICMP type=echo-reply code=0 chksum=0x0 id=0x0 seq=0x0
|<Raw load='HelloWorld' |>>>
Packets – Something a little different?
• DNS?
• Port Scanner?
• Traceroute?
• This is actually a ICMP & TCP traceroute, default
destination port is 80 (which you can change of course).
>>> p = sr1(IP(dst="8.8.8.8")/UDP()/DNS(rd=1,qd=DNSQR(qname="www.citrix.com")))
>>> p=sr(IP(dst="10.1.99.1")/TCP(dport=[23,80,53,443]))
>>> p=sr(IP(dst="10.1.99.1")/TCP(dport=80))
>>> traceroute (["www.google.com"], maxttl=20)
>>> traceroute(["www.google.com"], dport=443, maxttl=20)
Packets – HTTP GET Request
• HTTP packets require the TCP 3 way
handshake to be completed first.
• Using Python + Scapy it is easier to create the
necessary packets.
• Scapy uses Raw packets which might get
dropped by your Kernel/OS. You may need to
run this command (on Linux).
iptables -A OUTPUT -p tcp --tcp-flags RST RST -s [source IP] -j DROP
Packets – HTTP GET Request
• Using Python the GET Request looks like this:
#!/usr/bin/env python
from scapy.all import *
# Set the GET request
get='GET / HTTP/1.0nn'
# Set your target
ip=IP(dst="www.google.com")
# Create a random source port (not needed but nice to have)
port=RandNum(1024,65535)
# Create the SYN packet
SYN=ip/TCP(sport=port, dport=80, flags="S", seq=666)
# Send SYN and receive SYN,ACK
SYNACK=sr1(SYN)
# Create ACK with GET request
ACK=ip/TCP(sport=SYNACK.dport, dport=80, flags="A", seq=SYNACK.ack, ack=SYNACK.seq + 1) / get
# SEND our ACK-GET request
reply,error=sr(ACK)
# Print the reply
print reply.show()
PCAPS – The 3 R’s
• Reading
>>> pkts = rdpcap('pcap/evidence02.pcap')
>>> pkts
<evidence02.pcap: TCP:490 UDP:52 ICMP:0 Other:30>
>>> pkts.summary()
>>> pkts.nsummary()
>>> pkts[48]
Pull out DNS packets
>>> x = []
>>> for p in pkts:
>>> if p.haslayer(UDP) and p.haslayer(DNS):
>>> x.append(p)
>>>
>>> x.nsummary()
PCAPS – The 3 R’s
• Replaying
>>> pkts = rdpcap('pcap/replay1.pcap')
>>> del pkts[0][Ether].dst
>>> del pkts[0][Ether].src
>>> pkts[0][IP].src = '10.1.99.28'
>>> pkts[0][IP].dst = '8.8.8.8'
>>> del pkts[0][IP].chksum
>>> del pkts[0][UDP].chksum
>>> x = srp1(pkts[0])
>>> x.summary()
'Ether / IP / UDP / DNS Ans "smtp.cs.com." '
>>> srploop(pkts[0])
>>> wrpcap(‘pcap/replay2.pcap’, pkts[0])
Python – Importing Scapy
• The quick way
• Turn off “warning messages”
• Turn off verbose in Scapy interactive
from scapy.all import *
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
>>> conf.verb = 0
(default is 2)
Python – Simple Packet Sniffer
• Sniff all the packets
#!/usr/bin/env python
import sys
from scapy.all import *
iface = sys.argv[1]
pkts = sniff(iface=iface, prn=lambda x: x.summary())
Python – Simple Packet Sniffer
• Sniff some of the packets
• Scapy uses Berkeley Packet Filter for filtering
packets when sniffing (same as TCPDUMP).
#!/usr/bin/env python
import sys
from scapy.all import *
iface = sys.argv[1]
pkts = sniff(iface=iface, filter=sys.argv[2], prn=lambda x: x.summary())
sudo ./simplesniffer.py en1 'tcp port 80'
Python – Parse a pcap file
• Looking for HTTP traffic??
def find_http_requests(pkts):
get_requests = []
http_get = 'GET /'
for p in pkts:
if p.haslayer(TCP) and p.haslayer(Raw):
raw = p.getlayer(Raw).load
if http_get in raw:
dstip = p.getlayer(IP).dst
dport = p.getlayer(TCP).dport
srcip = p.getlayer(IP).src
new_raw = p.getlayer(Raw).load
request = ''
host = ''
for t in re.finditer('(GET) (S*)', new_raw):
request = t.group(2)
for s in re.finditer('(Host:) (S*)', new_raw):
host = s.group(2)
talker = request, srcip, dstip, dport, host
if talker not in get_requests:
get_requests.append(talker)
for url, src, dst, port, host in get_requests:
print GREEN + '[+] Web traffic from: ' + str(src) + ' to ' + str(dst) + ' on port ’/
+ str(port) + ' to ' + host + ' for ' + url + END
Python – WiFi Fun??
• Create your own De Auth packets??
• Sniff some beacons??
packet = RadioTap()/Dot11(type=0,subtype=12,addr1=client,addr2=bssid,addr3=bssid)/Dot11Deauth(reason=7)
def sniffBeacons(p):
if p.haslayer(Dot11Beacon):
enc = ''
ssid = p[Dot11Elt].info
bssid = p[Dot11].addr3
channel = int(ord(p[Dot11Elt:3].info))
capability = p.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}{Dot11ProbeResp:%Dot11ProbeResp.cap%}")
rssi = (ord(p.notdecoded[-4:-3])-256)
if re.search("privacy", capability):
enc = 'Y'
else:
enc = 'N'
entity = ssid, bssid, channel, enc, rssi, interface
sniff(iface=interface, prn=sniffBeacons)