Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICMP Extension Header wrong padding placement #4281

Closed
ventaquil opened this issue Feb 14, 2024 · 3 comments · Fixed by #4332
Closed

ICMP Extension Header wrong padding placement #4281

ventaquil opened this issue Feb 14, 2024 · 3 comments · Fixed by #4332
Assignees
Labels
Milestone

Comments

@ventaquil
Copy link

ventaquil commented Feb 14, 2024

Brief description

While attempting to convert a ICMP Extension Header packet into a bytes object using the raw(icmp) function, the padding is placed in the incorrect location. As a result, the value returned by raw(icmp) differs from the original pkt packet, leading to functionality errors.

Scapy version

2.5.0.dev272

Python version

3.10.12

Operating system

Linux 5.15.133.1

Additional environment information

Ubuntu 22.04 WSL2

How to reproduce

  1. Take prepared packet with ICMP Extension Header.

    >>> pkt = b'\x00\x15]\x94AY\x00\x15]\x07\xcb\x04\x08\x00E\x00\x00\xb0?2\x00\x00\xe6\x01\x1b\xabh,\x1f\x1d\xac\x1cF\n\x0b\x00Ll\x00\x11\x00\x00E \x00<\x96\xdf\x00\x00\x02\x11\xa7\xc6\xac\x1cF\n(Q_t\xb8-\x82\xb3\x00(xt@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x02\xff\x00\x10\x01\x01\tp2\x01\x05\xde\xd2\x01\x05\x9c\xc3\x02'
  2. Add binding to ICMP Extension Header layer.

    >>> from scapy.contrib.icmp_extensions import ICMPExtensionHeader
    >>> bind_layers(ICMP, ICMPExtensionHeader, type=11, code=0)
  3. Forge Ether packet.

    >>> ether = Ether(pkt)
    >>> ether
    <Ether  dst=00:15:5d:94:41:59 src=00:15:5d:07:cb:04 type=IPv4 |<IP  version=4 ihl=5 tos=0x0 len=176 id=16178 flags= frag=0 ttl=230 proto=icmp chksum=0x1bab src=104.44.31.29 dst=172.28.70.10 |<ICMP  type=time-exceeded code=ttl-zero-during-transit chksum=0x4c6c reserved=0 length=17 unused=0 |<IPerror  version=4 ihl=5 tos=0x20 len=60 id=38623 flags= frag=0 ttl=2 proto=udp chksum=0xa7c6 src=172.28.70.10 dst=40.81.95.116 |<UDPerror  sport=47149 dport=33459 len=40 chksum=0x7874 |<Raw  load=b'@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_' |<Padding  load=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |<ICMPExtensionHeader  version=2 reserved=0 chksum=767 |<ICMPExtensionMPLS  len=16 classnum=1 classtype=1 stack=[<MPLS  label=38659 cos=1 s=0 ttl=1 |<MPLS  label=24045 cos=1 s=0 ttl=1 |<MPLS  label=22988 cos=1 s=1 ttl=2 |>>>] |>>>>>>>>>
  4. Turn into bytes and compare.

    >>> raw(ether)
    b'\x00\x15]\x94AY\x00\x15]\x07\xcb\x04\x08\x00E\x00\x00\xb0?2\x00\x00\xe6\x01\x1b\xabh,\x1f\x1d\xac\x1cF\n\x0b\x00Ll\x00\x11\x00\x00E \x00<\x96\xdf\x00\x00\x02\x11\xa7\xc6\xac\x1cF\n(Q_t\xb8-\x82\xb3\x00(xt@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ \x00\x02\xff\x00\x10\x01\x01\tp2\x01\x05\xde\xd2\x01\x05\x9c\xc3\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
    >>> pkt
    b'\x00\x15]\x94AY\x00\x15]\x07\xcb\x04\x08\x00E\x00\x00\xb0?2\x00\x00\xe6\x01\x1b\xabh,\x1f\x1d\xac\x1cF\n\x0b\x00Ll\x00\x11\x00\x00E \x00<\x96\xdf\x00\x00\x02\x11\xa7\xc6\xac\x1cF\n(Q_t\xb8-\x82\xb3\x00(xt@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x02\xff\x00\x10\x01\x01\tp2\x01\x05\xde\xd2\x01\x05\x9c\xc3\x02'

Actual result

b'\x00\x15]\x94AY\x00\x15]\x07\xcb\x04\x08\x00E\x00\x00\xb0?2\x00\x00\xe6\x01\x1b\xabh,\x1f\x1d\xac\x1cF\n\x0b\x00Ll\x00\x11\x00\x00E \x00<\x96\xdf\x00\x00\x02\x11\xa7\xc6\xac\x1cF\n(Q_t\xb8-\x82\xb3\x00(xt@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ \x00\x02\xff\x00\x10\x01\x01\tp2\x01\x05\xde\xd2\x01\x05\x9c\xc3\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

Expected result

b'\x00\x15]\x94AY\x00\x15]\x07\xcb\x04\x08\x00E\x00\x00\xb0?2\x00\x00\xe6\x01\x1b\xabh,\x1f\x1d\xac\x1cF\n\x0b\x00Ll\x00\x11\x00\x00E \x00<\x96\xdf\x00\x00\x02\x11\xa7\xc6\xac\x1cF\n(Q_t\xb8-\x82\xb3\x00(xt@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x02\xff\x00\x10\x01\x01\tp2\x01\x05\xde\xd2\x01\x05\x9c\xc3\x02'

Related resources

No response

@ventaquil
Copy link
Author

ventaquil commented Feb 15, 2024

Essentially, the problem is that Padding is treated as... well, padding.

scapy/scapy/packet.py

Lines 751 to 761 in 0708e67

def build(self):
# type: () -> bytes
"""
Create the current layer
:return: string of the packet with the payload
"""
p = self.do_build()
p += self.build_padding()
p = self.build_done(p)
return p

The ICMPExtensionHeader.do_build method returns data before Padding.build_padding does.

scapy/scapy/packet.py

Lines 1941 to 1953 in 0708e67

class Padding(Raw):
name = "Padding"
def self_build(self, field_pos_list=None):
# type: (Optional[Any]) -> bytes
return b""
def build_padding(self):
# type: () -> bytes
return (
bytes_encode(self.load) if self.raw_packet_cache is None
else self.raw_packet_cache
) + self.payload.build_padding()

Take a look at this simple example.

>>> (Padding(16) / ICMPExtensionHeader()).do_build()
b' \x00\xdf\xff'
>>> (Padding(16) / ICMPExtensionHeader()).build_padding()
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> (Padding(16) / ICMPExtensionHeader()).build()
b' \x00\xdf\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

As a result we may observe moving Padding behind the ICMP Extension Header struct.

The fix is simple and obvious - treat Padding as space between without moving it to the end of the datagram. However I cannot guess negative impact of such change.

@gpotter2 gpotter2 added this to the 2.6.0 milestone Mar 23, 2024
@gpotter2 gpotter2 self-assigned this Mar 23, 2024
@gpotter2 gpotter2 added the bug label Mar 23, 2024
@gpotter2
Copy link
Member

This should be fixed in #4332

@ventaquil
Copy link
Author

Excellent, thank you @gpotter2! I am waiting for merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants