Autopsy  4.12.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
CentralRepoIngestModule.java
Go to the documentation of this file.
1 /*
2  * Central Repository
3  *
4  * Copyright 2011-2018 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.ingestmodule;
20 
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.List;
25 import java.util.logging.Level;
26 import java.util.stream.Collectors;
27 import org.openide.util.NbBundle.Messages;
49 import org.sleuthkit.datamodel.AbstractFile;
50 import org.sleuthkit.datamodel.Blackboard;
51 import org.sleuthkit.datamodel.BlackboardArtifact;
52 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT;
53 import org.sleuthkit.datamodel.BlackboardAttribute;
54 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT;
55 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
56 import org.sleuthkit.datamodel.HashUtility;
57 import org.sleuthkit.datamodel.SleuthkitCase;
58 import org.sleuthkit.datamodel.TskCoreException;
59 import org.sleuthkit.datamodel.TskData;
60 
65 @Messages({"CentralRepoIngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)",
66  "CentralRepoIngestModule.prevCaseComment.text=Previous Case: "})
67 final class CentralRepoIngestModule implements FileIngestModule {
68 
69  private static final String MODULE_NAME = CentralRepoIngestModuleFactory.getModuleName();
70 
71  static final boolean DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS = true;
72  static final boolean DEFAULT_FLAG_PREVIOUS_DEVICES = true;
73  static final boolean DEFAULT_CREATE_CR_PROPERTIES = true;
74 
75  private final static Logger logger = Logger.getLogger(CentralRepoIngestModule.class.getName());
76  private final IngestServices services = IngestServices.getInstance();
77  private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
78  private static final IngestModuleReferenceCounter warningMsgRefCounter = new IngestModuleReferenceCounter();
79  private long jobId;
80  private CorrelationCase eamCase;
81  private CorrelationDataSource eamDataSource;
82  private CorrelationAttributeInstance.Type filesType;
83  private final boolean flagTaggedNotableItems;
84  private final boolean flagPreviouslySeenDevices;
85  private Blackboard blackboard;
86  private final boolean createCorrelationProperties;
87 
93  CentralRepoIngestModule(IngestSettings settings) {
94  flagTaggedNotableItems = settings.isFlagTaggedNotableItems();
95  flagPreviouslySeenDevices = settings.isFlagPreviousDevices();
96  createCorrelationProperties = settings.shouldCreateCorrelationProperties();
97  }
98 
99  @Override
100  public ProcessResult process(AbstractFile abstractFile) {
101  if (EamDb.isEnabled() == false) {
102  /*
103  * Not signaling an error for now. This is a workaround for the way
104  * all newly didscovered ingest modules are automatically anabled.
105  *
106  * TODO (JIRA-2731): Add isEnabled API for ingest modules.
107  */
108  return ProcessResult.OK;
109  }
110 
111  try {
112  blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard();
113  } catch (NoCurrentCaseException ex) {
114  logger.log(Level.SEVERE, "Exception while getting open case.", ex);
115  return ProcessResult.ERROR;
116  }
117 
118  if (!EamArtifactUtil.isSupportedAbstractFileType(abstractFile)) {
119  return ProcessResult.OK;
120  }
121 
122  if (abstractFile.getKnown() == TskData.FileKnown.KNOWN) {
123  return ProcessResult.OK;
124  }
125 
126  EamDb dbManager;
127  try {
128  dbManager = EamDb.getInstance();
129  } catch (EamDbException ex) {
130  logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex);
131  return ProcessResult.ERROR;
132  }
133 
134  // only continue if we are correlating filesType
135  if (!filesType.isEnabled()) {
136  return ProcessResult.OK;
137  }
138 
139  // get the hash because we're going to correlate it
140  String md5 = abstractFile.getMd5Hash();
141  if ((md5 == null) || (HashUtility.isNoDataMd5(md5))) {
142  return ProcessResult.OK;
143  }
144 
145  /*
146  * Search the central repo to see if this file was previously marked as
147  * being bad. Create artifact if it was.
148  */
149  if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) {
150  try {
151  TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Notable artifact query");
152  List<String> caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5);
153  HealthMonitor.submitTimingMetric(timingMetric);
154  if (!caseDisplayNamesList.isEmpty()) {
155  postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList);
156  }
157  } catch (EamDbException ex) {
158  logger.log(Level.SEVERE, "Error searching database for artifact.", ex); // NON-NLS
159  return ProcessResult.ERROR;
161  logger.log(Level.INFO, "Error searching database for artifact.", ex); // NON-NLS
162  return ProcessResult.ERROR;
163  }
164  }
165 
166  // insert this file into the central repository
167  if (createCorrelationProperties) {
168  try {
170  filesType,
171  md5,
172  eamCase,
173  eamDataSource,
174  abstractFile.getParentPath() + abstractFile.getName(),
175  null,
176  TskData.FileKnown.UNKNOWN // NOTE: Known status in the CR is based on tagging, not hashes like the Case Database.
177  ,
178  abstractFile.getId());
179  dbManager.addAttributeInstanceBulk(cefi);
180  } catch (EamDbException ex) {
181  logger.log(Level.SEVERE, "Error adding artifact to bulk artifacts.", ex); // NON-NLS
182  return ProcessResult.ERROR;
184  logger.log(Level.INFO, "Error adding artifact to bulk artifacts.", ex); // NON-NLS
185  return ProcessResult.ERROR;
186  }
187  }
188  return ProcessResult.OK;
189  }
190 
191  @Override
192  public void shutDown() {
194 
195  if ((EamDb.isEnabled() == false) || (eamCase == null) || (eamDataSource == null)) {
196  return;
197  }
198  EamDb dbManager;
199  try {
200  dbManager = EamDb.getInstance();
201  } catch (EamDbException ex) {
202  logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex);
203  return;
204  }
205  try {
206  dbManager.commitAttributeInstancesBulk();
207  } catch (EamDbException ex) {
208  logger.log(Level.SEVERE, "Error doing bulk insert of artifacts.", ex); // NON-NLS
209  }
210  try {
211  Long count = dbManager.getCountArtifactInstancesByCaseDataSource(eamDataSource);
212  logger.log(Level.INFO, "{0} artifacts in db for case: {1} ds:{2}", new Object[]{count, eamCase.getDisplayName(), eamDataSource.getName()}); // NON-NLS
213  } catch (EamDbException ex) {
214  logger.log(Level.SEVERE, "Error counting artifacts.", ex); // NON-NLS
215  }
216 
217  // TODO: once we implement shared cache, if refCounter is 1, then submit data in bulk.
218  refCounter.decrementAndGet(jobId);
219  }
220 
221  // see ArtifactManagerTimeTester for details
222  @Messages({
223  "CentralRepoIngestModule.notfyBubble.title=Central Repository Not Initialized",
224  "CentralRepoIngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Correlation Engine ingest module."
225  })
226  @Override
227  public void startUp(IngestJobContext context) throws IngestModuleException {
229 
230  /*
231  * Tell the IngestEventsListener to flag notable items based on the
232  * current module's configuration. This is a work around for the lack of
233  * an artifacts pipeline. Note that this can be changed by another
234  * module instance. All modules are affected by the value. While not
235  * ideal, this will be good enough until a better solution can be
236  * posited.
237  *
238  * Note: Flagging cannot be disabled if any other instances of the
239  * Correlation Engine module are running. This restriction is to prevent
240  * missing results in the case where the first module is flagging
241  * notable items, and the proceeding module (with flagging disabled)
242  * causes the first to stop flagging.
243  */
245  IngestEventsListener.setFlagNotableItems(flagTaggedNotableItems);
246  }
248  IngestEventsListener.setFlagSeenDevices(flagPreviouslySeenDevices);
249  }
251  IngestEventsListener.setCreateCrProperties(createCorrelationProperties);
252  }
253 
254  if (EamDb.isEnabled() == false) {
255  /*
256  * Not throwing the customary exception for now. This is a
257  * workaround for the way all newly didscovered ingest modules are
258  * automatically anabled.
259  *
260  * TODO (JIRA-2731): Add isEnabled API for ingest modules.
261  */
263  if (1L == warningMsgRefCounter.incrementAndGet(jobId)) {
264  MessageNotifyUtil.Notify.warn(Bundle.CentralRepoIngestModule_notfyBubble_title(), Bundle.CentralRepoIngestModule_errorMessage_isNotEnabled());
265  }
266  }
267  return;
268  }
269  Case autopsyCase;
270  try {
271  autopsyCase = Case.getCurrentCaseThrows();
272  } catch (NoCurrentCaseException ex) {
273  logger.log(Level.SEVERE, "Exception while getting open case.", ex);
274  throw new IngestModuleException("Exception while getting open case.", ex);
275  }
276 
277  // Don't allow sqlite central repo databases to be used for multi user cases
278  if ((autopsyCase.getCaseType() == Case.CaseType.MULTI_USER_CASE)
280  logger.log(Level.SEVERE, "Cannot run correlation engine on a multi-user case with a SQLite central repository.");
281  throw new IngestModuleException("Cannot run on a multi-user case with a SQLite central repository."); // NON-NLS
282  }
283  jobId = context.getJobId();
284 
285  EamDb centralRepoDb;
286  try {
287  centralRepoDb = EamDb.getInstance();
288  } catch (EamDbException ex) {
289  logger.log(Level.SEVERE, "Error connecting to central repository database.", ex); // NON-NLS
290  throw new IngestModuleException("Error connecting to central repository database.", ex); // NON-NLS
291  }
292 
293  try {
295  } catch (EamDbException ex) {
296  logger.log(Level.SEVERE, "Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS
297  throw new IngestModuleException("Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS
298  }
299 
300  try {
301  eamCase = centralRepoDb.getCase(autopsyCase);
302  } catch (EamDbException ex) {
303  throw new IngestModuleException("Unable to get case from central repository database ", ex);
304  }
305 
306  try {
307  eamDataSource = CorrelationDataSource.fromTSKDataSource(eamCase, context.getDataSource());
308  } catch (EamDbException ex) {
309  logger.log(Level.SEVERE, "Error getting data source info.", ex); // NON-NLS
310  throw new IngestModuleException("Error getting data source info.", ex); // NON-NLS
311  }
312  // TODO: once we implement a shared cache, load/init it here w/ syncronized and define reference counter
313  // if we are the first thread / module for this job, then make sure the case
314  // and image exist in the DB before we associate artifacts with it.
315  if (refCounter.incrementAndGet(jobId)
316  == 1) {
317  // ensure we have this data source in the EAM DB
318  try {
319  if (null == centralRepoDb.getDataSource(eamCase, eamDataSource.getDataSourceObjectID())) {
320  centralRepoDb.newDataSource(eamDataSource);
321  }
322  } catch (EamDbException ex) {
323  logger.log(Level.SEVERE, "Error adding data source to Central Repository.", ex); // NON-NLS
324  throw new IngestModuleException("Error adding data source to Central Repository.", ex); // NON-NLS
325  }
326 
327  }
328  }
329 
336  private void postCorrelatedBadFileToBlackboard(AbstractFile abstractFile, List<String> caseDisplayNames) {
337 
338  Collection<BlackboardAttribute> attributes = Arrays.asList(
339  new BlackboardAttribute(
340  TSK_SET_NAME, MODULE_NAME,
341  Bundle.CentralRepoIngestModule_prevTaggedSet_text()),
342  new BlackboardAttribute(
343  TSK_COMMENT, MODULE_NAME,
344  Bundle.CentralRepoIngestModule_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(","))));
345  try {
346 
347  // Create artifact if it doesn't already exist.
348  if (!blackboard.artifactExists(abstractFile, TSK_INTERESTING_FILE_HIT, attributes)) {
349  BlackboardArtifact tifArtifact = abstractFile.newArtifact(TSK_INTERESTING_FILE_HIT);
350  tifArtifact.addAttributes(attributes);
351  try {
352  // index the artifact for keyword search
353  blackboard.postArtifact(tifArtifact, MODULE_NAME);
354  } catch (Blackboard.BlackboardException ex) {
355  logger.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
356  }
357  // send inbox message
358  sendBadFileInboxMessage(tifArtifact, abstractFile.getName(), abstractFile.getMd5Hash());
359  }
360  } catch (TskCoreException ex) {
361  logger.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS
362  } catch (IllegalStateException ex) {
363  logger.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS
364  }
365  }
366 
375  @Messages({"CentralRepoIngestModule.postToBB.fileName=File Name",
376  "CentralRepoIngestModule.postToBB.md5Hash=MD5 Hash",
377  "CentralRepoIngestModule.postToBB.hashSetSource=Source of Hash",
378  "CentralRepoIngestModule.postToBB.eamHit=Central Repository",
379  "# {0} - Name of file that is Notable",
380  "CentralRepoIngestModule.postToBB.knownBadMsg=Notable: {0}"})
381  public void sendBadFileInboxMessage(BlackboardArtifact artifact, String name, String md5Hash) {
382  StringBuilder detailsSb = new StringBuilder();
383  //details
384  detailsSb.append("<table border='0' cellpadding='4' width='280'>"); //NON-NLS
385  //hit
386  detailsSb.append("<tr>"); //NON-NLS
387  detailsSb.append("<th>") //NON-NLS
388  .append(Bundle.CentralRepoIngestModule_postToBB_fileName())
389  .append("</th>"); //NON-NLS
390  detailsSb.append("<td>") //NON-NLS
391  .append(name)
392  .append("</td>"); //NON-NLS
393  detailsSb.append("</tr>"); //NON-NLS
394 
395  detailsSb.append("<tr>"); //NON-NLS
396  detailsSb.append("<th>") //NON-NLS
397  .append(Bundle.CentralRepoIngestModule_postToBB_md5Hash())
398  .append("</th>"); //NON-NLS
399  detailsSb.append("<td>").append(md5Hash).append("</td>"); //NON-NLS
400  detailsSb.append("</tr>"); //NON-NLS
401 
402  detailsSb.append("<tr>"); //NON-NLS
403  detailsSb.append("<th>") //NON-NLS
404  .append(Bundle.CentralRepoIngestModule_postToBB_hashSetSource())
405  .append("</th>"); //NON-NLS
406  detailsSb.append("<td>").append(Bundle.CentralRepoIngestModule_postToBB_eamHit()).append("</td>"); //NON-NLS
407  detailsSb.append("</tr>"); //NON-NLS
408 
409  detailsSb.append("</table>"); //NON-NLS
410 
412  Bundle.CentralRepoIngestModule_postToBB_knownBadMsg(name),
413  detailsSb.toString(),
414  name + md5Hash,
415  artifact));
416  }
417 }
CorrelationDataSource newDataSource(CorrelationDataSource eamDataSource)
static IngestMessage createDataMessage(String source, String subject, String detailsHtml, String uniqueKey, BlackboardArtifact data)
List< String > getListCasesHavingArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value)
static CorrelationDataSource fromTSKDataSource(CorrelationCase correlationCase, Content dataSource)
static TimingMetric getTimingMetric(String name)
void addAttributeInstanceBulk(CorrelationAttributeInstance eamArtifact)
CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long caseDbDataSourceId)
CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId)
void postMessage(final IngestMessage message)
Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource)
static void submitTimingMetric(TimingMetric metric)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void warn(String title, String message)
static synchronized IngestServices getInstance()

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