From e8d22dd6cd607254e626b14cec85aa6de3c6d8c3 Mon Sep 17 00:00:00 2001 From: elhoim Date: Mon, 31 Aug 2026 01:16:05 +0000 Subject: [PATCH] fix: [export_mod/yara_export] escape attribute values in generated YARA string/meta literals The dynamically-generated rule (YaraRule.__str__) interpolates attribute values and event/org metadata directly into double-quoted YARA string literals without escaping backslashes or embedded double quotes. An attacker-influenced attribute value (or event info/org name) containing a `"` breaks out of the literal and corrupts the generated rule; unlike the handle_yara path, which validates the raw YARA text supplied by a user via yara.compile(), this generated path was never validated at all, so a broken rule was silently exported as if it were valid YARA. Both string and meta values are now backslash/quote-escaped before being quoted, and the full generated ruleset is compiled with yara.compile() before being returned; if it fails to compile, the module now reports an error instead of silently emitting an invalid ruleset. Verified with flake8 (clean) and the full test suite against a locally started misp-modules server on port 6784: 161 passed, 4 skipped, 5 subtests passed, matching baseline, including the existing test_yara_export case (which exercises the handle_yara path and is unaffected). Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018dfYpyaSZd1nxSRLr8suj8 --- misp_modules/modules/export_mod/yara_export.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/misp_modules/modules/export_mod/yara_export.py b/misp_modules/modules/export_mod/yara_export.py index 84e421f4..e1f18d02 100644 --- a/misp_modules/modules/export_mod/yara_export.py +++ b/misp_modules/modules/export_mod/yara_export.py @@ -70,17 +70,20 @@ def __str__(self): for key, values in self.meta.items(): i = 0 if len(values) == 1: - result.append(f' {key} = "{values[0]}"') + escaped_value = values[0].replace("\\", "\\\\").replace('"', '\\"') + result.append(f' {key} = "{escaped_value}"') continue for value in values: - result.append(f' {key}_{i} = "{value}"') + escaped_value = value.replace("\\", "\\\\").replace('"', '\\"') + result.append(f' {key}_{i} = "{escaped_value}"') i += 1 result.append(" strings:") for key, values in self.strings.items(): i = 0 for value in values: - result.append(f' ${key}_{i} = "{value}"') + escaped_value = value.replace("\\", "\\\\").replace('"', '\\"') + result.append(f' ${key}_{i} = "{escaped_value}"') i += 1 result.append(" condition:") @@ -267,9 +270,15 @@ def handler(q=False): # ignore unsupported types pass yara_rules.append(str(yr)) + ruleset = "\n".join(yara_rules) + try: + yara.compile(source=ruleset) + except Exception: + misperrors["error"] = "The generated YARA ruleset does not compile." + return misperrors r = { "response": [], - "data": str(base64.b64encode(bytes("\n".join(yara_rules), "utf-8")), "utf-8"), + "data": str(base64.b64encode(bytes(ruleset, "utf-8")), "utf-8"), } return r