From 5501fd11289c7789a3508ec72a4e8f486720f50c Mon Sep 17 00:00:00 2001 From: doomedraven Date: Thu, 27 Aug 2026 12:07:37 +0000 Subject: [PATCH] Detect API spamming in behavior analysis and prompt user to resubmit with exclude-apis --- conf/default/processing.conf.default | 5 ++++ modules/processing/behavior.py | 31 ++++++++++++++++++++-- web/templates/analysis/overview/_info.html | 14 ++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/conf/default/processing.conf.default b/conf/default/processing.conf.default index 4e3df106fac..73b370e36ee 100644 --- a/conf/default/processing.conf.default +++ b/conf/default/processing.conf.default @@ -33,6 +33,11 @@ enabled = no enabled = no [behavior] +# Detect API spamming and suggest exclude-apis in the web interface +detect_apispam = yes +# Limit at which to consider an API as spammed (default limit in capemon is 256 / 0x100) +apispam_limit = 256 + enabled = yes # Toggle specific modules within the BehaviorAnalysis class anomaly = yes diff --git a/modules/processing/behavior.py b/modules/processing/behavior.py index 633b888cade..521df7c5b21 100644 --- a/modules/processing/behavior.py +++ b/modules/processing/behavior.py @@ -44,6 +44,7 @@ bytes2str, convert_to_printable, default_converter, + get_options, logtime, pretty_print_arg, pretty_print_retval, @@ -526,7 +527,7 @@ class Summary: key = "summary" - def __init__(self, options): + def __init__(self, options, task=None): self.keys = [] self.read_keys = [] self.write_keys = [] @@ -540,7 +541,9 @@ def __init__(self, options): self.created_services = [] self.executed_commands = [] self.resolved_apis = [] + self.api_counts = defaultdict(int) self.options = options + self.task = task self.dispatch = { "NtCreateKey": self._handle_NtCreateKey, @@ -740,6 +743,7 @@ def event_apicall(self, call, process): @return: None. """ api = call["api"] + self.api_counts[api] += 1 handler = self.dispatch.get(api) if handler: handler(call, process) @@ -813,6 +817,27 @@ def run(self): """Get registry keys, mutexes and files. @return: Summary of keys, read keys, written keys, mutexes and files. """ + detect_apispam = getattr(self.options, "detect_apispam", True) + apispam_limit = int(getattr(self.options, "apispam_limit", 256)) + + apispam = [] + apispam_exclude_apis = "" + + if detect_apispam: + apispam = [api for api, count in self.api_counts.items() if count >= apispam_limit] + + if apispam and self.task: + task_options = self.task.get("options", "") + if isinstance(task_options, str): + parsed_options = get_options(task_options) + else: + parsed_options = task_options or {} + + existing_exclude = parsed_options.get("exclude-apis", "") + existing = existing_exclude.split(":") if existing_exclude else [] + merged = sorted(list(set(existing + apispam))) + apispam_exclude_apis = ":".join(merged) + return { "files": self.files, "read_files": self.read_files, @@ -827,6 +852,8 @@ def run(self): "mutexes": self.mutexes, "created_services": self.created_services, "started_services": self.started_services, + "apispam": apispam, + "apispam_exclude_apis": apispam_exclude_apis, } @@ -1511,7 +1538,7 @@ def run(self): instances = [ Anomaly(), ProcessTree(), - Summary(self.options), + Summary(self.options, task=self.task), Enhanced(), EncryptedBuffers(), NetworkMap(), diff --git a/web/templates/analysis/overview/_info.html b/web/templates/analysis/overview/_info.html index 969ae5cfd75..a90953af343 100644 --- a/web/templates/analysis/overview/_info.html +++ b/web/templates/analysis/overview/_info.html @@ -1,5 +1,19 @@
+ + {% if analysis.behavior.summary.apispam %} + + {% endif %} + {% if analysis.detections %}