From 4a66ea26aed816e31ed7191ab29cd885647ddfe8 Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Mon, 28 Jun 2021 13:21:04 -0400 Subject: [PATCH] Added OsAccount to CR Add OsAccount Code to CR --- .../application/OtherOccurrences.java | 41 ++++++ .../OtherOccurrencesNodeWorker.java | 14 +- .../datamodel/Bundle.properties-MERGED | 1 + .../CorrelationAttributeInstance.java | 4 +- .../eventlisteners/Bundle.properties-MERGED | 3 + .../eventlisteners/CaseEventListener.java | 131 ++++++++++++------ .../autopsy/datamodel/FileTypes.java | 10 ++ 7 files changed, 157 insertions(+), 47 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java index 934c8015a4..5adc34cc76 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java @@ -31,6 +31,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.logging.Level; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTimeZone; @@ -52,6 +53,9 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.OsAccount; +import org.sleuthkit.datamodel.OsAccountInstance; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -69,6 +73,43 @@ public final class OtherOccurrences { private OtherOccurrences() { } + public static Collection getCorrelationAttributeFromOsAccount(Node node, OsAccount osAccount) { + Collection ret = new ArrayList<>(); + Optional osAccountAddr = osAccount.getAddr(); + + if (osAccountAddr.isPresent()) { + try { + for (OsAccountInstance instance : osAccount.getOsAccountInstances()) { + DataSource osAccountDataSource = instance.getDataSource(); + try { + CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); + CorrelationAttributeInstance correlationAttributeInstance = new CorrelationAttributeInstance( + CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID), + osAccountAddr.get(), + correlationCase, + CorrelationDataSource.fromTSKDataSource(correlationCase, instance.getDataSource()), + "", + "", + TskData.FileKnown.KNOWN, + osAccount.getId()); + + ret.add(correlationAttributeInstance); + } catch (CentralRepoException ex) { + logger.log(Level.SEVERE, String.format("Cannot get central repository for OsAccount: %s.", osAccountAddr.get()), ex); //NON-NLS + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, String.format("Exception while getting open case looking up osAccount %s.", osAccountAddr.get()), ex); //NON-NLS + } catch (CorrelationAttributeNormalizationException ex) { + logger.log(Level.SEVERE, String.format("Exception with Correlation Attribute Normalization for osAccount %s.", osAccountAddr.get()), ex); //NON-NLS + } + } + } catch (TskCoreException ex) { + logger.log(Level.INFO, String.format("Unable to check create CorrelationAttribtueInstance for osAccount %s.", osAccountAddr.get()), ex); + } + } + + return ret; + } + /** * Determine what attributes can be used for correlation based on the node. * If EamDB is not enabled, get the default Files correlation. diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesNodeWorker.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesNodeWorker.java index 0654002f6f..ab8821931a 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesNodeWorker.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesNodeWorker.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.centralrepository.contentviewer; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -37,6 +38,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.TskException; /** @@ -60,7 +62,11 @@ class OtherOccurrencesNodeWorker extends SwingWorker @Override protected OtherOccurrencesData doInBackground() throws Exception { + OsAccount osAccount = node.getLookup().lookup(OsAccount.class); AbstractFile file = OtherOccurrences.getAbstractFileFromNode(node); + if (osAccount != null) { + file = node.getLookup().lookup(AbstractFile.class); + } String deviceId = ""; String dataSourceName = ""; Map caseNames = new HashMap<>(); @@ -77,8 +83,12 @@ class OtherOccurrencesNodeWorker extends SwingWorker // @@@ Review this behavior return null; } - Collection correlationAttributes = OtherOccurrences.getCorrelationAttributesFromNode(node, file); - + Collection correlationAttributes = new ArrayList<>(); + if (osAccount != null) { + correlationAttributes = OtherOccurrences.getCorrelationAttributeFromOsAccount(node, osAccount); + } else { + correlationAttributes = OtherOccurrences.getCorrelationAttributesFromNode(node, file); + } int totalCount = 0; Set dataSources = new HashSet<>(); for (CorrelationAttributeInstance corAttr : correlationAttributes) { diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED index d18133dac4..a80f1f7d86 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED @@ -25,6 +25,7 @@ CorrelationType.ICCID.displayName=ICCID Number CorrelationType.IMEI.displayName=IMEI Number CorrelationType.IMSI.displayName=IMSI Number CorrelationType.MAC.displayName=MAC Addresses +CorrelationType.OS_ACCOUNT.displayName=Os Account CorrelationType.PHONE.displayName=Phone Numbers CorrelationType.PROG_NAME.displayName=Installed Programs CorrelationType.SSID.displayName=Wireless Networks diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java index 5fe6ae1fa6..64d41dcf25 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java @@ -279,7 +279,8 @@ public class CorrelationAttributeInstance implements Serializable { "CorrelationType.IMEI.displayName=IMEI Number", "CorrelationType.IMSI.displayName=IMSI Number", "CorrelationType.PROG_NAME.displayName=Installed Programs", - "CorrelationType.ICCID.displayName=ICCID Number"}) + "CorrelationType.ICCID.displayName=ICCID Number", + "CorrelationType.OS_ACCOUNT.displayName=Os Account"}) public static List getDefaultCorrelationTypes() throws CentralRepoException { List defaultCorrelationTypes = new ArrayList<>(); @@ -294,6 +295,7 @@ public class CorrelationAttributeInstance implements Serializable { defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(IMSI_TYPE_ID, Bundle.CorrelationType_IMSI_displayName(), "imsi_number", true, true)); //NON-NLS defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(ICCID_TYPE_ID, Bundle.CorrelationType_ICCID_displayName(), "iccid_number", true, true)); //NON-NLS defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(INSTALLED_PROGS_TYPE_ID, Bundle.CorrelationType_PROG_NAME_displayName(), "installed_programs", true, true)); //NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(OSACCOUNT_TYPE_ID, Bundle.CorrelationType_OS_ACCOUNT_displayName(), "os_accounts", true, true)); //NON-NLS // Create Correlation Types for Accounts. int correlationTypeId = ADDITIONAL_TYPES_BASE_ID; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Bundle.properties-MERGED index e95a759c4f..d71782c0ee 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Bundle.properties-MERGED @@ -1,4 +1,7 @@ caseeventlistener.evidencetag=Evidence +CaseEventsListener.module.name=Central Repository +CaseEventsListener.prevCaseComment.text=Users seen in previous cases +CaseEventsListener.prevExists.text=Previously Seen Users (Central Repository) CentralRepositoryNotificationDialog.bulletHeader=This data is used to: CentralRepositoryNotificationDialog.bulletOne=Ignore common items (files, domains, and accounts) CentralRepositoryNotificationDialog.bulletThree=Create personas that group accounts diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index dd2b58a117..ee8fbdb0e6 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.centralrepository.eventlisteners; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Arrays; +import java.util.Collection; import java.util.EnumSet; import java.util.List; import java.util.Optional; @@ -28,8 +30,10 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Level; +import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; import org.openide.util.Exceptions; +import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -60,8 +64,15 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.datamodel.Tag; import org.sleuthkit.autopsy.events.AutopsyEvent; +import org.sleuthkit.datamodel.Blackboard; +import org.sleuthkit.datamodel.BlackboardAttribute; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME; import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccountInstance; +import org.sleuthkit.datamodel.Score; +import org.sleuthkit.datamodel.SleuthkitCase; /** * Listen for case events and update entries in the Central Repository database @@ -81,7 +92,8 @@ public final class CaseEventListener implements PropertyChangeListener { Case.Events.DATA_SOURCE_ADDED, Case.Events.TAG_DEFINITION_CHANGED, Case.Events.CURRENT_CASE, - Case.Events.DATA_SOURCE_NAME_CHANGED, Case.Events.OS_ACCOUNTS_ADDED); + Case.Events.DATA_SOURCE_NAME_CHANGED, + Case.Events.OS_ACCT_INSTANCES_ADDED); public CaseEventListener() { jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(CASE_EVENT_THREAD_NAME).build()); @@ -138,9 +150,10 @@ public final class CaseEventListener implements PropertyChangeListener { break; case OS_ACCT_INSTANCES_ADDED: { if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.LOCAL) { - jobProcessingExecutor.submit(new OsAccountInstancesAddedTask(dbManager, evt)); + jobProcessingExecutor.submit(new OsAccountInstancesAddedTask(dbManager, evt)); } } + break; } } @@ -300,10 +313,10 @@ public final class CaseEventListener implements PropertyChangeListener { * Sets the known status for the correlation attribute instance for the * given abstract file. * - * @param af The abstract file for which to set the correlation - * attribute instance. + * @param af The abstract file for which to set the correlation + * attribute instance. * @param knownStatus The new known status for the correlation attribute - * instance. + * instance. */ private void setContentKnownStatus(AbstractFile af, TskData.FileKnown knownStatus) { final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile(af); @@ -396,7 +409,7 @@ public final class CaseEventListener implements PropertyChangeListener { * for the item. If there are, set known status as notable. If not set * status as unknown. * - * @param content The content for the tag that was added or deleted. + * @param content The content for the tag that was added or deleted. * @param bbArtifact The artifact for the tag that was added or deleted. */ private void handleTagChange(Content content, BlackboardArtifact bbArtifact) { @@ -441,7 +454,7 @@ public final class CaseEventListener implements PropertyChangeListener { * Sets the known status of a blackboard artifact in the central * repository. * - * @param bbArtifact The blackboard artifact to set known status. + * @param bbArtifact The blackboard artifact to set known status. * @param knownStatus The new known status. */ private void setArtifactKnownStatus(BlackboardArtifact bbArtifact, TskData.FileKnown knownStatus) { @@ -646,11 +659,15 @@ public final class CaseEventListener implements PropertyChangeListener { } // CURRENT_CASE } + @NbBundle.Messages({"CaseEventsListener.module.name=Central Repository", + "CaseEventsListener.prevCaseComment.text=Users seen in previous cases", + "CaseEventsListener.prevExists.text=Previously Seen Users (Central Repository)"}) private final class OsAccountInstancesAddedTask implements Runnable { private final CentralRepository dbManager; private final PropertyChangeEvent event; - + private final String MODULE_NAME = Bundle.CaseEventsListener_module_name(); + private OsAccountInstancesAddedTask(CentralRepository db, PropertyChangeEvent evt) { dbManager = db; event = evt; @@ -661,48 +678,75 @@ public final class CaseEventListener implements PropertyChangeListener { if (!CentralRepository.isEnabled()) { return; } - - final OsAcctInstancesAddedEvent osAcctInstancesAddedEvent = (OsAcctInstancesAddedEvent) event; - List addedOsAccountNew = osAcctInstancesAddedEvent.getOsAccountInstances(); - for (OsAccountInstance osAccountInstance: addedOsAccountNew) { - try { - OsAccount osAccount = osAccountInstance.getOsAccount(); - Optional accountAddr = osAccount.getAddr(); - // Check address if it is null or one of the ones below we want to ignore it since they will always be one a windows system - // and they are not unique - if (!accountAddr.isPresent() || accountAddr.get().equals("S-1-5-18") || accountAddr.get().equals("S-1-5-19") || accountAddr.get().equals("S-1-5-20")) { - return; - } + + final OsAcctInstancesAddedEvent osAcctInstancesAddedEvent = (OsAcctInstancesAddedEvent) event; + List addedOsAccountNew = osAcctInstancesAddedEvent.getOsAccountInstances(); + for (OsAccountInstance osAccountInstance : addedOsAccountNew) { try { + OsAccount osAccount = osAccountInstance.getOsAccount(); + Optional accountAddr = osAccount.getAddr(); + // Check address if it is null or one of the ones below we want to ignore it since they will always be one a windows system + // and they are not unique + if (!accountAddr.isPresent() || accountAddr.get().equals("S-1-5-18") || accountAddr.get().equals("S-1-5-19") || accountAddr.get().equals("S-1-5-20")) { + return; + } + try { - CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); - CorrelationAttributeInstance correlationAttributeInstance = new CorrelationAttributeInstance( - CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID), - accountAddr.get(), - correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, osAccountInstance.getDataSource()), - "", - "", - TskData.FileKnown.KNOWN, - osAccount.getId()); + CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); + CorrelationAttributeInstance correlationAttributeInstance = new CorrelationAttributeInstance( + CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID), + accountAddr.get(), + correlationCase, + CorrelationDataSource.fromTSKDataSource(correlationCase, osAccountInstance.getDataSource()), + "", + "", + TskData.FileKnown.KNOWN, + osAccount.getId()); - dbManager.addArtifactInstance(correlationAttributeInstance); - } catch (CentralRepoException ex) { - LOGGER.log(Level.SEVERE, "Cannot get central repository for OsAccount: " + "OsAccount", ex); //NON-NLS - } catch (NoCurrentCaseException ex) { - LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS - } catch (CorrelationAttributeNormalizationException ex) { - LOGGER.log(Level.SEVERE, "Exception with Correlation Attribute Normalization.", ex); //NON-NLS + dbManager.addArtifactInstance(correlationAttributeInstance); + + List previousOccurences = dbManager.getArtifactInstancesByTypeValue(CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID), correlationAttributeInstance.getCorrelationValue()); + List caseDisplayNames; + for (CorrelationAttributeInstance instance : previousOccurences) { + if (!instance.getCorrelationCase().getCaseUUID().equals(correlationAttributeInstance.getCorrelationCase().getCaseUUID())) { + caseDisplayNames = dbManager.getListCasesHavingArtifactInstances(correlationAttributeInstance.getCorrelationType(), correlationAttributeInstance.getCorrelationValue()); + SleuthkitCase tskCase = osAccount.getSleuthkitCase(); + Blackboard blackboard = tskCase.getBlackboard(); + + Collection attributesForNewArtifact = Arrays.asList( + new BlackboardAttribute( + TSK_SET_NAME, MODULE_NAME, + Bundle.CaseEventsListener_prevExists_text()), + new BlackboardAttribute( + TSK_COMMENT, MODULE_NAME, + Bundle.CaseEventsListener_prevCaseComment_text())); + BlackboardArtifact newAnalysisResult = osAccount.newAnalysisResult( + BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, Score.SCORE_LIKELY_NOTABLE, + null, Bundle.CaseEventsListener_prevExists_text(), null, attributesForNewArtifact, osAccountInstance.getDataSource().getId()).getAnalysisResult(); + try { + // index the artifact for keyword search + blackboard.postArtifact(newAnalysisResult, MODULE_NAME); + } catch (Blackboard.BlackboardException ex) { + LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + newAnalysisResult.getArtifactID(), ex); //NON-NLS + } + } + } + + } catch (CentralRepoException ex) { + LOGGER.log(Level.SEVERE, String.format("Cannot get central repository for OsAccount: %s.", accountAddr.get()), ex); //NON-NLS + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + } catch (CorrelationAttributeNormalizationException ex) { + LOGGER.log(Level.SEVERE, "Exception with Correlation Attribute Normalization.", ex); //NON-NLS + } + + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Cannot get central repository for OsAccount: " + "OsAccount", ex); } - - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Cannot get central repository for OsAccount: " + "OsAccount", ex); } - LOGGER.log(Level.INFO, "Error connecting to Central Repository database."); //NON-NLS } } - } - + private final class DataSourceNameChangedTask implements Runnable { private final CentralRepository dbManager; @@ -739,4 +783,3 @@ public final class CaseEventListener implements PropertyChangeListener { } // DATA_SOURCE_NAME_CHANGED } } - diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java index 742d656a82..9404362218 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java @@ -397,6 +397,11 @@ public final class FileTypes implements AutopsyVisitableItem { return content.newDataArtifact(artifactType, attributesList, osAccountId); } + @Override + public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection attributesList, Long osAccountId, long dataSourceId) throws TskCoreException { + return content.newDataArtifact(artifactType, attributesList, osAccountId, dataSourceId); + } + @Override public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection attributesList) throws TskCoreException { return content.newDataArtifact(artifactType, attributesList); @@ -467,6 +472,11 @@ public final class FileTypes implements AutopsyVisitableItem { return content.newAnalysisResult(type, score, string, string1, string2, clctn); } + @Override + public AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type type, Score score, String string, String string1, String string2, Collection clctn, long dataSourceId) throws TskCoreException { + return content.newAnalysisResult(type, score, string, string1, string2, clctn, dataSourceId); + } + @Override public Score getAggregateScore() throws TskCoreException { return content.getAggregateScore();