Esempio n. 1
0
def get_task_manager():
    """Return task manager object based on config.

  Returns
    Initialized TaskManager object.
  """
    config.LoadConfig()
    if config.TASK_MANAGER == u'PSQ':
        return PSQTaskManager()
    else:
        msg = u'Task Manager type "{0:s}" not implemented'.format(
            config.TASK_MANAGER)
        raise turbinia.TurbiniaException(msg)
Esempio n. 2
0
def get_state_manager():
  """Return state manager object based on config.

  Returns
    Initialized StateManager object.
  """
  config.LoadConfig()
  if config.STATE_MANAGER == 'Datastore':
    return DatastoreStateManager()
  else:
    msg = 'State Manager type "{0:s}" not implemented'.format(
        config.STATE_MANAGER)
    raise TurbiniaException(msg)
Esempio n. 3
0
    def run(self, evidence, result):
        """Extracts artifacts using Plaso image_export.py.

    Args:
        evidence: evidence to be processed.
        result: A TurbiniaTaskResult object to place task results into.

    Returns:
        TurbiniaTaskResult object.
    """
        config.LoadConfig()

        export_directory = os.path.join(self.output_dir, 'export')
        image_export_log = os.path.join(self.output_dir,
                                        '{0:s}.log'.format(self.id))

        cmd = [
            'image_export.py',
            '--logfile',
            image_export_log,
            '-w',
            export_directory,
            '--artifact_filters',
            self.artifact_name,
        ]
        if config.DEBUG_TASKS:
            cmd.append('-d')

        # Path to the source image/directory.
        cmd.append(evidence.local_path)

        result.log('Running image_export as [{0:s}]'.format(' '.join(cmd)))

        ret, _ = self.execute(cmd, result, save_files=[image_export_log])
        if ret:
            result.close(self, False, 'image_export.py failed.')
            return result

        for dirpath, _, filenames in os.walk(export_directory):
            for filename in filenames:
                exported_artifact = ExportedFileArtifact(
                    artifact_name=self.artifact_name)
                exported_artifact.local_path = os.path.join(dirpath, filename)
                result.log('Adding artifact {0:s}'.format(filename))
                result.add_evidence(exported_artifact, evidence.config)

        result.close(
            self, True, 'Extracted {0:d} new {1:s} artifacts'.format(
                len(result.evidence), self.artifact_name))

        return result
Esempio n. 4
0
def setup():
    """Set up logging parameters.

  This will also set the root logger, which is the default logger when a named
  logger is not specified.  We currently use 'turbinia' as the named logger,
  however some external modules that are called by Turbinia can use the root
  logger, so we want to be able to optionally configure that as well.
  """
    # TODO(aarontp): Add a config option to set the log level
    config.LoadConfig()
    logger = logging.getLogger('turbinia')
    # Eliminate double logging from root logger
    logger.propagate = False
    need_file_handler = True
    need_stream_handler = True

    # We only need a handler if one of that type doesn't exist already
    if logger.handlers:
        for handler in logger.handlers:
            # Want to do strict type-checking here because is instance will include
            # subclasses and so won't distinguish between StreamHandlers and
            # FileHandlers.
            # pylint: disable=unidiomatic-typecheck
            if type(handler) == logging.FileHandler:
                need_file_handler = False

            # pylint: disable=unidiomatic-typecheck
            if type(handler) == logging.StreamHandler:
                need_stream_handler = False

    file_handler = logging.FileHandler(config.LOG_FILE)
    formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(message)s')
    file_handler.setFormatter(formatter)
    file_handler.setLevel(logging.DEBUG)
    if need_file_handler:
        logger.addHandler(file_handler)

    console_handler = logging.StreamHandler()
    formatter = logging.Formatter('[%(levelname)s] %(message)s')
    console_handler.setFormatter(formatter)
    if need_stream_handler:
        logger.addHandler(console_handler)

    # Configure the root logger to use exactly our handlers because other modules
    # like PSQ use this, and we want to see log messages from it when executing
    # from CLI.
    root_log = logging.getLogger()
    for handler in root_log.handlers:
        root_log.removeHandler(handler)
    root_log.addHandler(console_handler)
    root_log.addHandler(file_handler)
