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<>();
 
  271                     attributesList.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, 
HashLookupModuleFactory.getModuleName(), hashSetName));
 
  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 synchronized IngestServices getInstance()