Skip to content

Commit

Permalink
[LLMNR] tolerate malformed queries/responses (#4381)
Browse files Browse the repository at this point in the history
when showing summaries.

Now that the question and answer sections are PacketListFields they can
contain Raw instances without the qname/rrname attributes. This patch
prevents `mysummary` from throwing the AttributeError exception when it
encounters queries/responses like that.

It's a follow-up to dda902e.

Fixes:
```
  File "scapy/scapy/sendrecv.py", line 1439, in tshark
    sniff(prn=_cb, store=False, *args, **kargs)
  File "scapy/scapy/sendrecv.py", line 1311, in sniff
    sniffer._run(*args, **kwargs)
  File "scapy/scapy/sendrecv.py", line 1254, in _run
    session.on_packet_received(p)
  File "scapy/scapy/sessions.py", line 109, in on_packet_received
    result = self.prn(pkt)
  File "scapy/scapy/sendrecv.py", line 1436, in _cb
    print("%5d\t%s" % (i[0], pkt.summary()))
  File "scapy/scapy/packet.py", line 1650, in summary
    return self._do_summary()[1]
  File "scapy/scapy/packet.py", line 1624, in _do_summary
    found, s, needed = self.payload._do_summary()
  File "scapy/scapy/packet.py", line 1624, in _do_summary
    found, s, needed = self.payload._do_summary()
  File "scapy/scapy/packet.py", line 1624, in _do_summary
    found, s, needed = self.payload._do_summary()
  File "scapy/scapy/packet.py", line 1627, in _do_summary
    ret = self.mysummary()
  File "scapy/scapy/layers/llmnr.py", line 60, in mysummary
    self.qd[0].qname.decode(errors="backslashreplace"),
  File "scapy/scapy/packet.py", line 469, in __getattr__
    return self.payload.__getattr__(attr)
  File "scapy/scapy/packet.py", line 467, in __getattr__
    fld, v = self.getfield_and_val(attr)
  File "scapy/scapy/packet.py", line 1793, in getfield_and_val
    raise AttributeError(attr)
AttributeError: qname. Did you mean: '_name'?
```
  • Loading branch information
evverx committed May 12, 2024
1 parent 82c2ace commit 041f3ef
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 8 deletions.
25 changes: 17 additions & 8 deletions scapy/layers/llmnr.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
DNSCompressedPacket,
DNS_am,
DNS,
DNSQR,
DNSRR,
)


Expand Down Expand Up @@ -57,15 +59,22 @@ def hashret(self):
return struct.pack("!H", self.id)

def mysummary(self):
if self.an:
return "LLMNRResponse '%s' is at '%s'" % (
self.an[0].rrname.decode(errors="backslashreplace"),
self.an[0].rdata,
), [UDP]
if self.qd:
return "LLMNRQuery who has '%s'" % (
s = self.__class__.__name__
if self.qr:
if self.an and isinstance(self.an[0], DNSRR):
s += " '%s' is at '%s'" % (
self.an[0].rrname.decode(errors="backslashreplace"),
self.an[0].rdata,
)
else:
s += " [malformed]"
elif self.qd and isinstance(self.qd[0], DNSQR):
s += " who has '%s'" % (
self.qd[0].qname.decode(errors="backslashreplace"),
), [UDP]
)
else:
s += " [malformed]"
return s, [UDP]


class LLMNRResponse(LLMNRQuery):
Expand Down
14 changes: 14 additions & 0 deletions test/scapy/layers/llmnr.uts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,22 @@ assert b.answers(a)
assert not a.answers(b)

= Summary
q = LLMNRQuery(b'\xd5\xd5\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x00\x00\x01\x00\x01')
assert q.mysummary()[0] == r"LLMNRQuery who has 'example.'"

q = LLMNRQuery(b'Yy\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x01\xff\x00\x00\x01\x00\x01')
assert q.mysummary()[0] == r"LLMNRQuery who has '\xff.'"

with no_debug_dissector():
q = LLMNRQuery(b'@@\x00\x1b\xed7\x96J\x00\x00\x00\x01\x00\x00')
assert q.mysummary()[0] == r"LLMNRQuery [malformed]"

r = LLMNRResponse(b'e\xcc\x80\x00\x00\x01\x00\x01\x00\x00\x00\x00\x07example\x00\x00\x01\x00\x01\x07example\x00\x00\x01\x00\x01\x00\x00\x00\x1e\x00\x04\xc0\x00\x02\x01')
assert r.mysummary()[0] == r"LLMNRResponse 'example.' is at '192.0.2.1'"

r = LLMNRResponse(b'\n\xe6\x80\x00\x00\x01\x00\x01\x00\x00\x00\x00\x01\xff\x00\x00\x1c\x00\x01\xc0\x0c\x00\x1c\x00\x01\x00\x00\x00\x1e\x00\x10\xfe\x80\x00\x00\x00\x00\x00\x00xu\x17\xff\xfe\xbc\xac\xcb')
assert r.mysummary()[0] == r"LLMNRResponse '\xff.' is at 'fe80::7875:17ff:febc:accb'"

with no_debug_dissector():
r = LLMNRResponse(b'\xd3<\x80\x00\x00\x01\x00\x01\x00\x00\x00\x00\x04H\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x1e\x00\x04\xc0\xa88\x04')
assert r.mysummary()[0] == r"LLMNRResponse [malformed]"

0 comments on commit 041f3ef

Please sign in to comment.