Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes to make timeliner support date-less log formats #4697 #4854

Merged
merged 1 commit into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion config/dpkg/control
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Description: Data files for plaso (log2timeline)

Package: python3-plaso
Architecture: all
Depends: plaso-data (>= ${binary:Version}), libbde-python3 (>= 20220121), libcaes-python3 (>= 20240114), libcreg-python3 (>= 20200725), libesedb-python3 (>= 20220806), libevt-python3 (>= 20191104), libevtx-python3 (>= 20220724), libewf-python3 (>= 20131210), libfcrypto-python3 (>= 20240114), libfsapfs-python3 (>= 20220709), libfsext-python3 (>= 20220829), libfsfat-python3 (>= 20220925), libfshfs-python3 (>= 20220831), libfsntfs-python3 (>= 20211229), libfsxfs-python3 (>= 20220829), libfvde-python3 (>= 20220121), libfwnt-python3 (>= 20210717), libfwsi-python3 (>= 20240225), liblnk-python3 (>= 20230716), libluksde-python3 (>= 20220121), libmodi-python3 (>= 20210405), libmsiecf-python3 (>= 20150314), libolecf-python3 (>= 20151223), libphdi-python3 (>= 20220228), libqcow-python3 (>= 20201213), libregf-python3 (>= 20201002), libscca-python3 (>= 20190605), libsigscan-python3 (>= 20230109), libsmdev-python3 (>= 20140529), libsmraw-python3 (>= 20140612), libvhdi-python3 (>= 20201014), libvmdk-python3 (>= 20140421), libvsapm-python3 (>= 20230506), libvsgpt-python3 (>= 20211115), libvshadow-python3 (>= 20160109), libvslvm-python3 (>= 20160109), python3-acstore (>= 20240121), python3-artifacts (>= 20220219), python3-bencode, python3-certifi (>= 2016.9.26), python3-cffi-backend (>= 1.9.1), python3-chardet (>= 2.0.1), python3-dateutil (>= 1.5), python3-defusedxml (>= 0.5.0), python3-dfdatetime (>= 20221112), python3-dfvfs (>= 20240115), python3-dfwinreg (>= 20240229), python3-dtfabric (>= 20230518), python3-flor (>= 1.1.3), python3-future (>= 0.16.0), python3-idna (>= 2.5), python3-lz4 (>= 0.10.0), python3-opensearch, python3-pefile (>= 2021.5.24), python3-psutil (>= 5.4.3), python3-pyparsing (>= 3.0.0), python3-pytsk3 (>= 20210419), python3-redis (>= 3.4), python3-requests (>= 2.18.0), python3-six (>= 1.1.0), python3-tz, python3-urllib3 (>= 1.21.1), python3-xattr (>= 0.7.2), python3-xlsxwriter (>= 0.9.3), python3-yaml (>= 3.10), python3-yara (>= 3.4.0), python3-zmq (>= 2.1.11), python3-zstd (>= 1.3.0.2), ${misc:Depends}
Depends: plaso-data (>= ${binary:Version}), libbde-python3 (>= 20220121), libcaes-python3 (>= 20240114), libcreg-python3 (>= 20200725), libesedb-python3 (>= 20220806), libevt-python3 (>= 20191104), libevtx-python3 (>= 20220724), libewf-python3 (>= 20131210), libfcrypto-python3 (>= 20240114), libfsapfs-python3 (>= 20220709), libfsext-python3 (>= 20220829), libfsfat-python3 (>= 20220925), libfshfs-python3 (>= 20220831), libfsntfs-python3 (>= 20211229), libfsxfs-python3 (>= 20220829), libfvde-python3 (>= 20220121), libfwnt-python3 (>= 20210717), libfwsi-python3 (>= 20240225), liblnk-python3 (>= 20230716), libluksde-python3 (>= 20220121), libmodi-python3 (>= 20210405), libmsiecf-python3 (>= 20150314), libolecf-python3 (>= 20151223), libphdi-python3 (>= 20220228), libqcow-python3 (>= 20201213), libregf-python3 (>= 20201002), libscca-python3 (>= 20190605), libsigscan-python3 (>= 20230109), libsmdev-python3 (>= 20140529), libsmraw-python3 (>= 20140612), libvhdi-python3 (>= 20201014), libvmdk-python3 (>= 20140421), libvsapm-python3 (>= 20230506), libvsgpt-python3 (>= 20211115), libvshadow-python3 (>= 20160109), libvslvm-python3 (>= 20160109), python3-acstore (>= 20240121), python3-artifacts (>= 20220219), python3-bencode, python3-certifi (>= 2016.9.26), python3-cffi-backend (>= 1.9.1), python3-chardet (>= 2.0.1), python3-dateutil (>= 1.5), python3-defusedxml (>= 0.5.0), python3-dfdatetime (>= 20240330), python3-dfvfs (>= 20240115), python3-dfwinreg (>= 20240229), python3-dtfabric (>= 20230518), python3-flor (>= 1.1.3), python3-future (>= 0.16.0), python3-idna (>= 2.5), python3-lz4 (>= 0.10.0), python3-opensearch, python3-pefile (>= 2021.5.24), python3-psutil (>= 5.4.3), python3-pyparsing (>= 3.0.0), python3-pytsk3 (>= 20210419), python3-redis (>= 3.4), python3-requests (>= 2.18.0), python3-six (>= 1.1.0), python3-tz, python3-urllib3 (>= 1.21.1), python3-xattr (>= 0.7.2), python3-xlsxwriter (>= 0.9.3), python3-yaml (>= 3.10), python3-yara (>= 3.4.0), python3-zmq (>= 2.1.11), python3-zstd (>= 1.3.0.2), ${misc:Depends}
Description: Python 3 module of plaso (log2timeline)
Plaso (log2timeline) is a framework to create super timelines. Its
purpose is to extract timestamps from various files found on typical
Expand Down
2 changes: 1 addition & 1 deletion dependencies.ini
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ version_property: __version__

