Wednesday, April 26, 2017

Scapy part 1: the Python packet Swiss army knife

Scapy is a Python module which allows you to manipulate network packets in pretty much any conceivable way. Want to sniff SMTP and save credentials to a CSV? Sure, no problem. Want to Fuzz some unknown UDP protocols? Scapy has you covered. Finally, my favorite...can't put a traditional sniffer on an exploited box? Scapy to the rescue! In this post I will discuss this incredibly powerful library and demonstrate how you can use it to implement a highly functional packet capturing tool which can be used to bypass certain defensive measures.
First, you should already be familiar with Wireshark (and/or TShark), Berkly Packet Filter Syntax (BPF), and the general concepts of sniffing traffic. If you are not, I have included some helpful resources at the bottom. Also, If you want a refresher check out the many courses on https://www.Cybrary.it

Capturing Packets

Scapy has the mentality "Capture once, process any number of times" built into how it views and treats packets. In it's simplest form, you can begin to capture packets in 1 line (not including the imports)

import sys
from scapy.all import *
print sniff(iface=sys.argv[1])

Just run that in a python file and pass it the interface you want to capture as the first argument. Wait for a bit (or open another terminal and ping a site). The hit Ctrl-C to exit. You should see a summary like the one below.

Result of sniffing during an outbound ping
It's worth mentioning that you can do it without the interface argument to sniff on all interfaces by default. Alright. Not bad so far. Not really useful either, though. Next, let's discuss what to do with a packet when it is captured. A really nice thing to do would to be to count how many packets have been seen, save them to a pcap file, and dump each one's contents to the screen. All of these things can easily be accomplished as well. Scapy allows you to define a parameter which is a pointer to a callback function. The function should take one argument (which contains the captured packet). Create a function called packet_recv(packet) to handle the grunt work

A custom packet processing function

A snippet of an ICMP packet.
The .show() output is fun to watch for a minute or two but doesn't really allow you the time you need to do analysis. Good thing it is logging all the packets to a pcap file called "sniffer.pcap" now. The additional prn=packet_recv parameter to the sniff function tells it where to send the packets.

Filtering Traffic

On a busy network you might not want all the packets, all the time. Sometimes you want to watch for a very specific set of packets. This is where the Berkly Packet Filter Syntax comes into play. I highly HIGHLY suggest reading the BPF syntax breakdown in the Resources section for more in-depth information on that. For now, I am going to focus on a couple of useful and easy to grasp filters and leave it to you to expand on. To make the sniffer understand BPF we only need to make one small change. Add filter=sys.argv[2] to the sniff function's parameters

sniff(iface=sys.argv[1], filter=sys.argv[2], prn=packet_recv)

Now the script is ready for some real useful traffic capture. One of my favorite things to sniff is, of course, HTTP traffic. One way to achieve this is to assume all HTTP traffic would be on 80 and all traffic to any port 80 is HTTP. This rule of thumb is fairly safe, but not guaranteed to catch all the HTTP traffic (proxy requests to port 8080 for instance). it is also possible not all the traffic captured actually IS HTTP since it is reasonable to think someone could run any application on port 80, not just a web server.

results of a scan with the filter "port 80"
Here are some fun and useful filters for offensive work
  • udp port 53 - Monitor DNS queries
  • net 192.168.1.1/22 and port 80 - Grab http traffic from a certain network segment.
  • (port 80 or port 443) and not host 192.168.1.182 - Web traffic excluding a particular host
  • tcp port 80 or tcp port 21 or tcp port 23 or tcp port 25 - Popular Plain-Text protocols

 ARP Sniff and Spoof

Sniffing your own traffic can be fun. Especially when you want to understand what a local application is doing on a network exactly. That is only one side of the coin, though. on the other side you have the rest of the network's communications. in modern networks it is becoming a rarity to find a hub. Indeed promiscuous mode by itself has become less helpful for snooping on the network traffic of other users. Luckily, there are a couple of ways around this. One is get control of the router device. That is out of the scope of this post though. Another option is to trick your target and gateway into sending you the traffic in a true Man in the Middle (MitM) attack. Below is a rough outline of the steps to an ARP Poisoning attack
  1. Record Gateway MAC address (from IP)
  2. Record Target MAC address (from IP)
  3. Turn on packet forwarding
  4. Start sniffing on the interface
  5. Craft unsolicited ARP response telling the gateway we are the new target
  6. Craft unsolicited ARP response telling the target we are the new gateway
  7. resend as needed to keep the target(s) poisoned.
  8. When finished, reverse the changes so the target never loses connectivity
Here  is a function which will re-poison the target and gateway every 2 seconds until a sentinel variable is set to False. This code is meant to be the target of a child thread so you must add import threading to the import section. You can see the original source for this code in the Book "BlackHat Python" from No Starch Press.
A function to start intercepting traffic


The left cmd is before the ARP poisoning, the right is after. The attacker's view is in the middle.
The last step is resetting the network when you exit. I did not change this code from the implementation in BlackHat Python, so rather than post it I will leave it to you to read the book for how to implement that. What I did change from the book however, was the way in which SIGINT is handled. First add import signal to the import list. Then you can write an interrupt handler

Finally, at program startup, you register your interrupt handler with the system using the signal module.

Beautification  

If you were paying close attention to the images you might have noticed I was using more tradition argument flags  like -t (as opposed to the positional arguments as presented here. I often develop the core script first then go back over it and add an argument parser. In this case I identified logic to apply filters, choose ARP poisoning targets, save pcaps, etc.

Conclusion

What I have covered here is only the smallest glimpse of a fraction of the surface Scapy can be used to cover. Since Scapy can be used to both send and receive packets it could make a useful proxy. It can be used to test other pcap analysis signatures. The list goes on and on. I can say without a doubt that the Scapy module is an invaluable asset in the Pentester's arsenal. Spending the time to learn it's uses will pay you back in the long run.
Here is the full code (Including some features and logic I left out for brevity):

Resources

BPF Syntax - The best breakdown I have found to date.
http://www.infosecwriters.com/text_resources/pdf/JStebelton_BPF.pdf

Scapy Cheat Sheet
https://blogs.sans.org/pen-testing/files/2016/04/ScapyCheatSheet_v0.2.pdf

A handy Cheat sheet. it is for wireshark, but there is a lot of overlap. Plus, who doesn't love a good Wireshark Cheat Sheet?
http://packetlife.net/media/library/13/Wireshark_Display_Filters.pdf

BlackHat Python: no Starch Press
https://www.nostarch.com/blackhatpython

Wifitap uses Scapy to achieve an awesome way of direct communication
http://sid.rstack.org/static/articles/w/i/f/Wifitap_EN_9613.html

No comments:

Post a Comment