Skip to content

Commit fe2e337

Browse files
doomedravenjershmagershdependabot[bot]actions-user
authored
Use UTC-aware datetimes for task and machine timestamps (#2841)
* Adding fix for yara-python installation (#2825) * Bump aiohttp from 3.13.2 to 3.13.3 (#2826) --- updated-dependencies: - dependency-name: aiohttp dependency-version: 3.13.3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump pynacl from 1.5.0 to 1.6.2 (#2828) Bumps [pynacl](https://github.com/pyca/pynacl) from 1.5.0 to 1.6.2. - [Changelog](https://github.com/pyca/pynacl/blob/main/CHANGELOG.rst) - [Commits](pyca/pynacl@1.5.0...1.6.2) --- updated-dependencies: - dependency-name: pynacl dependency-version: 1.6.2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump urllib3 from 2.3.0 to 2.6.3 (#2832) Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.3.0 to 2.6.3. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](urllib3/urllib3@2.3.0...2.6.3) --- updated-dependencies: - dependency-name: urllib3 dependency-version: 2.6.3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update behavior.py * Bump pypdf from 5.2.0 to 6.6.0 (#2835) Bumps [pypdf](https://github.com/py-pdf/pypdf) from 5.2.0 to 6.6.0. - [Release notes](https://github.com/py-pdf/pypdf/releases) - [Changelog](https://github.com/py-pdf/pypdf/blob/main/CHANGELOG.md) - [Commits](py-pdf/pypdf@5.2.0...6.6.0) --- updated-dependencies: - dependency-name: pypdf dependency-version: 6.6.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump werkzeug from 3.1.4 to 3.1.5 (#2834) Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.1.4 to 3.1.5. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst) - [Commits](pallets/werkzeug@3.1.4...3.1.5) --- updated-dependencies: - dependency-name: werkzeug dependency-version: 3.1.5 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * ci: Update requirements.txt * Bump aiohttp from 3.13.2 to 3.13.3 (#2837) --- updated-dependencies: - dependency-name: aiohttp dependency-version: 3.13.3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump urllib3 from 2.3.0 to 2.6.3 (#2836) Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.3.0 to 2.6.3. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](urllib3/urllib3@2.3.0...2.6.3) --- updated-dependencies: - dependency-name: urllib3 dependency-version: 2.6.3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix mongo_search_query not defined when hash doesnt exist in mongodb * webgui timezone moved to config * Use UTC-aware datetimes for task and machine timestamps ✦ I have standardized the timestamps in lib/cuckoo/core/database.py to use naive UTC, ensuring consistency across the database schema and logic. Summary of Changes: 1. Defaults: Updated Guest.started_on to use a naive UTC lambda default (lambda: datetime.now(timezone.utc).replace(tzinfo=None)). 2. Logic: Replaced all occurrences of datetime.now() (local time) and datetime.utcnow() (deprecated) with datetime.now(timezone.utc).replace(tzinfo=None) in the following methods: - set_task_status - lock_machine / unlock_machine - set_machine_status - guest_stop - check_file_uniq - add (for PCAP/Static) - clean_timed_out_tasks - update_clock 3. Fixes: - Fixed minmax_tasks to correctly handle naive UTC timestamps when converting to Unix timestamps (preventing local timezone offset issues). - Updated datetime.utcfromtimestamp(0) calls to datetime.fromtimestamp(0, timezone.utc).replace(tzinfo=None). This ensures that all timestamps stored and processed in lib/cuckoo/core/database.py are consistently naive UTC. Note on Tests: The file tests/test_database.py contains assertions using datetime.datetime.now() (local time). Depending on your testing environment's timezone and freezegun configuration, you may need to update those tests to expect naive UTC timestamps to match these changes. * fix --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Josh R. <jershmagersh@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: GitHub Actions <action@github.com>
1 parent d8572ce commit fe2e337

File tree

10 files changed

+183
-167
lines changed

10 files changed

+183
-167
lines changed

conf/default/web.conf.default

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ disposable_email_disable = yes
2929
disposable_domain_list = data/safelist/disposable_domain_list.txt
3030

3131
[general]
32+
timezone = UTC
3233
# Prescan new file tasks with YARA for sample identification and custom execution
3334
# Useful to set options, tags, timeout, etc for packers/obfuscators/cryptors
3435
yara_recon = no

installer/cape2.sh

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -802,16 +802,14 @@ function install_yara_python() {
802802
--config-settings=\"--global-option=build\" \
803803
--config-settings=\"--global-option=--enable-cuckoo\" \
804804
--config-settings=\"--global-option=--enable-magic\" \
805-
--config-settings=\"--global-option=--enable-profiling\" \
806-
--config-settings=\"--global-option=--dynamic-linking\""
805+
--config-settings=\"--global-option=--enable-profiling\""
807806
else
808807
sudo -u ${USER} $PYTHON_MGR --directory $CAPE_ROOT $PYTHON_MGR_CMD pip install yara-python \
809808
--no-binary :all: \
810809
--config-settings="--global-option=build" \
811810
--config-settings="--global-option=--enable-cuckoo" \
812811
--config-settings="--global-option=--enable-magic" \
813-
--config-settings="--global-option=--enable-profiling" \
814-
--config-settings="--global-option=--dynamic-linking"
812+
--config-settings="--global-option=--enable-profiling"
815813
fi
816814

817815
# Install from local source (commented out)

lib/cuckoo/common/web_utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,8 @@ def perform_search(
14221422
{"$project": perform_search_filters},
14231423
]
14241424
retval = list(mongo_aggregate(FILES_COLL, pipeline))
1425+
if not retval:
1426+
return []
14251427
elif isinstance(search_term_map[term], str):
14261428
mongo_search_query = {search_term_map[term]: query_val}
14271429
elif isinstance(search_term_map[term], list):

lib/cuckoo/core/database.py

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
from datetime import datetime, timedelta, timezone
1515
from typing import Any, List, Optional, Union, Tuple, Dict
1616

17+
18+
def _utcnow_naive():
19+
"""Returns the current time in UTC as a naive datetime object."""
20+
return datetime.now(timezone.utc).replace(tzinfo=None)
21+
22+
1723
# Sflock does a good filetype recon
1824
from sflock.abstracts import File as SflockFile
1925
from sflock.ident import identify as sflock_identify
@@ -307,7 +313,9 @@ class Guest(Base):
307313
platform: Mapped[str] = mapped_column(nullable=False)
308314
manager: Mapped[str] = mapped_column(nullable=False)
309315

310-
started_on: Mapped[datetime] = mapped_column(DateTime(timezone=False), default=datetime.now, nullable=False)
316+
started_on: Mapped[datetime] = mapped_column(
317+
DateTime(timezone=False), default=_utcnow_naive, nullable=False
318+
)
311319
shutdown_on: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=False), nullable=True)
312320
task_id: Mapped[int] = mapped_column(ForeignKey("tasks.id", ondelete="cascade"), nullable=False, unique=True)
313321
task: Mapped["Task"] = relationship(back_populates="guest")
@@ -474,12 +482,12 @@ class Task(Base):
474482
enforce_timeout: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
475483
clock: Mapped[datetime] = mapped_column(
476484
DateTime(timezone=False),
477-
default=lambda: datetime.now(timezone.utc).replace(tzinfo=None),
485+
default=_utcnow_naive,
478486
nullable=False,
479487
)
480488
added_on: Mapped[datetime] = mapped_column(
481489
DateTime(timezone=False),
482-
default=lambda: datetime.now(timezone.utc).replace(tzinfo=None),
490+
default=_utcnow_naive,
483491
nullable=False,
484492
)
485493
started_on: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=False), nullable=True)
@@ -818,23 +826,23 @@ def update_clock(self, task_id):
818826
if not row:
819827
return
820828
# datetime.fromtimestamp(0, tz=timezone.utc)
821-
if row.clock == datetime.utcfromtimestamp(0):
829+
if row.clock == datetime.fromtimestamp(0, timezone.utc).replace(tzinfo=None):
822830
if row.category == "file":
823831
# datetime.now(timezone.utc)
824-
row.clock = datetime.utcnow() + timedelta(days=self.cfg.cuckoo.daydelta)
832+
row.clock = _utcnow_naive() + timedelta(days=self.cfg.cuckoo.daydelta)
825833
else:
826834
# datetime.now(timezone.utc)
827-
row.clock = datetime.utcnow()
835+
row.clock = _utcnow_naive()
828836
return row.clock
829837

