Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
e2bd101
Ruff (#2410)
doomedraven Feb 2, 2025
ff09024
Update zip_utils.py
doomedraven Feb 2, 2025
7871a71
Update zip_utils.py
doomedraven Feb 2, 2025
462fb0c
Merge branch 'master' into staging
doomedraven Feb 6, 2025
8db0425
Merge branch 'master' into staging
doomedraven Feb 7, 2025
82be043
Update rooter.py
doomedraven Feb 7, 2025
2299dc0
Merge branch 'master' into staging
doomedraven Feb 7, 2025
8228c21
Update plugins.py
doomedraven Feb 7, 2025
6f4df2b
Update abstracts.py
doomedraven Feb 7, 2025
e812fe1
Update plugins.py
doomedraven Feb 7, 2025
bf15a9d
Update plugins.py
doomedraven Feb 7, 2025
07b9f84
Merge branch 'master' into staging
doomedraven Feb 7, 2025
54de070
Merge branch 'master' into staging
doomedraven Feb 7, 2025
b392b01
Merge branch 'master' into staging
doomedraven Feb 9, 2025
bcec6d9
Update tls.py
doomedraven Feb 9, 2025
269a449
sync
doomedraven Feb 11, 2025
e145063
Merge branch 'master' into staging
doomedraven Feb 12, 2025
a8f768a
sync
doomedraven Feb 12, 2025
3cd15fd
Merge branch 'master' into staging
doomedraven Feb 15, 2025
50d7f54
Downloaders (#2493)
doomedraven Feb 16, 2025
12999c2
ci: Update requirements.txt
actions-user Feb 16, 2025
9145bac
improve docs
doomedraven Feb 17, 2025
07afabf
typo
doomedraven Feb 17, 2025
61bbeae
fix typo
doomedraven Feb 17, 2025
47b0c34
Merge branch 'master' into staging
doomedraven Feb 18, 2025
37e8eb8
Update load_extra_modules.py
doomedraven Feb 18, 2025
c12b2f0
sync
doomedraven Feb 18, 2025
85777cc
fix static
doomedraven Feb 19, 2025
d8082fd
fix rtf
doomedraven Feb 19, 2025
ae22386
Merge branch 'master' into staging
doomedraven Feb 28, 2025
0b1c8e3
sync
doomedraven Mar 1, 2025
5c37b79
Create test_strings.py
doomedraven Mar 1, 2025
d51af8f
Update database.py
doomedraven Mar 1, 2025
d4e6557
Update database.py
doomedraven Mar 1, 2025
5e45d94
Update test_strings.py
doomedraven Mar 1, 2025
f2d604a
Update changelog.md
doomedraven Mar 1, 2025
747a069
Merge branch 'master' into staging
doomedraven Mar 1, 2025
245bed8
Merge branch 'master' into staging
doomedraven Jun 6, 2025
7c3e65b
ci: Update requirements.txt
actions-user Jun 6, 2025
7a27af3
Merge branch 'master' into staging
doomedraven Jun 12, 2025
3c287cd
ci: Update requirements.txt
actions-user Jun 12, 2025
4f6e17c
Merge branch 'master' into staging
doomedraven Jul 3, 2025
8555305
sqlalchemy 2 (#2636)
doomedraven Jul 8, 2025
be0e80a
ci: Update requirements.txt
actions-user Jul 8, 2025
a637ad1
Update dist.py
doomedraven Jul 10, 2025
746be3f
Merge branch 'master' into staging
doomedraven Jul 10, 2025
28e4ddf
db cleanup (#2644)
doomedraven Jul 14, 2025
13e1e1e
Proper relationship parent-child samples (#2645)
doomedraven Jul 15, 2025
100b7cf
drop also old dist migrations
doomedraven Jul 15, 2025
32e3170
Update web_utils.py
doomedraven Jul 15, 2025
cc2584a
Update lib/cuckoo/common/dist_db.py
doomedraven Jul 15, 2025
150b933
Update 2. Database cleanup.py
doomedraven Jul 15, 2025
d4380a3
Update web_utils.py
doomedraven Jul 16, 2025
e44ea81
Update dist.py
doomedraven Jul 16, 2025
33a2a8c
Create iocs.py
doomedraven Jul 16, 2025
b0e83f4
Update views.py
doomedraven Jul 17, 2025
c325da5
Revert "Update views.py"
doomedraven Jul 17, 2025
c7d3809
Improve exception handling in Guacamole view & Vpshere (#2655)
Kyrd0x Jul 28, 2025
fde3933
Update database.py
doomedraven Aug 5, 2025
0b758e9
Merge branch 'master' into staging
doomedraven Aug 6, 2025
606a714
Merge branch 'master' into staging
doomedraven Aug 11, 2025
949c9d9
Merge branch 'master' into staging
doomedraven Aug 13, 2025
f6f70fd
Merge branch 'master' into staging
doomedraven Aug 27, 2025
3f9fe99
Update database.py
doomedraven Aug 27, 2025
93cd6e7
Update tests/test_database.py
doomedraven Aug 27, 2025
c0221f2
Revert "Update tests/test_database.py"
doomedraven Aug 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions analyzer/windows/data/yara/NitrogenLoader.yar
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,12 @@ rule NitrogenLoaderConfig
$taskman_2 = {B9 4D 00 00 00 88 84 24 [4] E8 [4] B9 61 00 00 00 88 84 24 [4] E8 [4] B9 6E 00 00 00 88 84 24 [4] E8 [3] FF}
$taskman_3 = {B9 61 00 00 00 88 84 24 [4] E8 [4] B9 67 00 00 00 88 84 24 [4] E8 [4] B9 65 00 00 00 88 84 24 [4] E8 [3] FF}
$taskman_4 = {B9 72 00 00 00 88 84 24 [4] E8 [4] 31 C9 88 84 24 [4] E8 [3] FF}
$rc4decrypt_1 = {48 89 ?? 48 89 ?? E8 [4] 48 8B ?? 24 [1-4] 4? 89 ?? 48 89 ?? 4? 89 C1 89 EA E8 [4] 48 89}
$installers_1 = {B9 49 00 00 00 E8 [4] B9 6E 00 00 00 88 84 24 [4] E8 [4] B9 73 00 00 00 88 84 24 [4] E8 [3] FF}
$installers_2 = {B9 74 00 00 00 88 84 24 [4] E8 [4] B9 61 00 00 00 88 84 24 [4] E8 [4] B9 6C 00 00 00 88 84 24 [4] E8 [3] FF}
$installers_3 = {B9 6C 00 00 00 88 84 24 [4] E8 [4] B9 65 00 00 00 88 84 24 [4] E8 [3] FF}
$installers_4 = {B9 72 00 00 00 88 84 24 [4] E8 [4] B9 73 00 00 00 88 84 24 [4] E8 [3] FF}
$rc4decrypt_1 = {48 89 ?? 4? 89 ?? E8 [4] 4? 8B ?? 24 [1-4] 4? 89 ?? 4? 89 ?? 4? 89 C1 [0-1] 89 ?? E8 [4] 4? 89}
$rc4decrypt_2 = {E8 [4] 8B ?? 24 [1-4] 4? 89 ?? 48 89 ?? 4? 89 C1 E8 [3] FF}
condition:
any of ($decrypt*) or ($key and (3 of ($taskman_*) and 1 of ($rc4decrypt_*)))
any of ($decrypt*) or ($key and (3 of ($taskman_*) or 3 of ($installers*) and 1 of ($rc4decrypt_*)))
}
Binary file modified analyzer/windows/dll/capemon.dll
Binary file not shown.
Binary file modified analyzer/windows/dll/capemon_x64.dll
Binary file not shown.
21 changes: 21 additions & 0 deletions analyzer/windows/modules/packages/nodejs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from lib.common.abstracts import Package
from lib.common.common import check_file_extension
from lib.common.constants import OPT_ARGUMENTS


class NodeJS(Package):
"""Package for executing JavaScript files using NodeJS."""

PATHS = [
("ProgramFiles", "NodeJS", "node.exe"),
("LOCALAPPDATA", "Programs", "NodeJS", "node.exe"),
]
summary = "Executes a JS sample using NodeJS."
description = "Uses node.exe instead of wscript.exe to execute JavaScript files."
option_names = (OPT_ARGUMENTS,)

def start(self, path):
node = self.get_path("node.exe")
path = check_file_extension(path, ".js")
args = self.options.get(OPT_ARGUMENTS, "")
return self.execute(node, f'"{path}" {args}', path)
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
### [18.08.2025]
* Monitor update: YaraHarness: fix issue with ParseOptionLine() adding imagebase to sysbps (thanks @ClaudioWayne)

### [13.08.2025]
* Monitor update: Fix internal WMI_GetObjectAsync yara

### [05.08.2025]
* Monitor updates:
* Enhance dynamic patching capability: new PatchBytes() function, submission/yara option patch=<address>:<bytes>
Expand Down
3 changes: 0 additions & 3 deletions conf/default/web.conf.default
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,6 @@ enabled = no
[display_office_martians]
enabled = no

[display_shrike]
enabled = no

[display_task_tags]
# displays custom tags, if set during sample submission
enabled = no
Expand Down
2 changes: 1 addition & 1 deletion cuckoo.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def cuckoo_main(max_analysis_count=0):
except CuckooCriticalError as e:
message = "{0}: {1}".format(e.__class__.__name__, e)
if any(filter(lambda hdlr: not isinstance(hdlr, logging.NullHandler), log.handlers)):
log.critical(message)
log.critical(message, exc_info=True)
else:
sys.stderr.write("{0}\n".format(message))

Expand Down
7 changes: 4 additions & 3 deletions data/yara/CAPE/Amadey.yar
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
rule Amadey
{
meta:
author = "kevoreilly"
author = "kevoreilly, YungBinary"
description = "Amadey Payload"
cape_type = "Amadey Payload"
hash = "988258716d5296c1323303e8fe4efd7f4642c87bfdbe970fe9a3bb3f410f70a4"
strings:
$decode1 = {8B D1 B8 FF FF FF 7F D1 EA 2B C2 3B C8 76 07 BB FF FF FF 7F EB 08 8D 04 0A 3B D8 0F 42 D8}
$decode2 = {33 D2 8B 4D ?? 8B C7 F7 F6 8A 84 3B [4] 2A 44 0A 01 88 87 [4] 47 8B 45 ?? 8D 50 01}
$decode3 = {8A 04 02 88 04 0F 41 8B 7D ?? 8D 42 01 3B CB 7C}
$decode2 = {2B C8 8D 04 0A 33 D2 F7 F3 8B 5D ?? 8B CB 83 7B ?? 10}
$decode3 = {33 D2 8B 4D ?? 8B C7 F7 F6 8A 84 3B [4] 2A 44 0A 01 88 87 [4] 47 8B 45 ?? 8D 50 01}
$decode4 = {8A 04 02 88 04 0F 41 8B 7D ?? 8D 42 01 3B CB 7C}
condition:
uint16(0) == 0x5A4D and 2 of them
}
6 changes: 5 additions & 1 deletion data/yara/CAPE/NitrogenLoader.yar
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ rule NitrogenLoader
$taskman_2 = {B9 4D 00 00 00 88 84 24 [4] E8 [4] B9 61 00 00 00 88 84 24 [4] E8 [4] B9 6E 00 00 00 88 84 24 [4] E8 [3] FF}
$taskman_3 = {B9 61 00 00 00 88 84 24 [4] E8 [4] B9 67 00 00 00 88 84 24 [4] E8 [4] B9 65 00 00 00 88 84 24 [4] E8 [3] FF}
$taskman_4 = {B9 72 00 00 00 88 84 24 [4] E8 [4] 31 C9 88 84 24 [4] E8 [3] FF}
$installers_1 = {B9 49 00 00 00 E8 [4] B9 6E 00 00 00 88 84 24 [4] E8 [4] B9 73 00 00 00 88 84 24 [4] E8 [3] FF}
$installers_2 = {B9 74 00 00 00 88 84 24 [4] E8 [4] B9 61 00 00 00 88 84 24 [4] E8 [4] B9 6C 00 00 00 88 84 24 [4] E8 [3] FF}
$installers_3 = {B9 6C 00 00 00 88 84 24 [4] E8 [4] B9 65 00 00 00 88 84 24 [4] E8 [3] FF}
$installers_4 = {B9 72 00 00 00 88 84 24 [4] E8 [4] B9 73 00 00 00 88 84 24 [4] E8 [3] FF}
$rc4decrypt_1 = {48 89 ?? 4? 89 ?? E8 [4] 4? 8B ?? 24 [1-4] 4? 89 ?? 4? 89 ?? 4? 89 C1 [0-1] 89 ?? E8 [4] 4? 89}
$rc4decrypt_2 = {E8 [4] 8B ?? 24 [1-4] 4? 89 ?? 48 89 ?? 4? 89 C1 E8 [3] FF}
condition:
(2 of ($string*) and any of ($syscall*)) or 4 of ($decrypt*) or (3 of ($taskman_*) and all of ($rc4decrypt_*))
(2 of ($string*) and any of ($syscall*)) or 4 of ($decrypt*) or ((3 of ($taskman_*) or 3 of ($installers*)) and all of ($rc4decrypt_*))
}
2 changes: 1 addition & 1 deletion data/yara/CAPE/Stealc.yar
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ rule Stealc
$nugget1 = {68 04 01 00 00 6A 00 FF 15 [4] 50 FF 15}
$nugget2 = {64 A1 30 00 00 00 8B 40 0C 8B 40 0C 8B 00 8B 00 8B 40 18 89 45 FC}
condition:
uint16(0) == 0x5A4D and any of them
uint16(0) == 0x5A4D and all of them
}

rule StealcV2
Expand Down
7 changes: 7 additions & 0 deletions lib/cuckoo/common/abstracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,13 @@ def availables(self, label=None, platform=None, tags=None, arch=None, include_re
label=label, platform=platform, tags=tags, arch=arch, include_reserved=include_reserved, os_version=os_version
)

def find_machine_to_service_task(self, task):
"""Find a machine that is able to service the given task.
This can be overridden by machinery modules for custom logic.
By default, it delegates to the database implementation.
"""
return self.db.find_machine_to_service_task(task)

def scale_pool(self, machine: Machine) -> None:
"""This can be overridden in sub-classes to scale the pool of machines once one has been acquired."""
return
Expand Down
175 changes: 96 additions & 79 deletions lib/cuckoo/common/dist_db.py
Original file line number Diff line number Diff line change
@@ -1,112 +1,126 @@
import sys
from datetime import datetime
from typing import List, Optional

# http://pythoncentral.io/introductory-tutorial-python-sqlalchemy/
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Index, Integer, String, Table, Text, create_engine
from sqlalchemy import (
Column,
create_engine,
DateTime,
ForeignKey,
Integer,
String,
Table,
Text,
)
from sqlalchemy.exc import OperationalError
from sqlalchemy.orm import declarative_base, relationship, sessionmaker
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, sessionmaker
from sqlalchemy.types import TypeDecorator

Base = declarative_base()

# 1. Use DeclarativeBase as the modern starting point
class Base(DeclarativeBase):
pass


schema = "83fd58842164"

# This association table definition is correct and doesn't need changes
worker_exitnodes = Table(
"worker_exitnodes",
Base.metadata,
Column("node_id", Integer, ForeignKey("node.id"), primary_key=True),
Column("exit_id", Integer, ForeignKey("exitnodes.id"), primary_key=True),
)

class ExitNodes(Base):
"""Exit nodes to route traffic."""

# 2. Modernized all models with Mapped/mapped_column and explicit relationships
class ExitNodes(Base):
__tablename__ = "exitnodes"

id = Column(Integer(), primary_key=True)
name = Column(String(255), nullable=False, unique=True)
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(255), unique=True)

def __repr__(self):
return f"<Exit node('{self.id}','{self.name}')>"
# This relationship completes the link from the Node model
nodes: Mapped[List["Node"]] = relationship(secondary=worker_exitnodes, back_populates="exitnodes")

def __init__(self, name):
self.name = name
def __repr__(self) -> str:
return f"<ExitNode(id={self.id}, name='{self.name}')>"


# Secondary table used in association Worker - Exit node.
worker_exitnodes = Table(
"worker_exitnodes",
Base.metadata,
Column("node_id", Integer, ForeignKey("node.id")),
Column("exit_id", Integer, ForeignKey("exitnodes.id")),
)
class Node(Base):
__tablename__ = "node"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(Text)
url: Mapped[Optional[str]] = mapped_column(Text)
enabled: Mapped[bool] = mapped_column(default=False)
apikey: Mapped[str] = mapped_column(String(255))
last_check: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=False))