Esempio n. 5
0
def PreprocessMountDisk(loopdevice_path, partition_number):
  """Locally mounts disk in an instance.

  Args:
    loopdevice_path(str): The path to the block device to mount.
    partition_number(int): The partition number.

  Raises:
    TurbiniaException: if the mount command failed to run.

  Returns:
    str: the path to the mounted filesystem.
  """
  config.LoadConfig()
  mount_prefix = config.MOUNT_DIR_PREFIX

  if os.path.exists(mount_prefix) and not os.path.isdir(mount_prefix):
    raise TurbiniaException(
        'Mount dir {0:s} exists, but is not a directory'.format(mount_prefix))
  if not os.path.exists(mount_prefix):
    log.info('Creating local mount parent directory {0:s}'.format(mount_prefix))
    try:
      os.makedirs(mount_prefix)
    except OSError as e:
      raise TurbiniaException(
          'Could not create mount directory {0:s}: {1!s}'.format(
              mount_prefix, e))

  mount_path = tempfile.mkdtemp(prefix='turbinia', dir=mount_prefix)

  if not partition_number:
    # The first partition loop-device made by losetup is loopXp1
    partition_number = 1

  path_to_partition = '{0:s}p{1:d}'.format(loopdevice_path, partition_number)

  if not os.path.exists(path_to_partition):
    log.info(
        'Could not find {0:s}, trying {1:s}'.format(
            path_to_partition, loopdevice_path))
    # Else, the partition's block device is actually /dev/loopX
    path_to_partition = loopdevice_path

  mount_cmd = ['sudo', 'mount', path_to_partition, mount_path]
  log.info('Running: {0:s}'.format(' '.join(mount_cmd)))
  try:
    subprocess.check_call(mount_cmd)
  except subprocess.CalledProcessError as e:
    raise TurbiniaException('Could not mount directory {0!s}'.format(e))

  return mount_path
Esempio n. 6
0
def PreprocessMountPartition(partition_path, filesystem_type):
  """Locally mounts disk partition in an instance.

  Args:
    partition_path(str): A path to a partition block device
    filesystem_type(str): Filesystem of the partition to be mounted

  Raises:
    TurbiniaException: if the mount command failed to run.

  Returns:
    str: the path to the mounted filesystem.
  """
  config.LoadConfig()
  mount_prefix = config.MOUNT_DIR_PREFIX

  if not os.path.exists(partition_path):
    raise TurbiniaException(
        'Could not mount partition {0:s}, the path does not exist'.format(
            partition_path))

  if os.path.exists(mount_prefix) and not os.path.isdir(mount_prefix):
    raise TurbiniaException(
        'Mount dir {0:s} exists, but is not a directory'.format(mount_prefix))
  if not os.path.exists(mount_prefix):
    log.info('Creating local mount parent directory {0:s}'.format(mount_prefix))
    try:
      os.makedirs(mount_prefix)
    except OSError as e:
      raise TurbiniaException(
          'Could not create mount directory {0:s}: {1!s}'.format(
              mount_prefix, e))

  mount_path = tempfile.mkdtemp(prefix='turbinia', dir=mount_prefix)

  mount_cmd = ['sudo', 'mount', '-o', 'ro']
  if filesystem_type == 'EXT':
    # This is in case the underlying filesystem is dirty, as we want to mount
    # everything read-only.
    mount_cmd.extend(['-o', 'noload'])
  elif filesystem_type == 'XFS':
    mount_cmd.extend(['-o', 'norecovery'])
  mount_cmd.extend([partition_path, mount_path])

  log.info('Running: {0:s}'.format(' '.join(mount_cmd)))
  try:
    subprocess.check_call(mount_cmd)
  except subprocess.CalledProcessError as e:
    raise TurbiniaException('Could not mount directory {0!s}'.format(e))

  return mount_path
