Skip to content

Commit f44f9e0

Browse files
committed
Release hotfix 1.0.2 for Scapy 2.4.5 compat
2 parents 523306b + 70a0f55 commit f44f9e0

File tree

6 files changed

+59
-11
lines changed

6 files changed

+59
-11
lines changed

bof/layers/raw_scapy/knx.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ class LcEMI(Packet):
352352
BitEnumField("sequence_type", 0, 1, {
353353
0: "unnumbered"
354354
}),
355-
BitField("reserved", 0, 4),
355+
BitField("reserved2", 0, 4),
356356
BitEnumField("acpi", 2, 4, KNX_ACPI_CODES),
357357
ConditionalField(BitField("data", 0, 6),
358358
lambda pkt:pkt.packet_type==0)

bof/packet.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ def _field_generator(self, start_packet:object=None, terminal=False) -> tuple:
323323
for field in packet.fields_desc:
324324
if isinstance(field, MultipleTypeField):
325325
field = field._find_fld()
326+
elif isinstance(field, ConditionalField) and field._evalcond(packet):
327+
field = field.fld
326328
if isinstance(field, PacketField) or isinstance(field, Packet):
327329
yield from self._field_generator(getattr(packet, field.name))
328330
if isinstance(field, Field):
@@ -339,7 +341,10 @@ def _get_field(self, name:str, start_packet:object=None, packets:bool=False) ->
339341
"""
340342
for field, parent in self._field_generator(start_packet):
341343
if field.name == name:
342-
field_and_val = parent.getfield_and_val(name)
344+
try:
345+
field_and_val = parent.getfield_and_val(name)
346+
except ValueError:
347+
field_and_val = None
343348
# We do not return packetfields directly because we should not
344349
# manipulate them outside direct call to Scapy or direct access
345350
# to the fields they contain.
@@ -402,7 +407,7 @@ def _any2i(self, parent, field, new_value) -> bool:
402407
self._setattr(parent, field, new_value)
403408
raw(parent)
404409
return True
405-
except struct_error:
410+
except (ValueError, struct_error):
406411
pass # Any other exception is unexpected and we let it happen
407412
return False
408413

docs/man/user.rst

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,14 @@ free to interact with the Scapy packet directly as well.**
4646
:width: 450
4747
:align: center
4848

49-
For instance, in the code sample below, lines 2 and 3 do the same thing and
50-
modify the same packet object. However for line 2, you set a value to the
51-
``field1`` from **BOF**'s packet, applying any change provided by BOF when
52-
setting a value. In line 3, the field is modified directly in **Scapy**'s
53-
packet, BOF does not interfer.
49+
For instance, in the code sample below, lines 2 and 3 do the same
50+
thing and modify the same packet object. However for line 2, you set a
51+
value to the ``field1`` from **BOF**'s packet, applying any change
52+
provided by BOF when setting a value. In line 3, the field is modified
53+
directly in **Scapy**'s packet, BOF does not interfer. In other words,
54+
a ``BOFPacket`` object (here ``KNXPacket``) acts as a wrapper around a
55+
Scapy object representing the actual packet using the specified
56+
protocol.
5457

5558
.. code-block:: python
5659
:linenos:
@@ -59,6 +62,46 @@ packet, BOF does not interfer.
5962
packet.field1 = 1
6063
packet.scapy_pkt.field1 = 1
6164
65+
The reason we did that is because there is nothing
66+
better than Scapy to handle protocol implementations, and by using
67+
Scapy we can also use all the implementations that were written for
68+
it. But BOF and Scapy do not have the same usage and aim: First, we
69+
made some choices about BOF's script syntax and sometimes Scapy's
70+
syntax don't follow these choices. But most of all, we sometimes can't
71+
rely on Scapy's behavior for what we want to do with BOF because they
72+
are not compatible. Just to mention a few:
73+
74+
:Field-oriented usage:
75+
BOF's preferred usage when altering packets is to change specific
76+
fields directly. Why? Because BOF has been written to write attack
77+
scripts, including fuzzers. In these fuzzers, we want to stick to
78+
the protocol's specification because if we don't, devices we target
79+
may just drop our frames. And to stick to the specification, we
80+
have to keep a valid frame format, and to do that we just modify
81+
specific fields. Scapy does not work this way and, although we can
82+
modify isolated fields, it's hard to get and set values in a
83+
script, mostly because we can't refer to a field without referring
84+
to its parent packet holding its value.
85+
:BOF does not care about types:
86+
But Scapy does. Field objects in Scapy have a type and you can't
87+
change it easily or just use a field objectthat doesn't have a type
88+
without losing some capabilities. For us, packets are just a bunch
89+
of bytes so we might as well set values directly as bytes to fields,
90+
and Scapy won't allow that. It won't allow setting a value with the
91+
wrong type either, and we don't want field types to be a thing in
92+
BOF: a user should not need to know the type of a field, or she may
93+
be able to implicitly change it. That's what BOF's wrapper around
94+
the Scapy object does.
95+
96+
.. code-block:: python
97+
98+
# Setting value to field from BOF, type is changed automatically
99+
bofpacket.host_protocol = "test"
100+
101+
# Setting value to field directly on Scapy packet, type is invalid
102+
# and will trigger an error when the packet is reconstructed.
103+
bofpacket.scapy_pkt.control_endpoint.host_protocol = "test"
104+
62105
TL;DR
63106
=====
64107

examples/knx/cemi_fuzzer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def fuzz(ip:str, generator:object, base_pkt:KNXPacket) -> None:
142142
# Open log file
143143
LOG_FD = open(LOG_FILENAME, "w+")
144144
# Create the base frame to mutate during fuzzing
145-
base_pkt = KNXPacket(type=SID.configuration_request, cemi=CEMI.propread_req)
145+
base_pkt = KNXPacket(type=SID.configuration_request, cemi=CEMI.m_propread_req)
146146
base_pkt.number_of_elements = 1
147147
base_pkt.show2()
148148

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
scapy
1+
scapy==2.4.5

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="boiboite-opener-framework",
8-
version="1.0.0",
8+
version="1.0.2",
99
author="Claire Vacherot",
1010
author_email="claire.vacherot@orange.com",
1111
description="Industrial network protocols testing framework",

0 commit comments

Comments
 (0)