# Replaced legacy `backref` with explicit `back_populates`
machines: Mapped[List["Machine"]] = relationship(back_populates="node")
exitnodes: Mapped[List["ExitNodes"]] = relationship(
secondary=worker_exitnodes, back_populates="nodes", lazy="subquery"
) # really need lazy?


# The TypeDecorator is a valid pattern; added type hints for clarity
class StringList(TypeDecorator):
"""List of comma-separated strings as field."""
"""Saves a Python list of strings as a single comma-separated string in the DB."""

impl = Text
cache_ok = True # Indicates the type is safe to cache

def process_bind_param(self, value, dialect):
def process_bind_param(self, value: Optional[List[str]], dialect) -> Optional[str]:
if value is None:
return None
return ", ".join(value)

def process_result_value(self, value, dialect):
return value.split(", ")
def process_result_value(self, value: Optional[str], dialect) -> Optional[List[str]]:
if value is None:
return None
return [item.strip() for item in value.split(",")]


class Machine(Base):
"""Machine database model related to a Cuckoo node."""

__tablename__ = "machine"
id = Column(Integer, primary_key=True)
name = Column(Text, nullable=False)
platform = Column(Text, nullable=False)
tags = Column(StringList)
node_id = Column(Integer, ForeignKey("node.id"))
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(Text)
platform: Mapped[str] = mapped_column(Text)
tags: Mapped[Optional[List[str]]] = mapped_column(StringList)
node_id: Mapped[Optional[int]] = mapped_column(ForeignKey("node.id"))


