We’re slowly heading towards the end of our HackPy series. This time you’re going to learn a bit different way of sniffing – using scapy for offline pcap file analysis.
It’s been a kind of a break for me since I was releasing materials prepared long before even I even started this blog. To be honest the recent period has been hard for my creativity for various reasons. In spite of the ongoing pandemy, which is hard to go through having kids under the roof, I’ve started working on something that might be interesting for you. But it’s a story to be released in 2 weeks 😉
This example may seem strange at first, but the fact is that it’s been the actual production usage of scapy in my case. I needed to sniff network and discover situations where certain sequece of control bytes was sent, extract some information out of it and send it to external server.
In this example I’ll create such a sequence, add some valid data, save it as pcap file and then extract it with scapy. Let’s begin with adding sequence of
0x01 0x02 0x03 0x04 0x05 in packets’ payload in front of a byte of actual data to send.
import socket, sys HOST = 'localhost' PORT = 4321 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sender: sender.connect((HOST, PORT)) for char in sys.argv: sender.sendall(b'\x01\x02\x03\x04\x05' + char.encode('utf-8'))
Now we can start netcat server:
$ nc -l 127.0.0.1 4321
And listen to the network with wireshark filtering connections in loopback (localhost) and on port 4321:
What we also need is sending actual data. Let’s run the script prepared earlier:
$ python send.py "I made it! 🤘"
Scapy – pcap file analysis – code
We need to modify the code a little bit. First of all we need to sniff offline data saved in pcap files instead of live network communication. In order to achieve it we need to pass
offline argument with the name of the file we want to analyze. In order to extract desired packets, we need to pass proper function reference as
lfilter argument and
prn to process filtered packets.
class Sniffer: def __init__(self): super().__init__() self._message = b'' # ... def run(self): sniff( offline='dump.pcapng', lfilter=self.my_filter, prn=self.display_filtered_packet )
Next, we need to filter the packets that contain the sequence defined earlier:
def my_filter(self, packet: Packet) -> bool: return b'\x01\x02\x03\x04\x05' in raw(packet.payload)
The last step is to clear data and display it on exit:
class Sniffer: # ... def __exit__(self, exc_type, exc_val, exc_tb): print(self._message.decode('utf-8')) def display_filtered_packet(self, packet: Packet): raw_packet = raw(packet.payload) position = raw_packet.find(b'\x01\x02\x03\x04\x05') raw_packet = raw_packet[position:].replace(b'\x01\x02\x03\x04\x05', b'').replace(b'\r', b'') self._message += raw_packet
display_filtered_packet builds a message, but does not show it immediately since it would result in showing it byte by byte and this will be a problem with utf-8 characters that are saved in several bytes.
Having built our custom pcap file analyzer, let’s run it against the prepared file.
$ python analyze.py I made it! 🤘
As you can see, I really made it, message was decoded correctly, including the utf-8 I entered.
Learn more about scapy
I strongly encourage you to visit scapy project page. You’ll learn more about making HTTP requests or fuzzing. If you have any interesting tool built with scapy, let me know in the comments so that we can share more knowledge. You’ll find full code example on my Gitlab.
Check out the latest posts on the blog: