Skip to content

Commit 42fa1c2

Browse files
authored
DCE/RPC: fix length_is bug (#4785)
1 parent d386396 commit 42fa1c2

2 files changed

Lines changed: 40 additions & 7 deletions

File tree

scapy/layers/dcerpc.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1988,9 +1988,15 @@ class _NDRVarField:
19881988
COUNT_FROM = False
19891989

19901990
def __init__(self, *args, **kwargs):
1991-
# size is either from the length_is, if specified, or the "actual_count"
1992-
self.from_actual = "length_is" not in kwargs
1993-
length_is = kwargs.pop("length_is", lambda pkt: pkt.actual_count)
1991+
# We build the length_is function by taking into account both the
1992+
# actual_count (from the varying field) and a potentially provided
1993+
# length_is field.
1994+
if "length_is" in kwargs:
1995+
_length_is = kwargs.pop("length_is")
1996+
length_is = lambda pkt: (_length_is(pkt.underlayer) or pkt.actual_count)
1997+
else:
1998+
length_is = lambda pkt: pkt.actual_count
1999+
# Pass it to the sub-field (actually subclass)
19942000
if self.LENGTH_FROM:
19952001
kwargs["length_from"] = length_is
19962002
elif self.COUNT_FROM:
@@ -2008,11 +2014,9 @@ def getfield(self, pkt, s):
20082014
ndrendian=pkt.ndrendian,
20092015
offset=offset,
20102016
actual_count=actual_count,
2017+
_underlayer=pkt,
20112018
)
2012-
if self.from_actual:
2013-
remain, val = super(_NDRVarField, self).getfield(final, remain)
2014-
else:
2015-
remain, val = super(_NDRVarField, self).getfield(pkt, remain)
2019+
remain, val = super(_NDRVarField, self).getfield(final, remain)
20162020
final.value = super(_NDRVarField, self).i2h(pkt, val)
20172021
return remain, final
20182022

test/scapy/layers/dcerpc.uts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,35 @@ assert [x.floors[3].rhs.decode().rstrip("\x00") for x in towers if x.floors[3].p
446446
tower = next(x for x in towers if x.floors[3].protocol_identifier == 15 and x.floors[3].rhs == b"\\PIPE\\ROUTER\x00")
447447
assert tower.floors[0].uuid
448448

449+
= DCE/RPC 5 NDR: Test length_is with size_is with after-the-fact size
450+
451+
# From [MS-RRP]
452+
453+
class BaseRegQueryValue_Response(NDRPacket):
454+
fields_desc = [
455+
NDRFullPointerField(NDRIntField("lpType", 0)),
456+
NDRFullPointerField(
457+
NDRConfVarStrLenField(
458+
"lpData",
459+
"",
460+
size_is=lambda pkt: (pkt.lpcbData if pkt.lpcbData else 0),
461+
length_is=lambda pkt: (pkt.lpcbLen if pkt.lpcbLen else 0),
462+
)
463+
),
464+
NDRFullPointerField(NDRIntField("lpcbData", 0)),
465+
NDRFullPointerField(NDRIntField("lpcbLen", 0)),
466+
NDRIntField("status", 0),
467+
]
468+
469+
470+
pkt = BaseRegQueryValue_Response(b'\x00\x00\x02\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00W\x00i\x00n\x00d\x00o\x00w\x00s\x00 \x00U\x00s\x00e\x00r\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00', ndr64=True)
471+
472+
assert pkt.valueof("lpType") == 1
473+
assert pkt.valueof("lpData").decode("utf-16le") == 'Windows User\x00'
474+
assert pkt.valueof("lpcbData") == 26
475+
assert pkt.valueof("lpcbLen") == 26
476+
assert pkt.status == 0
477+
449478
= DCE/RPC 5 NDR: Test DEPORTED_CONFORMANTS with offsetted padding
450479

451480
from scapy.layers.msrpce.mseerr import *

0 commit comments

Comments
 (0)