Esempio n. 7
0
    def __init__(self, jobs_denylist=None, jobs_allowlist=None):
        """Initialization for PSQ Worker.

    Args:
      jobs_denylist (Optional[list[str]]): Jobs we will exclude from running
      jobs_allowlist (Optional[list[str]]): The only Jobs we will include to run
    """
        config.LoadConfig()
        psq_publisher = pubsub.PublisherClient()
        psq_subscriber = pubsub.SubscriberClient()
        datastore_client = datastore.Client(project=config.TURBINIA_PROJECT)
        try:
            self.psq = psq.Queue(
                psq_publisher,
                psq_subscriber,
                config.TURBINIA_PROJECT,
                name=config.PSQ_TOPIC,
                storage=psq.DatastoreStorage(datastore_client))
        except exceptions.GoogleCloudError as e:
            msg = 'Error creating PSQ Queue: {0:s}'.format(str(e))
            log.error(msg)
            raise TurbiniaException(msg)

        # Deregister jobs from denylist/allowlist.
        job_manager.JobsManager.DeregisterJobs(jobs_denylist, jobs_allowlist)
        disabled_jobs = list(
            config.DISABLED_JOBS) if config.DISABLED_JOBS else []
        disabled_jobs = [j.lower() for j in disabled_jobs]
        # Only actually disable jobs that have not been allowlisted.
        if jobs_allowlist:
            disabled_jobs = list(set(disabled_jobs) - set(jobs_allowlist))
        if disabled_jobs:
            log.info(
                'Disabling non-allowlisted jobs configured to be disabled in the '
                'config file: {0:s}'.format(', '.join(disabled_jobs)))
            job_manager.JobsManager.DeregisterJobs(jobs_denylist=disabled_jobs)

        # Check for valid dependencies/directories.
        dependencies = config.ParseDependencies()
        if config.DOCKER_ENABLED:
            check_docker_dependencies(dependencies)
        check_system_dependencies(dependencies)
        check_directory(config.MOUNT_DIR_PREFIX)
        check_directory(config.OUTPUT_DIR)
        check_directory(config.TMP_DIR)

        jobs = job_manager.JobsManager.GetJobNames()
        log.info('Dependency check complete. The following jobs are enabled '
                 'for this worker: {0:s}'.format(','.join(jobs)))
        log.info('Starting PSQ listener on queue {0:s}'.format(self.psq.name))
        self.worker = psq.Worker(queue=self.psq)
Esempio n. 8
0
 def setup_publisher(self):
     """Set up the pubsub publisher."""
     config.LoadConfig()
     self.publisher = pubsub.PublisherClient()
     self.topic_path = self.publisher.topic_path(config.PROJECT,
                                                 self.topic_name)
     try:
         log.debug('Trying to create pubsub topic {0:s}'.format(
             self.topic_path))
         self.publisher.create_topic(self.topic_path)
     except exceptions.Conflict:
         log.debug('PubSub topic {0:s} already exists.'.format(
             self.topic_path))
     log.debug('Setup PubSub publisher at {0:s}'.format(self.topic_path))
Esempio n. 9
0
  def run(self, evidence, result):
    """Task that process data with Plaso.

    Args:
        evidence: Path to data to process.
        result: A TurbiniaTaskResult object to place task results into.

    Returns:
        TurbiniaTaskResult object.
    """
    config.LoadConfig()
    plaso_evidence = PlasoFile()

    # Write plaso file into tmp_dir because sqlite has issues with some shared
    # filesystems (e.g NFS).
    plaso_file = os.path.join(self.tmp_dir, '{0:s}.plaso'.format(self.id))
    plaso_evidence.local_path = plaso_file
    plaso_log = os.path.join(self.output_dir, '{0:s}.log'.format(self.id))

    # TODO(aarontp): Move these flags into a recipe
    cmd = (
        'log2timeline.py --status_view none --hashers all '
        '--partition all --vss_stores all').split()
    if config.DEBUG_TASKS:
      cmd.append('-d')

    if isinstance(evidence, (APFSEncryptedDisk, BitlockerDisk)):
      if evidence.recovery_key:
        cmd.extend([
            '--credential', 'recovery_password:{0:s}'.format(
                evidence.recovery_key)
        ])
      elif evidence.password:
        cmd.extend(['--credential', 'password:{0:s}'.format(evidence.password)])
      else:
        result.close(
            self, False, 'No credentials were provided '
            'for a bitlocker disk.')
        return result

    cmd.extend(['--logfile', plaso_log])
    cmd.extend([plaso_file, evidence.local_path])

    result.log('Running plaso as [{0:s}]'.format(' '.join(cmd)))

    self.execute(
        cmd, result, log_files=[plaso_log], new_evidence=[plaso_evidence],
        close=True)

    return result