830838
def set_task_status(self, task: Task, status) -> Task:
831839
if status != TASK_DISTRIBUTED_COMPLETED:
832840
task.status = status
833841

834842
if status in (TASK_RUNNING, TASK_DISTRIBUTED):
835-
task.started_on = datetime.now()
843+
task.started_on = _utcnow_naive()
836844
elif status in (TASK_COMPLETED, TASK_DISTRIBUTED_COMPLETED):
837-
task.completed_on = datetime.now()
845+
task.completed_on = _utcnow_naive()
838846

839847
self.session.add(task)
840848
return task
@@ -965,7 +973,7 @@ def guest_stop(self, guest_id):
965973
"""
966974
guest = self.session.get(Guest, guest_id)
967975
if guest:
968-
guest.shutdown_on = datetime.now()
976+
guest.shutdown_on = _utcnow_naive()
969977

970978
@staticmethod
971979
def filter_machines_by_arch(statement: Select, arch: list) -> Select:
@@ -1061,7 +1069,7 @@ def lock_machine(self, machine: Machine) -> Machine:
10611069
@return: locked machine
10621070
"""
10631071
machine.locked = True
1064-
machine.locked_changed_on = datetime.now()
1072+
machine.locked_changed_on = _utcnow_naive()
10651073
self.set_machine_status(machine, MACHINE_RUNNING)
10661074
self.session.add(machine)
10671075

