kbandla / dpkt

fast, simple packet creation / parsing, with definitions for the basic TCP/IP protocols
Other
1.09k stars 270 forks source link

IndexError: index out of range unpacking IPv6 options header #477

Closed crosser closed 4 years ago

crosser commented 4 years ago

When parsing an ICMP6 packet, I am getting "IndexError: index out of range" error:

got data from ('vnet0', 0, 4, 1, b'RT\x00\x863\xd9') : b'525400f3836f5254008633d986dd6000000005083afffd000000000000000000000000000002fd0000000000000000000000000000010200d2f30000050000000000000000000001fd0000000000000000000000000000020050d4341a4824506d8db3c2801001f646e800000101080ad79d6b8a3ad1f458616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161'
Traceback (most recent call last):
  File "rawsock.py", line 75, in <module>
    pkt = dpkt.ethernet.Ethernet(data)
  File "/usr/lib/python3/dist-packages/dpkt/ethernet.py", line 79, in __init__
    dpkt.Packet.__init__(self, *args, **kwargs)
  File "/usr/lib/python3/dist-packages/dpkt/dpkt.py", line 89, in __init__
    self.unpack(args[0])
  File "/usr/lib/python3/dist-packages/dpkt/ethernet.py", line 136, in unpack
    self._unpack_data(self.data)
  File "/usr/lib/python3/dist-packages/dpkt/ethernet.py", line 127, in _unpack_data
    self.data = self._typesw[next_type](buf)
  File "/usr/lib/python3/dist-packages/dpkt/dpkt.py", line 89, in __init__
    self.unpack(args[0])
  File "/usr/lib/python3/dist-packages/dpkt/ip6.py", line 88, in unpack
    self.data = self._protosw[next_ext_hdr](buf)
  File "/usr/lib/python3/dist-packages/dpkt/dpkt.py", line 89, in __init__
    self.unpack(args[0])
  File "/usr/lib/python3/dist-packages/dpkt/icmp6.py", line 84, in unpack
    self.data = self._typesw[self.type](self.data)
  File "/usr/lib/python3/dist-packages/dpkt/dpkt.py", line 89, in __init__
    self.unpack(args[0])
  File "/usr/lib/python3/dist-packages/dpkt/icmp6.py", line 64, in unpack
    self.data = self.ip6 = ip6.IP6(self.data)
  File "/usr/lib/python3/dist-packages/dpkt/dpkt.py", line 89, in __init__
    self.unpack(args[0])
  File "/usr/lib/python3/dist-packages/dpkt/ip6.py", line 77, in unpack
    ext = ext_hdrs_cls[next_ext_hdr](buf)
  File "/usr/lib/python3/dist-packages/dpkt/dpkt.py", line 89, in __init__
    self.unpack(args[0])
  File "/usr/lib/python3/dist-packages/dpkt/ip6.py", line 149, in unpack
    opt_type = compat_ord(self.data[index])
IndexError: index out of range

I believe this is because the IPv6 option header unpacker uses bit length of the header when it should use byte length:

    def unpack(self, buf):
        dpkt.Packet.unpack(self, buf)
        self.length = (self.len + 1) * 8
        options = []

        index = 0

        while index < self.length - 2:
            opt_type = compat_ord(self.data[index])

I am not 100% sure of my fix, but changing while index < self.length - 2: to while index < self.len - 2: seems like a right thing, and it does fix the crash. I will submit a pull request momentarily.

obormot commented 4 years ago

I think the only possible improvement would be if dpkt threw NeedData exception here. Looks like the required data is outside of the packet boundary and likely requires reassembly (i.e. more packets). The options header decoding is using the correct length, expressed in octets, according to RFC 2460. Note that Wireshark (I tested v3.0.1 on OSX) refuses to decode this single packet as well, not even getting to decoding options. image

crosser commented 4 years ago

Indeed the partial copy of the packet that induced "TooBig" response, that was included in the ICMP6 packet, was broken. I wonder though if it is a correct behaviour if broken "payload" crashes parsing of the packet?..

obormot commented 4 years ago

I think it's correct behavior (throwing NeedData that is, not crashing of course). If one were building a reassembling parser and received NeedData, one would add the next packet's payload and re-attempt parsing. I'm going to reopen this to fix the crash. Thanks.

obormot commented 4 years ago

@crosser please see pull request #489; let me know if the proposed solution works for you