Esempio n. 10
0
  def run(self, evidence, result):
    """Task that extracts binaries with image_export.py.

    Args:
        evidence (Evidence object):  The evidence we will process.
        result (TurbiniaTaskResult): The object to place task results into.

    Returns:
        TurbiniaTaskResult object.
    """

    config.LoadConfig()
    binary_extraction_evidence = BinaryExtraction()

    binary_extraction_evidence.local_path = self.output_dir
    binary_extraction_evidence.uncompressed_directory = self.output_dir
    image_export_log = os.path.join(self.output_dir, 'binary_extraction.log')
    self.binary_extraction_dir = os.path.join(
        self.output_dir, 'extracted_binaries')
    self.json_path = os.path.join(self.binary_extraction_dir, 'hashes.json')

    cmd = [
        'image_export.py', '--partitions', 'all', '--no_vss', '--signatures',
        'elf,exe_mz', '--logfile', image_export_log
    ]
    if config.DEBUG_TASKS or evidence.config.get('debug_tasks'):
      cmd.append('-d')
    cmd.extend(['-w', self.binary_extraction_dir, evidence.local_path])

    result.log('Running image_export as [{0:s}]'.format(' '.join(cmd)))
    self.execute(
        cmd, result, log_files=[image_export_log, self.json_path],
        new_evidence=[binary_extraction_evidence], close=True)

    binary_cnt, hash_cnt = self.check_extraction()

    result.status = (
        'Extracted {0:d} hashes and {1:d} binaries from the '
        'evidence.'.format(hash_cnt, binary_cnt))

    if hash_cnt != binary_cnt:
      result.log(
          'Number of extracted binaries is not equal to the number '
          'of extracted hashes. This might indicate issues with '
          'image_export.py. Check binary_extraction.log for more '
          'details.', logging.WARNING)

    binary_extraction_evidence.compress()

    return result
Esempio n. 11
0
    def test_analyse_jupyter_config(self):
        """Tests the analyze_jupyter_config method."""
        config.LoadConfig()
        task = jupyter.JupyterAnalysisTask()

        (report, priority,
         summary) = task.analyse_config(self.BAD_JUPYTER_CONFIG)
        self.assertEqual(report, self.BAD_CONFIG_REPORT)
        self.assertEqual(priority, 20)
        self.assertEqual(summary, self.BAD_CONFIG_SUMMARY)

        (report, priority,
         summary) = task.analyse_config(self.GOOD_JUPYTER_CONFIG)
        self.assertEqual(report, self.GOOD_CONFIG_REPORT)
Esempio n. 12
0
  def GetContainers(self, evidence):
    """Lists the containers from an input Evidence.

    We use subprocess to run the DockerExplorer script, instead of using the
    Python module, because we need to make sure all DockerExplorer code runs
    as root.

    Args:
      evidence (Evidence): the input Evidence.

    Returns:
      a list(dict) containing information about the containers found.

    Raises:
      TurbiniaException: when the docker-explorer tool cannot be found or failed
          to run.
    """
    config.LoadConfig()
    docker_dir = GetDockerPath(evidence.mount_path)

    containers_info = None

    # TODO(rgayon): use docker-explorer exposed constant when
    # https://github.com/google/docker-explorer/issues/80 is in.
    de_binary = utils.get_exe_path('de.py')
    if not de_binary:
      raise TurbiniaException('Cannot find de.py in path')

    docker_explorer_command = ['sudo', de_binary]

    if config.DEBUG_TASKS or evidence.config.get('debug_tasks'):
      docker_explorer_command.append('-d')

    docker_explorer_command.extend(['-r', docker_dir, 'list', 'all_containers'])

    log.info('Running {0:s}'.format(' '.join(docker_explorer_command)))
    try:
      json_string = subprocess.check_output(docker_explorer_command).decode(
          'utf-8')
    except json.JSONDecodeError as e:
      raise TurbiniaException(
          'Error decoding JSON output from de.py: {0!s}'.format(e))
    except subprocess.CalledProcessError as e:
      raise TurbiniaException('de.py returned an error: {0!s}'.format(e))

    containers_info = json.loads(json_string)

    return containers_info
Esempio n. 13
0
    def testParseDependencies(self):
        """Tests a valid config for the ParseDependencies() method."""
        smpl_depends = 'DEPENDENCIES = [{"job": "PlasoJob","programs": ["test"], \
                   "docker_image": "test", "timeout":30}]'

        self.WriteConfig(smpl_depends)
        config.LoadConfig()
        smpl_out = {
            'plasojob': {
                'programs': ['test'],
                'docker_image': 'test',
                'timeout': 30
            }
        }
        smpl_test = config.ParseDependencies()
        self.assertEqual(smpl_out, smpl_test)
Esempio n. 14
0
    def test_analyze_jenkins_no_findings(self, bruteforce_mock):
        """Test that analyze_jenkins returns valid output with no findings."""
        config.LoadConfig()
        task = jenkins.JenkinsAnalysisTask()

        bruteforce_mock.return_value = []
        (report, priority,
         summary) = task.analyze_jenkins(self.EXPECTED_VERSION,
                                         self.EXPECTED_CREDENTIALS)

        self.assertEqual(report, self.JENKINS_ANALYSIS_EMPTY_REPORT)
        self.assertEqual(priority, 50)
        self.assertEqual(
            summary,
            'Jenkins version 2.121.2 found with 1 credentials, but no issues '
            'detected')
