diff options
author | Hannes Mezger <hannes.mezger@ascolab.com> | 2018-07-12 18:35:08 +0200 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2018-09-14 04:11:20 +0000 |
commit | 28a7a79cac425d1b1ecf06e73add41edd2241e49 (patch) | |
tree | 499ea77d713811d336279c7741dca2d076bb217e /plugins/epan | |
parent | cd95e197ca78feb1e83ec737b87ada0a1dd57d10 (diff) |
opcua: prevent opcua dissector crash by limiting nesting depth
The OPC UA types DiagnosticInfo, Variant and ExtensionObject can be
nested, which can lead to stack overflows when parsing specially
crafted packets. This is fixed by storing the current nesting depth
as expert info.
The corresponding CVE is https://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-12086
The corresponding security bulletin of the OPC Foundation is https://opcfoundation-onlineapplications.org/faq/SecurityBulletins/OPC_Foundation_Security_Bulletin_CVE-2018-12086.pdf
Change-Id: I5f6da3a3e269f6db1b690b77470ddf60045bcedd
Reviewed-on: https://code.wireshark.org/review/29645
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'plugins/epan')
-rw-r--r-- | plugins/epan/opcua/opcua.c | 2 | ||||
-rw-r--r-- | plugins/epan/opcua/opcua_simpletypes.c | 36 |
2 files changed, 37 insertions, 1 deletions
diff --git a/plugins/epan/opcua/opcua.c b/plugins/epan/opcua/opcua.c index fc26d9f30d..4ca68a9e83 100644 --- a/plugins/epan/opcua/opcua.c +++ b/plugins/epan/opcua/opcua.c @@ -38,7 +38,7 @@ void proto_reg_handoff_opcua(void); /* declare parse function pointer */ typedef int (*FctParse)(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset); -static int proto_opcua = -1; +int proto_opcua = -1; static dissector_handle_t opcua_handle; /** Official IANA registered port for OPC UA Binary Protocol. */ #define OPCUA_PORT_RANGE "4840" diff --git a/plugins/epan/opcua/opcua_simpletypes.c b/plugins/epan/opcua/opcua_simpletypes.c index a787f21c35..ab006b7552 100644 --- a/plugins/epan/opcua/opcua_simpletypes.c +++ b/plugins/epan/opcua/opcua_simpletypes.c @@ -20,6 +20,7 @@ #include <epan/packet.h> #include <epan/expert.h> #include <epan/dissectors/packet-windows-common.h> +#include <epan/proto_data.h> #include "opcua_simpletypes.h" #include "opcua_hfindeces.h" #include "opcua_statuscode.h" @@ -80,6 +81,7 @@ /* Chosen arbitrarily */ #define MAX_ARRAY_LEN 10000 +#define MAX_NESTING_DEPTH 100 static int hf_opcua_diag_mask = -1; static int hf_opcua_diag_mask_symbolicflag = -1; @@ -168,6 +170,9 @@ int hf_opcua_resultMask_displayname = -1; int hf_opcua_resultMask_typedefinition = -1; static expert_field ei_array_length = EI_INIT; +static expert_field ei_nesting_depth = EI_INIT; + +extern int proto_opcua; /** NodeId encoding mask table */ static const value_string g_nodeidmasks[] = { @@ -526,6 +531,7 @@ void registerSimpleTypes(int proto) static ei_register_info ei[] = { { &ei_array_length, { "opcua.array.length", PI_UNDECODED, PI_ERROR, "Max array length exceeded", EXPFILL }}, + { &ei_nesting_depth, { "opcua.nestingdepth", PI_UNDECODED, PI_ERROR, "Max nesting depth exceeded", EXPFILL }}, }; proto_register_field_array(proto, hf, array_length(hf)); @@ -802,9 +808,19 @@ void parseDiagnosticInfo(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gi guint8 EncodingMask; proto_tree *subtree; proto_item *ti; + guint opcua_nested_count; subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, ett_opcua_diagnosticinfo, &ti, "%s: DiagnosticInfo", szFieldName); + /* prevent a too high nesting depth */ + opcua_nested_count = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_opcua, 0)); + if (++opcua_nested_count > MAX_NESTING_DEPTH) + { + expert_add_info(pinfo, ti, &ei_nesting_depth); + return; + } + p_add_proto_data(pinfo->pool, pinfo, proto_opcua, 0, GUINT_TO_POINTER(opcua_nested_count)); + /* parse encoding mask */ EncodingMask = tvb_get_guint8(tvb, iOffset); proto_tree_add_bitmask(subtree, tvb, iOffset, hf_opcua_diag_mask, ett_opcua_diagnosticinfo_encodingmask, diag_mask, ENC_LITTLE_ENDIAN); @@ -912,6 +928,16 @@ void parseVariant(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOf gint iOffset = *pOffset; guint8 EncodingMask; gint32 ArrayDimensions = 0; + guint opcua_nested_count; + + /* prevent a too high nesting depth */ + opcua_nested_count = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_opcua, 0)); + if (++opcua_nested_count > MAX_NESTING_DEPTH) + { + expert_add_info(pinfo, ti, &ei_nesting_depth); + return; + } + p_add_proto_data(pinfo->pool, pinfo, proto_opcua, 0, GUINT_TO_POINTER(opcua_nested_count)); EncodingMask = tvb_get_guint8(tvb, iOffset); proto_tree_add_item(subtree, hf_opcua_variant_encodingmask, tvb, iOffset, 1, ENC_LITTLE_ENDIAN); @@ -1167,10 +1193,20 @@ void parseExtensionObject(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, g guint32 TypeId; proto_tree *extobj_tree; proto_item *ti; + guint opcua_nested_count; /* add extension object subtree */ extobj_tree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, ett_opcua_extensionobject, &ti, "%s: ExtensionObject", szFieldName); + /* prevent a too high nesting depth */ + opcua_nested_count = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_opcua, 0)); + if (++opcua_nested_count > MAX_NESTING_DEPTH) + { + expert_add_info(pinfo, ti, &ei_nesting_depth); + return; + } + p_add_proto_data(pinfo->pool, pinfo, proto_opcua, 0, GUINT_TO_POINTER(opcua_nested_count)); + /* add nodeid subtree */ TypeId = getExtensionObjectType(tvb, &iOffset); parseExpandedNodeId(extobj_tree, tvb, pinfo, &iOffset, "TypeId"); |