class Node(Base):
"""Cuckoo node database model."""

__tablename__ = "node"
id = Column(Integer, primary_key=True)
name = Column(Text, nullable=False)
url = Column(Text, nullable=True)
enabled = Column(Boolean, default=False)
apikey = Column(String(255), nullable=False)
last_check = Column(DateTime(timezone=False))
machines = relationship(Machine, backref="node", lazy="dynamic")
exitnodes = relationship(ExitNodes, secondary=worker_exitnodes, backref="node", lazy="subquery")
# This relationship completes the link from the Node model
node: Mapped["Node"] = relationship(back_populates="machines")


class Task(Base):
"""Analysis task database model."""

__tablename__ = "task"
id = Column(Integer, primary_key=True)
path = Column(Text)
category = Column(Text)
package = Column(Text)
timeout = Column(Integer)
priority = Column(Integer)
options = Column(Text)
machine = Column(Text)
platform = Column(Text)
route = Column(Text)
tags = Column(Text)
custom = Column(Text)
memory = Column(Text)
clock = Column(DateTime(timezone=False), default=datetime.now(), nullable=False)
enforce_timeout = Column(Text)
tlp = Column(Text, nullable=True)
# Cuckoo node and Task ID this has been submitted to.
node_id = Column(Integer, ForeignKey("node.id"))
task_id = Column(Integer)
finished = Column(Boolean, nullable=False, default=False)
main_task_id = Column(Integer)
retrieved = Column(Boolean, nullable=False, default=False)
notificated = Column(Boolean, nullable=True, default=False)
deleted = Column(Boolean, nullable=False, default=False)

