Project

General

Profile

Actions

Security #8624

closed
PA PA

detect/dataset/ndjson: NULL dereference on unexpected ndjson files

Security #8624: detect/dataset/ndjson: NULL dereference on unexpected ndjson files

Added by Philippe Antoine 21 days ago. Updated about 2 hours ago.

Status:
Closed
Priority:
Normal
Target version:
Affected Versions:
Label:
CVE:
Git IDs:
Severity:
LOW
Disclosure Date:

Description

Original report

Hello Suricata Security Team
I am writing to report a NULL pointer dereference vulnerability in Suricata 8.0.5 that causes the IDS/IPS process to crash (SIGSEGV) during startup or rule reload when loading JSON/NDJSON dataset enrichment files.

  ─────────────────────────────────────────────────────────────────────────────
  SUMMARY
  ─────────────────────────────────────────────────────────────────────────────
Component : src/datasets-context-json.c
Affected  : Suricata 8.0.5 (latest release at time of writing)
CWE       : CWE-476 (NULL Pointer Dereference)
Severity  : Medium
Impact    : Crash of the Suricata process; denial of detection/prevention
Attack surface: Local JSON/NDJSON enrichment feed files or rule/intel feed
update pipelines (no network traffic required)
 ─────────────────────────────────────────────────────────────────────────────
 ROOT CAUSE
─────────────────────────────────────────────────────────────────────────────