@@ -1073,7 +1081,7 @@ def unlock_machine(self, machine: Machine) -> Machine:
10731081
@return: unlocked machine
10741082
"""
10751083
machine.locked = False
1076-
machine.locked_changed_on = datetime.now()
1084+
machine.locked_changed_on = _utcnow_naive()
10771085
self.session.merge(machine)
10781086
return machine
10791087

@@ -1119,7 +1127,7 @@ def set_machine_status(self, machine_or_label: Union[str, Machine], status):
11191127

11201128
if machine:
11211129
machine.status = status
1122-
machine.status_changed_on = datetime.now()
1130+
machine.status_changed_on = _utcnow_naive()
11231131
# No need for session.add() here; the ORM tracks changes to loaded objects.
11241132

11251133
def add_error(self, message, task_id):
@@ -1250,7 +1258,7 @@ def add(
12501258

12511259
if isinstance(obj, (PCAP, Static)):
12521260
# since no VM will operate on this PCAP
1253-
task.started_on = datetime.now()
1261+
task.started_on = _utcnow_naive()
12541262

12551263
elif isinstance(obj, URL):
12561264
task = Task(obj.url)
@@ -1292,12 +1300,12 @@ def add(
12921300
task.clock = datetime.strptime(clock, "%m-%d-%Y %H:%M:%S")
12931301
except ValueError:
12941302
log.warning("The date you specified has an invalid format, using current timestamp")
1295-
task.clock = datetime.utcfromtimestamp(0)
1303+
task.clock = datetime.fromtimestamp(0, timezone.utc).replace(tzinfo=None)
12961304

12971305
else:
12981306
task.clock = clock
12991307
else:
1300-
task.clock = datetime.utcfromtimestamp(0)
1308+
task.clock = datetime.fromtimestamp(0, timezone.utc).replace(tzinfo=None)
13011309

13021310
task.user_id = user_id
13031311

@@ -1982,7 +1990,7 @@ def check_file_uniq(self, sha256: str, hours: int = 0):
19821990
# sha256 is unique.
19831991
uniq = False
19841992
if hours and sha256:
1985-
date_since = datetime.now() - timedelta(hours=hours)
1993+
date_since = _utcnow_naive() - timedelta(hours=hours)
19861994

19871995
stmt = (
19881996
select(Task)
@@ -2225,7 +2233,7 @@ def clean_timed_out_tasks(self, timeout: int):
22252233
return
22262234

22272235
# Calculate the cutoff time before which tasks are considered timed out.
2228-
timeout_threshold = datetime.utcnow() - timedelta(seconds=timeout)
2236+
timeout_threshold = _utcnow_naive() - timedelta(seconds=timeout)
22292237

22302238
# Build a single, efficient DELETE statement that filters in the database.
22312239
delete_stmt = delete(Task).where(Task.status == TASK_PENDING).where(Task.added_on < timeout_threshold)
@@ -2246,7 +2254,7 @@ def minmax_tasks(self) -> Tuple[int, int]:
22462254

22472255
if min_val and max_val:
22482256
# .timestamp() is the modern way to get a unix timestamp.
2249-
return int(min_val.timestamp()), int(max_val.timestamp())
2257+
return int(min_val.replace(tzinfo=timezone.utc).timestamp()), int(max_val.replace(tzinfo=timezone.utc).timestamp())
22502258

22512259
return 0, 0
22522260

modules/processing/behavior.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def parse_first_and_reset(self):
127127

128128
if self.use_mmap:
129129
self.mm_pos = 0
130-
else:
130+
elif self.fd:
131131
self.fd.seek(0)
132132

133133
def read(self, length):

poetry.lock

Lines changed: 7 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ dependencies = [
7474
"psutil==6.1.1",
7575
"peepdf-3==5.0.0",
7676
"pyre2>=0.3.10",
77-
"Werkzeug==3.1.4",
77+
"Werkzeug==3.1.5",
7878
"packaging==24.2",
7979
"setuptools==78.1.1",
8080
# command line config manipulation

0 commit comments

Comments
 (0)