[dfdatetime]
dpkg_name: python3-dfdatetime
minimum_version: 20221112
minimum_version: 20240330
rpm_name: python3-dfdatetime
version_property: __version__

Expand Down
18 changes: 9 additions & 9 deletions docs/sources/user/Using-log2timeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,19 @@ Checking availability and versions of dependencies.
[OK]


Source path : /PATH/image.E01
Source type : storage media image
Processing time : 00:00:00
Source path : /PATH/image.E01
Source type : storage media image
Processing time : 00:00:00

Processing started.
```

```bash
plaso - log2timeline version 20210412

Source path : /PATH/image.E01
Source type : storage media image
Processing time : 00:04:57
Source path : /PATH/image.E01
Source type : storage media image
Processing time : 00:04:57

Tasks: Queued Processing Merging Abandoned Total
0 0 0 0 18675
Expand Down Expand Up @@ -186,9 +186,9 @@ every discovered file. To do more targeted extraction a filter file can be used.
```bash
$ log2timeline.py -f filter --storage-file timeline.plaso test.vhd

Source path : /PATH/test.vhd
Source type : storage media image
Filter file : filter
Source path : /PATH/test.vhd
Source type : storage media image
Filter file : filter

Processing started.
...
Expand Down
4 changes: 2 additions & 2 deletions plaso/cli/status_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ def _PrintAnalysisStatusHeader(self, processing_status):
f'Storage file\t\t: {self._storage_file_path:s}\n')

processing_time = self._FormatProcessingTime(processing_status)
self._output_writer.Write(f'Processing time\t\t: {processing_time:s}\n')
self._output_writer.Write(f'Processing time\t: {processing_time:s}\n')

if processing_status and processing_status.events_status:
self._PrintEventsStatus(processing_status.events_status)
Expand Down Expand Up @@ -525,7 +525,7 @@ def PrintExtractionStatusHeader(self, processing_status):
self._output_writer.Write(f'Filter file\t\t: {self._filter_file:s}\n')

processing_time = self._FormatProcessingTime(processing_status)
self._output_writer.Write(f'Processing time\t\t: {processing_time:s}\n')
self._output_writer.Write(f'Processing time\t: {processing_time:s}\n')

self._PrintTasksStatus(processing_status)
self._output_writer.Write('\n')
Expand Down
47 changes: 47 additions & 0 deletions plaso/containers/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class DateLessLogHelper(interface.AttributeContainer):
Attributes:
earliest_date (list[int, int, int]): earliest possible date the event data
stream was created. The date is a tuple of year, month and day of month.
granularity (str): granularity of the date-less log format.
last_relative_date (list[int, int, int]): last relative date determined by
the date-less log helper. The date is a tuple of year, month and day of
month.
Expand All @@ -100,17 +101,25 @@ class DateLessLogHelper(interface.AttributeContainer):
SCHEMA = {
'_event_data_stream_identifier': 'AttributeContainerIdentifier',
'earliest_date': 'List[int]',
'granularity': 'str',
'last_relative_date': 'List[int]',
'latest_date': 'List[int]'}

_SERIALIZABLE_PROTECTED_ATTRIBUTES = [
'_event_data_stream_identifier']

# The date-less log format only supports time.
GRANULARITY_NO_DATE = 'd'

# The date-less log format only supports month and day of month.
GRANULARITY_NO_YEARS = 'y'

def __init__(self):
"""Initializes a date-less log helper attribute container."""
super(DateLessLogHelper, self).__init__()
self._event_data_stream_identifier = None
self.earliest_date = None
self.granularity = self.GRANULARITY_NO_YEARS
self.last_relative_date = None
self.latest_date = None

Expand All @@ -123,9 +132,22 @@ def CopyFromYearLessLogHelper(self, year_less_log_helper):
year_less_log_helper (YearLessLogHelper): year-less log helper.
"""
self.earliest_date = (year_less_log_helper.earliest_year, 1, 1)
self.granularity = self.GRANULARITY_NO_YEARS
self.last_relative_date = (year_less_log_helper.last_relative_year, 0, 0)
self.latest_date = (year_less_log_helper.latest_year, 1, 1)

def GetEarliestDate(self):
"""Retrieves the earliest date adjusted to the granularity.

Returns:
tuple[int, int, int]: earliest date as tuple of year, month and day of
month or None if not available.
"""
if self.earliest_date and self.granularity == self.GRANULARITY_NO_YEARS:
return self.earliest_date[0], 0, 0

return self.earliest_date

def GetEventDataStreamIdentifier(self):
"""Retrieves the identifier of the associated event data stream.

Expand All @@ -137,6 +159,31 @@ def GetEventDataStreamIdentifier(self):
"""
return self._event_data_stream_identifier

def GetLastRelativeDate(self):
"""Retrieves the last relative date adjusted to the granularity.

Returns:
tuple[int, int, int]: last relative date as tuple of year, month and day
of month or None if not available.
"""
if (self.last_relative_date and
self.granularity == self.GRANULARITY_NO_YEARS):
return self.last_relative_date[0], 0, 0

return self.last_relative_date

def GetLatestDate(self):
"""Retrieves the latest date adjusted to the granularity.

Returns:
tuple[int, int, int]: latest date as tuple of year, month and day of
month or None if not available.
"""
if self.latest_date and self.granularity == self.GRANULARITY_NO_YEARS:
return self.latest_date[0], 0, 0

return self.latest_date

def SetEventDataStreamIdentifier(self, event_data_stream_identifier):
"""Sets the identifier of the associated event data stream.

Expand Down
2 changes: 1 addition & 1 deletion plaso/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
'certifi': ('__version__', '2016.9.26', None, True),
'dateutil': ('__version__', '1.5', None, True),
'defusedxml': ('__version__', '0.5.0', None, True),
'dfdatetime': ('__version__', '20221112', None, True),
'dfdatetime': ('__version__', '20240330', None, True),
'dfvfs': ('__version__', '20240115', None, True),
'dfwinreg': ('__version__', '20240229', None, True),
'dtfabric': ('__version__', '20230518', None, True),
Expand Down
105 changes: 66 additions & 39 deletions plaso/engine/timeliner.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def __init__(
"""
super(EventDataTimeliner, self).__init__()
self._attribute_mappings = {}
self._base_years = {}
self._current_year = self._GetCurrentYear()
self._base_dates = {}
self._current_date = self._GetCurrentDate()
self._data_location = data_location
self._place_holder_event = set()
self._preferred_time_zone = None
Expand Down Expand Up @@ -75,92 +75,119 @@ def _CreateTimeZonePerPathSpec(self, system_configurations):
self._time_zone_per_path_spec[path_spec.parent] = (
system_configuration.time_zone)

def _GetBaseYear(self, storage_writer, event_data):
"""Retrieves the base year.
def _GetBaseDate(self, storage_writer, event_data):
"""Retrieves the base date.

Args:
storage_writer (StorageWriter): storage writer.
event_data (EventData): event data.

Returns:
int: base year.
tuple[int, int, int]: base date, as a tuple of year, month, day of month.
"""
# If preferred year is set considered it a user override, otherwise try
# to determine the year based on the date-less log helper or fallback to
# the current year.

if self._preferred_year:
return self._preferred_year
current_date = (self._preferred_year, 1, 1)
else:
current_date = self._current_date

event_data_stream_identifier = event_data.GetEventDataStreamIdentifier()
if not event_data_stream_identifier:
return self._current_year
return current_date[0], 0, 0

lookup_key = event_data_stream_identifier.CopyToString()

base_year = self._base_years.get(lookup_key, None)
if base_year:
return base_year
base_date = self._base_dates.get(lookup_key, None)
if base_date:
return base_date

filter_expression = f'_event_data_stream_identifier == "{lookup_key:s}"'
date_less_log_helpers = list(storage_writer.GetAttributeContainers(
events.DateLessLogHelper.CONTAINER_TYPE,
filter_expression=filter_expression))
if not date_less_log_helpers:
message = (
f'missing date-less log helper, defaulting to current year: '
f'{self._current_year:d}')
f'missing date-less log helper, defaulting to date: '
f'{current_date[0]:d}-{current_date[1]:d}-{current_date[2]:d}')
self._ProduceTimeliningWarning(storage_writer, event_data, message)

base_year = self._current_year
base_date = (current_date[0], 0, 0)

else:
earliest_date = date_less_log_helpers[0].earliest_date
last_relative_date = date_less_log_helpers[0].last_relative_date
latest_date = date_less_log_helpers[0].latest_date
date_less_log_helper = date_less_log_helpers[0]

earliest_date = date_less_log_helper.GetEarliestDate()
last_relative_date = date_less_log_helper.GetLastRelativeDate()
latest_date = date_less_log_helper.GetLatestDate()

if date_less_log_helper.granularity == (
date_less_log_helper.GRANULARITY_NO_YEARS):
current_date = (current_date[0], 0, 0)

if earliest_date is None or last_relative_date is None:
last_date = None
else:
last_date = tuple(map(
lambda earliest, last_relative: earliest + last_relative,
earliest_date, last_relative_date))

if earliest_date is None and latest_date is None:
message = (
f'missing earliest and latest year in date-less log helper, '
f'defaulting to current year: {self._current_year:d}')
f'missing earliest and latest date in date-less log helper, '
f'defaulting to date: {current_date[0]:d}-{current_date[1]:d}-'
f'{current_date[2]:d}')
self._ProduceTimeliningWarning(storage_writer, event_data, message)

base_year = self._current_year
base_date = current_date

elif earliest_date[0] + last_relative_date[0] < self._current_year:
base_year = earliest_date[0]
elif last_date < current_date:
base_date = earliest_date

elif latest_date[0] < self._current_year:
elif latest_date < current_date:
message = (
f'earliest year: {earliest_date[0]:d} as base year would exceed '
f'current year: {self._current_year:d} + '
f'{last_relative_date[0]:d}, using latest year: {latest_date[0]:d}')
f'earliest date: {earliest_date[0]:d}-{earliest_date[1]:d}-'
f'{earliest_date[2]:d} as base date would exceed : '
f'{current_date[0]:d}-{current_date[1]:d}-{current_date[2]:d} + '
f'{last_relative_date[0]:d}-{last_relative_date[1]:d}-'
f'{last_relative_date[2]:d}, using latest date: {latest_date[0]:d}-'
f'{latest_date[1]:d}-{latest_date[2]:d}')
self._ProduceTimeliningWarning(storage_writer, event_data, message)

base_year = latest_date[0] - last_relative_date[0]
base_date = tuple(map(
lambda latest, last_relative: latest - last_relative,
latest_date, last_relative_date))

else:
message = (
f'earliest year: {earliest_date[0]:d} and latest: year: '
f'{latest_date[0]:d} as base year would exceed current year: '
f'{self._current_year:d} + {last_relative_date[0]:d}, using '
f'current year')
f'earliest date: {earliest_date[0]:d}-{earliest_date[1]:d}-'
f'{earliest_date[2]:d} and latest: date: {latest_date[0]:d}-'
f'{latest_date[1]:d}-{latest_date[2]:d} as base date would exceed '
f'date: {current_date[0]:d}-{current_date[1]:d}-'
f'{current_date[2]:d} + {last_relative_date[0]:d}-'
f'{last_relative_date[1]:d}-{last_relative_date[2]:d}, using date: '
f'{current_date[0]:d}-{current_date[1]:d}-{current_date[2]:d}')
self._ProduceTimeliningWarning(storage_writer, event_data, message)

base_year = self._current_year - last_relative_date[0]
base_date = tuple(map(
lambda current, last_relative: current - last_relative,
current_date, last_relative_date))

self._base_years[lookup_key] = base_year
self._base_dates[lookup_key] = base_date

return base_year
return base_date

def _GetCurrentYear(self):
"""Retrieves current year.
def _GetCurrentDate(self):
"""Retrieves current date.

Returns:
int: the current year.
tuple[int, int, int]: current date, as a tuple of year, month, day of
month.
"""
datetime_object = datetime.datetime.now(pytz.UTC)
return datetime_object.year
return datetime_object.year, datetime_object.month, datetime_object.day

def _GetEvent(
self, storage_writer, event_data, event_data_stream, date_time,
Expand All @@ -180,10 +207,10 @@ def _GetEvent(
"""
timestamp = None
if date_time.is_delta:
base_year = self._GetBaseYear(storage_writer, event_data)
base_date = self._GetBaseDate(storage_writer, event_data)

try:
date_time = date_time.NewFromDeltaAndYear(base_year)
date_time = date_time.NewFromDeltaAndDate(*base_date)
except ValueError as exception:
self._ProduceTimeliningWarning(
storage_writer, event_data, str(exception))
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ bencode.py
certifi >= 2016.9.26
cffi >= 1.9.1
defusedxml >= 0.5.0
dfdatetime >= 20221112
dfdatetime >= 20240330
dfvfs >= 20240115
dfwinreg >= 20240229
dtfabric >= 20230518
Expand Down
Loading
Loading