Python Forum

Full Version: Packet Sniffer - TypeError: a bytes-like object is required, not 'str'
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi folks, I'm in the process of creating a packet sniffer using Python 3.8. The goal is for it to isolate the RAW layer/load portion of a packet and print it to screen. I'm running into an error (possible decoding error?) in the for loop when it tries to iterate the keywords list. It's expecting a bytes-type value, getting a string and crashing. I've googled the error and it seems like it pops up quite a bit with Py3, but couldn't find a relevant solution for my particular code that worked. Any expertise and thoughts are appreciated. Thanks. Wall

#!/usr/bin/env python

import scapy.all as scapy
from scapy.layers import http


def sniff(interface):
    scapy.sniff(iface=interface, store=False, prn=process_sniffed_packet)


def process_sniffed_packet(packet):
    if packet.haslayer(http.HTTPRequest):
        if packet.haslayer(scapy.Raw):
            load = packet[scapy.Raw].load
            keywords = ["username", "name", "user", "email", "usr", "login", "password", "pass", "pwd", "passwd"]
            for keyword in keywords:
                if keyword in load:
                    print(load)
                    break

sniff("eth0")
Traceback Output:

Error:
Traceback (most recent call last): File "pack_sniff3.py", line 21, in <module> sniff("eth0") File "pack_sniff3.py", line 8, in sniff scapy.sniff(iface=interface, store=False, prn=process_sniffed_packet) File "/usr/lib/python3/dist-packages/scapy/sendrecv.py", line 972, in sniff sniffer._run(*args, **kwargs) File "/usr/lib/python3/dist-packages/scapy/sendrecv.py", line 925, in _run session.on_packet_received(p) File "/usr/lib/python3/dist-packages/scapy/sessions.py", line 47, in on_packet_received result = self.prn(pkt) File "pack_sniff3.py", line 17, in process_sniffed_packet if keyword in load: TypeError: a bytes-like object is required, not 'str'
Load is a bytes object and your keyword are strings. Those can't be directly compared.

>>> load = b"bytes object with ascii data"
>>> "with" in load
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: a bytes-like object is required, not 'str'
If the data you captured was UTF-8, you could decode it to a str, or you could have your list of matching keywords as bytes. Either might make sense.

>>> b"with" in load
True
>>> "with" in load.decode()
True
bowlofred for the win! I ended up fixing this by changing the str to bytes in line 15. See below, it's working like a champ now. Thanks.

keywords = ["username".encode(), "name".encode(), "user".encode(), "email".encode(), "usr".encode(), "login".encode(), "password".encode(), "pass".encode(), "pwd".encode(), "passwd".encode()]
That's a lot of extra typing. Big Grin Next time maybe:

keywords = ["username", "name", "user", "email", "usr", "login", "password", "pass", "pwd", "passwd"]
keywords = [x.encode() for x in keywords]
(Jun-12-2020, 02:23 AM)bowlofred Wrote: [ -> ]That's a lot of extra typing. Big Grin Next time maybe:

keywords = ["username", "name", "user", "email", "usr", "login", "password", "pass", "pwd", "passwd"]
keywords = [x.encode() for x in keywords]

Gotcha, that's definitely a bit more elegant. Smile