diff --git a/doc/userguide/upgrade.rst b/doc/userguide/upgrade.rst index fca2523771..459749f659 100644 --- a/doc/userguide/upgrade.rst +++ b/doc/userguide/upgrade.rst @@ -40,10 +40,11 @@ Upgrading to 8.0.3 Other Changes ~~~~~~~~~~~~~ -- ``dnp3`` has reduced the default maximum number of outstanding - transactions from 500 down to 32. A ``max-tx`` parameter has been - added to the ``dnp3`` parser for users that need a larger number of - in-flight transactions. +- ``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. Upgrading to 8.0.2 ------------------ diff --git a/rules/dnp3-events.rules b/rules/dnp3-events.rules index e4890f8843..61c347b168 100644 --- a/rules/dnp3-events.rules +++ b/rules/dnp3-events.rules @@ -24,3 +24,9 @@ alert dnp3 any any -> any any (msg:"SURICATA DNP3 Bad transport CRC"; \ # Unknown object. alert dnp3 any any -> any any (msg:"SURICATA DNP3 Unknown object"; \ app-layer-event:dnp3.unknown_object; classtype:protocol-command-decode; sid:2270004; rev:2;) + +# Too many points in a message. +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;) diff --git a/src/app-layer-dnp3.c b/src/app-layer-dnp3.c index 18e3b18082..77f39ea936 100644 --- a/src/app-layer-dnp3.c +++ b/src/app-layer-dnp3.c @@ -91,15 +91,19 @@ enum { * attacks. */ static uint64_t dnp3_max_tx = 32; +/* The maximum number of points allowed per message (configurable). */ +static uint64_t max_points = 16384; + /* Decoder event map. */ SCEnumCharMap dnp3_decoder_event_table[] = { - {"FLOODED", DNP3_DECODER_EVENT_FLOODED}, - {"LEN_TOO_SMALL", DNP3_DECODER_EVENT_LEN_TOO_SMALL}, - {"BAD_LINK_CRC", DNP3_DECODER_EVENT_BAD_LINK_CRC}, - {"BAD_TRANSPORT_CRC", DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC}, - {"MALFORMED", DNP3_DECODER_EVENT_MALFORMED}, - {"UNKNOWN_OBJECT", DNP3_DECODER_EVENT_UNKNOWN_OBJECT}, - {NULL, -1}, + { "FLOODED", DNP3_DECODER_EVENT_FLOODED }, + { "LEN_TOO_SMALL", DNP3_DECODER_EVENT_LEN_TOO_SMALL }, + { "BAD_LINK_CRC", DNP3_DECODER_EVENT_BAD_LINK_CRC }, + { "BAD_TRANSPORT_CRC", DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC }, + { "MALFORMED", DNP3_DECODER_EVENT_MALFORMED }, + { "UNKNOWN_OBJECT", DNP3_DECODER_EVENT_UNKNOWN_OBJECT }, + { "TOO_MANY_POINTS", DNP3_DECODER_EVENT_TOO_MANY_POINTS }, + { NULL, -1 }, }; /* Calculate the next transport sequence number. */ @@ -698,6 +702,7 @@ static int DNP3DecodeApplicationObjects(DNP3Transaction *tx, const uint8_t *buf, uint32_t len, DNP3ObjectList *objects) { int retval = 0; + uint64_t point_count = 0; if (buf == NULL || len == 0) { return 1; @@ -828,6 +833,13 @@ static int DNP3DecodeApplicationObjects(DNP3Transaction *tx, const uint8_t *buf, goto next; } + /* Check if we've exceeded the maximum number of points per message. */ + point_count += object->count; + if (point_count > max_points) { + DNP3SetEventTx(tx, DNP3_DECODER_EVENT_TOO_MANY_POINTS); + goto done; + } + int event = DNP3DecodeObject(header->group, header->variation, &buf, &len, object->prefix_code, object->start, object->count, object->points); @@ -1596,6 +1608,13 @@ void RegisterDNP3Parsers(void) if (SCConfGetInt("app-layer.protocols.dnp3.max-tx", &value)) { dnp3_max_tx = (uint64_t)value; } + + /* Parse max-points configuration. */ + if (SCConfGetInt("app-layer.protocols.dnp3.max-points", &value)) { + if (value > 0) { + max_points = (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 fb142305ef..f50974f77d 100644 --- a/src/app-layer-dnp3.h +++ b/src/app-layer-dnp3.h @@ -109,6 +109,7 @@ enum { DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC, DNP3_DECODER_EVENT_MALFORMED, DNP3_DECODER_EVENT_UNKNOWN_OBJECT, + DNP3_DECODER_EVENT_TOO_MANY_POINTS, }; /** diff --git a/suricata.yaml.in b/suricata.yaml.in index 33c98980bf..030606c349 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1232,6 +1232,7 @@ app-layer: detection-ports: dp: 20000 #max-tx: 32 + #max-points: 16384 # SCADA EtherNet/IP and CIP protocol support enip: