Autopsy  4.10.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
IngestEventsListener.java
Go to the documentation of this file.
1 /*
2  * Central Repository
3  *
4  * Copyright 2015-2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.centralrepository.eventlisteners;
20 
21 import com.google.common.util.concurrent.ThreadFactoryBuilder;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import static java.lang.Boolean.FALSE;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.LinkedHashSet;
28 import java.util.List;
29 import java.util.concurrent.ExecutorService;
30 import java.util.concurrent.Executors;
31 import java.util.logging.Level;
32 import java.util.stream.Collectors;
33 import org.apache.commons.lang3.StringUtils;
34 import org.openide.util.NbBundle;
48 import org.sleuthkit.datamodel.AbstractFile;
49 import org.sleuthkit.datamodel.BlackboardArtifact;
50 import org.sleuthkit.datamodel.BlackboardAttribute;
51 import org.sleuthkit.datamodel.TskCoreException;
55 import org.sleuthkit.datamodel.Content;
56 import org.sleuthkit.datamodel.Image;
57 import org.sleuthkit.datamodel.SleuthkitCase;
58 
63 public class IngestEventsListener {
64 
65  private static final Logger LOGGER = Logger.getLogger(CorrelationAttributeInstance.class.getName());
66 
67  final Collection<String> recentlyAddedCeArtifacts = new LinkedHashSet<>();
68  private static int correlationModuleInstanceCount;
69  private static boolean flagNotableItems;
70  private static boolean flagSeenDevices;
71  private static boolean createCrProperties;
72  private final ExecutorService jobProcessingExecutor;
73  private static final String INGEST_EVENT_THREAD_NAME = "Ingest-Event-Listener-%d";
74  private final PropertyChangeListener pcl1 = new IngestModuleEventListener();
75  private final PropertyChangeListener pcl2 = new IngestJobEventListener();
76 
78  jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(INGEST_EVENT_THREAD_NAME).build());
79  }
80 
81  void shutdown() {
82  ThreadUtils.shutDownTaskExecutor(jobProcessingExecutor);
83  }
84 
85  /*
86  * Add all of our Ingest Event Listeners to the IngestManager Instance.
87  */
88  public void installListeners() {
91  }
92 
93  /*
94  * Remove all of our Ingest Event Listeners from the IngestManager Instance.
95  */
96  public void uninstallListeners() {
99  }
100 
105  public synchronized static void incrementCorrelationEngineModuleCount() {
106  correlationModuleInstanceCount++; //Should be called once in the Correlation Engine module's startup method.
107  }
108 
113  public synchronized static void decrementCorrelationEngineModuleCount() {
114  if (getCeModuleInstanceCount() > 0) { //prevent it ingestJobCounter from going negative
115  correlationModuleInstanceCount--; //Should be called once in the Correlation Engine module's shutdown method.
116  }
117  }
118 
123  synchronized static void resetCeModuleInstanceCount() {
124  correlationModuleInstanceCount = 0; //called when a case is opened in case for some reason counter was not reset
125  }
126 
133  public synchronized static int getCeModuleInstanceCount() {
135  }
136 
142  public synchronized static boolean isFlagNotableItems() {
143  return flagNotableItems;
144  }
145 
151  public synchronized static boolean isFlagSeenDevices() {
152  return flagSeenDevices;
153  }
154 
160  public synchronized static boolean shouldCreateCrProperties() {
161  return createCrProperties;
162  }
163 
169  public synchronized static void setFlagNotableItems(boolean value) {
170  flagNotableItems = value;
171  }
172 
178  public synchronized static void setFlagSeenDevices(boolean value) {
179  flagSeenDevices = value;
180  }
181 
187  public synchronized static void setCreateCrProperties(boolean value) {
188  createCrProperties = value;
189  }
190 
191  @NbBundle.Messages({"IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)",
192  "IngestEventsListener.prevCaseComment.text=Previous Case: ",
193  "IngestEventsListener.ingestmodule.name=Correlation Engine"})
194  static private void postCorrelatedBadArtifactToBlackboard(BlackboardArtifact bbArtifact, List<String> caseDisplayNames) {
195 
196  try {
197  String MODULE_NAME = Bundle.IngestEventsListener_ingestmodule_name();
198 
199  Collection<BlackboardAttribute> attributes = new ArrayList<>();
200  attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME,
201  Bundle.IngestEventsListener_prevTaggedSet_text()));
202  attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME,
203  Bundle.IngestEventsListener_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(",", "", ""))));
204  attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID()));
205 
206  SleuthkitCase tskCase = bbArtifact.getSleuthkitCase();
207  AbstractFile abstractFile = tskCase.getAbstractFileById(bbArtifact.getObjectID());
208  org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard();
209  // Create artifact if it doesn't already exist.
210  if (!tskBlackboard.artifactExists(abstractFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT, attributes)) {
211  BlackboardArtifact tifArtifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
212  tifArtifact.addAttributes(attributes);
213 
214  try {
215  // index the artifact for keyword search
217  blackboard.indexArtifact(tifArtifact);
219  LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
220  }
221 
222  // fire event to notify UI of this new artifact
223  IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT));
224  }
225  } catch (TskCoreException ex) {
226  LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS
227  } catch (IllegalStateException ex) {
228  LOGGER.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS
229  }
230  }
231 
238  @NbBundle.Messages({"IngestEventsListener.prevExists.text=Previously Seen Devices (Central Repository)",
239  "# {0} - typeName",
240  "# {1} - count",
241  "IngestEventsListener.prevCount.text=Number of previous {0}: {1}"})
242  static private void postCorrelatedPreviousArtifactToBlackboard(BlackboardArtifact bbArtifact) {
243 
244  try {
245  String MODULE_NAME = Bundle.IngestEventsListener_ingestmodule_name();
246 
247  Collection<BlackboardAttribute> attributes = new ArrayList<>();
248  BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME,
249  Bundle.IngestEventsListener_prevExists_text());
250  attributes.add(att);
251  attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID()));
252 
253  SleuthkitCase tskCase = bbArtifact.getSleuthkitCase();
254  AbstractFile abstractFile = bbArtifact.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID());
255  org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard();
256  // Create artifact if it doesn't already exist.
257  if (!tskBlackboard.artifactExists(abstractFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT, attributes)) {
258  BlackboardArtifact tifArtifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
259  tifArtifact.addAttributes(attributes);
260 
261  try {
262  // index the artifact for keyword search
264  blackboard.indexArtifact(tifArtifact);
266  LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
267  }
268 
269  // fire event to notify UI of this new artifact
270  IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT));
271  }
272  } catch (TskCoreException ex) {
273  LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS
274  } catch (IllegalStateException ex) {
275  LOGGER.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS
276  }
277  }
278 
279  private class IngestModuleEventListener implements PropertyChangeListener {
280 
281  @Override
282  public void propertyChange(PropertyChangeEvent evt) {
283  //if ingest is running we want there to check if there is a Correlation Engine module running
284  //sometimes artifacts are generated by DSPs or other sources while ingest is not running
285  //in these cases we still want to create correlation attributes for those artifacts when appropriate
287  EamDb dbManager;
288  try {
289  dbManager = EamDb.getInstance();
290  } catch (EamDbException ex) {
291  LOGGER.log(Level.SEVERE, "Failed to connect to Central Repository database.", ex);
292  return;
293  }
294  switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
295  case DATA_ADDED: {
296  //if ingest isn't running create the interesting items otherwise use the ingest module setting to determine if we create interesting items
297  boolean flagNotable = !IngestManager.getInstance().isIngestRunning() || isFlagNotableItems();
298  boolean flagPrevious = !IngestManager.getInstance().isIngestRunning() || isFlagSeenDevices();
299  boolean createAttributes = !IngestManager.getInstance().isIngestRunning() || shouldCreateCrProperties();
300  jobProcessingExecutor.submit(new DataAddedTask(dbManager, evt, flagNotable, flagPrevious, createAttributes));
301  break;
302  }
303  default:
304  break;
305  }
306  }
307  }
308  }
309 
310  private class IngestJobEventListener implements PropertyChangeListener {
311 
312  @Override
313  public void propertyChange(PropertyChangeEvent evt) {
314  EamDb dbManager;
315  try {
316  dbManager = EamDb.getInstance();
317  } catch (EamDbException ex) {
318  LOGGER.log(Level.SEVERE, "Failed to connect to Central Repository database.", ex);
319  return;
320  }
321 
322  switch (IngestManager.IngestJobEvent.valueOf(evt.getPropertyName())) {
323  case DATA_SOURCE_ANALYSIS_COMPLETED: {
324  jobProcessingExecutor.submit(new AnalysisCompleteTask(dbManager, evt));
325  break;
326  }
327  default:
328  break;
329  }
330  }
331 
332  }
333 
334  private final class AnalysisCompleteTask implements Runnable {
335 
336  private final EamDb dbManager;
337  private final PropertyChangeEvent event;
338 
339  private AnalysisCompleteTask(EamDb db, PropertyChangeEvent evt) {
340  dbManager = db;
341  event = evt;
342  }
343 
344  @Override
345  public void run() {
346  // clear the tracker to reduce memory usage
347  if (getCeModuleInstanceCount() == 0) {
348  recentlyAddedCeArtifacts.clear();
349  }
350  //else another instance of the Correlation Engine Module is still being run.
351 
352  /*
353  * Ensure the data source in the Central Repository has hash values
354  * that match those in the case database.
355  */
356  if (!EamDb.isEnabled()) {
357  return;
358  }
359  Content dataSource;
360  String dataSourceName = "";
361  long dataSourceObjectId = -1;
362  try {
363  dataSource = ((DataSourceAnalysisCompletedEvent) event).getDataSource();
364 
365  /*
366  * We only care about Images for the purpose of
367  * updating hash values.
368  */
369  if (!(dataSource instanceof Image)) {
370  return;
371  }
372 
373  dataSourceName = dataSource.getName();
374  dataSourceObjectId = dataSource.getId();
375 
376  Case openCase = Case.getCurrentCaseThrows();
377 
378  CorrelationCase correlationCase = dbManager.getCase(openCase);
379  if (null == correlationCase) {
380  correlationCase = dbManager.newCase(openCase);
381  }
382 
383  CorrelationDataSource correlationDataSource = dbManager.getDataSource(correlationCase, dataSource.getId());
384  if (correlationDataSource == null) {
385  // Add the data source.
386  CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource);
387  } else {
388  // Sync the data source hash values if necessary.
389  if (dataSource instanceof Image) {
390  Image image = (Image) dataSource;
391 
392  String imageMd5Hash = image.getMd5();
393  if (imageMd5Hash == null) {
394  imageMd5Hash = "";
395  }
396  String crMd5Hash = correlationDataSource.getMd5();
397  if (StringUtils.equals(imageMd5Hash, crMd5Hash) == false) {
398  correlationDataSource.setMd5(imageMd5Hash);
399  }
400 
401  String imageSha1Hash = image.getSha1();
402  if (imageSha1Hash == null) {
403  imageSha1Hash = "";
404  }
405  String crSha1Hash = correlationDataSource.getSha1();
406  if (StringUtils.equals(imageSha1Hash, crSha1Hash) == false) {
407  correlationDataSource.setSha1(imageSha1Hash);
408  }
409 
410  String imageSha256Hash = image.getSha256();
411  if (imageSha256Hash == null) {
412  imageSha256Hash = "";
413  }
414  String crSha256Hash = correlationDataSource.getSha256();
415  if (StringUtils.equals(imageSha256Hash, crSha256Hash) == false) {
416  correlationDataSource.setSha256(imageSha256Hash);
417  }
418  }
419  }
420  } catch (EamDbException ex) {
421  LOGGER.log(Level.SEVERE, String.format(
422  "Unable to fetch data from the Central Repository for data source '%s' (obj_id=%d)",
423  dataSourceName, dataSourceObjectId), ex);
424  } catch (NoCurrentCaseException ex) {
425  LOGGER.log(Level.SEVERE, "No current case opened.", ex);
426  } catch (TskCoreException ex) {
427  LOGGER.log(Level.SEVERE, String.format(
428  "Unable to fetch data from the case database for data source '%s' (obj_id=%d)",
429  dataSourceName, dataSourceObjectId), ex);
430  }
431  } // DATA_SOURCE_ANALYSIS_COMPLETED
432  }
433 
434  private final class DataAddedTask implements Runnable {
435 
436  private final EamDb dbManager;
437  private final PropertyChangeEvent event;
438  private final boolean flagNotableItemsEnabled;
439  private final boolean flagPreviousItemsEnabled;
440  private final boolean createCorrelationAttributes;
441 
442  private DataAddedTask(EamDb db, PropertyChangeEvent evt, boolean flagNotableItemsEnabled, boolean flagPreviousItemsEnabled, boolean createCorrelationAttributes) {
443  dbManager = db;
444  event = evt;
445  this.flagNotableItemsEnabled = flagNotableItemsEnabled;
446  this.flagPreviousItemsEnabled = flagPreviousItemsEnabled;
447  this.createCorrelationAttributes = createCorrelationAttributes;
448  }
449 
450  @Override
451  public void run() {
452  if (!EamDb.isEnabled()) {
453  return;
454  }
455  final ModuleDataEvent mde = (ModuleDataEvent) event.getOldValue();
456  Collection<BlackboardArtifact> bbArtifacts = mde.getArtifacts();
457  if (null == bbArtifacts) { //the ModuleDataEvents don't always have a collection of artifacts set
458  return;
459  }
460  List<CorrelationAttributeInstance> eamArtifacts = new ArrayList<>();
461 
462  for (BlackboardArtifact bbArtifact : bbArtifacts) {
463  // eamArtifact will be null OR a EamArtifact containing one EamArtifactInstance.
464  List<CorrelationAttributeInstance> convertedArtifacts = EamArtifactUtil.makeInstancesFromBlackboardArtifact(bbArtifact, true);
465  for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
466  try {
467  // Only do something with this artifact if it's unique within the job
468  if (recentlyAddedCeArtifacts.add(eamArtifact.toString())) {
469  // Was it previously marked as bad?
470  // query db for artifact instances having this TYPE/VALUE and knownStatus = "Bad".
471  // if getKnownStatus() is "Unknown" and this artifact instance was marked bad in a previous case,
472  // create TSK_INTERESTING_ARTIFACT_HIT artifact on BB.
473  if (flagNotableItemsEnabled) {
474  List<String> caseDisplayNames;
475  try {
476  caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue());
477  if (!caseDisplayNames.isEmpty()) {
479  caseDisplayNames);
480  }
482  LOGGER.log(Level.INFO, String.format("Unable to flag notable item: %s.", eamArtifact.toString()), ex);
483  }
484  }
485  if (flagPreviousItemsEnabled
486  && (eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.USBID_TYPE_ID
487  || eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.ICCID_TYPE_ID
488  || eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.IMEI_TYPE_ID
489  || eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.IMSI_TYPE_ID
490  || eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.MAC_TYPE_ID)) {
491  try {
492  Long countPreviousOccurences = dbManager.getCountArtifactInstancesByTypeValue(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue());
493  if (countPreviousOccurences > 0) {
495  }
497  LOGGER.log(Level.INFO, String.format("Unable to flag notable item: %s.", eamArtifact.toString()), ex);
498  }
499  }
500  if (createCorrelationAttributes) {
501  eamArtifacts.add(eamArtifact);
502  }
503  }
504  } catch (EamDbException ex) {
505  LOGGER.log(Level.SEVERE, "Error counting notable artifacts.", ex);
506  }
507  }
508  }
509  if (FALSE == eamArtifacts.isEmpty()) {
510  for (CorrelationAttributeInstance eamArtifact : eamArtifacts) {
511  try {
512  dbManager.addArtifactInstance(eamArtifact);
513  } catch (EamDbException ex) {
514  LOGGER.log(Level.SEVERE, "Error adding artifact to database.", ex); //NON-NLS
515  }
516  }
517  } // DATA_ADDED
518  }
519  }
520 }
Collection< BlackboardArtifact > getArtifacts()
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static List< CorrelationAttributeInstance > makeInstancesFromBlackboardArtifact(BlackboardArtifact artifact, boolean checkEnabled)
static synchronized IngestManager getInstance()
DataAddedTask(EamDb db, PropertyChangeEvent evt, boolean flagNotableItemsEnabled, boolean flagPreviousItemsEnabled, boolean createCorrelationAttributes)
List< String > getListCasesHavingArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value)
Long getCountArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value)
CorrelationCase newCase(CorrelationCase eamCase)
static CorrelationDataSource fromTSKDataSource(CorrelationCase correlationCase, Content dataSource)
void removeIngestJobEventListener(final PropertyChangeListener listener)
static void shutDownTaskExecutor(ExecutorService executor)
CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long caseDbDataSourceId)
void addIngestJobEventListener(final PropertyChangeListener listener)
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
void addIngestModuleEventListener(final PropertyChangeListener listener)
synchronized void indexArtifact(BlackboardArtifact artifact)
Definition: Blackboard.java:58
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void postCorrelatedBadArtifactToBlackboard(BlackboardArtifact bbArtifact, List< String > caseDisplayNames)
void addArtifactInstance(CorrelationAttributeInstance eamArtifact)
static synchronized IngestServices getInstance()

Copyright © 2012-2018 Basis Technology. Generated on: Fri Mar 22 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.