diff --git a/doc/userguide/upgrade.rst b/doc/userguide/upgrade.rst index 673f10ee01..08f141475a 100644 --- a/doc/userguide/upgrade.rst +++ b/doc/userguide/upgrade.rst @@ -57,10 +57,11 @@ Other Changes - tcp.window - ``dnp3`` has reduced the maximum number of open transactions from - 500 down to 32, and the maximum number of points per message from - unbounded to 16384. Configuration options, ``max-tx`` and - ``max-points`` have been added for users who may need to change - these defaults. + 500 down to 32, the maximum number of points per message from + unbounded to 16384, and the maximum number of objects per message + from unbounded to 2048. Configuration options, ``max-tx``, + ``max-points``, and ``max-objects`` have been added for users who + may need to change these defaults. Upgrading to 8.0.1 ------------------ diff --git a/rules/dnp3-events.rules b/rules/dnp3-events.rules index 61c347b168..a6e2d9dac8 100644 --- a/rules/dnp3-events.rules +++ b/rules/dnp3-events.rules @@ -30,3 +30,9 @@ alert dnp3 any any -> any any (msg:"SURICATA DNP3 Too many points in message"; \ app-layer-event:dnp3.too_many_points; \ threshold:type backoff, track by_flow, count 1, multiplier 10; \ classtype:protocol-command-decode; sid:2270005; rev:1;) + +# Too many objects. +alert dnp3 any any -> any any (msg:"SURICATA DNP3 Too many objects"; \ + app-layer-event:dnp3.too_many_objects; \ + threshold:type backoff, track by_flow, count 1, multiplier 10; \ + classtype:protocol-command-decode; sid:2270006; rev:1;) diff --git a/src/app-layer-dnp3.c b/src/app-layer-dnp3.c index 9693473b3d..d541fc5ff3 100644 --- a/src/app-layer-dnp3.c +++ b/src/app-layer-dnp3.c @@ -94,6 +94,9 @@ static uint64_t dnp3_max_tx = 32; /* The maximum number of points allowed per message (configurable). */ static uint64_t max_points = 16384; +/* The maximum number of objects allowed per message (configurable). */ +static uint64_t dnp3_max_objects = 2048; + /* Decoder event map. */ SCEnumCharMap dnp3_decoder_event_table[] = { { "FLOODED", DNP3_DECODER_EVENT_FLOODED }, @@ -103,6 +106,7 @@ SCEnumCharMap dnp3_decoder_event_table[] = { { "MALFORMED", DNP3_DECODER_EVENT_MALFORMED }, { "UNKNOWN_OBJECT", DNP3_DECODER_EVENT_UNKNOWN_OBJECT }, { "TOO_MANY_POINTS", DNP3_DECODER_EVENT_TOO_MANY_POINTS }, + { "TOO_MANY_OBJECTS", DNP3_DECODER_EVENT_TOO_MANY_OBJECTS }, { NULL, -1 }, }; @@ -703,6 +707,7 @@ static int DNP3DecodeApplicationObjects(DNP3Transaction *tx, const uint8_t *buf, { int retval = 0; uint64_t point_count = 0; + uint64_t object_count = 0; if (buf == NULL || len == 0) { return 1; @@ -717,6 +722,12 @@ static int DNP3DecodeApplicationObjects(DNP3Transaction *tx, const uint8_t *buf, DNP3ObjHeader *header = (DNP3ObjHeader *)buf; offset += sizeof(DNP3ObjHeader); + /* Check if we've exceeded the maximum number of objects. */ + if (++object_count > dnp3_max_objects) { + DNP3SetEventTx(tx, DNP3_DECODER_EVENT_TOO_MANY_OBJECTS); + goto done; + } + DNP3Object *object = DNP3ObjectAlloc(); if (unlikely(object == NULL)) { goto done; @@ -1615,6 +1626,13 @@ void RegisterDNP3Parsers(void) max_points = (uint64_t)value; } } + + /* Parse max-objects configuration. */ + if (SCConfGetInt("app-layer.protocols.dnp3.max-objects", &value)) { + if (value > 0) { + dnp3_max_objects = (uint64_t)value; + } + } } else { SCLogConfig("Parser disabled for protocol %s. " "Protocol detection still on.", proto_name); diff --git a/src/app-layer-dnp3.h b/src/app-layer-dnp3.h index f50974f77d..ab77198080 100644 --- a/src/app-layer-dnp3.h +++ b/src/app-layer-dnp3.h @@ -110,6 +110,7 @@ enum { DNP3_DECODER_EVENT_MALFORMED, DNP3_DECODER_EVENT_UNKNOWN_OBJECT, DNP3_DECODER_EVENT_TOO_MANY_POINTS, + DNP3_DECODER_EVENT_TOO_MANY_OBJECTS, }; /** diff --git a/suricata.yaml.in b/suricata.yaml.in index 76e1b9c833..53abe0f29d 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1231,6 +1231,7 @@ app-layer: dp: 20000 #max-tx: 32 #max-points: 16384 + #max-objects: 2048 # SCADA EtherNet/IP and CIP protocol support enip: