Reinventing the low-level network tools would never be complete without famous Wireshark and I’m going to fill this gap today. How to perform network analysis with scapy?
Before we begin, I’d like to remind you that you can sign up to the newsletter to get info about latest post and support me on Patreon.
Let’s say we want to be able to eavesdrop some network communication, maybe to a blog which is not secured by HTTPS. Moreover, we want to be able to perform some analysis of the packets on the fly, so actually using wireshark may not be the perfect choice. At the same time we don’t want to collect rubbish from other communication that we have, so the ability to filter out packets is a must have.
We’re going to need the
sniff function from scapy’s library and two custom functions. The usage is very simple:
class Sniffer: # ... def run(self): sniff( filter='tcp', lfilter=self.my_filter, iface=self.interface, prn=self.display_filtered_packet )
We’re telling it to apply
tcp filter (more can be found in the docs), then also apply our locally defined
my_filter method. The last step is to process packets using
display_filtered_packet method. The
filters argument AFAIK takes exactly the same syntax as the wireshark does and it allows for quite advanced filters.
my_filter only checks if packet is sent from the desired host and port. It returns a boolean value so that indicating whether our code should pass or drop from further analysis.
def my_filter(self, packet: Packet) -> bool: return ( packet.getlayer(IP).src == self.host and packet.getlayer(TCP).sport == 80 )
Simple as it seems, this allows to do pattern matching inside packets. For example if I wanted to view only packets that contain information about redirects I could modify the above code and inspect payload with:
def my_filter(self, packet: Packet) -> bool: return ( packet.getlayer(IP).src == self.host and packet.getlayer(TCP).sport == 80 and b'301' in bytes(packet.payload) )
Which would result in displaying:
$ sudo python3 sniffer.py 18.104.22.168 en0 b'E\x02\x01(\x9f\xc2@\x00:\x06\xb1\xfb.\xf2\xfd\x0f\xc0\xa8\x01f\x00P\xc3\x1f\xd0\xfc\x81\xefF\x05\x17\xe1\x80\x18\x00\xeb_\xb2\x00\x00\x01\x01\x08\n\xf4`\x1e\x861\xf8\t\xffHTTP/1.1 301 Moved Permanently\r\nDate: Tue, 17 Mar 2020 06:42:37 GMT\r\nContent-Type: text/html; charset=UTF-8\r\nTransfer-Encoding: chunked\r\nConnection: keep-alive\r\nServer: Apache\r\nX-Redirect-By: WordPress\r\nLocation: https://blacksheephacks.pl/\r\n\r\n'
Talking of which brings us to the last point.
Analyze network with bare eye
The above code was displayed with this simple function we passed as
def display_filtered_packet(self, packet: Packet): return packet.payload
It is, however, barely readable. In order to improve it we can modify it the following way:
def display_filtered_packet(self, packet: Packet): return ''.join( chr(ss) for ss in filter( lambda s: chr(s) in string.printable, bytes(packet.getlayer(TCP).payload) ) )
And finally it’ll display:
$ sudo python3 sniffer.py 22.214.171.124 en0 HTTP/1.1 301 Moved Permanently Date: Tue, 17 Mar 2020 07:03:08 GMT Content-Type: text/html; charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive Server: Apache X-Redirect-By: WordPress Location: https://blacksheephacks.pl/ 0
That’s it folks.
As always I encourage you to subscribe to the newsletter, support me on Patreon and make use of the following links:
- Source code on Gitlab – not only you’ll find full example of this network analysis with scapy, but also find an interesting bonus 😉
- Scapy docs
Check out other posts: