From 116cf3a5a9b6db1f5af780efc12c23947f652d7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 18:29:23 +0100 Subject: [PATCH 1/6] Bump werkzeug from 3.1.3 to 3.1.4 (#2764) Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.1.3 to 3.1.4. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/werkzeug/compare/3.1.3...3.1.4) --- updated-dependencies: - dependency-name: werkzeug dependency-version: 3.1.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4f635467a40..4710a7057ce 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4930,18 +4930,18 @@ files = [ [[package]] name = "werkzeug" -version = "3.1.3" +version = "3.1.4" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"}, - {file = "werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"}, + {file = "werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905"}, + {file = "werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e"}, ] [package.dependencies] -MarkupSafe = ">=2.1.1" +markupsafe = ">=2.1.1" [package.extras] watchdog = ["watchdog (>=2.3)"] @@ -5140,4 +5140,4 @@ maco = ["maco"] [metadata] lock-version = "2.1" python-versions = ">=3.10, <4.0" -content-hash = "fd7e1020fffc66c6fa3e2dc348efe0c6d2ce13060dec37dc4b05777d1e0416e9" +content-hash = "a7785ea80f31041e93e2e59e60002879fac9292780a92155f077271ca26097dd" diff --git a/pyproject.toml b/pyproject.toml index ff417a16506..94caf77391a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ paramiko = "3.5.0" psutil = "6.1.1" peepdf-3 = "5.0.0" pyre2-updated = ">=0.3.8" -Werkzeug = "3.1.3" +Werkzeug = "3.1.4" packaging = "24.2" setuptools = "78.1.1" # command line config manipulation From 6417ae8e70d200d62726a37fcd1309a995322fc5 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 4 Dec 2025 17:30:00 +0000 Subject: [PATCH 2/6] ci: Update requirements.txt --- requirements.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/requirements.txt b/requirements.txt index ed4f6b3100c..b555ccd8c3d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -380,9 +380,9 @@ django-recaptcha==4.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5316438f97700c431d65351470d1255047e3f2cd9af0f2f13592b637dad9213e django-settings-export==1.2.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fceeae49fc597f654c1217415d8e049fc81c930b7154f5d8f28c432db738ff79 -django==5.1.15 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:117871e58d6eda37f09870b7d73a3d66567b03aecd515b386b1751177c413432 \ - --hash=sha256:46a356b5ff867bece73fc6365e081f21c569973403ee7e9b9a0316f27d0eb947 +django==5.1.14 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2a4b9c20404fd1bf50aaaa5542a19d860594cba1354f688f642feb271b91df27 \ + --hash=sha256:b98409fb31fdd6e8c3a6ba2eef3415cc5c0020057b43b21ba7af6eff5f014831 djangorestframework==3.15.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20 \ --hash=sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad @@ -1509,9 +1509,9 @@ pyopenssl==25.0.0 ; python_version >= "3.10" and python_version < "4.0" \ pyparsing==3.2.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1 \ --hash=sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a -pypdf==6.4.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4769d471f8ddc3341193ecc5d6560fa44cf8cd0abfabf21af4e195cc0c224072 \ - --hash=sha256:55ab9837ed97fd7fcc5c131d52fcc2223bc5c6b8a1488bbf7c0e27f1f0023a79 +pypdf==5.2.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:7c38e68420f038f2c4998fd9d6717b6db4f6cef1642e9cf384d519c9cf094663 \ + --hash=sha256:d107962ec45e65e3bd10c1d9242bdbbedaa38193c9e3a6617bd6d996e5747b19 pyre2-updated==0.3.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2bda9bf4d59568152e085450ffc1c08fcf659000d06766861f7ff340ba601c3e \ --hash=sha256:350be9580700b67af87f5227453d1123bc9f4513f0bcc60450574f1bc46cb24f \ @@ -2179,9 +2179,9 @@ websockets==14.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:f390024a47d904613577df83ba700bd189eedc09c57af0a904e5c39624621270 \ --hash=sha256:f8a86a269759026d2bde227652b87be79f8a734e582debf64c9d302faa1e9f03 \ --hash=sha256:fd475a974d5352390baf865309fe37dec6831aafc3014ffac1eea99e84e83fc2 -werkzeug==3.1.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e \ - --hash=sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746 +werkzeug==3.1.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905 \ + --hash=sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e win-unicode-console==0.5 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows" and platform_python_implementation != "PyPy" \ --hash=sha256:d4142d4d56d46f449d6f00536a73625a871cba040f0bc1a2e305a04578f07d1e xmltodict==0.14.2 ; python_version >= "3.10" and python_version < "4.0" \ From 915615a6d2597b331919d54836a64899a23b468f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 18:35:31 +0100 Subject: [PATCH 3/6] Bump django from 5.1.14 to 5.1.15 (#2767) Bumps [django](https://github.com/django/django) from 5.1.14 to 5.1.15. - [Commits](https://github.com/django/django/compare/5.1.14...5.1.15) --- updated-dependencies: - dependency-name: django dependency-version: 5.1.15 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index b555ccd8c3d..9ab463a1a7f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -380,9 +380,9 @@ django-recaptcha==4.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5316438f97700c431d65351470d1255047e3f2cd9af0f2f13592b637dad9213e django-settings-export==1.2.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fceeae49fc597f654c1217415d8e049fc81c930b7154f5d8f28c432db738ff79 -django==5.1.14 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2a4b9c20404fd1bf50aaaa5542a19d860594cba1354f688f642feb271b91df27 \ - --hash=sha256:b98409fb31fdd6e8c3a6ba2eef3415cc5c0020057b43b21ba7af6eff5f014831 +django==5.1.15 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:117871e58d6eda37f09870b7d73a3d66567b03aecd515b386b1751177c413432 \ + --hash=sha256:46a356b5ff867bece73fc6365e081f21c569973403ee7e9b9a0316f27d0eb947 djangorestframework==3.15.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20 \ --hash=sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad From dc8af919ef03c8932e9c56785ae32ac4e7c100ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 18:35:52 +0100 Subject: [PATCH 4/6] Bump pypdf from 5.2.0 to 6.4.0 (#2768) Bumps [pypdf](https://github.com/py-pdf/pypdf) from 5.2.0 to 6.4.0. - [Release notes](https://github.com/py-pdf/pypdf/releases) - [Changelog](https://github.com/py-pdf/pypdf/blob/main/CHANGELOG.md) - [Commits](https://github.com/py-pdf/pypdf/compare/5.2.0...6.4.0) --- updated-dependencies: - dependency-name: pypdf dependency-version: 6.4.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 9ab463a1a7f..e5984e12136 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1509,9 +1509,9 @@ pyopenssl==25.0.0 ; python_version >= "3.10" and python_version < "4.0" \ pyparsing==3.2.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1 \ --hash=sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a -pypdf==5.2.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:7c38e68420f038f2c4998fd9d6717b6db4f6cef1642e9cf384d519c9cf094663 \ - --hash=sha256:d107962ec45e65e3bd10c1d9242bdbbedaa38193c9e3a6617bd6d996e5747b19 +pypdf==6.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:4769d471f8ddc3341193ecc5d6560fa44cf8cd0abfabf21af4e195cc0c224072 \ + --hash=sha256:55ab9837ed97fd7fcc5c131d52fcc2223bc5c6b8a1488bbf7c0e27f1f0023a79 pyre2-updated==0.3.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2bda9bf4d59568152e085450ffc1c08fcf659000d06766861f7ff340ba601c3e \ --hash=sha256:350be9580700b67af87f5227453d1123bc9f4513f0bcc60450574f1bc46cb24f \ From 500db67bda10424d3cf32c2b242d2ed0f9df5e1d Mon Sep 17 00:00:00 2001 From: cccs-mog <117194682+cccs-mog@users.noreply.github.com> Date: Thu, 4 Dec 2025 13:02:52 -0500 Subject: [PATCH 5/6] Update scheduler.py to reflect migration for timeout function (#2763) * Update scheduler.py to reflect migration for timeout function * Update database.py --- lib/cuckoo/core/database.py | 2 +- lib/cuckoo/core/scheduler.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cuckoo/core/database.py b/lib/cuckoo/core/database.py index 4498db25a10..4037dc34dcf 100644 --- a/lib/cuckoo/core/database.py +++ b/lib/cuckoo/core/database.py @@ -2223,7 +2223,7 @@ def clean_timed_out_tasks(self, timeout: int): return # Calculate the cutoff time before which tasks are considered timed out. - timeout_threshold = datetime.now() - timedelta(seconds=timeout) + timeout_threshold = datetime.utcnow() - timedelta(seconds=timeout) # Build a single, efficient DELETE statement that filters in the database. delete_stmt = delete(Task).where(Task.status == TASK_PENDING).where(Task.added_on < timeout_threshold) diff --git a/lib/cuckoo/core/scheduler.py b/lib/cuckoo/core/scheduler.py index 518b77380fd..f7251bc8c55 100644 --- a/lib/cuckoo/core/scheduler.py +++ b/lib/cuckoo/core/scheduler.py @@ -105,7 +105,7 @@ def do_main_loop_work(self, error_queue: queue.Queue) -> SchedulerCycleDelay: if self.next_timeout_time < time.time(): self.next_timeout_time = time.time() + self.cfg.cuckoo.get("task_timeout_scan_interval", 30) with self.db.session.begin(): - self.db.check_tasks_timeout(self.cfg.cuckoo.get("task_pending_timeout", 0)) + self.db.clean_timed_out_tasks(self.cfg.cuckoo.get("task_pending_timeout", 0)) analysis_manager: Optional[AnalysisManager] = None with self.db.session.begin(): From 5d54c5c5ec3e063bf4f3c97652ac8306e053ed0a Mon Sep 17 00:00:00 2001 From: doomedraven Date: Thu, 4 Dec 2025 19:03:31 +0100 Subject: [PATCH 6/6] Refactor yara_detected for better matching and self-extraction (#2759) * Refactor yara_detected for better matching and self-extraction Refactor yara_detected method to improve matching logic and encapsulate self-extraction processing. * Apply suggestions from code review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update lib/cuckoo/common/abstracts.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- lib/cuckoo/common/abstracts.py | 151 +++++++++++++++++---------------- 1 file changed, 79 insertions(+), 72 deletions(-) diff --git a/lib/cuckoo/common/abstracts.py b/lib/cuckoo/common/abstracts.py index 5d8547f4271..f4d4a1f3892 100644 --- a/lib/cuckoo/common/abstracts.py +++ b/lib/cuckoo/common/abstracts.py @@ -887,82 +887,89 @@ def set_path(self, analysis_path): CuckooReportError(e) def yara_detected(self, name): - target = self.results.get("target", {}) - if target.get("category") in ("file", "static") and target.get("file"): + name_pattern = re.compile(name, re.I) + + def _check_matches(data_block, path, label_override=None): + if not isinstance(data_block, dict): + return + for keyword in ("cape_yara", "yara"): - for yara_block in self.results["target"]["file"].get(keyword, []): - if re.findall(name, yara_block["name"], re.I): - yield "sample", self.results["target"]["file"]["path"], yara_block, self.results["target"]["file"] - - if target["file"].get("selfextract"): - for _, toolsblock in target["file"]["selfextract"].items(): - for block in toolsblock.get("extracted_files", []): - for keyword in ("cape_yara", "yara"): - for yara_block in block[keyword]: - if re.findall(name, yara_block["name"], re.I): - # we can't use here values from set_path - yield "sample", block["path"], yara_block, block - - for block in self.results.get("CAPE", {}).get("payloads", []) or []: - for sub_keyword in ("cape_yara", "yara"): - for yara_block in block.get(sub_keyword, []): - if re.findall(name, yara_block["name"], re.I): - yield sub_keyword, block["path"], yara_block, block - - if block.get("selfextract", {}): - for _, toolsblock in block["selfextract"].items(): - for subblock in toolsblock.get("extracted_files", []): - for keyword in ("cape_yara", "yara"): - for yara_block in subblock[keyword]: - if re.findall(name, yara_block["name"], re.I): - yield "sample", subblock["path"], yara_block, block - - for keyword in ("procdump", "procmemory", "extracted", "dropped"): - if self.results.get(keyword) is not None: - for block in self.results.get(keyword, []): - if not isinstance(block, dict): - continue - for sub_keyword in ("cape_yara", "yara"): - for yara_block in block.get(sub_keyword, []): - if re.findall(name, yara_block["name"], re.I): - path = block["path"] if block.get("path", False) else "" - yield keyword, path, yara_block, block - - if keyword == "procmemory": - for pe in block.get("extracted_pe", []) or []: - for sub_keyword in ("cape_yara", "yara"): - for yara_block in pe.get(sub_keyword, []) or []: - if re.findall(name, yara_block["name"], re.I): - yield "extracted_pe", pe["path"], yara_block, block - - if block.get("selfextract", {}): - for _, toolsblock in block["selfextract"].items(): - for subblock in toolsblock.get("extracted_files", []): - for keyword in ("cape_yara", "yara"): - for yara_block in subblock[keyword]: - if re.findall(name, yara_block["name"], re.I): - yield "sample", subblock["path"], yara_block, block - - macro_path = os.path.join(CUCKOO_ROOT, "storage", "analyses", str(self.results["info"]["id"]), "macros") - for macroname in self.results.get("static", {}).get("office", {}).get("Macro", {}).get("info", []) or []: - for yara_block in self.results["static"]["office"]["Macro"]["info"].get("macroname", []) or []: - for sub_block in self.results["static"]["office"]["Macro"]["info"]["macroname"].get(yara_block, []) or []: - if re.findall(name, sub_block["name"], re.I): - yield ( - "macro", - os.path.join(macro_path, macroname), - sub_block, - self.results["static"]["office"]["Macro"]["info"], - ) - - if self.results.get("static", {}).get("office", {}).get("XLMMacroDeobfuscator", False): - for yara_block in self.results["static"]["office"]["XLMMacroDeobfuscator"].get("info", []).get("yara_macro", []) or []: - if re.findall(name, yara_block["name"], re.I): + for yara_block in data_block.get(keyword, []): + if name_pattern.search(yara_block.get("name", "")): + label = label_override if label_override else keyword + yield label, path, yara_block, data_block + + def _process_selfextract(parent_block): + selfextract = parent_block.get("selfextract") + if not selfextract: + return + + tools_iter = selfextract.values() if isinstance(selfextract, dict) else [] + + for toolsblock in tools_iter: + for extracted_file in toolsblock.get("extracted_files", []) or []: + yield from _check_matches( + extracted_file, + path=extracted_file.get("path"), + label_override="sample" + ) + + results = self.results + target = results.get("target", {}) + + # 1. Procesar Target + if target.get("category") in ("file", "static") and target.get("file"): + file_info = target["file"] + yield from _check_matches(file_info, file_info.get("path"), label_override="sample") + yield from _process_selfextract(file_info) + + cape_payloads = results.get("CAPE", {}).get("payloads", []) or [] + for block in cape_payloads: + yield from _check_matches(block, block.get("path")) + yield from _process_selfextract(block) + + search_keys = ("procdump", "procmemory", "extracted", "dropped") + for keyword in search_keys: + blocks = results.get(keyword, []) or [] + if not blocks: + continue + + for block in blocks: + if not isinstance(block, dict): + continue + + path = block.get("path", "") + yield from _check_matches(block, path, label_override=keyword) + + if keyword == "procmemory": + for pe in block.get("extracted_pe", []) or []: + yield from _check_matches(pe, pe.get("path"), label_override="extracted_pe") + + yield from _process_selfextract(block) + + # ToDo not sure if static still exist + office_info = results.get("static", {}).get("office", {}) + macro_info = office_info.get("Macro", {}).get("info", []) + analysis_id = str(results.get("info", {}).get("id", "unknown")) + macro_base_path = os.path.join(CUCKOO_ROOT, "storage", "analyses", analysis_id, "macros") + + if macro_info: + if isinstance(macro_info, list): + for item in macro_info: + yield from _check_matches(item, os.path.join(macro_base_path, item.get("name", "macro")), label_override="macro") + elif isinstance(macro_info, dict): + for macroname, macro_data in macro_info.items(): + yield from _check_matches(macro_data, os.path.join(macro_base_path, macroname), label_override="macro") + + xlm_info = office_info.get("XLMMacroDeobfuscator", {}).get("info", {}) + if xlm_info: + for yara_block in xlm_info.get("yara_macro", []) or []: + if name_pattern.search(yara_block.get("name", "")): yield ( "macro", - os.path.join(macro_path, "xlm_macro"), + os.path.join(macro_base_path, "xlm_macro"), yara_block, - self.results["static"]["office"]["XLMMacroDeobfuscator"]["info"], + xlm_info ) def signature_matched(self, signame: str) -> bool: