19 package org.sleuthkit.autopsy.modules.hashdatabase;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.concurrent.atomic.AtomicLong;
27 import java.util.logging.Level;
28 import org.openide.util.NbBundle;
29 import org.openide.util.NbBundle.Messages;
44 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
46 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
58 "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash set.",
59 "HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=Notable file search will not be executed.",
60 "HashDbIngestModule.noKnownHashDbSetMsg=No known hash set.",
61 "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed."
66 private static final int MAX_COMMENT_SIZE = 500;
70 private final HashLookupModuleSettings
settings;
71 private final List<HashDb> knownBadHashSets =
new ArrayList<>();
72 private final List<HashDb> knownHashSets =
new ArrayList<>();
74 private static final HashMap<Long, IngestJobTotals> totalsForIngestJobs =
new HashMap<>();
83 private final AtomicLong totalKnownBadCount =
new AtomicLong(0);
84 private final AtomicLong totalCalctime =
new AtomicLong(0);
85 private final AtomicLong totalLookuptime =
new AtomicLong(0);
92 totalsForIngestJobs.put(ingestJobId, totals);
107 this.settings = settings;
113 jobId = context.getJobId();
114 if (!hashDbManager.verifyAllDatabasesLoadedCorrectly()) {
115 throw new IngestModuleException(
"Could not load all hash sets");
122 getTotalsForIngestJobs(jobId);
125 if (knownBadHashSets.isEmpty()) {
128 Bundle.HashDbIngestModule_noKnownBadHashDbSetMsg(),
129 Bundle.HashDbIngestModule_knownBadFileSearchWillNotExecuteWarn()));
132 if (knownHashSets.isEmpty()) {
135 Bundle.HashDbIngestModule_noKnownHashDbSetMsg(),
136 Bundle.HashDbIngestModule_knownFileSearchWillNotExecuteWarn()));
148 enabledHashSets.clear();
149 for (
HashDb db : allHashSets) {
150 if (settings.isHashSetEnabled(db)) {
153 enabledHashSets.add(db);
155 }
catch (TskCoreException ex) {
156 logger.log(Level.WARNING,
"Error getting index status for " + db.getDisplayName() +
" hash set", ex);
164 "HashDbIngestModule.dialogTitle.errorFindingArtifacts=Error Finding Artifacts: {0}",
166 "HashDbIngestModule.errorMessage.lookingForFileArtifacts=Error encountered while looking for existing artifacts for {0}."
173 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
178 if ((file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
179 || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) {
194 if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (!settings.shouldCalculateHashes())) {
202 String name = file.getName();
203 long fileId = file.getId();
204 String md5Hash = file.getMd5Hash();
205 if (md5Hash == null || md5Hash.isEmpty()) {
208 long calcstart = System.currentTimeMillis();
209 md5Hash = HashUtility.calculateMd5Hash(file);
210 if (file.getSize() > 0) {
214 if (file.getSize() < 1000000) {
221 file.setMd5Hash(md5Hash);
222 long delta = (System.currentTimeMillis() - calcstart);
225 }
catch (IOException ex) {
226 logger.log(Level.WARNING, String.format(
"Error calculating hash of file '%s' (id=%d).", name, fileId), ex);
229 NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.fileReadErrorMsg", name),
230 NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.calcHashValueErr",
231 file.getParentPath() + file.getName(),
232 file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)?
"Allocated File" :
"Deleted File")));
238 boolean foundBad =
false;
240 for (
HashDb db : knownBadHashSets) {
242 long lookupstart = System.currentTimeMillis();
243 HashHitInfo hashInfo = db.lookupMD5(file);
244 if (null != hashInfo) {
248 file.setKnown(TskData.FileKnown.BAD);
250 String hashSetName = db.getDisplayName();
253 ArrayList<String> comments = hashInfo.getComments();
255 for (String c : comments) {
260 if (comment.length() > MAX_COMMENT_SIZE) {
261 comment = comment.substring(0, MAX_COMMENT_SIZE) +
"...";
270 List<BlackboardAttribute> attributesList =
new ArrayList<>();
273 org.
sleuthkit.datamodel.Blackboard tskBlackboard = skCase.getBlackboard();
274 if (tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, attributesList) ==
false) {
275 postHashSetHitToBlackboard(file, md5Hash, hashSetName, comment, db.getSendIngestMessages());
277 }
catch (TskCoreException ex) {
278 logger.log(Level.SEVERE, String.format(
279 "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", name, fileId), ex);
282 Bundle.HashDbIngestModule_dialogTitle_errorFindingArtifacts(name),
283 Bundle.HashDbIngestModule_errorMessage_lookingForFileArtifacts(name)));
287 long delta = (System.currentTimeMillis() - lookupstart);
290 }
catch (TskException ex) {
291 logger.log(Level.WARNING, String.format(
292 "Couldn't lookup notable hash for file '%s' (id=%d) - see sleuthkit log for details", name, fileId), ex);
295 NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.hashLookupErrorMsg", name),
296 NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.lookingUpKnownBadHashValueErr", name)));
305 for (
HashDb db : knownHashSets) {
307 long lookupstart = System.currentTimeMillis();
308 if (db.lookupMD5Quick(file)) {
309 file.setKnown(TskData.FileKnown.KNOWN);
312 long delta = (System.currentTimeMillis() - lookupstart);
315 }
catch (TskException ex) {
316 logger.log(Level.WARNING, String.format(
317 "Couldn't lookup known hash for file '%s' (id=%d) - see sleuthkit log for details", name, fileId), ex);
320 NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.hashLookupErrorMsg", name),
321 NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.lookingUpKnownHashValueErr", name)));
341 "HashDbIngestModule.indexError.message=Failed to index hashset hit artifact for keyword search."
343 private void postHashSetHitToBlackboard(AbstractFile abstractFile, String md5Hash, String hashSetName, String comment,
boolean showInboxMessage) {
346 BlackboardArtifact badFile = abstractFile.newArtifact(ARTIFACT_TYPE.TSK_HASHSET_HIT);
347 Collection<BlackboardAttribute> attributes =
new ArrayList<>();
350 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, moduleName, hashSetName));
351 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HASH_MD5, moduleName, md5Hash));
352 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, moduleName, comment));
354 badFile.addAttributes(attributes);
361 blackboard.postArtifact(badFile, moduleName);
362 }
catch (Blackboard.BlackboardException ex) {
363 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + badFile.getArtifactID(), ex);
365 Bundle.HashDbIngestModule_indexError_message(), badFile.getDisplayName());
368 if (showInboxMessage) {
369 StringBuilder detailsSb =
new StringBuilder();
371 detailsSb.append(
"<table border='0' cellpadding='4' width='280'>");
373 detailsSb.append(
"<tr>");
374 detailsSb.append(
"<th>")
375 .append(NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.postToBB.fileName"))
377 detailsSb.append(
"<td>")
378 .append(abstractFile.getName())
380 detailsSb.append(
"</tr>");
382 detailsSb.append(
"<tr>");
383 detailsSb.append(
"<th>")
384 .append(NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.postToBB.md5Hash"))
386 detailsSb.append(
"<td>").append(md5Hash).append(
"</td>");
387 detailsSb.append(
"</tr>");
389 detailsSb.append(
"<tr>");
390 detailsSb.append(
"<th>")
391 .append(NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.postToBB.hashsetName"))
393 detailsSb.append(
"<td>").append(hashSetName).append(
"</td>");
394 detailsSb.append(
"</tr>");
396 detailsSb.append(
"</table>");
399 NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.postToBB.knownBadMsg", abstractFile.getName()),
400 detailsSb.toString(),
401 abstractFile.getName() + md5Hash,
404 }
catch (TskException ex) {
405 logger.log(Level.WARNING,
"Error creating blackboard artifact", ex);
417 List<HashDb> knownBadHashSets, List<HashDb> knownHashSets) {
419 totalsForIngestJobs.remove(jobId);
421 if ((!knownBadHashSets.isEmpty()) || (!knownHashSets.isEmpty())) {
422 StringBuilder detailsSb =
new StringBuilder();
424 detailsSb.append(
"<table border='0' cellpadding='4' width='280'>");
426 detailsSb.append(
"<tr><td>")
427 .append(NbBundle.getMessage(
HashDbIngestModule.class,
"HashDbIngestModule.complete.knownBadsFound"))
429 detailsSb.append(
"<td>").append(jobTotals.
totalKnownBadCount.get()).append(
"</td></tr>");
431 detailsSb.append(
"<tr><td>")
432 .append(NbBundle.getMessage(
HashDbIngestModule.class,
"HashDbIngestModule.complete.totalCalcTime"))
433 .append(
"</td><td>").append(jobTotals.
totalCalctime.get()).append(
"</td></tr>\n");
434 detailsSb.append(
"<tr><td>")
435 .append(NbBundle.getMessage(
HashDbIngestModule.class,
"HashDbIngestModule.complete.totalLookupTime"))
436 .append(
"</td><td>").append(jobTotals.
totalLookuptime.get()).append(
"</td></tr>\n");
437 detailsSb.append(
"</table>");
439 detailsSb.append(
"<p>")
440 .append(NbBundle.getMessage(
HashDbIngestModule.class,
"HashDbIngestModule.complete.databasesUsed"))
441 .append(
"</p>\n<ul>");
442 for (
HashDb db : knownBadHashSets) {
443 detailsSb.append(
"<li>").append(db.getHashSetName()).append(
"</li>\n");
446 detailsSb.append(
"</ul>");
451 NbBundle.getMessage(
HashDbIngestModule.class,
"HashDbIngestModule.complete.hashLookupResults"),
452 detailsSb.toString()));
459 postSummary(jobId, knownBadHashSets, knownHashSets);
synchronized long decrementAndGet(long jobId)
ProcessResult process(AbstractFile file)
static IngestMessage createDataMessage(String source, String subject, String detailsHtml, String uniqueKey, BlackboardArtifact data)
final HashLookupModuleSettings settings
static IngestMessage createErrorMessage(String source, String subject, String detailsHtml)
void startUp(org.sleuthkit.autopsy.ingest.IngestJobContext context)
synchronized long incrementAndGet(long jobId)
static IngestMessage createMessage(MessageType messageType, String source, String subject, String detailsHtml)
static synchronized IngestJobTotals getTotalsForIngestJobs(long ingestJobId)
final AtomicLong totalLookuptime
final AtomicLong totalCalctime
void updateEnabledHashSets(List< HashDb > allHashSets, List< HashDb > enabledHashSets)
static TimingMetric getTimingMetric(String name)
void postHashSetHitToBlackboard(AbstractFile abstractFile, String md5Hash, String hashSetName, String comment, boolean showInboxMessage)
final SleuthkitCase skCase
synchronized List< HashDb > getKnownBadFileHashSets()
static synchronized HashDbManager getInstance()
final AtomicLong totalKnownBadCount
void postMessage(final IngestMessage message)
SleuthkitCase getSleuthkitCase()
static void submitTimingMetric(TimingMetric metric)
static synchronized void postSummary(long jobId, List< HashDb > knownBadHashSets, List< HashDb > knownHashSets)
static void error(String title, String message)
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
static IngestMessage createWarningMessage(String source, String subject, String detailsHtml)
static void submitNormalizedTimingMetric(TimingMetric metric, long normalization)
synchronized List< HashDb > getKnownFileHashSets()
static String getModuleName()
static synchronized IngestServices getInstance()