Esempio n. 15
0
    def test_analyze_jenkins(self, bruteforce_mock):
        """Test that analyze_jenkins returns valid output with findings."""
        config.LoadConfig()
        task = jenkins.JenkinsAnalysisTask()

        bruteforce_mock.return_value = [
            ('$2a$10$DSltvO4YXZuoLuUU77R871627TEST', 'weakpassword')
        ]
        (report, priority,
         summary) = task.analyze_jenkins(self.EXPECTED_VERSION,
                                         self.EXPECTED_CREDENTIALS)

        report = report + '\n'
        self.assertEqual(report, self.JENKINS_ANALYSIS_REPORT)
        self.assertEqual(priority, 10)
        self.assertEqual(summary, 'Jenkins analysis found potential issues')
Esempio n. 16
0
def get_turbinia_client(run_local=False):
    """Return Turbinia client based on config.

  Returns:
    Initialized BaseTurbiniaClient or TurbiniaCeleryClient object.
  """
    config.LoadConfig()
    # pylint: disable=no-else-return
    if config.TASK_MANAGER.lower() == 'psq':
        return BaseTurbiniaClient(run_local=run_local)
    elif config.TASK_MANAGER.lower() == 'celery':
        return TurbiniaCeleryClient(run_local=run_local)
    else:
        msg = 'Task Manager type "{0:s}" not implemented'.format(
            config.TASK_MANAGER)
        raise TurbiniaException(msg)
Esempio n. 17
0
    def test_analyse_tomcat_file(self):
        """Tests the analyze_tomcat_file method."""
        config.LoadConfig()
        task = tomcat.TomcatAnalysisTask()

        (report, priority,
         summary) = task.analyse_tomcat_file(self.TOMCAT_PASSWORD_FILE)
        self.assertEqual(report, self.TOMCAT_PASSWORD_FILE_REPORT)
        self.assertEqual(priority, 20)
        self.assertEqual(summary, self.TOMCAT_PASSWORD_FILE_REPORT_SUMMARY)

        report = task.analyse_tomcat_file(self.TOMCAT_APP_DEPLOY_LOG)[0]
        self.assertEqual(report, self.TOMCAT_APP_DEPLOY_LOG_REPORT)

        report = task.analyse_tomcat_file(self.TOMCAT_ACCESS_LOG)[0]
        self.assertEqual(report, self.TOMCAT_ACCESS_LOG_REPORT)
Esempio n. 18
0
def get_task_manager():
    """Return task manager object based on config.

  Returns
    Initialized TaskManager object.
  """
    config.LoadConfig()
    # pylint: disable=no-else-return
    if config.TASK_MANAGER.lower() == 'psq':
        return PSQTaskManager()
    elif config.TASK_MANAGER.lower() == 'celery':
        return CeleryTaskManager()
    else:
        msg = 'Task Manager type "{0:s}" not implemented'.format(
            config.TASK_MANAGER)
        raise turbinia.TurbiniaException(msg)
Esempio n. 19
0
def get_state_manager():
    """Return state manager object based on config.

  Returns:
    Initialized StateManager object.
  """
    config.LoadConfig()
    # pylint: disable=no-else-return
    if config.STATE_MANAGER.lower() == 'datastore':
        return DatastoreStateManager()
    elif config.STATE_MANAGER.lower() == 'redis':
        return RedisStateManager()
    else:
        msg = 'State Manager type "{0:s}" not implemented'.format(
            config.STATE_MANAGER)
        raise TurbiniaException(msg)
Esempio n. 20
0
def log_and_report(message, trace):
  """Log an error and if enabled, send to GCP Error Reporting API.

  Args:
    message(str): The user defined message to log.
    trace(str): The error traceback message to log.
  """
  from turbinia import config
  from turbinia.lib import google_cloud

  log.error(message)
  log.error(trace)
  # If GCP Error Reporting is enabled.
  config.LoadConfig()
  if config.STACKDRIVER_TRACEBACK:
    client = google_cloud.setup_stackdriver_traceback(config.TURBINIA_PROJECT)
    client.report_exception()