__table_args__ = (
Index("node_id_index", "node_id"),
Index("task_id_index", "task_id"),
Index("main_task_id_index", "main_task_id", unique=False),
)
id: Mapped[int] = mapped_column(primary_key=True)
path: Mapped[Optional[str]] = mapped_column(Text)
category: Mapped[Optional[str]] = mapped_column(Text)
package: Mapped[Optional[str]] = mapped_column(Text)
timeout: Mapped[Optional[int]] = mapped_column(Integer)
priority: Mapped[Optional[int]] = mapped_column(Integer)
options: Mapped[Optional[str]] = mapped_column(Text)
machine: Mapped[Optional[str]] = mapped_column(Text)
platform: Mapped[Optional[str]] = mapped_column(Text)
route: Mapped[Optional[str]] = mapped_column(Text)
tags: Mapped[Optional[str]] = mapped_column(Text)
custom: Mapped[Optional[str]] = mapped_column(Text)
memory: Mapped[Optional[str]] = mapped_column(Text)
clock: Mapped[datetime] = mapped_column(default=datetime.now)
enforce_timeout: Mapped[Optional[str]] = mapped_column(Text)
tlp: Mapped[Optional[str]] = mapped_column(Text)

node_id: Mapped[Optional[int]] = mapped_column(ForeignKey("node.id"), index=True)
task_id: Mapped[Optional[int]] = mapped_column(index=True)
main_task_id: Mapped[Optional[int]] = mapped_column(index=True)

