Tim Broberg | 14 Oct 2009 23:53
Favicon

RE: Modifying a packet in a post_build routine

I've had similar isssues, Jim, and I think I understand the issue, but have always side-stepped it instead of solving it.

 

The issue is that when you use the '/' operator, Scapy makes a copy of your object, and the attribute you added isn't getting copied.

    encaps = PKT_Encapsulate()
    encaps.modify_pkt = 33
    pkt_base = (Ether(dst="00:80:52:00:00:00")/
                 MyPacket(type=TYPE_UNSOLICITED_MSG,
                      ack="req",
                      err=0,
                      src=0x0112,
                      dst=1)/ #This division operator calls Packet.__div__(Ether()/MyPacket(), encaps)
                 encaps)

class Packet(BasePacket):
...

    def __div__(self, other):
        if isinstance(other, Packet):
            cloneA = self.copy()
            cloneB = other.copy() # Your attribute lost here
            cloneA.add_payload(cloneB)
            return cloneA
        elif type(other) is str:
            return self/conf.raw_layer(load=other)
        else:
            return other.__rdiv__(self)

I *think* the possible solutions are:

  1. Put the attributes you want to preserve in a field value or default value
  2. Make the correct value get derived in the constructor from the field values so that it gets rederived correctly.
  3. Add a copy() method to your packet class that preserves the value.

There are similar issues in clone_with() which will get used when expanding a list comprehension of your packet (e.g. q = IP(src=[x,y,z]), [p for p in q]) or expanding fuzzed values. I don't see any calls to copy() in there, so I'm not sure solution #3 will solve this half of the problem.

 

Personally, I've chickened out when I hit this stage and looked for an easier solution, so I'd love to hear how you resolve the issue.

 

HTH,

    - Tim.
________________________________________
From: Jim Comen [Jim.Comen <at> exar.com]
Sent: Wednesday, October 14, 2009 1:27 PM
To: scapy.ml <at> secdev.org
Subject: RE: [scapy.ml] Modifying a packet in a post_build routine

One more note:
When I assign modify_pkt " encaps.modify_pkt = 33", in the debugger, I do 'dir(encaps)'

libnet', 'lower_bonds', 'modify_pkt', 'mysummary', 'name', 'overload_fields'


However, in the post_build routine, in the debugger, I do 'dir(self)'

ibnet', 'lower_bonds', 'mysummary', 'name', 'overload_fields'


It no longer knows about modify_pkt


Thanks
Jim
-----Original Message-----
From: Jim Comen [mailto:Jim.Comen <at> exar.com]
Sent: Wednesday, October 14, 2009 4:18 PM
To: scapy.ml <at> secdev.org
Subject: RE: [scapy.ml] Modifying a packet in a post_build routine

Dirk,
Hi,
Thank you for the help!! - I think I'm partially there now.  I'm getting an error in my post_build routine.  I'd like to be able to set my value on a per instance basis.  I apologize I described my situation a bit incorrectly earlier - the post_build routine I want to work with is from a layer within 'MyPacket'

I'm getting an error when I try to access 'self.modify_pkt' in the post_build routine

Taking your help, here is what I've got - I'm not sure what I'm doing wrong.

    encaps = PKT_Encapsulate()
    encaps.modify_pkt = 33
    pkt_base = (Ether(dst="00:80:52:00:00:00")/
                 MyPacket(type=TYPE_UNSOLICITED_MSG,
                      ack="req",
                      err=0,
                      src=0x0112,
                      dst=1)/
                 encaps)


class PKT_Encapsulate(Packet):
    fields_desc = [
        ByteEnumField("EncapsCode", ENCAPS_CODE_RPC, encaps_codes),
        X3BytesField("Length", None)
    ]
    def post_build(self, p, pay):
        print "modify is ", self.modify_pkt
        p += pay
        if self.Length is None:
            l = len(pay)
            p = p[:1]+struct.pack("!I",l)[1:]+p[4:]
        return p

Thanks
Jim

-----Original Message-----
From: Dirk Loss [mailto:lists <at> dirk-loss.de]
Sent: Wednesday, October 14, 2009 3:08 PM
To: scapy.ml <at> secdev.org
Subject: Re: [scapy.ml] Modifying a packet in a post_build routine

Jim Comen wrote:
> Hi, I am trying to modify a packet in a post_build routine. I want to
> check the value of a variable and then, based on its value, make some
> modifications to the packet

Shall the variable always have the same value for all instances of the
packet class or to the same value or for each instance separately?

The following code shows both variants. Uncomment either of the two
"modify_packet =" lines.

--
from scapy.all import *

# Just to make the posted example work
READ_STATUS = 0
TYPE_UNSOLICITED_MSG = 0
NoError = 0
Mytypes = {}
direction = {"req":0}
errors = {}

class MyPacket(Packet):
     fields_desc = [ ByteEnumField("type", READ_STATUS, Mytypes),
                     BitEnumField("ack", 0, 1, direction),
                     BitEnumField("err", 0, 11, errors),
                     BitField("seq", 0, 12),
                     XShortField("src", 2),
                     XShortField("dst", 0) ]

     def post_build(self, p, pay):
         p += pay
         if self.modify_packet:
             # Example: shorten the packet to 1 byte
             p = p[:1]
         return p

     # Variant 1: same for all instances
     #modify_packet = "class attribute" # uncomment either this

m = MyPacket(type=TYPE_UNSOLICITED_MSG,
                       ack="req",
                       err=NoError,
                       src=0x0112,
                       dst=1)

# Variant 2: separately set for each instance
#m.modify_packet = "instance attribute" # or uncomment this

# Show what variant we use. Will throw AttributeError if
# neither line is uncommented.
print m.modify_packet

# This will build the packet and show its length
# Should be 1 if the packet is modified
print len(str(m))
--

You cannot use the constructor to set instance variables of Scapy
Packets because (apart from the internal args) everything you pass will
be taken as fields:

class Packet(BasePacket):
    def __init__(self, _pkt="", post_transform=None, _internal=0,
                 _underlayer=None, **fields):

Hope that helps.

Regards
Dirk

---------------------------------------------------------------------
To unsubscribe, send a mail to scapy.ml-unsubscribe <at> secdev.org

The information and any attached documents contained in this message
may be confidential and/or legally privileged.  The message is
intended solely for the addressee(s).  If you are not the intended
recipient, you are hereby notified that any use, dissemination, or
reproduction is strictly prohibited and may be unlawful.  If you are
not the intended recipient, please contact the sender immediately by
return e-mail and destroy all copies of the original message.


---------------------------------------------------------------------
To unsubscribe, send a mail to scapy.ml-unsubscribe <at> secdev.org

The information and any attached documents contained in this message
may be confidential and/or legally privileged.  The message is
intended solely for the addressee(s).  If you are not the intended
recipient, you are hereby notified that any use, dissemination, or
reproduction is strictly prohibited and may be unlawful.  If you are
not the intended recipient, please contact the sender immediately by
return e-mail and destroy all copies of the original message.


---------------------------------------------------------------------
To unsubscribe, send a mail to scapy.ml-unsubscribe <at> secdev.org


The information and any attached documents contained in this message
may be confidential and/or legally privileged. The message is
intended solely for the addressee(s). If you are not the intended
recipient, you are hereby notified that any use, dissemination, or
reproduction is strictly prohibited and may be unlawful. If you are
not the intended recipient, please contact the sender immediately by
return e-mail and destroy all copies of the original message.

Gmane