When loading a dataset with format json or ndjson, the four functions below call json_string_value() to retrieve the string for the value_key field of each JSON object. Jansson's json_string_value()  returns NULL when the node is not of JSON string type (e.g. integer, boolean, null, array, or object). The returned pointer is passed directly to strlen(), inet_pton(), or DatasetParseIpv6String()
  without a NULL check, causing a NULL pointer dereference and process crash.
  Affected functions and lines (src/datasets-context-json.c):
  Line 470 – DatajsonAddMd5Element
    const char *hash_string = json_string_value(key);
    if (strlen(hash_string) != SC_MD5_HEX_LEN) { ... }   // NULL dereference

  Line 514 – DatajsonAddSha256Element
    const char *hash_string = json_string_value(key);
    if (strlen(hash_string) != SC_SHA256_HEX_LEN) { ... } // NULL dereference

  Line 559 – DatajsonAddIpv4Element
    const char *ip_string = json_string_value(key);
    if (inet_pton(AF_INET, ip_string, &in) != 1) { ... }  // NULL dereference

  Line 599 – DatajsonAddIPv6Element
    const char *ip_string = json_string_value(key);
    int ret = DatasetParseIpv6String(set, ip_string, &in6); // NULL dereference

  For the IPv4/IPv6 path, the crash occurs inside DatasetParseIpv6String() (src/datasets.c:159) where strchr(line, ':') is called with a NULL pointer:

  int DatasetParseIpv6String(Dataset *set, const char *line, struct in6_addr *in6)
  {
      const char *got_colon = strchr(line, ':');  // crashes when line == NULL

  ─────────────────────────────────────────────────────────────────────────────
  PROOF OF CONCEPT
  ─────────────────────────────────────────────────────────────────────────────

  The crash is triggered by loading a syntactically valid NDJSON file where the field referenced by value_key holds a non-string JSON value. No special privileges or network access are required — only
  the ability to influence the local enrichment file (e.g. via a threat-intel feed update pipeline).
  Four crash cases were confirmed on Suricata 8.0.5 (with debug symbols):
  Case 1: md5 dataset, value_key is a JSON integer
  NDJSON file:
  {"md5_value": 12345, "extra": "context"}
  Suricata rule:
  alert dns any any -> any any (
    msg:"poc md5"; dns.query;
    dataset:isset,test_md5,type md5,
      load bad_md5.ndjson, format ndjson,
      value_key md5_value, context_key extra;
    sid:1001; rev:1;)
  Crash stack (sig 11):
  DatajsonAddMd5Element+0x58
  DatajsonLoadTypeFromJsonline → DatajsonGet → DetectDatasetSetup
  SigParse → SigLoadSignatures → SuricataInit → main

  Case 2: sha256 dataset, value_key is a JSON boolean
  NDJSON file:
  {"sha256_value": true, "extra": "context"}
  Suricata rule:
  alert dns any any -> any any (
    msg:"poc sha256"; dns.query;
    dataset:isset,test_sha256,type sha256,
      load bad_sha256.ndjson, format ndjson,
      value_key sha256_value, context_key extra;
    sid:1002; rev:1;)
  Crash stack (sig 11):
  DatajsonAddSha256Element+0x58
  DatajsonLoadTypeFromJsonline → DatajsonGet → DetectDatasetSetup ...

  Case 3: ip dataset, value_key is JSON null
  NDJSON file:
  {"ip_value": null, "extra": "context"}
  Suricata rule:
  alert tcp any any -> any any (
    msg:"poc ip null"; flow:to_server; ip.dst;
    dataset:isset,test_ip,type ip,
      load bad_ipv4.ndjson, format ndjson,
      value_key ip_value, context_key extra;
    sid:1003; rev:1;)
  Crash stack (sig 11):
  DatasetParseIpv6String+0x32   ← strchr(NULL, ':')
  DatajsonAddIPv6Element+0x5e   
  DatajsonLoadTypeFromJsonline → DatajsonGet → DetectDatasetSetup ...

  Case 4: ip dataset, value_key is a JSON array
  NDJSON file:
  {"ip_value": [1, 2, 3], "extra": "context"}
  Same rule structure as Case 3. Same crash path: strchr(NULL, ':') inside DatasetParseIpv6String.

  All four cases were reproduced using suricata -T (config test mode), confirming the crash occurs at dataset load time before any traffic is processed.

  ─────────────────────────────────────────────────────────────────────────────
  SUGGESTED FIX
  ─────────────────────────────────────────────────────────────────────────────

  Add a NULL guard immediately after every json_string_value() call in the four affected functions:

  const char *s = json_string_value(key);
  if (s == NULL) {
      FatalErrorOnInit("dataset %s: value_key '%s' is not a JSON string",
                       set->name, json_key);
      return 0;
  }
  /* proceed with strlen / inet_pton / DatasetParseIpv6String */

We also recommend adding regression tests for all four dataset types (md5, sha256, ipv4, ipv6/ip) with non-string value_key values (integer, boolean, null, array, object) in both json and ndjson formats.

Please let me know if you need additional information, a patch, or test cases. I am happy to coordinate on a responsible disclosure timeline.

Bug does not exist in 7 as datasets-context-json.c was introduced in 8

[Credits]
Changcheng Wu, Clouditera (https://github.com/Clouditera)


Subtasks 1 (0 open1 closed)

Security #8625: detect/dataset/ndjson: NULL dereference on unexpected ndjson files (8.0.x backport)ClosedPhilippe AntoineActions

Related issues 1 (1 open0 closed)

Related to Suricata - Optimization #3590: fuzz: target for dataset/datarep filesAssignedPhilippe AntoineActions

OT Updated by OISF Ticketbot 21 days ago Actions #1

  • Subtask #8625 added

OT Updated by OISF Ticketbot 21 days ago Actions #2

  • Label deleted (Needs backport to 8.0)

PA Updated by Philippe Antoine 21 days ago Actions #3

PA Updated by Philippe Antoine 21 days ago Actions #4

  • Status changed from Assigned to In Review

Gitlab MR

PA Updated by Philippe Antoine 5 days ago Actions #5

  • Severity set to LOW

Low severity as it comes from rules parsing

PA Updated by Philippe Antoine about 21 hours ago Actions #7

  • Status changed from In Review to Resolved

JI Updated by Jason Ish about 18 hours ago Actions #8

  • Description updated (diff)

JI Updated by Jason Ish about 18 hours ago Actions #9

  • Private changed from Yes to No

JI Updated by Jason Ish about 18 hours ago Actions #10

  • GHSA set to GHSA-vqqx-88xw-qqvc

PA Updated by Philippe Antoine about 2 hours ago Actions #11

  • Status changed from Resolved to Closed
Actions

Also available in: PDF Atom