Esempio n. 21
0
    def get_task_dict(self, task):
        """Creates a dict of the fields we want to persist into storage.

    This combines attributes from both the Task and the TaskResult into one flat
    object representing the overall state.

    Args:
      task: A TurbiniaTask object.

    Returns:
      A dict of task attributes.
    """
        task_dict = {}
        for attr in task.STORED_ATTRIBUTES:
            if not hasattr(task, attr):
                raise TurbiniaException(
                    'Task {0:s} does not have attribute {1:s}'.format(
                        task.name, attr))
            task_dict[attr] = getattr(task, attr)
            if isinstance(task_dict[attr], str):
                task_dict[attr] = unicode(task_dict[attr])

        if task.result:
            for attr in task.result.STORED_ATTRIBUTES:
                if not hasattr(task.result, attr):
                    raise TurbiniaException(
                        'Task {0:s} result does not have attribute {1:s}'.
                        format(task.name, attr))
                task_dict[attr] = getattr(task.result, attr)
                if isinstance(task_dict[attr], str):
                    task_dict[attr] = unicode(task_dict[attr])

        # Set all non-existent keys to None
        all_attrs = set(TurbiniaTask.STORED_ATTRIBUTES +
                        TurbiniaTaskResult.STORED_ATTRIBUTES)
        task_dict.update(
            {k: None
             for k in all_attrs if not task_dict.has_key(k)})
        task_dict = self._validate_data(task_dict)

        # Using the pubsub topic as an instance attribute in order to have a unique
        # namespace per Turbinia installation.
        # TODO(aarontp): Migrate this to actual Datastore namespaces
        config.LoadConfig()
        task_dict.update({'instance': config.INSTANCE_ID})
        return task_dict
Esempio n. 22
0
    def SetUp(self, disk_name, project, turbinia_zone, sketch_id,
              run_all_jobs):
        """Sets up the object attributes.

    Args:
      disk_name (str): name of the disk to process.
      project (str): name of the GPC project containing the disk to process.
      turbinia_zone (str): GCP zone in which the Turbinia server is running.
      sketch_id (int): The Timesketch sketch id
      run_all_jobs (bool): Whether to run all jobs instead of a faster subset.
    """
        # TODO: Consider the case when multiple disks are provided by the previous
        # module or by the CLI.

        if project is None or turbinia_zone is None:
            self.state.AddError(
                'project or turbinia_zone are not all specified, bailing out',
                critical=True)
            return

        self.disk_name = disk_name
        self.project = project
        self.turbinia_zone = turbinia_zone
        self.sketch_id = sketch_id
        self.run_all_jobs = run_all_jobs

        try:
            turbinia_config.LoadConfig()
            self.turbinia_region = turbinia_config.TURBINIA_REGION
            self.instance = turbinia_config.PUBSUB_TOPIC
            if turbinia_config.TURBINIA_PROJECT != self.project:
                self.state.AddError(
                    'Specified project {0!s} does not match Turbinia configured '
                    'project {1!s}. Use gcp_turbinia_import recipe to copy the disk '
                    'into the same project.'.format(
                        self.project, turbinia_config.TURBINIA_PROJECT),
                    critical=True)
                return
            self._output_path = tempfile.mkdtemp()
            self.client = turbinia_client.TurbiniaClient()
        except TurbiniaException as exception:
            # TODO: determine if exception should be converted into a string as
            # elsewhere in the codebase.
            self.state.AddError(exception, critical=True)
            return
Esempio n. 23
0
    def run(self, evidence, result):
        """Task that process data with Plaso.

    Args:
        evidence (Evidence object):  The evidence we will process.
        result (TurbiniaTaskResult): The object to place task results into.

    Returns:
        TurbiniaTaskResult object.
    """

        config.LoadConfig()

        # Write plaso file into tmp_dir because sqlite has issues with some shared
        # filesystems (e.g NFS).
        plaso_file = os.path.join(self.tmp_dir, '{0:s}.plaso'.format(self.id))
        plaso_evidence = PlasoFile(source_path=plaso_file)
        plaso_log = os.path.join(self.output_dir, '{0:s}.log'.format(self.id))

        cmd = self.build_plaso_command('log2timeline.py', self.task_config)

        if config.DEBUG_TASKS or self.task_config.get('debug_tasks'):
            cmd.append('-d')

        if evidence.credentials:
            for credential_type, credential_data in evidence.credentials:
                cmd.extend([
                    '--credential',
                    '{0:s}:{1:s}'.format(credential_type, credential_data)
                ])

        cmd.extend(['--temporary_directory', self.tmp_dir])
        cmd.extend(['--logfile', plaso_log])
        cmd.extend(['--unattended'])
        cmd.extend(['--storage_file', plaso_file])
        cmd.extend([evidence.local_path])

        result.log('Running plaso as [{0:s}]'.format(' '.join(cmd)))
        self.execute(cmd,
                     result,
                     log_files=[plaso_log],
                     new_evidence=[plaso_evidence],
                     close=True)

        return result
