Import from old repository

This commit is contained in:
Stefan
2020-04-06 18:48:34 +02:00
commit 0da6783a45
762 changed files with 103065 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2013 The Plaso Project Authors.
# Please see the AUTHORS file for details on individual authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This file contains an import statement for each bencode related plugin."""
from plaso.parsers.bencode_plugins import transmission
from plaso.parsers.bencode_plugins import utorrent
+205
View File
@@ -0,0 +1,205 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright 2013 The Plaso Project Authors.
# Please see the AUTHORS file for details on individual authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""bencode_interface contains basic interface for bencode plugins within Plaso.
Bencoded files are only one example of a type of object that the Plaso tool is
expected to encounter and process. There can be and are many other parsers
which are designed to process specific data types.
BencodePlugin defines the attributes necessary for registration, discovery
and operation of plugins for bencoded files which will be used by
BencodeParser.
"""
import abc
import logging
from plaso.lib import errors
from plaso.parsers import plugins
class BencodePlugin(plugins.BasePlugin):
"""This is an abstract class from which plugins should be based."""
# BENCODE_KEYS is a list of keys required by a plugin.
# This is expected to be overridden by the processing plugin.
# Ex. frozenset(['activity-date', 'done-date'])
BENCODE_KEYS = frozenset(['any'])
# This is expected to be overridden by the processing plugin.
# URLS should contain a list of URLs with additional information about
# this key or value.
# Ex. ['https://wiki.theory.org/BitTorrentSpecification#Bencoding']
URLS = []
NAME = 'bencode'
def _GetKeys(self, data, keys, depth=1):
"""Helper function to return keys nested in a bencode dict.
By default this function will return the values for the named keys requested
by a plugin in match{}. The default setting is to look a single layer down
from the root (same as the check for plugin applicability). This level is
suitable for most cases.
For cases where there is variability in the name at the first level
(e.g. it is the MAC addresses of a device, or a UUID) it is possible to
override the depth limit and use _GetKeys to fetch from a deeper level.
Args:
data: bencode data in dictionary form.
keys: A list of keys that should be returned.
depth: Defines how many levels deep to check for a match.
Returns:
A dictionary with just the keys requested.
"""
keys = set(keys)
match = {}
if depth == 1:
for key in keys:
match[key] = data[key]
else:
for _, parsed_key, parsed_value in self._RecurseKey(
data, depth=depth):
if parsed_key in keys:
match[parsed_key] = parsed_value
if set(match.keys()) == keys:
return match
return match
def _RecurseKey(self, recur_item, root='', depth=15):
"""Flattens nested dictionaries and lists by yielding it's values.
The hierarchy of a bencode file is a series of nested dictionaries and
lists. This is a helper function helps plugins navigate the structure
without having to reimplement their own recursive methods.
This method implements an overridable depth limit to prevent processing
extremely deeply nested dictionaries. If the limit is reached a debug
message is logged indicating which key processing stopped on.
Args:
recur_item: An object to be checked for additional nested items.
root: The pathname of the current working key.
depth: A counter to ensure we stop at the maximum recursion depth.
Yields:
A tuple of the root, key, and value from a bencoded file.
"""
if depth < 1:
logging.debug(u'Recursion limit hit for key: {0:s}'.format(root))
return
if type(recur_item) in (list, tuple):
for recur in recur_item:
for key in self._RecurseKey(recur, root, depth):
yield key
return
if not hasattr(recur_item, 'iteritems'):
return
for key, value in recur_item.iteritems():
yield root, key, value
if isinstance(value, dict):
value = [value]
if isinstance(value, list):
for item in value:
if isinstance(item, dict):
for keyval in self._RecurseKey(
item, root=root + u'/' + key, depth=depth - 1):
yield keyval
@abc.abstractmethod
def GetEntries(
self, parser_context, file_entry=None, parser_chain=None, data=None,
match=None, **kwargs):
"""Extracts event object from the values of entries within a bencoded file.
This is the main method that a bencode plugin needs to implement.
The contents of the bencode keys defined in BENCODE_KEYS can be made
available to the plugin as both a matched{'KEY': 'value'} and as the
entire bencoded data dictionary. The plugin should implement logic to parse
the most relevant data set into a useful event for incorporation into the
Plaso timeline.
The attributes for a BencodeEvent should include the following:
root = Root key this event was extracted from.
key = Key the value resided in.
time = Date this artifact was created in microseconds(usec) from epoch.
desc = Short description.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
data: Bencode data in dictionary form. The default is None.
match: Optional dictionary containing only the keys selected in the
BENCODE_KEYS. The default is None.
"""
def Process(
self, parser_context, file_entry=None, parser_chain=None,
data=None, **kwargs):
"""Determine if this is the correct plugin; if so proceed with processing.
Process() checks if the current bencode file being processed is a match for
a plugin by comparing the PATH and KEY requirements defined by a plugin. If
both match processing continues; else raise WrongBencodePlugin.
This function also extracts the required keys as defined in
self.BENCODE_KEYS from the file and stores the result in match[key]
and calls self.GetEntries() which holds the processing logic implemented by
the plugin.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
data: Bencode data in dictionary form. The default is None.
Raises:
WrongBencodePlugin: If this plugin is not able to process the given file.
ValueError: If top level is not set.
"""
if data is None:
raise ValueError(u'Data is not set.')
if not set(data.keys()).issuperset(self.BENCODE_KEYS):
raise errors.WrongBencodePlugin(self.NAME)
# This will raise if unhandled keyword arguments are passed.
super(BencodePlugin, self).Process(parser_context, **kwargs)
logging.debug(u'Bencode Plugin Used: {0:s}'.format(self.NAME))
match = self._GetKeys(data, self.BENCODE_KEYS, 3)
# Add ourselves to the parser chain, which will be used in all subsequent
# event creation in this parser.
parser_chain = self._BuildParserChain(parser_chain)
self.GetEntries(
parser_context, file_entry=file_entry, parser_chain=parser_chain,
data=data, match=match)
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright 2014 The Plaso Project Authors.
# Please see the AUTHORS file for details on individual authors.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Bencode plugin related functions and classes for testing."""
from plaso.parsers import test_lib
class BencodePluginTestCase(test_lib.ParserTestCase):
"""The unit test case for a bencode plugin."""
@@ -0,0 +1,102 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright 2013 The Plaso Project Authors.
# Please see the AUTHORS file for details on individual authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This file contains a bencode plugin for Transmission BitTorrent data."""
from plaso.events import time_events
from plaso.lib import eventdata
from plaso.parsers import bencode_parser
from plaso.parsers.bencode_plugins import interface
class TransmissionEvent(time_events.PosixTimeEvent):
"""Convenience class for a Transmission BitTorrent activity event."""
DATA_TYPE = 'p2p:bittorrent:transmission'
def __init__(self, timestamp, timestamp_description, destination, seedtime):
"""Initializes the event.
Args:
timestamp: The POSIX timestamp of the event.
timestamp_desc: A short description of the meaning of the timestamp.
destination: Downloaded file name within .torrent file
seedtime: Number of seconds client seeded torrent
"""
super(TransmissionEvent, self).__init__(timestamp, timestamp_description)
self.destination = destination
self.seedtime = seedtime // 60 # Convert seconds to minutes.
class TransmissionPlugin(interface.BencodePlugin):
"""Parse Transmission BitTorrent activity file for current torrents."""
NAME = 'bencode_transmission'
DESCRIPTION = u'Parser for Transmission bencoded files.'
BENCODE_KEYS = frozenset([
'activity-date', 'done-date', 'added-date', 'destination',
'seeding-time-seconds'])
def GetEntries(
self, parser_context, file_entry=None, parser_chain=None, data=None,
**unused_kwargs):
"""Extract data from Transmission's resume folder files.
This is the main parsing engine for the parser. It determines if
the selected file is the proper file to parse and extracts current
running torrents.
Transmission stores an individual Bencoded file for each active download
in a folder named resume under the user's application data folder.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
data: Optional bencode data in dictionary form. The default is None.
"""
# Place the obtained values into the event.
destination = data.get('destination', None)
seeding_time = data.get('seeding-time-seconds', None)
# Create timeline events based on extracted values.
if data.get('added-date', 0):
event_object = TransmissionEvent(
data.get('added-date'), eventdata.EventTimestamp.ADDED_TIME,
destination, seeding_time)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
if data.get('done-date', 0):
event_object = TransmissionEvent(
data.get('done-date'), eventdata.EventTimestamp.FILE_DOWNLOADED,
destination, seeding_time)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
if data.get('activity-date', None):
event_object = TransmissionEvent(
data.get('activity-date'), eventdata.EventTimestamp.ACCESS_TIME,
destination, seeding_time)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
bencode_parser.BencodeParser.RegisterPlugin(TransmissionPlugin)
+137
View File
@@ -0,0 +1,137 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright 2013 The Plaso Project Authors.
# Please see the AUTHORS file for details on individual authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This file contains a bencode plugin for uTorrent data."""
from plaso.events import time_events
from plaso.lib import errors
from plaso.lib import eventdata
from plaso.parsers import bencode_parser
from plaso.parsers.bencode_plugins import interface
class UTorrentEvent(time_events.PosixTimeEvent):
"""Convenience class for a uTorrent active torrents history entries."""
DATA_TYPE = 'p2p:bittorrent:utorrent'
def __init__(
self, timestamp, timestamp_description, path, caption, seedtime):
"""Initialize the event.
Args:
path: Torrent download location
caption: Official name of package
seedtime: Number of seconds client seeded torrent
"""
super(UTorrentEvent, self).__init__(timestamp, timestamp_description)
self.path = path
self.caption = caption
self.seedtime = seedtime // 60 # Convert seconds to minutes.
class UTorrentPlugin(interface.BencodePlugin):
"""Plugin to extract uTorrent active torrent events."""
NAME = 'bencode_utorrent'
DESCRIPTION = u'Parser for uTorrent bencoded files.'
# The following set is used to determine if the bencoded data is appropriate
# for this plugin. If there's a match, the entire bencoded data block is
# returned for analysis.
BENCODE_KEYS = frozenset(['.fileguard'])
def GetEntries(
self, parser_context, file_entry=None, parser_chain=None, data=None,
**unused_kwargs):
"""Extracts uTorrent active torrents.
This is the main parsing engine for the plugin. It determines if
the selected file is the proper file to parse and extracts current
running torrents.
interface.Process() checks for the given BENCODE_KEYS set, ensures
that it matches, and then passes the bencoded data to this function for
parsing. This plugin then parses the entire set of bencoded data to extract
the variable file-name keys to retrieve their values.
uTorrent creates a file, resume.dat, and a backup, resume.dat.old, to
for all active torrents. This is typically stored in the user's
application data folder.
These files, at a minimum, contain a '.fileguard' key and a dictionary
with a key name for a particular download with a '.torrent' file
extension.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
data: Optional bencode data in dictionary form. The default is None.
"""
# Walk through one of the torrent keys to ensure it's from a valid file.
for key, value in data.iteritems():
if not u'.torrent' in key:
continue
caption = value.get('caption')
path = value.get('path')
seedtime = value.get('seedtime')
if not caption or not path or seedtime < 0:
raise errors.WrongBencodePlugin(self.NAME)
for torrent, value in data.iteritems():
if not u'.torrent' in torrent:
continue
path = value.get('path', None)
caption = value.get('caption', None)
seedtime = value.get('seedtime', None)
# Create timeline events based on extracted values.
for event_key, event_value in value.iteritems():
if event_key == 'added_on':
event_object = UTorrentEvent(
event_value, eventdata.EventTimestamp.ADDED_TIME,
path, caption, seedtime)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
elif event_key == 'completed_on':
event_object = UTorrentEvent(
event_value, eventdata.EventTimestamp.FILE_DOWNLOADED,
path, caption, seedtime)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
elif event_key == 'modtimes':
for modtime in event_value:
# Some values are stored as 0, skip those.
if not modtime:
continue
event_object = UTorrentEvent(
modtime, eventdata.EventTimestamp.MODIFICATION_TIME,
path, caption, seedtime)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain,
file_entry=file_entry)
bencode_parser.BencodeParser.RegisterPlugin(UTorrentPlugin)