Repository: secdev/scapy

Issue:
BER decoding fails during Varbind packet extraction due to noSuchInstance on some
### Brief description

Any OID that has _noSuchInstance_ (as shown in in tcpdump) fails with:

```
Exception has occurred: BER_Decoding_Error
Unknown prefix [81] for [b'\x81\x00']
### Already decoded ###
None
### Remaining ###
```

this in turn causes the whole SNMPResponse packet to be dropped/ignored.

I'm parsing a pcap file with sniff(...), no filters, doing nothing special.



### Scapy version

2.5.0

### Python version

3.11

### Operating system

Linux x86_64

### Additional environment information

_No response_

### How to reproduce

pick some pcap where there are noSuchIsntace responses.

Basically, run tcpdump on some device and ask/get non existing OIDs

### Actual result

The whole SNMP response packet is ignored

### Expected result

At least return the packet with the right / extracted varbinds and ignore the noSuchInstance ones, or create new relevant type NONE ASN1_Tag doesnt handle that.

### Related resources

_No response_


Discussion:
Hi, could you provide a pcap? (or something reproducible?) Thanks
> Hi, could you provide a pcap? (or something reproducible?) Thanks

sure, i will generate one and attach asap

Resolving patch:
diff --git a/scapy/layers/snmp.py b/scapy/layers/snmp.py
--- a/scapy/layers/snmp.py
+++ b/scapy/layers/snmp.py
@@ -11,7 +11,7 @@
 from scapy.asn1packet import ASN1_Packet
 from scapy.asn1fields import ASN1F_INTEGER, ASN1F_IPADDRESS, ASN1F_OID, \
     ASN1F_SEQUENCE, ASN1F_SEQUENCE_OF, ASN1F_STRING, ASN1F_TIME_TICKS, \
-    ASN1F_enum_INTEGER, ASN1F_field, ASN1F_CHOICE
+    ASN1F_enum_INTEGER, ASN1F_field, ASN1F_CHOICE, ASN1F_optional, ASN1F_NULL
 from scapy.asn1.asn1 import ASN1_Class_UNIVERSAL, ASN1_Codecs, ASN1_NULL, \
     ASN1_SEQUENCE
 from scapy.asn1.ber import BERcodec_SEQUENCE
@@ -177,9 +177,17 @@ class ASN1F_SNMP_PDU_TRAPv2(ASN1F_SEQUENCE):
 
 class SNMPvarbind(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
-    ASN1_root = ASN1F_SEQUENCE(ASN1F_OID("oid", "1.3"),
-                               ASN1F_field("value", ASN1_NULL(0))
-                               )
+    ASN1_root = ASN1F_SEQUENCE(
+        ASN1F_OID("oid", "1.3"),
+        ASN1F_optional(
+            ASN1F_field("value", ASN1_NULL(0))
+        ),
+
+        # exceptions in responses
+        ASN1F_optional(ASN1F_NULL("noSuchObject", None, implicit_tag=0x80)),
+        ASN1F_optional(ASN1F_NULL("noSuchInstance", None, implicit_tag=0x81)),
+        ASN1F_optional(ASN1F_NULL("endOfMibView", None, implicit_tag=0x82)),
+    )
 
 
 class SNMPget(ASN1_Packet):


Test patch:
diff --git a/test/scapy/layers/snmp.uts b/test/scapy/layers/snmp.uts
--- a/test/scapy/layers/snmp.uts
+++ b/test/scapy/layers/snmp.uts
@@ -44,10 +44,17 @@ x = SNMPvarbind(oid=ASN1_OID("1.3.6.1.2.1.1.4.0"), value=RandBin())
 x = SNMPvarbind(raw(x))
 assert isinstance(x.value, ASN1_STRING)
 
+= SNMPvarbind noSuchInstance dissection
+~ SNMP ASN1
+x = SNMPvarbind(b'0\x10\x06\x0c+\x06\x01\x02\x01/\x01\x01\x01\x01\n\x01\x81\x00')
+assert not x.noSuchObject
+assert x.noSuchInstance
+assert not x.endOfMibView
+
 = Failing SNMPvarbind dissection
 ~ SNMP ASN1
 try:
-    SNMP('0a\x02\x01\x00\x04\x06public\xa3T\x02\x02D\xd0\x02\x01\x00\x02\x01\x000H0F\x06\x08+\x06\x01\x02\x01\x01\x05\x00\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D')
+    SNMP(b'0a\x02\x01\x00\x04\x06public\xa3T\x02\x02D\xd0\x02\x01\x00\x02\x01\x000H0F\x06\x08+\x06\x01\x02\x01\x01\x05\x00\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D\x00\x03\x01\x02D')
     assert False
 except BER_Decoding_Error:
     pass