Converting hex string to packet in Scapy

11,108

You can rebuild the packet using the class of the original packet, however there are other errors in your program.

The official API documentation on the sniff function states that it returns a list:

sniff(prn=None, lfilter=None, count=0, store=1, offline=None, L2socket=None, timeout=None)

Sniffs packets from the network and return them in a packet list.

Therefore, rather than extracting the packet with pkt_hex = str(pkt), the correct form to extract the packet is pkt_hex = str(pkt[0]).

Once that is done, you are free to alter the packet, update its checksum (as suggested here) and rebuild it using the class of the original packet, as follows (note my comments):

from scapy.all import *
from struct import pack
from struct import unpack

pkts = sniff(offline="my.pcap", count=1)

pkt = pkts[0] # <--- NOTE: correctly extract the packet

del pkt.chksum # <--- NOTE: prepare for checksum recalculation
del pkt[TCP].chksum # <--- NOTE: prepare for TCP checksum recalculation (depends on the transport layer protocol in use)

pkt_hex = str(pkt)
# getting output like '\x00\x04\x00 ... ... \x06j' <--- NOTE: there is no trailing ']'

last_4 = unpack('!I',pkt_hex[-4:])[0]
# getting last 4 bytes and converting it to integer

rest = pkt_hex[:-4]
# getting whole packet in string except last 4 bytes

new_hex_pkt = rest + pack('>I',(last_4+1))
# created the whole packet again with last 4 bytes incremented by 1
# the new string is like '\x00\x04\x00 ... ... \x06k' <--- NOTE: 'j' was incremented to 'k' (rather than ']' to '^')

new_pkt = pkt.__class__(new_hex_pkt) # <--- NOTE: rebuild the packet and recalculate its checksum

sendp(new_pkt) # <--- NOTE: send the new packet

EDIT:

Note that this doesn't preserve the packet's timestamp, which would change to the current time. In order to retain the original timestamp, assign it to new_pkt.time:

new_pkt.time = pkt.time

However, as explained here, even after changing the packet's timestamp and sending it, the updated timestamp won't be reflected in the received packet on the other end since the timestamp is set in the receiving machine as the packet is received.

Share:
11,108
RatDon
Author by

RatDon

Always a dict. :P #SOreadytohelp

Updated on September 02, 2022

Comments

  • RatDon
    RatDon over 1 year

    My aim is to sniff a packet from a pcap file, modify the last 4 bytes of the packet and send it. For now, I'm doing like this:

    from scapy.all import *
    from struct import pack
    from struct import unpack
    
    pkt = sniff(offline="my.pcap", count=1)
    
    pkt_hex = str(pkt)
    # getting output like '\x00\x04\x00 ... ... \x06j]'
    
    last_4 = unpack('!I',pkt_hex[-4:])[0]
    # getting last 4 bytes and converting it to integer
    
    rest = pkt_hex[:-4]
    # getting whole packet in string except last 4 bytes
    
    new_pkt = rest + pack('>I',(last_4+1))
    # created the whole packet again with last 4 bytes incremented by 1
    # the new string is like '\x00\x04\x00 ... ... \x06j^'
    

    Now My problem is I'm unable to convert it back to a layered packet object of Scapy and hence unable to send it using sendp.

    PS: I've to recalculate the checksum. But once I'll convert it to a packet object, I can recalculate the checksum following this.

  • RatDon
    RatDon over 9 years
    Thanks for the answer. Since I'm sniffing only 1 packet, it works fine without pkt = pkt[0] also. No doubt having it also doesn't affect the program.