Esempio n. 24
0
    def __init__(self, gcs_path=None, *args, **kwargs):
        """Initialization for GCSOutputWriter.

    Args:
      gcs_path (string): GCS path to put output results into.
    """
        super(GCSOutputWriter, self).__init__(*args, **kwargs)
        self.name = 'GCSWriter'
        config.LoadConfig()
        self.client = storage.Client(project=config.PROJECT)

        match = re.search(r'gs://(.*)/(.*)', gcs_path)
        if not match:
            raise TurbiniaException(
                'Cannot find bucket and path from GCS config {0:s}'.format(
                    gcs_path))
        self.bucket = match.group(1)
        self.base_output_dir = match.group(2)
Esempio n. 25
0
 def setup(self):
     """Set up Celery"""
     config.LoadConfig()
     self.app = celery.Celery('turbinia',
                              broker=config.CELERY_BROKER,
                              backend=config.CELERY_BACKEND)
     self.app.conf.update(
         task_default_queue=config.INSTANCE_ID,
         accept_content=['json'],
         # TODO(ericzinnikas): Without task_acks_late Celery workers will start
         # on one task and prefetch another (i.e. can result in 1 worker getting
         # 2 plaso jobs while another worker is free). But enabling this causes
         # problems with certain Celery brokers (duplicated work).
         task_acks_late=False,
         task_track_started=True,
         worker_concurrency=1,
         worker_prefetch_multiplier=1,
     )
Esempio n. 26
0
def PreprocessAttachDisk(disk_name):
    """Attaches Google Cloud Disk to an instance.

  Args:
    disk_name(str): The name of the Cloud Disk to attach.

  Returns:
    (str, list(str)): a tuple consisting of the path to the 'disk' block device
      and a list of paths to partition block devices. For example:
      (
       '/dev/disk/by-id/google-disk0',
       ['/dev/disk/by-id/google-disk0-part1', '/dev/disk/by-id/google-disk0-p2']
      )
  """
    path = '/dev/disk/by-id/google-{0:s}'.format(disk_name)
    if IsBlockDevice(path):
        log.info('Disk {0:s} already attached!'.format(disk_name))
        return (path, glob.glob('{0:s}-part*'.format(path)))

    config.LoadConfig()
    instance_name = GetLocalInstanceName()
    project = gcp_project.GoogleCloudProject(config.TURBINIA_PROJECT,
                                             default_zone=config.TURBINIA_ZONE)
    instance = project.compute.GetInstance(instance_name,
                                           zone=config.TURBINIA_ZONE)

    disk = instance.GetDisk(disk_name)
    log.info('Attaching disk {0:s} to instance {1:s}'.format(
        disk_name, instance_name))
    instance.AttachDisk(disk)

    # Make sure we have a proper block device
    for _ in xrange(RETRY_MAX):
        if IsBlockDevice(path):
            log.info('Block device {0:s} successfully attached'.format(path))
            break
        if os.path.exists(path):
            log.info('Block device {0:s} mode is {1}'.format(
                path,
                os.stat(path).st_mode))
        time.sleep(1)

    return (path, glob.glob('{0:s}-part*'.format(path)))
Esempio n. 27
0
    def setup(self, disk_name, project, turbinia_zone):
        """Sets up the object attributes.

    Args:
      disk_name (string): Name of the disk to process
      project (string): The project containing the disk to process
      turbinia_zone (string): The zone containing the disk to process
    """
        # TODO: Consider the case when multiple disks are provided by the previous
        # module or by the CLI.
        if self.state.input and not disk_name:
            _, disk = self.state.input[0]
            disk_name = disk.name
            print('Using disk {0:s} from previous collector'.format(disk_name))

        if disk_name is None or project is None or turbinia_zone is None:
            self.state.add_error(
                'disk_name, project or turbinia_zone are not all specified, bailing '
                'out',
                critical=True)
            return
        self.disk_name = disk_name
        self.project = project
        self.turbinia_zone = turbinia_zone

        try:
            turbinia_config.LoadConfig()
            self.turbinia_region = turbinia_config.TURBINIA_REGION
            self.instance = turbinia_config.PUBSUB_TOPIC
            if turbinia_config.PROJECT != self.project:
                self.state.add_error(
                    'Specified project {0:s} does not match Turbinia configured '
                    'project {1:s}. Use gcp_turbinia_import recipe to copy the disk '
                    'into the same project.'.format(self.project,
                                                    turbinia_config.PROJECT),
                    critical=True)
                return
            self._output_path = tempfile.mkdtemp()
            self.client = turbinia_client.TurbiniaClient()
        except TurbiniaException as e:
            self.state.add_error(e, critical=True)
            return