finished: Mapped[bool] = mapped_column(default=False)
retrieved: Mapped[bool] = mapped_column(default=False)
notificated: Mapped[bool] = mapped_column(default=False)
deleted: Mapped[bool] = mapped_column(default=False)

def __init__(
self,
Expand Down Expand Up @@ -150,11 +164,14 @@ def __init__(
self.tlp = tlp


def create_session(db_connectionn: str, echo=False) -> sessionmaker:
# ToDo add schema version check
# 4. Modernized database initialization function
def create_session(db_connection: str, echo: bool = False) -> sessionmaker:
"""Initializes the database engine and creates tables."""
try:
engine = create_engine(db_connectionn, echo=echo) # pool_size=40, max_overflow=0,
engine = create_engine(db_connection, echo=echo)
Base.metadata.create_all(engine)
return sessionmaker(autoflush=True, bind=engine)
# Return the session factory for use in the application
return sessionmaker(bind=engine, autoflush=False)
except OperationalError as e:
sys.exit(e)
print(f"Database Error: {e}")
sys.exit(1)
11 changes: 7 additions & 4 deletions lib/cuckoo/common/integrations/capa.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@
from capa.rules import InvalidRule, InvalidRuleSet, InvalidRuleWithPath
from pydantic_core._pydantic_core import ValidationError

# Disable vivisect logging
logging.getLogger("vivisect").setLevel(logging.NOTSET)
logging.getLogger("vivisect.base").setLevel(logging.NOTSET)
logging.getLogger("vivisect.impemu").setLevel(logging.NOTSET)
# Reduce vivisect logging verbosity
logging.getLogger("vivisect").setLevel(logging.INFO)
logging.getLogger("vivisect.base").setLevel(logging.CRITICAL)
logging.getLogger("vivisect.impemu").setLevel(logging.CRITICAL)
logging.getLogger("vivisect.parsers").setLevel(logging.CRITICAL)
logging.getLogger("vivisect.tools").setLevel(logging.CRITICAL)
logging.getLogger("vivisect.analysis").setLevel(logging.CRITICAL)

rules_path = os.path.join(CUCKOO_ROOT, "data", "capa-rules")
if path_exists(rules_path):
Expand Down
Loading
Loading