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.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.concurrent.atomic.AtomicLong;
28 import java.util.logging.Level;
29 import org.openide.util.NbBundle;
30 import org.openide.util.NbBundle.Messages;
46 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
48 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
57 "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash set.",
58 "HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=Notable file search will not be executed.",
59 "HashDbIngestModule.noKnownHashDbSetMsg=No known hash set.",
60 "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed."
65 private static final int MAX_COMMENT_SIZE = 500;
69 private final HashLookupModuleSettings
settings;
70 private List<HashDb> knownBadHashSets =
new ArrayList<>();
71 private List<HashDb> knownHashSets =
new ArrayList<>();
73 private static final HashMap<Long, IngestJobTotals> totalsForIngestJobs =
new HashMap<>();
79 private AtomicLong totalKnownBadCount =
new AtomicLong(0);
80 private AtomicLong totalCalctime =
new AtomicLong(0);
81 private AtomicLong totalLookuptime =
new AtomicLong(0);
88 totalsForIngestJobs.put(ingestJobId, totals);
94 this.settings = settings;
100 jobId = context.getJobId();
101 if (!hashDbManager.verifyAllDatabasesLoadedCorrectly()) {
102 throw new IngestModuleException(
"Could not load all hash sets");
109 getTotalsForIngestJobs(jobId);
112 if (knownBadHashSets.isEmpty()) {
115 Bundle.HashDbIngestModule_noKnownBadHashDbSetMsg(),
116 Bundle.HashDbIngestModule_knownBadFileSearchWillNotExecuteWarn()));
119 if (knownHashSets.isEmpty()) {
122 Bundle.HashDbIngestModule_noKnownHashDbSetMsg(),
123 Bundle.HashDbIngestModule_knownFileSearchWillNotExecuteWarn()));
135 enabledHashSets.clear();
136 for (
HashDb db : allHashSets) {
137 if (settings.isHashSetEnabled(db)) {
140 enabledHashSets.add(db);
142 }
catch (TskCoreException ex) {
143 logger.log(Level.WARNING,
"Error getting index status for " + db.getDisplayName()+
" hash set", ex);
154 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
159 if ((file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) ||
160 file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) {
175 if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (!settings.shouldCalculateHashes())) {
183 String name = file.getName();
184 String md5Hash = file.getMd5Hash();
185 if (md5Hash == null || md5Hash.isEmpty()) {
188 long calcstart = System.currentTimeMillis();
189 md5Hash = HashUtility.calculateMd5Hash(file);
190 if (file.getSize() > 0) {
194 if (file.getSize() < 1000000) {
201 file.setMd5Hash(md5Hash);
202 long delta = (System.currentTimeMillis() - calcstart);
205 }
catch (IOException ex) {
206 logger.log(Level.WARNING,
"Error calculating hash of file " + name, ex);
209 NbBundle.getMessage(this.getClass(),
210 "HashDbIngestModule.fileReadErrorMsg",
212 NbBundle.getMessage(this.getClass(),
213 "HashDbIngestModule.calcHashValueErr",
220 boolean foundBad =
false;
222 for (
HashDb db : knownBadHashSets) {
224 long lookupstart = System.currentTimeMillis();
225 HashHitInfo hashInfo = db.lookupMD5(file);
226 if (null != hashInfo) {
230 file.setKnown(TskData.FileKnown.BAD);
232 String hashSetName = db.getDisplayName();
235 ArrayList<String> comments = hashInfo.getComments();
237 for (String c : comments) {
242 if (comment.length() > MAX_COMMENT_SIZE) {
243 comment = comment.substring(0, MAX_COMMENT_SIZE) +
"...";
248 postHashSetHitToBlackboard(file, md5Hash, hashSetName, comment, db.getSendIngestMessages());
250 long delta = (System.currentTimeMillis() - lookupstart);
253 }
catch (TskException ex) {
254 logger.log(Level.WARNING,
"Couldn't lookup notable hash for file " + name +
" - see sleuthkit log for details", ex);
257 NbBundle.getMessage(this.getClass(),
258 "HashDbIngestModule.hashLookupErrorMsg",
260 NbBundle.getMessage(this.getClass(),
261 "HashDbIngestModule.lookingUpKnownBadHashValueErr",
271 for (
HashDb db : knownHashSets) {
273 long lookupstart = System.currentTimeMillis();
274 if (db.lookupMD5Quick(file)) {
275 file.setKnown(TskData.FileKnown.KNOWN);
278 long delta = (System.currentTimeMillis() - lookupstart);
281 }
catch (TskException ex) {
282 logger.log(Level.WARNING,
"Couldn't lookup known hash for file " + name +
" - see sleuthkit log for details", ex);
285 NbBundle.getMessage(this.getClass(),
286 "HashDbIngestModule.hashLookupErrorMsg",
288 NbBundle.getMessage(this.getClass(),
289 "HashDbIngestModule.lookingUpKnownHashValueErr",
299 @Messages({
"HashDbIngestModule.indexError.message=Failed to index hashset hit artifact for keyword search."})
300 private void postHashSetHitToBlackboard(AbstractFile abstractFile, String md5Hash, String hashSetName, String comment,
boolean showInboxMessage) {
302 String MODULE_NAME = NbBundle.getMessage(
HashDbIngestModule.class,
"HashDbIngestModule.moduleName");
304 BlackboardArtifact badFile = abstractFile.newArtifact(ARTIFACT_TYPE.TSK_HASHSET_HIT);
305 Collection<BlackboardAttribute> attributes =
new ArrayList<>();
308 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, hashSetName));
309 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HASH_MD5, MODULE_NAME, md5Hash));
310 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME, comment));
312 badFile.addAttributes(attributes);
318 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + badFile.getArtifactID(), ex);
320 Bundle.HashDbIngestModule_indexError_message(), badFile.getDisplayName());
323 if (showInboxMessage) {
324 StringBuilder detailsSb =
new StringBuilder();
326 detailsSb.append(
"<table border='0' cellpadding='4' width='280'>");
328 detailsSb.append(
"<tr>");
329 detailsSb.append(
"<th>")
330 .append(NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.postToBB.fileName"))
332 detailsSb.append(
"<td>")
333 .append(abstractFile.getName())
335 detailsSb.append(
"</tr>");
337 detailsSb.append(
"<tr>");
338 detailsSb.append(
"<th>")
339 .append(NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.postToBB.md5Hash"))
341 detailsSb.append(
"<td>").append(md5Hash).append(
"</td>");
342 detailsSb.append(
"</tr>");
344 detailsSb.append(
"<tr>");
345 detailsSb.append(
"<th>")
346 .append(NbBundle.getMessage(
this.getClass(),
"HashDbIngestModule.postToBB.hashsetName"))
348 detailsSb.append(
"<td>").append(hashSetName).append(
"</td>");
349 detailsSb.append(
"</tr>");
351 detailsSb.append(
"</table>");
354 NbBundle.getMessage(this.getClass(),
355 "HashDbIngestModule.postToBB.knownBadMsg",
356 abstractFile.getName()),
357 detailsSb.toString(),
358 abstractFile.getName() + md5Hash,
362 }
catch (TskException ex) {
363 logger.log(Level.WARNING,
"Error creating blackboard artifact", ex);
368 List<HashDb> knownBadHashSets, List<HashDb> knownHashSets) {
370 totalsForIngestJobs.remove(jobId);
372 if ((!knownBadHashSets.isEmpty()) || (!knownHashSets.isEmpty())) {
373 StringBuilder detailsSb =
new StringBuilder();
375 detailsSb.append(
"<table border='0' cellpadding='4' width='280'>");
377 detailsSb.append(
"<tr><td>")
378 .append(NbBundle.getMessage(
HashDbIngestModule.class,
"HashDbIngestModule.complete.knownBadsFound"))
380 detailsSb.append(
"<td>").append(jobTotals.
totalKnownBadCount.get()).append(
"</td></tr>");
382 detailsSb.append(
"<tr><td>")
383 .append(NbBundle.getMessage(
HashDbIngestModule.class,
"HashDbIngestModule.complete.totalCalcTime"))
384 .append(
"</td><td>").append(jobTotals.
totalCalctime.get()).append(
"</td></tr>\n");
385 detailsSb.append(
"<tr><td>")
386 .append(NbBundle.getMessage(
HashDbIngestModule.class,
"HashDbIngestModule.complete.totalLookupTime"))
387 .append(
"</td><td>").append(jobTotals.
totalLookuptime.get()).append(
"</td></tr>\n");
388 detailsSb.append(
"</table>");
390 detailsSb.append(
"<p>")
391 .append(NbBundle.getMessage(
HashDbIngestModule.class,
"HashDbIngestModule.complete.databasesUsed"))
392 .append(
"</p>\n<ul>");
393 for (
HashDb db : knownBadHashSets) {
394 detailsSb.append(
"<li>").append(db.getHashSetName()).append(
"</li>\n");
397 detailsSb.append(
"</ul>");
403 "HashDbIngestModule.complete.hashLookupResults"),
404 detailsSb.toString()));
411 postSummary(jobId, knownBadHashSets, knownHashSets);
synchronized long decrementAndGet(long jobId)
ProcessResult process(AbstractFile file)
static void submitTimingMetric(TimingMetric metric)
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)
AtomicLong totalKnownBadCount
AtomicLong totalLookuptime
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)
void updateEnabledHashSets(List< HashDb > allHashSets, List< HashDb > enabledHashSets)
void postHashSetHitToBlackboard(AbstractFile abstractFile, String md5Hash, String hashSetName, String comment, boolean showInboxMessage)
static void submitNormalizedTimingMetric(TimingMetric metric, long normalization)
final SleuthkitCase skCase
synchronized List< HashDb > getKnownBadFileHashSets()
static synchronized HashDbManager getInstance()
static TimingMetric getTimingMetric(String name)
void postMessage(final IngestMessage message)
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
SleuthkitCase getSleuthkitCase()
Blackboard getBlackboard()
static synchronized void postSummary(long jobId, List< HashDb > knownBadHashSets, List< HashDb > knownHashSets)
static void error(String title, String message)
synchronized void indexArtifact(BlackboardArtifact artifact)
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
static IngestMessage createWarningMessage(String source, String subject, String detailsHtml)
synchronized List< HashDb > getKnownFileHashSets()
static synchronized IngestServices getInstance()