Esempio n. 28
0
    def __init__(self, jobs_blacklist=None, jobs_whitelist=None):
        """Initialization for PSQ Worker.

    Args:
      jobs_blacklist (Optional[list[str]]): Jobs we will exclude from running
      jobs_whitelist (Optional[list[str]]): The only Jobs we will include to run
    """
        config.LoadConfig()
        psq_publisher = pubsub.PublisherClient()
        psq_subscriber = pubsub.SubscriberClient()
        datastore_client = datastore.Client(project=config.TURBINIA_PROJECT)
        try:
            self.psq = psq.Queue(
                psq_publisher,
                psq_subscriber,
                config.TURBINIA_PROJECT,
                name=config.PSQ_TOPIC,
                storage=psq.DatastoreStorage(datastore_client))
        except exceptions.GoogleCloudError as e:
            msg = 'Error creating PSQ Queue: {0:s}'.format(str(e))
            log.error(msg)
            raise TurbiniaException(msg)

        # Deregister jobs from blacklist/whitelist.
        disabled_jobs = list(
            config.DISABLED_JOBS) if config.DISABLED_JOBS else []
        job_manager.JobsManager.DeregisterJobs(jobs_blacklist, jobs_whitelist)
        if disabled_jobs:
            log.info(
                'Disabling jobs that were configured to be disabled in the '
                'config file: {0:s}'.format(', '.join(disabled_jobs)))
            job_manager.JobsManager.DeregisterJobs(
                jobs_blacklist=disabled_jobs)

        # Check for valid dependencies/directories.
        check_dependencies(config.DEPENDENCIES)
        check_directory(config.MOUNT_DIR_PREFIX)
        check_directory(config.OUTPUT_DIR)
        check_directory(config.TMP_DIR)

        log.info('Starting PSQ listener on queue {0:s}'.format(self.psq.name))
        self.worker = psq.Worker(queue=self.psq)
Esempio n. 29
0
  def __init__(self, *_, **__):
    """Initialization for PSQ Worker."""
    config.LoadConfig()
    psq_publisher = pubsub.PublisherClient()
    psq_subscriber = pubsub.SubscriberClient()
    datastore_client = datastore.Client(project=config.TURBINIA_PROJECT)
    try:
      self.psq = psq.Queue(
          psq_publisher, psq_subscriber, config.TURBINIA_PROJECT,
          name=config.PSQ_TOPIC, storage=psq.DatastoreStorage(datastore_client))
    except exceptions.GoogleCloudError as e:
      msg = 'Error creating PSQ Queue: {0:s}'.format(str(e))
      log.error(msg)
      raise TurbiniaException(msg)

    check_directory(config.MOUNT_DIR_PREFIX)
    check_directory(config.OUTPUT_DIR)
    check_directory(config.TMP_DIR)

    log.info('Starting PSQ listener on queue {0:s}'.format(self.psq.name))
    self.worker = psq.Worker(queue=self.psq)
Esempio n. 30
0
    def setup_subscriber(self):
        """Set up the pubsub subscriber."""
        config.LoadConfig()
        self.subscriber = pubsub.SubscriberClient()
        subscription_path = self.subscriber.subscription_path(
            config.PROJECT, self.topic_name)
        if not self.topic_path:
            self.topic_path = self.subscriber.topic_path(
                config.PROJECT, self.topic_name)
        try:
            log.debug(
                'Trying to create subscription {0:s} on topic {1:s}'.format(
                    subscription_path, self.topic_path))
            self.subscriber.create_subscription(subscription_path,
                                                self.topic_path)
        except exceptions.Conflict:
            log.debug(
                'Subscription {0:s} already exists.'.format(subscription_path))

        log.debug('Setup PubSub Subscription {0:s}'.format(subscription_path))
        self.subscription = self.subscriber.subscribe(subscription_path,
                                                      self._callback)