19package org.sleuthkit.autopsy.modules.hashdatabase;
21import java.util.ArrayList;
22import java.util.Arrays;
23import java.util.HashMap;
25import java.util.concurrent.atomic.AtomicLong;
26import java.util.function.Function;
27import java.util.logging.Level;
28import java.util.stream.Stream;
29import org.openide.util.NbBundle;
30import org.openide.util.NbBundle.Messages;
31import org.sleuthkit.autopsy.casemodule.Case;
32import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
33import org.sleuthkit.autopsy.coreutils.Logger;
34import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
35import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
36import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
37import org.sleuthkit.autopsy.ingest.FileIngestModule;
38import org.sleuthkit.autopsy.ingest.IngestMessage;
39import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter;
40import org.sleuthkit.autopsy.ingest.IngestServices;
41import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb;
42import org.sleuthkit.datamodel.AbstractFile;
43import org.sleuthkit.datamodel.Blackboard;
44import org.sleuthkit.datamodel.BlackboardArtifact;
45import org.sleuthkit.datamodel.BlackboardAttribute;
46import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
47import org.sleuthkit.datamodel.HashHitInfo;
48import org.sleuthkit.datamodel.HashUtility;
49import org.sleuthkit.datamodel.Score;
50import org.sleuthkit.datamodel.SleuthkitCase;
51import org.sleuthkit.datamodel.TskCoreException;
52import org.sleuthkit.datamodel.TskData;
53import org.sleuthkit.datamodel.TskException;
59 "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash set.",
60 "HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=Notable file search will not be executed.",
61 "HashDbIngestModule.noKnownHashDbSetMsg=No known hash set.",
62 "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed.",
63 "# {0} - fileName",
"HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.",
64 "# {0} - fileName",
"HashDbIngestModule.lookingUpNoChangeHashValueErr=Error encountered while looking up no change hash value for {0}.",
65 "# {0} - fileName",
"HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}.",})
71 = (file) -> Bundle.HashDbIngestModule_lookingUpKnownBadHashValueErr(file.getName());
74 = (file) -> Bundle.HashDbIngestModule_lookingUpNoChangeHashValueErr(file.getName());
77 = (file) -> Bundle.HashDbIngestModule_lookingUpKnownHashValueErr(file.getName());
83 private final HashLookupModuleSettings
settings;
105 if (totals ==
null) {
106 totals =
new HashDbIngestModule.IngestJobTotals();
122 this.settings = settings;
128 jobId = context.getJobId();
143 Bundle.HashDbIngestModule_noKnownBadHashDbSetMsg(),
144 Bundle.HashDbIngestModule_knownBadFileSearchWillNotExecuteWarn()));
150 Bundle.HashDbIngestModule_noKnownHashDbSetMsg(),
151 Bundle.HashDbIngestModule_knownFileSearchWillNotExecuteWarn()));
163 for (
HashDb db : allHashSets) {
164 if (
settings.isHashSetEnabled(db)) {
167 switch (db.getKnownFilesType()) {
178 throw new TskCoreException(
"Unknown KnownFilesType: " + db.getKnownFilesType());
181 }
catch (TskCoreException ex) {
182 logger.log(Level.WARNING,
"Error getting index status for " + db.getDisplayName() +
" hash set", ex);
190 "HashDbIngestModule.dialogTitle.errorFindingArtifacts=Error Finding Artifacts: {0}",
192 "HashDbIngestModule.errorMessage.lookingForFileArtifacts=Error encountered while looking for existing artifacts for {0}."
199 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
213 }
catch (TskCoreException ex) {
214 logger.log(Level.WARNING, String.format(
"Error calculating hash of file '%s' (id=%d).", file.getName(), file.getId()), ex);
217 NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.fileReadErrorMsg", file.getName()),
218 NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.calcHashValueErr",
219 file.getParentPath() + file.getName(),
220 file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC) ?
"Allocated File" :
"Deleted File")));
230 boolean foundBad = knownBadResult.isFound();
231 if (knownBadResult.isError()) {
239 if (noChangeResult.isError()) {
249 long lookupstart = System.currentTimeMillis();
250 if (db.lookupMD5Quick(file)) {
251 file.setKnown(TskData.FileKnown.KNOWN);
254 long delta = (System.currentTimeMillis() - lookupstart);
257 }
catch (TskException ex) {
276 if ((file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
277 || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) {
308 private void reportLookupError(TskException ex, AbstractFile file, Function<AbstractFile, String> lookupErrorMessage) {
309 logger.log(Level.WARNING, String.format(
310 "Couldn't lookup notable hash for file '%s' (id=%d) - see sleuthkit log for details", file.getName(), file.getId()), ex);
313 NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.hashLookupErrorMsg", file.getName()),
314 lookupErrorMessage.apply(file)));
320 private static class FindInHashsetsResult {
325 FindInHashsetsResult(
boolean found,
boolean error) {
370 List<HashDb> hashSets, TskData.FileKnown statusIfFound, Function<AbstractFile, String> lookupErrorMessage) {
372 boolean found =
false;
373 boolean wasError =
false;
374 for (
HashDb db : hashSets) {
376 long lookupstart = System.currentTimeMillis();
377 HashHitInfo hashInfo = db.lookupMD5(file);
378 if (
null != hashInfo) {
381 totalCount.incrementAndGet();
382 file.setKnown(statusIfFound);
388 long delta = (System.currentTimeMillis() - lookupstart);
389 totalLookupTime.addAndGet(delta);
391 }
catch (TskException ex) {
409 ArrayList<String> comments = hashInfo.getComments();
411 for (String c : comments) {
438 List<BlackboardAttribute> attributesList =
new ArrayList<>();
441 Blackboard tskBlackboard =
skCase.getBlackboard();
442 if (tskBlackboard.artifactExists(file, BlackboardArtifact.Type.TSK_HASHSET_HIT, attributesList) ==
false) {
445 }
catch (TskCoreException ex) {
446 logger.log(Level.SEVERE, String.format(
447 "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", file.getName(), file.getId()), ex);
450 Bundle.HashDbIngestModule_dialogTitle_errorFindingArtifacts(file.getName()),
451 Bundle.HashDbIngestModule_errorMessage_lookingForFileArtifacts(file.getName())));
467 String md5Hash = file.getMd5Hash();
468 String sha256Hash = file.getSha256Hash();
469 if ((md5Hash !=
null && ! md5Hash.isEmpty())
470 && (sha256Hash !=
null && ! sha256Hash.isEmpty())) {
475 long calcstart = System.currentTimeMillis();
476 List<HashUtility.HashResult> newHashResults =
477 HashUtility.calculateHashes(file, Arrays.asList(HashUtility.HashType.MD5,HashUtility.HashType.SHA256 ));
478 if (file.getSize() > 0) {
482 if (file.getSize() < 1000000) {
489 for (HashUtility.HashResult hash : newHashResults) {
490 if (hash.getType().equals(HashUtility.HashType.MD5)) {
491 file.setMd5Hash(hash.getValue());
492 }
else if (hash.getType().equals(HashUtility.HashType.SHA256)) {
493 file.setSha256Hash(hash.getValue());
496 long delta = (System.currentTimeMillis() - calcstart);
497 totals.totalCalctime.addAndGet(delta);
506 if (knownFilesType ==
null) {
507 return Score.SCORE_UNKNOWN;
509 switch (knownFilesType) {
511 return Score.SCORE_NONE;
513 return Score.SCORE_NOTABLE;
516 return Score.SCORE_UNKNOWN;
528 "HashDbIngestModule.indexError.message=Failed to index hashset hit artifact for keyword search."
534 List<BlackboardAttribute> attributes = Arrays.asList(
535 new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, moduleName, db.getDisplayName()),
536 new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HASH_MD5, moduleName, md5Hash),
537 new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, moduleName, comment)
541 BlackboardArtifact badFile = abstractFile.newAnalysisResult(
543 null, db.getDisplayName(),
null,
545 ).getAnalysisResult();
553 }
catch (Blackboard.BlackboardException ex) {
554 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + badFile.getArtifactID(), ex);
556 Bundle.HashDbIngestModule_indexError_message(), badFile.getDisplayName());
560 StringBuilder detailsSb =
new StringBuilder();
562 detailsSb.append(
"<table border='0' cellpadding='4' width='280'>");
564 detailsSb.append(
"<tr>");
565 detailsSb.append(
"<th>")
566 .append(NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.postToBB.fileName"))
568 detailsSb.append(
"<td>")
569 .append(abstractFile.getName())
571 detailsSb.append(
"</tr>");
573 detailsSb.append(
"<tr>");
574 detailsSb.append(
"<th>")
575 .append(NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.postToBB.md5Hash"))
577 detailsSb.append(
"<td>").append(md5Hash).append(
"</td>");
578 detailsSb.append(
"</tr>");
580 detailsSb.append(
"<tr>");
581 detailsSb.append(
"<th>")
582 .append(NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.postToBB.hashsetName"))
584 detailsSb.append(
"<td>").append(db.getDisplayName()).append(
"</td>");
585 detailsSb.append(
"</tr>");
587 detailsSb.append(
"</table>");
590 NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.postToBB.knownBadMsg", abstractFile.getName()),
591 detailsSb.toString(),
592 abstractFile.getName() + md5Hash,
595 }
catch (TskException ex) {
596 logger.log(Level.WARNING,
"Error creating blackboard artifact", ex);
608 @Messages(
"HashDbIngestModule.complete.noChangesFound=No Change items found:")
616 StringBuilder detailsSb =
new StringBuilder();
619 "<table border='0' cellpadding='4' width='280'>" +
620 "<tr><td>" + NbBundle.getMessage(HashDbIngestModule.class,
"HashDbIngestModule.complete.knownBadsFound") +
"</td>" +
623 "<tr><td>" + Bundle.HashDbIngestModule_complete_noChangesFound() +
"</td>" +
626 "<tr><td>" + NbBundle.getMessage(HashDbIngestModule.class,
"HashDbIngestModule.complete.totalCalcTime") +
627 "</td><td>" + jobTotals.
totalCalctime.get() +
"</td></tr>\n" +
629 "<tr><td>" + NbBundle.getMessage(HashDbIngestModule.class,
"HashDbIngestModule.complete.totalLookupTime") +
630 "</td><td>" + jobTotals.
totalLookuptime.get() +
"</td></tr>\n</table>" +
632 "<p>" + NbBundle.getMessage(HashDbIngestModule.class,
"HashDbIngestModule.complete.databasesUsed") +
"</p>\n<ul>");
638 detailsSb.append(
"</ul>");
643 NbBundle.getMessage(HashDbIngestModule.class,
"HashDbIngestModule.complete.hashLookupResults"),
644 detailsSb.toString()));
SleuthkitCase getSleuthkitCase()
static Case getCurrentCaseThrows()
synchronized static Logger getLogger(String name)
static void error(String title, String message)
static TimingMetric getTimingMetric(String name)
static void submitTimingMetric(TimingMetric metric)
static void submitNormalizedTimingMetric(TimingMetric metric, long normalization)
static IngestMessage createMessage(MessageType messageType, String source, String subject, String detailsHtml)
static IngestMessage createDataMessage(String source, String subject, String detailsHtml, String uniqueKey, BlackboardArtifact data)
static IngestMessage createErrorMessage(String source, String subject, String detailsHtml)
static IngestMessage createWarningMessage(String source, String subject, String detailsHtml)
void postMessage(final IngestMessage message)
static synchronized IngestServices getInstance()
final AtomicLong totalKnownBadCount
final AtomicLong totalLookuptime
final AtomicLong totalNoChangeCount
final AtomicLong totalCalctime
ProcessResult process(AbstractFile file)
void reportLookupError(TskException ex, AbstractFile file, Function< AbstractFile, String > lookupErrorMessage)
void postHashSetHitToBlackboard(AbstractFile abstractFile, String md5Hash, HashDb db, String comment)
static final int MAX_COMMENT_SIZE
static final HashMap< Long, IngestJobTotals > totalsForIngestJobs
Score getScore(HashDb.KnownFilesType knownFilesType)
void calculateHashes(AbstractFile file, IngestJobTotals totals)
final SleuthkitCase skCase
final List< HashDb > knownBadHashSets
final Function< AbstractFile, String > noChangeLookupError
final Function< AbstractFile, String > knownBadLookupError
final List< HashDb > knownHashSets
final Function< AbstractFile, String > knownLookupError
void startUp(org.sleuthkit.autopsy.ingest.IngestJobContext context)
String generateComment(HashHitInfo hashInfo)
static synchronized void postSummary(long jobId, List< HashDb > knownBadHashSets, List< HashDb > noChangeHashSets, List< HashDb > knownHashSets)
void initializeHashsets(List< HashDb > allHashSets)
FindInHashsetsResult findInHashsets(AbstractFile file, AtomicLong totalCount, AtomicLong totalLookupTime, List< HashDb > hashSets, TskData.FileKnown statusIfFound, Function< AbstractFile, String > lookupErrorMessage)
final HashDbManager hashDbManager
boolean shouldSkip(AbstractFile file)
static synchronized IngestJobTotals getTotalsForIngestJobs(long ingestJobId)
static final Logger logger
final HashLookupModuleSettings settings
final IngestServices services
boolean createArtifactIfNotExists(AbstractFile file, String comment, HashDb db)
static final IngestModuleReferenceCounter refCounter
final List< HashDb > noChangeHashSets
abstract boolean getSendIngestMessages()
abstract String getHashSetName()
abstract HashDb.KnownFilesType getKnownFilesType()
static synchronized HashDbManager getInstance()
static String getModuleName()