Merge branch 'develop' of github.com:sleuthkit/autopsy into 7413-unixScripts

This commit is contained in:
Greg DiCristofaro 2021-09-27 11:11:19 -04:00
commit b8585e89ff
68 changed files with 1522 additions and 5589 deletions

View File

@ -71,7 +71,7 @@ public class AddBlackboardArtifactTagAction extends AddTagAction {
"AddBlackboardArtifactTagAction.singularTagResult"); "AddBlackboardArtifactTagAction.singularTagResult");
String pluralTagResult = NbBundle.getMessage(this.getClass(), String pluralTagResult = NbBundle.getMessage(this.getClass(),
"AddBlackboardArtifactTagAction.pluralTagResult"); "AddBlackboardArtifactTagAction.pluralTagResult");
return Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? pluralTagResult : singularTagResult; return Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactItem.class).size() > 1 ? pluralTagResult : singularTagResult;
} }
@Override @Override

View File

@ -21,12 +21,12 @@ package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
@ -40,6 +40,7 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactItem;
import org.sleuthkit.autopsy.tags.TagUtils; import org.sleuthkit.autopsy.tags.TagUtils;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardArtifactTag;
@ -158,7 +159,11 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
TagMenu() { TagMenu() {
this(new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class))); this(Utilities.actionsGlobalContext()
.lookupAll(BlackboardArtifactItem.class)
.stream()
.map((bai) -> (BlackboardArtifact) bai.getTskContent())
.collect(Collectors.toSet()));
} }
TagMenu(Collection<BlackboardArtifact> selectedBlackboardArtifactsList) { TagMenu(Collection<BlackboardArtifact> selectedBlackboardArtifactsList) {

View File

@ -0,0 +1,76 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.actions;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.SwingWorker;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
import org.sleuthkit.datamodel.BlackboardArtifact;
/**
* An action that navigates to an artifact.
*/
public class ViewArtifactAction extends AbstractAction {
private static final Logger logger = Logger.getLogger(ViewArtifactAction.class.getName());
private final BlackboardArtifact artifact;
/**
* Main constructor.
*
* @param artifact The artifact to navigate to in the action.
* @param displayName The display name of the menu item.
*/
public ViewArtifactAction(BlackboardArtifact artifact, String displayName) {
super(displayName);
this.artifact = artifact;
}
@Override
public void actionPerformed(ActionEvent e) {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
DirectoryTreeTopComponent.findInstance().viewArtifact(artifact);
return null;
}
@Override
protected void done() {
try {
get();
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, "Unexpected interrupt while navigating to artifact.", ex);
} catch (ExecutionException ex) {
logger.log(Level.SEVERE, "Error navigating to artifact.", ex);
}
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}.execute();
}
}

View File

@ -0,0 +1,77 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.actions;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.SwingWorker;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
import org.sleuthkit.datamodel.OsAccount;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* An action that navigates to an os account.
*/
public class ViewOsAccountAction extends AbstractAction {
private static final Logger logger = Logger.getLogger(ViewOsAccountAction.class.getName());
private final OsAccount osAccount;
/**
* Main constructor.
*
* @param osAccount The os account to navigate to in the action.
* @param displayName The display name of the menu item.
*/
public ViewOsAccountAction(OsAccount osAccount, String displayName) {
super(displayName);
this.osAccount = osAccount;
}
@Override
public void actionPerformed(ActionEvent e) {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
DirectoryTreeTopComponent.findInstance().viewOsAccount(osAccount);
return null;
}
@Override
protected void done() {
try {
get();
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, "Unexpected interrupt while navigating to OS Account.", ex);
} catch (ExecutionException ex) {
logger.log(Level.SEVERE, "Error navigating to OS Account.", ex);
}
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}.execute();
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2018-2019 Basis Technology Corp. * Copyright 2018-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -123,16 +123,6 @@ public class NodeData {
comment = newComment; comment = newComment;
} }
/**
* Check if this is a central repo node.
*
* @return true if this node was created from a central repo instance, false
* otherwise
*/
public boolean isCentralRepoNode() {
return (originalCorrelationInstance != null);
}
/** /**
* Get the case name * Get the case name
* *

View File

@ -25,8 +25,8 @@ import java.nio.file.Files;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -46,16 +46,11 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeIns
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccount;
import org.sleuthkit.datamodel.OsAccountInstance; import org.sleuthkit.datamodel.OsAccountInstance;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -81,151 +76,26 @@ public final class OtherOccurrences {
* @return A list of attributes that can be used for correlation * @return A list of attributes that can be used for correlation
*/ */
public static Collection<CorrelationAttributeInstance> getCorrelationAttributeFromOsAccount(Node node, OsAccount osAccount) { public static Collection<CorrelationAttributeInstance> getCorrelationAttributeFromOsAccount(Node node, OsAccount osAccount) {
Collection<CorrelationAttributeInstance> ret = new ArrayList<>();
Optional<String> osAccountAddr = osAccount.getAddr(); Optional<String> osAccountAddr = osAccount.getAddr();
if (osAccountAddr.isPresent()) { if (osAccountAddr.isPresent()) {
try { try {
for (OsAccountInstance instance : osAccount.getOsAccountInstances()) { for (OsAccountInstance instance : osAccount.getOsAccountInstances()) {
CorrelationAttributeInstance correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttr(instance.getOsAccount(), instance.getDataSource()); List<CorrelationAttributeInstance> correlationAttributeInstances = CorrelationAttributeUtil.makeCorrAttrsForSearch(instance);
if (correlationAttributeInstance != null) { if (!correlationAttributeInstances.isEmpty()) {
ret.add(correlationAttributeInstance); return correlationAttributeInstances;
} }
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.INFO, String.format("Unable to check create CorrelationAttribtueInstance for osAccount %s.", osAccountAddr.get()), ex); logger.log(Level.INFO, String.format("Unable to check create CorrelationAttribtueInstance for osAccount %s.", osAccountAddr.get()), ex);
} }
} }
return Collections.emptyList();
return ret;
}
/**
* Determine what attributes can be used for correlation based on the node.
* If EamDB is not enabled, get the default Files correlation.
*
* @param node The node to correlate.
* @param file The file to correlate.
*
* @return A list of attributes that can be used for correlation
*/
public static Collection<CorrelationAttributeInstance> getCorrelationAttributesFromNode(Node node, AbstractFile file) {
Collection<CorrelationAttributeInstance> ret = new ArrayList<>();
// correlate on blackboard artifact attributes if they exist and supported
BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node);
if (bbArtifact != null && CentralRepository.isEnabled()) {
ret.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch(bbArtifact));
}
// we can correlate based on the MD5 if it is enabled
if (file != null && CentralRepository.isEnabled() && file.getSize() > 0) {
try {
List<CorrelationAttributeInstance.Type> artifactTypes = CentralRepository.getInstance().getDefinedCorrelationTypes();
String md5 = file.getMd5Hash();
if (md5 != null && !md5.isEmpty() && null != artifactTypes && !artifactTypes.isEmpty()) {
for (CorrelationAttributeInstance.Type aType : artifactTypes) {
if (aType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) {
CorrelationCase corCase = CentralRepository.getInstance().getCase(Case.getCurrentCase());
try {
ret.add(new CorrelationAttributeInstance(
aType,
md5,
corCase,
CorrelationDataSource.fromTSKDataSource(corCase, file.getDataSource()),
file.getParentPath() + file.getName(),
"",
file.getKnown(),
file.getId()));
} catch (CorrelationAttributeNormalizationException ex) {
logger.log(Level.INFO, String.format("Unable to check create CorrelationAttribtueInstance for value %s and type %s.", md5, aType.toString()), ex);
}
break;
}
}
}
} catch (CentralRepoException | TskCoreException ex) {
logger.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
}
// If EamDb not enabled, get the Files default correlation type to allow Other Occurances to be enabled.
} else if (file != null && file.getSize() > 0) {
String md5 = file.getMd5Hash();
if (md5 != null && !md5.isEmpty()) {
try {
final CorrelationAttributeInstance.Type fileAttributeType
= CorrelationAttributeInstance.getDefaultCorrelationTypes()
.stream()
.filter(attrType -> attrType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID)
.findAny()
.get();
//The Central Repository is not enabled
ret.add(new CorrelationAttributeInstance(fileAttributeType, md5, null, null, "", "", TskData.FileKnown.UNKNOWN, file.getId()));
} catch (CentralRepoException ex) {
logger.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
} catch (CorrelationAttributeNormalizationException ex) {
logger.log(Level.INFO, String.format("Unable to create CorrelationAttributeInstance for value %s", md5), ex); // NON-NLS
}
}
}
return ret;
}
/**
* Get the associated BlackboardArtifact from a node, if it exists.
*
* @param node The node
*
* @return The associated BlackboardArtifact, or null
*/
public static BlackboardArtifact getBlackboardArtifactFromNode(Node node) {
BlackboardArtifactTag nodeBbArtifactTag = node.getLookup().lookup(BlackboardArtifactTag.class);
BlackboardArtifact nodeBbArtifact = node.getLookup().lookup(BlackboardArtifact.class);
if (nodeBbArtifactTag != null) {
return nodeBbArtifactTag.getArtifact();
} else if (nodeBbArtifact != null) {
return nodeBbArtifact;
}
return null;
}
/**
* Get the associated AbstractFile from a node, if it exists.
*
* @param node The node
*
* @return The associated AbstractFile, or null
*/
public static AbstractFile getAbstractFileFromNode(Node node) {
BlackboardArtifactTag nodeBbArtifactTag = node.getLookup().lookup(BlackboardArtifactTag.class);
ContentTag nodeContentTag = node.getLookup().lookup(ContentTag.class);
AbstractFile nodeAbstractFile = node.getLookup().lookup(AbstractFile.class);
if (nodeBbArtifactTag != null) {
Content content = nodeBbArtifactTag.getContent();
if (content instanceof AbstractFile) {
return (AbstractFile) content;
}
} else if (nodeContentTag != null) {
Content content = nodeContentTag.getContent();
if (content instanceof AbstractFile) {
return (AbstractFile) content;
}
} else if (nodeAbstractFile != null) {
return nodeAbstractFile;
}
return null;
} }
/** /**
* Query the central repo database (if enabled) and the case database to * Query the central repo database (if enabled) and the case database to
* find all artifact instances correlated to the given central repository * find all artifact instances correlated to the given central repository
* artifact. If the central repo is not enabled, this will only return files * artifact.
* from the current case with matching MD5 hashes.
* *
* @param file The current file. * @param file The current file.
* @param deviceId The device ID for the current data source. * @param deviceId The device ID for the current data source.
@ -234,7 +104,7 @@ public final class OtherOccurrences {
* *
* @return A collection of correlated artifact instances * @return A collection of correlated artifact instances
*/ */
public static Map<UniquePathKey, NodeData> getCorrelatedInstances(AbstractFile file, String deviceId, String dataSourceName, CorrelationAttributeInstance corAttr) { public static Map<UniquePathKey, NodeData> getCorrelatedInstances(String deviceId, String dataSourceName, CorrelationAttributeInstance corAttr) {
// @@@ Check exception // @@@ Check exception
try { try {
final Case openCase = Case.getCurrentCaseThrows(); final Case openCase = Case.getCurrentCaseThrows();
@ -251,25 +121,21 @@ public final class OtherOccurrences {
// - the case UUID is different // - the case UUID is different
// - the data source name is different // - the data source name is different
// - the data source device ID is different // - the data source device ID is different
// - the file path is different // - the object id for the underlying file is different
if (artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID) if (artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
&& (!StringUtils.isBlank(dataSourceName) && artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName)) && (!StringUtils.isBlank(dataSourceName) && artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName))
&& (!StringUtils.isBlank(deviceId) && artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)) && (!StringUtils.isBlank(deviceId) && artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId))) {
&& (file != null && artifactInstance.getFilePath().equalsIgnoreCase(file.getParentPath() + file.getName()))) { Long foundObjectId = artifactInstance.getFileObjectId();
Long currentObjectId = corAttr.getFileObjectId();
if (foundObjectId != null && currentObjectId != null && foundObjectId.equals(currentObjectId)) {
continue; continue;
} }
}
NodeData newNode = new NodeData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue()); NodeData newNode = new NodeData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue());
UniquePathKey uniquePathKey = new UniquePathKey(newNode); UniquePathKey uniquePathKey = new UniquePathKey(newNode);
nodeDataMap.put(uniquePathKey, newNode); nodeDataMap.put(uniquePathKey, newNode);
} }
} }
if (file != null && corAttr.getCorrelationType().getDisplayName().equals("Files")) {
List<AbstractFile> caseDbFiles = getCaseDbMatches(corAttr, openCase, file);
for (AbstractFile caseDbFile : caseDbFiles) {
addOrUpdateNodeData(openCase, nodeDataMap, caseDbFile);
}
}
return nodeDataMap; return nodeDataMap;
} catch (CentralRepoException ex) { } catch (CentralRepoException ex) {
logger.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS logger.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS
@ -277,48 +143,12 @@ public final class OtherOccurrences {
logger.log(Level.INFO, "Error getting artifact instances from database.", ex); // NON-NLS logger.log(Level.INFO, "Error getting artifact instances from database.", ex); // NON-NLS
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
} catch (TskCoreException ex) {
// do nothing.
// @@@ Review this behavior
logger.log(Level.SEVERE, "Exception while querying open case.", ex); // NON-NLS
} }
return new HashMap<>( return new HashMap<>(
0); 0);
} }
/**
* Get all other abstract files in the current case with the same MD5 as the
* selected node.
*
* @param corAttr The CorrelationAttribute containing the MD5 to search for
* @param openCase The current case
* @param file The current file.
*
* @return List of matching AbstractFile objects
*
* @throws NoCurrentCaseException
* @throws TskCoreException
* @throws CentralRepoException
*/
public static List<AbstractFile> getCaseDbMatches(CorrelationAttributeInstance corAttr, Case openCase, AbstractFile file) throws NoCurrentCaseException, TskCoreException, CentralRepoException {
List<AbstractFile> caseDbArtifactInstances = new ArrayList<>();
if (file != null) {
String md5 = corAttr.getCorrelationValue();
SleuthkitCase tsk = openCase.getSleuthkitCase();
List<AbstractFile> matches = tsk.findAllFilesWhere(String.format("md5 = '%s'", new Object[]{md5}));
for (AbstractFile fileMatch : matches) {
if (file.equals(fileMatch)) {
continue; // If this is the file the user clicked on
}
caseDbArtifactInstances.add(fileMatch);
}
}
return caseDbArtifactInstances;
}
/** /**
* Adds the file to the nodeDataMap map if it does not already exist * Adds the file to the nodeDataMap map if it does not already exist
* *
@ -423,7 +253,7 @@ public final class OtherOccurrences {
* *
* @throws IOException * @throws IOException
*/ */
public static void writeOtherOccurrencesToFileAsCSV(File destFile, AbstractFile abstractFile, Collection<CorrelationAttributeInstance> correlationAttList, String dataSourceName, String deviceId) throws IOException { public static void writeOtherOccurrencesToFileAsCSV(File destFile, Collection<CorrelationAttributeInstance> correlationAttList, String dataSourceName, String deviceId) throws IOException {
try (BufferedWriter writer = Files.newBufferedWriter(destFile.toPath())) { try (BufferedWriter writer = Files.newBufferedWriter(destFile.toPath())) {
//write headers //write headers
StringBuilder headers = new StringBuilder("\""); StringBuilder headers = new StringBuilder("\"");
@ -440,7 +270,7 @@ public final class OtherOccurrences {
for (CorrelationAttributeInstance corAttr : correlationAttList) { for (CorrelationAttributeInstance corAttr : correlationAttList) {
Map<UniquePathKey, NodeData> correlatedNodeDataMap = new HashMap<>(0); Map<UniquePathKey, NodeData> correlatedNodeDataMap = new HashMap<>(0);
// get correlation and reference set instances from DB // get correlation and reference set instances from DB
correlatedNodeDataMap.putAll(getCorrelatedInstances(abstractFile, deviceId, dataSourceName, corAttr)); correlatedNodeDataMap.putAll(getCorrelatedInstances(deviceId, dataSourceName, corAttr));
for (NodeData nodeData : correlatedNodeDataMap.values()) { for (NodeData nodeData : correlatedNodeDataMap.values()) {
writer.write(nodeData.toCsvString()); writer.write(nodeData.toCsvString());
} }

View File

@ -22,7 +22,6 @@ import java.util.Objects;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.contentviewer.OtherOccurrencesPanel;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;

View File

@ -24,14 +24,16 @@ import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JPanel; import javax.swing.JPanel;
import org.apache.commons.lang.StringUtils;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.centralrepository.application.OtherOccurrences;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.contentviewers.utils.ViewerPriority; import org.sleuthkit.autopsy.contentviewers.utils.ViewerPriority;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactItem;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccount;
/** /**
@ -89,20 +91,35 @@ public final class DataContentViewerOtherCases extends JPanel implements DataCon
@Override @Override
public boolean isSupported(Node node) { public boolean isSupported(Node node) {
//Ideally we would want to attempt to create correlation attributes for the node contents
// Is supported if one of the following is true: //and if none could be created determine that it was not supported.
// - The central repo is enabled and the node is not null //However that winds up being more work than we really want to be performing in this method so we perform a quicker check.
// - The central repo is disabled and the backing file has a valid MD5 hash //The result of this is that the Other Occurrences viewer could be enabled but without any correlation attributes in some situations.
// And the node has information which could be correlated on. // Is supported if:
// The central repo is enabled and the node is not null
if (CentralRepository.isEnabled() && node != null) { if (CentralRepository.isEnabled() && node != null) {
return OtherOccurrences.getAbstractFileFromNode(node) != null || OtherOccurrences.getBlackboardArtifactFromNode(node) != null || node.getLookup().lookup(OsAccount.class) != null; // And the node has information which could be correlated on.
} else if (node != null) { if (node.getLookup().lookup(OsAccount.class) != null) {
AbstractFile file = OtherOccurrences.getAbstractFileFromNode(node); //the node has an associated OsAccount to correlate on
return file != null return true;
&& file.getSize() > 0 }
&& ((file.getMd5Hash() != null) && (!file.getMd5Hash().isEmpty())); if (node.getLookup().lookup(BlackboardArtifactItem.class) != null) {
//it has a blackboard artifact which might have a correlation attribute
return true;
}
if (node.getLookup().lookup(BlackboardArtifactTag.class) != null) {
//Blackboard artifact tags may have their underlying artifact correlated on
return true;
}
AbstractFile file = node.getLookup().lookup(AbstractFile.class);
//the AbstractFile lookup will handle the usecase for file tags as well
if (file != null && !StringUtils.isBlank(file.getMd5Hash())) {
//there is an abstractFile lookup and it has an MD5 so could be correlated on
return true;
}
} }
return false; return false;
} }
@Override @Override

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2019 Basis Technology Corp. * Copyright 2019-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -29,7 +29,6 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -202,14 +201,10 @@ final class OccurrencePanel extends javax.swing.JPanel {
} }
String caseDate = ""; String caseDate = "";
try { try {
if (occurrence.isCentralRepoNode()) {
if (CentralRepository.isEnabled()) { if (CentralRepository.isEnabled()) {
CorrelationCase partialCase = occurrence.getCorrelationAttributeInstance().getCorrelationCase(); CorrelationCase partialCase = occurrence.getCorrelationAttributeInstance().getCorrelationCase();
caseDate = CentralRepository.getInstance().getCaseByUUID(partialCase.getCaseUUID()).getCreationDate(); caseDate = CentralRepository.getInstance().getCaseByUUID(partialCase.getCaseUUID()).getCreationDate();
} }
} else {
caseDate = Case.getCurrentCase().getCreatedDate();
}
} catch (CentralRepoException ex) { } catch (CentralRepoException ex) {
LOGGER.log(Level.WARNING, "Error getting case created date for other occurrence content viewer", ex); LOGGER.log(Level.WARNING, "Error getting case created date for other occurrence content viewer", ex);
} }

View File

@ -29,7 +29,6 @@ import java.util.logging.Level;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.application.NodeData; import org.sleuthkit.autopsy.centralrepository.application.NodeData;
import org.sleuthkit.autopsy.centralrepository.application.OtherOccurrences; import org.sleuthkit.autopsy.centralrepository.application.OtherOccurrences;
import org.sleuthkit.autopsy.centralrepository.application.UniquePathKey; import org.sleuthkit.autopsy.centralrepository.application.UniquePathKey;
@ -116,22 +115,12 @@ class OtherOccurrenceOneTypeWorker extends SwingWorker<OneTypeData, Void> {
if (isCancelled()) { if (isCancelled()) {
break; break;
} }
if (nodeData.isCentralRepoNode()) {
try { try {
dataSources.add(OtherOccurrences.makeDataSourceString(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getDeviceID(), nodeData.getDataSourceName())); dataSources.add(OtherOccurrences.makeDataSourceString(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getDeviceID(), nodeData.getDataSourceName()));
caseNames.put(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getCorrelationAttributeInstance().getCorrelationCase()); caseNames.put(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getCorrelationAttributeInstance().getCorrelationCase());
} catch (CentralRepoException ex) { } catch (CentralRepoException ex) {
logger.log(Level.WARNING, "Unable to get correlation case for displaying other occurrence for case: " + nodeData.getCaseName(), ex); logger.log(Level.WARNING, "Unable to get correlation case for displaying other occurrence for case: " + nodeData.getCaseName(), ex);
} }
} else {
try {
dataSources.add(OtherOccurrences.makeDataSourceString(Case.getCurrentCaseThrows().getName(), nodeData.getDeviceID(), nodeData.getDataSourceName()));
caseNames.put(Case.getCurrentCaseThrows().getName(), new CorrelationCase(Case.getCurrentCaseThrows().getName(), Case.getCurrentCaseThrows().getDisplayName()));
} catch (NoCurrentCaseException ex) {
logger.log(Level.WARNING, "No current case open for other occurrences", ex);
}
}
totalCount++; totalCount++;
} }
} }

View File

@ -28,16 +28,22 @@ import java.util.logging.Level;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.application.NodeData; import org.sleuthkit.autopsy.centralrepository.application.NodeData;
import org.sleuthkit.autopsy.centralrepository.application.OtherOccurrences; import org.sleuthkit.autopsy.centralrepository.application.OtherOccurrences;
import org.sleuthkit.autopsy.centralrepository.contentviewer.OtherOccurrencesNodeWorker.OtherOccurrencesData; import org.sleuthkit.autopsy.centralrepository.contentviewer.OtherOccurrencesNodeWorker.OtherOccurrencesData;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.TskContentItem;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.AnalysisResult;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccount;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
@ -62,16 +68,16 @@ class OtherOccurrencesNodeWorker extends SwingWorker<OtherOccurrencesData, Void>
@Override @Override
protected OtherOccurrencesData doInBackground() throws Exception { protected OtherOccurrencesData doInBackground() throws Exception {
OtherOccurrencesData data = null;
if (CentralRepository.isEnabled()) {
OsAccount osAccount = node.getLookup().lookup(OsAccount.class); OsAccount osAccount = node.getLookup().lookup(OsAccount.class);
AbstractFile file = OtherOccurrences.getAbstractFileFromNode(node);
if (osAccount != null) {
file = node.getLookup().lookup(AbstractFile.class);
}
String deviceId = ""; String deviceId = "";
String dataSourceName = ""; String dataSourceName = "";
Map<String, CorrelationCase> caseNames = new HashMap<>(); Map<String, CorrelationCase> caseNames = new HashMap<>();
Case currentCase = Case.getCurrentCaseThrows(); Case currentCase = Case.getCurrentCaseThrows();
OtherOccurrencesData data = null; //the file is currently being used for determining a correlation instance is not the selected instance
// for the purposes of ignoring the currently selected item
AbstractFile file = node.getLookup().lookup(AbstractFile.class);
try { try {
if (file != null) { if (file != null) {
Content dataSource = file.getDataSource(); Content dataSource = file.getDataSource();
@ -79,47 +85,56 @@ class OtherOccurrencesNodeWorker extends SwingWorker<OtherOccurrencesData, Void>
dataSourceName = dataSource.getName(); dataSourceName = dataSource.getName();
} }
} catch (TskException ex) { } catch (TskException ex) {
// do nothing. logger.log(Level.WARNING, "Exception occurred while trying to get the data source, current case, and device id for an AbstractFile in the other occurrences viewer", ex);
// @@@ Review this behavior return data;
return null;
} }
Collection<CorrelationAttributeInstance> correlationAttributes = new ArrayList<>(); Collection<CorrelationAttributeInstance> correlationAttributes = new ArrayList<>();
if (osAccount != null) { if (osAccount != null) {
correlationAttributes = OtherOccurrences.getCorrelationAttributeFromOsAccount(node, osAccount); correlationAttributes.addAll(OtherOccurrences.getCorrelationAttributeFromOsAccount(node, osAccount));
} else { } else {
correlationAttributes = OtherOccurrences.getCorrelationAttributesFromNode(node, file); TskContentItem<?> contentItem = node.getLookup().lookup(TskContentItem.class);
Content content = null;
if (contentItem != null) {
content = contentItem.getTskContent();
} else { //fallback and check ContentTags
ContentTag nodeContentTag = node.getLookup().lookup(ContentTag.class);
BlackboardArtifactTag nodeBbArtifactTag = node.getLookup().lookup(BlackboardArtifactTag.class);
if (nodeBbArtifactTag != null) {
content = nodeBbArtifactTag.getArtifact();
} else if (nodeContentTag != null) {
content = nodeContentTag.getContent();
}
}
if (content != null) {
if (content instanceof AbstractFile) {
correlationAttributes.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((AbstractFile) content));
} else if (content instanceof AnalysisResult) {
correlationAttributes.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((AnalysisResult) content));
} else if (content instanceof DataArtifact) {
correlationAttributes.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((DataArtifact) content));
}
}
} }
int totalCount = 0; int totalCount = 0;
Set<String> dataSources = new HashSet<>(); Set<String> dataSources = new HashSet<>();
for (CorrelationAttributeInstance corAttr : correlationAttributes) { for (CorrelationAttributeInstance corAttr : correlationAttributes) {
for (NodeData nodeData : OtherOccurrences.getCorrelatedInstances(file, deviceId, dataSourceName, corAttr).values()) { for (NodeData nodeData : OtherOccurrences.getCorrelatedInstances(deviceId, dataSourceName, corAttr).values()) {
if (nodeData.isCentralRepoNode()) {
try { try {
dataSources.add(OtherOccurrences.makeDataSourceString(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getDeviceID(), nodeData.getDataSourceName())); dataSources.add(OtherOccurrences.makeDataSourceString(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getDeviceID(), nodeData.getDataSourceName()));
caseNames.put(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getCorrelationAttributeInstance().getCorrelationCase()); caseNames.put(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getCorrelationAttributeInstance().getCorrelationCase());
} catch (CentralRepoException ex) { } catch (CentralRepoException ex) {
logger.log(Level.WARNING, "Unable to get correlation case for displaying other occurrence for case: " + nodeData.getCaseName(), ex); logger.log(Level.WARNING, "Unable to get correlation case for displaying other occurrence for case: " + nodeData.getCaseName(), ex);
} }
} else {
try {
dataSources.add(OtherOccurrences.makeDataSourceString(Case.getCurrentCaseThrows().getName(), nodeData.getDeviceID(), nodeData.getDataSourceName()));
caseNames.put(Case.getCurrentCaseThrows().getName(), new CorrelationCase(Case.getCurrentCaseThrows().getName(), Case.getCurrentCaseThrows().getDisplayName()));
} catch (NoCurrentCaseException ex) {
logger.log(Level.WARNING, "No current case open for other occurrences", ex);
}
}
totalCount++; totalCount++;
if (isCancelled()) { if (isCancelled()) {
break; break;
} }
} }
} }
if (!isCancelled()) { if (!isCancelled()) {
data = new OtherOccurrencesData(correlationAttributes, file, dataSourceName, deviceId, caseNames, totalCount, dataSources.size(), OtherOccurrences.getEarliestCaseDate()); data = new OtherOccurrencesData(correlationAttributes, file, dataSourceName, deviceId, caseNames, totalCount, dataSources.size(), OtherOccurrences.getEarliestCaseDate());
} }
}
return data; return data;
} }

View File

@ -278,7 +278,7 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
if (!selectedFile.getName().endsWith(".csv")) { // NON-NLS if (!selectedFile.getName().endsWith(".csv")) { // NON-NLS
selectedFile = new File(selectedFile.toString() + ".csv"); // NON-NLS selectedFile = new File(selectedFile.toString() + ".csv"); // NON-NLS
} }
CSVWorker csvWorker = new CSVWorker(selectedFile, file, dataSourceName, deviceId, Collections.unmodifiableCollection(correlationAttributes)); CSVWorker csvWorker = new CSVWorker(selectedFile, dataSourceName, deviceId, Collections.unmodifiableCollection(correlationAttributes));
csvWorker.execute(); csvWorker.execute();
} }
} }
@ -426,7 +426,7 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
worker = new SelectionWorker(correlationAttributes, file, deviceId, dataSourceName) { worker = new SelectionWorker(correlationAttributes, deviceId, dataSourceName) {
@Override @Override
public void done() { public void done() {
if (isCancelled()) { if (isCancelled()) {
@ -447,14 +447,10 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
for (NodeData nodeData : correlatedNodeDataMap.values()) { for (NodeData nodeData : correlatedNodeDataMap.values()) {
for (int selectedRow : selectedCaseIndexes) { for (int selectedRow : selectedCaseIndexes) {
try { try {
if (nodeData.isCentralRepoNode()) {
if (casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedRow)) != null if (casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedRow)) != null
&& casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedRow)).getCaseUUID().equals(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID())) { && casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedRow)).getCaseUUID().equals(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID())) {
dataSourcesTableModel.addNodeData(nodeData); dataSourcesTableModel.addNodeData(nodeData);
} }
} else if (currentCaseName != null && (casesTableModel.getCorrelationCase(casesTable.convertRowIndexToModel(selectedRow)).getCaseUUID().equals(currentCaseName))) {
dataSourcesTableModel.addNodeData(nodeData);
}
} catch (CentralRepoException ex) { } catch (CentralRepoException ex) {
logger.log(Level.WARNING, "Unable to get correlation attribute instance from OtherOccurrenceNodeInstanceData for case " + nodeData.getCaseName(), ex); logger.log(Level.WARNING, "Unable to get correlation attribute instance from OtherOccurrenceNodeInstanceData for case " + nodeData.getCaseName(), ex);
} }
@ -491,7 +487,7 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
final int[] selectedDataSources = dataSourcesTable.getSelectedRows(); final int[] selectedDataSources = dataSourcesTable.getSelectedRows();
filesTableModel.clearTable(); filesTableModel.clearTable();
worker = new SelectionWorker(correlationAttributes, file, deviceId, dataSourceName) { worker = new SelectionWorker(correlationAttributes, deviceId, dataSourceName) {
@Override @Override
public void done() { public void done() {
if (isCancelled()) { if (isCancelled()) {
@ -505,16 +501,10 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
for (int selectedDataSourceRow : selectedDataSources) { for (int selectedDataSourceRow : selectedDataSources) {
int rowModelIndex = dataSourcesTable.convertRowIndexToModel(selectedDataSourceRow); int rowModelIndex = dataSourcesTable.convertRowIndexToModel(selectedDataSourceRow);
try { try {
if (nodeData.isCentralRepoNode()) {
if (dataSourcesTableModel.getCaseUUIDForRow(rowModelIndex).equals(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID()) if (dataSourcesTableModel.getCaseUUIDForRow(rowModelIndex).equals(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID())
&& dataSourcesTableModel.getDeviceIdForRow(rowModelIndex).equals(nodeData.getDeviceID())) { && dataSourcesTableModel.getDeviceIdForRow(rowModelIndex).equals(nodeData.getDeviceID())) {
filesTableModel.addNodeData(nodeData); filesTableModel.addNodeData(nodeData);
} }
} else {
if (dataSourcesTableModel.getDeviceIdForRow(dataSourcesTable.convertRowIndexToModel(selectedDataSourceRow)).equals(nodeData.getDeviceID())) {
filesTableModel.addNodeData(nodeData);
}
}
} catch (CentralRepoException ex) { } catch (CentralRepoException ex) {
logger.log(Level.WARNING, "Unable to get correlation attribute instance from OtherOccurrenceNodeInstanceData for case " + nodeData.getCaseName(), ex); logger.log(Level.WARNING, "Unable to get correlation attribute instance from OtherOccurrenceNodeInstanceData for case " + nodeData.getCaseName(), ex);
} }
@ -618,7 +608,6 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
private class SelectionWorker extends SwingWorker<Map<UniquePathKey, NodeData>, Void> { private class SelectionWorker extends SwingWorker<Map<UniquePathKey, NodeData>, Void> {
private final Collection<CorrelationAttributeInstance> coAtInstances; private final Collection<CorrelationAttributeInstance> coAtInstances;
private final AbstractFile abstractFile;
private final String deviceIdStr; private final String deviceIdStr;
private final String dataSourceNameStr; private final String dataSourceNameStr;
@ -630,9 +619,8 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
* @param deviceIdStr * @param deviceIdStr
* @param dataSourceNameStr * @param dataSourceNameStr
*/ */
SelectionWorker(Collection<CorrelationAttributeInstance> coAtInstances, AbstractFile abstractFile, String deviceIdStr, String dataSourceNameStr) { SelectionWorker(Collection<CorrelationAttributeInstance> coAtInstances, String deviceIdStr, String dataSourceNameStr) {
this.coAtInstances = coAtInstances; this.coAtInstances = coAtInstances;
this.abstractFile = abstractFile;
this.dataSourceNameStr = dataSourceNameStr; this.dataSourceNameStr = dataSourceNameStr;
this.deviceIdStr = deviceIdStr; this.deviceIdStr = deviceIdStr;
} }
@ -641,7 +629,7 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
protected Map<UniquePathKey, NodeData> doInBackground() throws Exception { protected Map<UniquePathKey, NodeData> doInBackground() throws Exception {
Map<UniquePathKey, NodeData> correlatedNodeDataMap = new HashMap<>(); Map<UniquePathKey, NodeData> correlatedNodeDataMap = new HashMap<>();
for (CorrelationAttributeInstance corAttr : coAtInstances) { for (CorrelationAttributeInstance corAttr : coAtInstances) {
correlatedNodeDataMap.putAll(OtherOccurrences.getCorrelatedInstances(abstractFile, deviceIdStr, dataSourceNameStr, corAttr)); correlatedNodeDataMap.putAll(OtherOccurrences.getCorrelatedInstances(deviceIdStr, dataSourceNameStr, corAttr));
if (isCancelled()) { if (isCancelled()) {
return new HashMap<>(); return new HashMap<>();
@ -661,7 +649,6 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
private final String dataSourceName; private final String dataSourceName;
private final String deviceId; private final String deviceId;
private final File destFile; private final File destFile;
private final AbstractFile abstractFile;
/** /**
* Construct a CSVWorker * Construct a CSVWorker
@ -672,9 +659,8 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
* @param deviceId Id of the selected device. * @param deviceId Id of the selected device.
* @param correlationAttList * @param correlationAttList
*/ */
CSVWorker(File destFile, AbstractFile sourceFile, String dataSourceName, String deviceId, Collection<CorrelationAttributeInstance> correlationAttList) { CSVWorker(File destFile, String dataSourceName, String deviceId, Collection<CorrelationAttributeInstance> correlationAttList) {
this.destFile = destFile; this.destFile = destFile;
this.abstractFile = sourceFile;
this.dataSourceName = dataSourceName; this.dataSourceName = dataSourceName;
this.deviceId = deviceId; this.deviceId = deviceId;
this.correlationAttList = correlationAttList; this.correlationAttList = correlationAttList;
@ -682,7 +668,7 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
@Override @Override
protected Void doInBackground() throws Exception { protected Void doInBackground() throws Exception {
OtherOccurrences.writeOtherOccurrencesToFileAsCSV(this.destFile, this.abstractFile, this.correlationAttList, this.dataSourceName, this.deviceId); OtherOccurrences.writeOtherOccurrencesToFileAsCSV(this.destFile, this.correlationAttList, this.dataSourceName, this.deviceId);
return null; return null;
} }
@ -876,8 +862,7 @@ public final class OtherOccurrencesPanel extends javax.swing.JPanel {
int rowIndex = filesTable.getSelectedRow(); int rowIndex = filesTable.getSelectedRow();
List<NodeData> selectedFile = filesTableModel.getListOfNodesForFile(rowIndex); List<NodeData> selectedFile = filesTableModel.getListOfNodesForFile(rowIndex);
if (!selectedFile.isEmpty() && selectedFile.get(0) instanceof NodeData) { if (!selectedFile.isEmpty() && selectedFile.get(0) instanceof NodeData) {
NodeData instanceData = selectedFile.get(0); enableCentralRepoActions = true;
enableCentralRepoActions = instanceData.isCentralRepoNode();
} }
} }
showCaseDetailsMenuItem.setVisible(enableCentralRepoActions); showCaseDetailsMenuItem.setVisible(enableCentralRepoActions);

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2015-2020 Basis Technology Corp. * Copyright 2015-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -39,9 +40,11 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataArtifact; import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.HashUtility;
import org.sleuthkit.datamodel.InvalidAccountIDException; import org.sleuthkit.datamodel.InvalidAccountIDException;
import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccount;
import org.sleuthkit.datamodel.OsAccountInstance;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -78,13 +81,13 @@ public class CorrelationAttributeUtil {
return Bundle.CorrelationAttributeUtil_emailaddresses_text(); return Bundle.CorrelationAttributeUtil_emailaddresses_text();
} }
private static List<CorrelationAttributeInstance> makeCorrAttrsToSave(DataArtifact artifact) { public static List<CorrelationAttributeInstance> makeCorrAttrsToSave(DataArtifact artifact) {
int artifactTypeID = artifact.getArtifactTypeID(); int artifactTypeID = artifact.getArtifactTypeID();
//The account fields in these types are expected to be saved in a TSK_ACCOUNT artifact, which will be processed //The account fields in these types are expected to be saved in a TSK_ACCOUNT artifact, which will be processed
if (artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() if (artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) { || artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) {
return new ArrayList<>(); return Collections.emptyList();
} }
return CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact); return CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact);
} }
@ -102,71 +105,80 @@ public class CorrelationAttributeUtil {
* @return A list, possibly empty, of correlation attribute instances for * @return A list, possibly empty, of correlation attribute instances for
* the content. * the content.
*/ */
public static List<CorrelationAttributeInstance> makeCorrAttrsToSave(Content content) { public static List<CorrelationAttributeInstance> makeCorrAttrsToSave(AbstractFile file) {
if (content instanceof DataArtifact) { return makeCorrAttrsForSearch(file);
return makeCorrAttrsToSave((DataArtifact) content);
} else if (content instanceof AnalysisResult) {
//AnalysisResults should already have the correlation attributes they are correlating on saved
//This check replaces the check explicitly excluding keyword hits and interesting items that existed prior to the AnalysisResult designation
return new ArrayList<>();
} else {
return makeCorrAttrsForSearch(content);
} }
public static List<CorrelationAttributeInstance> makeCorrAttrsToSave(AnalysisResult file) {
return Collections.emptyList();
}
public static List<CorrelationAttributeInstance> makeCorrAttrsToSave(OsAccountInstance osAccountInstance) {
return makeCorrAttrsForSearch(osAccountInstance);
} }
/** /**
* Makes zero to many correlation attribute instances from the attributes of * Makes zero to many correlation attribute instances from the attributes of
* content that have correlatable data. The intention of this method is to * AnalysisResult that have correlatable data. The intention of this method
* use the results to correlate with, not to save. If you want to save, * is to use the results to correlate with, not to save. If you want to
* please use makeCorrAttrsToSave. An artifact that can have correlatable * save, please use makeCorrAttrsToSave. An artifact that can have data to
* data != An artifact that should be the source of data in the CR, so * search for != An artifact that should be the source of data in the CR, so
* results may be too lenient. * results may be too lenient.
* *
* IMPORTANT: The correlation attribute instances are NOT added to the * IMPORTANT: The correlation attribute instances are NOT added to the
* central repository by this method. * central repository by this method.
* *
* TODO (Jira-6088): The methods in this low-level, utility class should * JIRA-TODO (Jira-6088)
* throw exceptions instead of logging them. The reason for this is that the
* clients of the utility class, not the utility class itself, should be in
* charge of error handling policy, per the Autopsy Coding Standard. Note
* that clients of several of these methods currently cannot determine
* whether receiving a null return value is an error or not, plus null
* checking is easy to forget, while catching exceptions is enforced.
* *
* @param Content A Content object. * @param analysisResult An AnalysisResult object.
* *
* @return A list, possibly empty, of correlation attribute instances for * @return A list, possibly empty, of correlation attribute instances for
* the content. * the AnalysisResult.
*/ */
public static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(Content content) { public static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(AnalysisResult analysisResult) {
if (content instanceof DataArtifact) {
return makeCorrAttrsForSearch((DataArtifact) content);
} else if (content instanceof AnalysisResult) {
return makeCorrAttrsForSearch((AnalysisResult) content);
} else if (content instanceof AbstractFile) {
return makeCorrAttrsForSearch((AbstractFile) content);
} else {
return new ArrayList<>();
}
}
private static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(AnalysisResult analysisResult) {
List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>(); List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>();
try { try {
int artifactTypeID = analysisResult.getArtifactTypeID(); int artifactTypeID = analysisResult.getArtifactTypeID();
if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { if (artifactTypeID == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
BlackboardAttribute setNameAttr = analysisResult.getAttribute(BlackboardAttribute.Type.TSK_SET_NAME);
if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) {
makeCorrAttrFromArtifactAttr(correlationAttrs, analysisResult, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID, analysisResult.getAttributes());
}
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
BlackboardAttribute assocArtifactAttr = analysisResult.getAttribute(BlackboardAttribute.Type.TSK_ASSOCIATED_ARTIFACT); BlackboardAttribute assocArtifactAttr = analysisResult.getAttribute(BlackboardAttribute.Type.TSK_ASSOCIATED_ARTIFACT);
if (assocArtifactAttr != null) { if (assocArtifactAttr != null) {
BlackboardArtifact sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong()); BlackboardArtifact sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong());
return CorrelationAttributeUtil.makeCorrAttrsForSearch(sourceArtifact); if (sourceArtifact instanceof DataArtifact) {
correlationAttrs.addAll((CorrelationAttributeUtil.makeCorrAttrsForSearch((DataArtifact) sourceArtifact)));
} else if (sourceArtifact instanceof AnalysisResult) {
correlationAttrs.addAll((CorrelationAttributeUtil.makeCorrAttrsForSearch((AnalysisResult) sourceArtifact)));
} else {
String sourceName = sourceArtifact != null ? "SourceArtifact display name: " + sourceArtifact.getDisplayName() : "SourceArtifact was null";
logger.log(Level.WARNING, "Source artifact found through TSK_ASSOCIATED_ARTIFACT attribute was not a DataArtifact or "
+ "an Analysis Result. AssociateArtifactAttr Value: {0} {1}",
new Object[]{assocArtifactAttr.getValueString(), sourceName});
}
}
} else {
if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
BlackboardAttribute setNameAttr = analysisResult.getAttribute(BlackboardAttribute.Type.TSK_SET_NAME);
if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) {
correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(analysisResult, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID, analysisResult.getAttributes()));
} }
} }
correlationAttrs.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch(analysisResult.getParent())); Content parent = analysisResult.getParent();
if (parent instanceof AbstractFile) {
correlationAttrs.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((AbstractFile) parent));
} else if (parent instanceof AnalysisResult) {
correlationAttrs.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((AnalysisResult) parent));
} else if (parent instanceof DataArtifact) {
correlationAttrs.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((DataArtifact) parent));
} else if (parent instanceof OsAccount) {
for (OsAccountInstance osAccountInst : ((OsAccount) parent).getOsAccountInstances()) {
if (osAccountInst.getDataSource().equals(analysisResult.getDataSource())) {
correlationAttrs.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch(osAccountInst));
break;
}
}
}
}
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get information regarding correlation attributes from AnalysisResult", ex); logger.log(Level.SEVERE, "Failed to get information regarding correlation attributes from AnalysisResult", ex);
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
@ -177,7 +189,25 @@ public class CorrelationAttributeUtil {
return correlationAttrs; return correlationAttrs;
} }
private static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(DataArtifact artifact) { /**
* Makes zero to many correlation attribute instances from the attributes of
* a DataArtifact that have correlatable data. The intention of this method
* is to use the results to correlate with, not to save. If you want to
* save, please use makeCorrAttrsToSave. An artifact that can have data to
* search for != An artifact that should be the source of data in the CR, so
* results may be too lenient.
*
* IMPORTANT: The correlation attribute instances are NOT added to the
* central repository by this method.
*
* JIRA-TODO (Jira-6088)
*
* @param artifact A DataArtifact object.
*
* @return A list, possibly empty, of correlation attribute instances for
* the DataArtifact.
*/
public static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(DataArtifact artifact) {
List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>(); List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>();
try { try {
@ -188,52 +218,50 @@ public class CorrelationAttributeUtil {
BlackboardAttribute domainAttr = getAttribute(attributes, new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN)); BlackboardAttribute domainAttr = getAttribute(attributes, new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN));
if ((domainAttr != null) if ((domainAttr != null)
&& !domainsToSkip.contains(domainAttr.getValueString())) { && !domainsToSkip.contains(domainAttr.getValueString())) {
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID, attributes); correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID, attributes));
} }
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) { } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) {
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
Content dataSource = sourceContent.getDataSource(); Content dataSource = sourceContent.getDataSource();
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID, correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID,
attributes, sourceContent, dataSource); attributes, sourceContent, dataSource));
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID,
attributes, sourceContent, dataSource); attributes, sourceContent, dataSource));
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) { } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) {
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID, attributes); correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID, attributes));
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID() } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) { || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) {
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, attributes); correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, attributes));
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) { } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) {
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
Content dataSource = sourceContent.getDataSource(); Content dataSource = sourceContent.getDataSource();
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID, correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID,
attributes, sourceContent, dataSource); attributes, sourceContent, dataSource));
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID, correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID,
attributes, sourceContent, dataSource); attributes, sourceContent, dataSource));
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID, correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID,
attributes, sourceContent, dataSource); attributes, sourceContent, dataSource));
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) { } else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) {
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
Content dataSource = sourceContent.getDataSource(); Content dataSource = sourceContent.getDataSource();
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID, correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID,
attributes, sourceContent, dataSource); attributes, sourceContent, dataSource));
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID, correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID,
attributes, sourceContent, dataSource); attributes, sourceContent, dataSource));
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) { } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) {
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
Content dataSource = sourceContent.getDataSource(); Content dataSource = sourceContent.getDataSource();
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID, correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID,
attributes, sourceContent, dataSource); attributes, sourceContent, dataSource));
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID, correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID,
attributes, sourceContent, dataSource); attributes, sourceContent, dataSource));
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { } else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
makeCorrAttrFromAcctArtifact(correlationAttrs, artifact); makeCorrAttrFromAcctArtifact(correlationAttrs, artifact);
@ -245,14 +273,14 @@ public class CorrelationAttributeUtil {
pathAttrString = setNameAttr.getValueString(); pathAttrString = setNameAttr.getValueString();
} }
if (pathAttrString != null && !pathAttrString.isEmpty()) { if (pathAttrString != null && !pathAttrString.isEmpty()) {
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes); correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes));
} else { } else {
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes); correlationAttrs.addAll(makeCorrAttrFromArtifactAttr(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes));
} }
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() } else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) { || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) {
makeCorrAttrsFromCommunicationArtifacts(correlationAttrs, artifact, attributes); correlationAttrs.addAll(makeCorrAttrsFromCommunicationArtifact(artifact, attributes));
} }
} catch (CorrelationAttributeNormalizationException ex) { } catch (CorrelationAttributeNormalizationException ex) {
logger.log(Level.WARNING, String.format("Error normalizing correlation attribute (%s)", artifact), ex); // NON-NLS logger.log(Level.WARNING, String.format("Error normalizing correlation attribute (%s)", artifact), ex); // NON-NLS
@ -298,6 +326,7 @@ public class CorrelationAttributeUtil {
* *
* @param corrAttrInstances Correlation attributes will be added to this. * @param corrAttrInstances Correlation attributes will be added to this.
* @param artifact An artifact with a phone number attribute. * @param artifact An artifact with a phone number attribute.
* @param attributes List of attributes.
* *
* @throws TskCoreException If there is an error * @throws TskCoreException If there is an error
* querying the case * querying the case
@ -309,8 +338,9 @@ public class CorrelationAttributeUtil {
* in normalizing the * in normalizing the
* attribute. * attribute.
*/ */
private static void makeCorrAttrsFromCommunicationArtifacts(List<CorrelationAttributeInstance> corrAttrInstances, BlackboardArtifact artifact, private static List<CorrelationAttributeInstance> makeCorrAttrsFromCommunicationArtifact(BlackboardArtifact artifact,
List<BlackboardAttribute> attributes) throws TskCoreException, CentralRepoException, CorrelationAttributeNormalizationException { List<BlackboardAttribute> attributes) throws TskCoreException, CentralRepoException, CorrelationAttributeNormalizationException {
/* /*
* Extract the phone number from the artifact attribute. * Extract the phone number from the artifact attribute.
*/ */
@ -325,6 +355,7 @@ public class CorrelationAttributeUtil {
/* /*
* Normalize the phone number. * Normalize the phone number.
*/ */
List<CorrelationAttributeInstance> corrAttrInstances = Collections.emptyList();
if (value != null if (value != null
&& CorrelationAttributeNormalizer.isValidPhoneNumber(value)) { && CorrelationAttributeNormalizer.isValidPhoneNumber(value)) {
value = CorrelationAttributeNormalizer.normalizePhone(value); value = CorrelationAttributeNormalizer.normalizePhone(value);
@ -333,6 +364,7 @@ public class CorrelationAttributeUtil {
corrAttrInstances.add(corrAttr); corrAttrInstances.add(corrAttr);
} }
} }
return corrAttrInstances;
} }
/** /**
@ -393,11 +425,12 @@ public class CorrelationAttributeUtil {
* *
* @param corrAttrInstances A list of correlation attribute instances. * @param corrAttrInstances A list of correlation attribute instances.
* @param artifact An artifact. * @param artifact An artifact.
* @param artAttrType The type of the atrribute of the artifact that * @param artAttrType The type of the attribute of the artifact that
* is to be made into a correlatin attribute * is to be made into a correlation attribute
* instance. * instance.
* @param typeId The type ID for the desired correlation * @param typeId The type ID for the desired correlation
* attribute instance. * attribute instance.
* @param attributes List of attributes.
* @param sourceContent The source content object. * @param sourceContent The source content object.
* @param dataSource The data source content object. * @param dataSource The data source content object.
* *
@ -406,9 +439,9 @@ public class CorrelationAttributeUtil {
* @throws TskCoreException If there is an error querying the case * @throws TskCoreException If there is an error querying the case
* database. * database.
*/ */
private static void makeCorrAttrFromArtifactAttr(List<CorrelationAttributeInstance> corrAttrInstances, BlackboardArtifact artifact, ATTRIBUTE_TYPE artAttrType, int typeId, private static List<CorrelationAttributeInstance> makeCorrAttrFromArtifactAttr(BlackboardArtifact artifact, ATTRIBUTE_TYPE artAttrType, int typeId,
List<BlackboardAttribute> attributes, Content sourceContent, Content dataSource) throws CentralRepoException, TskCoreException { List<BlackboardAttribute> attributes, Content sourceContent, Content dataSource) throws CentralRepoException, TskCoreException {
List<CorrelationAttributeInstance> corrAttrInstances = new ArrayList<>();
BlackboardAttribute attribute = getAttribute(attributes, new BlackboardAttribute.Type(artAttrType)); BlackboardAttribute attribute = getAttribute(attributes, new BlackboardAttribute.Type(artAttrType));
if (attribute != null) { if (attribute != null) {
String value = attribute.getValueString(); String value = attribute.getValueString();
@ -419,6 +452,7 @@ public class CorrelationAttributeUtil {
} }
} }
} }
return corrAttrInstances;
} }
/** /**
@ -427,21 +461,22 @@ public class CorrelationAttributeUtil {
* *
* @param corrAttrInstances A list of correlation attribute instances. * @param corrAttrInstances A list of correlation attribute instances.
* @param artifact An artifact. * @param artifact An artifact.
* @param artAttrType The type of the atrribute of the artifact that * @param artAttrType The type of the attribute of the artifact that
* is to be made into a correlatin attribute * is to be made into a correlation attribute
* instance. * instance.
* @param typeId The type ID for the desired correlation * @param typeId The type ID for the desired correlation
* attribute instance. * attribute instance.
* @param attributes List of attributes.
* *
* @throws CentralRepoException If there is an error querying the central * @throws CentralRepoException If there is an error querying the central
* repository. * repository.
* @throws TskCoreException If there is an error querying the case * @throws TskCoreException If there is an error querying the case
* database. * database.
*/ */
private static void makeCorrAttrFromArtifactAttr(List<CorrelationAttributeInstance> corrAttrInstances, BlackboardArtifact artifact, ATTRIBUTE_TYPE artAttrType, int typeId, private static List<CorrelationAttributeInstance> makeCorrAttrFromArtifactAttr(BlackboardArtifact artifact, ATTRIBUTE_TYPE artAttrType, int typeId,
List<BlackboardAttribute> attributes) throws CentralRepoException, TskCoreException { List<BlackboardAttribute> attributes) throws CentralRepoException, TskCoreException {
makeCorrAttrFromArtifactAttr(corrAttrInstances, artifact, artAttrType, typeId, attributes, null, null); return makeCorrAttrFromArtifactAttr(artifact, artAttrType, typeId, attributes, null, null);
} }
/** /**
@ -550,51 +585,6 @@ public class CorrelationAttributeUtil {
} }
} }
/**
* Makes a correlation attribute instance of a given type from an OS
* account. Checks address if it is null, or one of the ones always present
* on a windows system and thus not unique.
*
* @param osAccoun The OS account.
* @param dataSource The data source content object.
*
* @return The correlation attribute instance or null, if an error occurred.
*/
public static CorrelationAttributeInstance makeCorrAttr(OsAccount osAccount, Content dataSource) {
Optional<String> 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 null;
}
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, dataSource),
"",
"",
TskData.FileKnown.KNOWN,
osAccount.getId());
return correlationAttributeInstance;
} catch (CentralRepoException ex) {
logger.log(Level.SEVERE, String.format("Cannot get central repository for OsAccount: %s.", accountAddr.get()), ex); //NON-NLS
return null;
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
return null;
} catch (CorrelationAttributeNormalizationException ex) {
logger.log(Level.SEVERE, "Exception with Correlation Attribute Normalization.", ex); //NON-NLS
return null;
}
}
// @@@ BC: This seems like it should go into a DB-specific class because it is // @@@ BC: This seems like it should go into a DB-specific class because it is
// much different from the other methods in this class. It is going to the DB for data. // much different from the other methods in this class. It is going to the DB for data.
/** /**
@ -694,9 +684,10 @@ public class CorrelationAttributeUtil {
* *
* @param file The file. * @param file The file.
* *
* @return The correlation attribute instance or null, if an error occurred. * @return The correlation attribute instance in a list, or an empty list if
* an error occurred.
*/ */
private static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(AbstractFile file) { public static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(AbstractFile file) {
List<CorrelationAttributeInstance> fileTypeList = new ArrayList<>(); // will be an empty or single element list as was decided in 7852 List<CorrelationAttributeInstance> fileTypeList = new ArrayList<>(); // will be an empty or single element list as was decided in 7852
if (!isSupportedAbstractFileType(file)) { if (!isSupportedAbstractFileType(file)) {
return fileTypeList; return fileTypeList;
@ -765,6 +756,48 @@ public class CorrelationAttributeUtil {
} }
} }
public static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(OsAccountInstance osAccountInst) {
List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>();
OsAccount account = null;
DataSource dataSource = null;
if (osAccountInst != null) {
try {
account = osAccountInst.getOsAccount();
dataSource = osAccountInst.getDataSource();
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting information from OsAccountInstance.", ex);
}
}
if (account != null && dataSource != null) {
Optional<String> accountAddr = account.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")) {
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, dataSource),
"",
"",
TskData.FileKnown.KNOWN,
account.getId());
correlationAttrs.add(correlationAttributeInstance);
} 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
}
}
}
return correlationAttrs;
}
/** /**
* Prevent instantiation of this utility class. * Prevent instantiation of this utility class.
*/ */

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2015-2020 Basis Technology Corp. * Copyright 2015-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -58,8 +58,8 @@ final class SqliteCentralRepo extends RdbmsCentralRepo {
* *
* @return the singleton instance of SqliteEamDb * @return the singleton instance of SqliteEamDb
* *
* @throws CentralRepoException if one or more default correlation type(s) have an * @throws CentralRepoException if one or more default correlation type(s)
* invalid db table name. * have an invalid db table name.
*/ */
public synchronized static SqliteCentralRepo getInstance() throws CentralRepoException { public synchronized static SqliteCentralRepo getInstance() throws CentralRepoException {
if (instance == null) { if (instance == null) {
@ -71,9 +71,9 @@ final class SqliteCentralRepo extends RdbmsCentralRepo {
/** /**
* *
* @throws CentralRepoException if the AbstractSqlEamDb class has one or more * @throws CentralRepoException if the AbstractSqlEamDb class has one or
* default correlation type(s) having an invalid db * more default correlation type(s) having an
* table name. * invalid db table name.
*/ */
private SqliteCentralRepo() throws CentralRepoException { private SqliteCentralRepo() throws CentralRepoException {
dbSettings = new SqliteCentralRepoSettings(); dbSettings = new SqliteCentralRepoSettings();
@ -231,6 +231,7 @@ final class SqliteCentralRepo extends RdbmsCentralRepo {
protected Connection getEphemeralConnection() { protected Connection getEphemeralConnection() {
return this.dbSettings.getEphemeralConnection(); return this.dbSettings.getEphemeralConnection();
} }
/** /**
* Add a new name/value pair in the db_info table. * Add a new name/value pair in the db_info table.
* *
@ -1224,8 +1225,8 @@ final class SqliteCentralRepo extends RdbmsCentralRepo {
* *
* @return the lock, or null if locking is not supported * @return the lock, or null if locking is not supported
* *
* @throws CentralRepoException if the coordination service is running but we fail * @throws CentralRepoException if the coordination service is running but
* to get the lock * we fail to get the lock
*/ */
@Override @Override
public CoordinationService.Lock getExclusiveMultiUserDbLock() throws CentralRepoException { public CoordinationService.Lock getExclusiveMultiUserDbLock() throws CentralRepoException {

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.centralrepository.eventlisteners;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.EnumSet; import java.util.EnumSet;
@ -64,12 +65,14 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNor
import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.AnalysisResult;
import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_OTHER_CASES; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_OTHER_CASES;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_TYPE; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_TYPE;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_VALUE; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_VALUE;
import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccount;
import org.sleuthkit.datamodel.OsAccountInstance; import org.sleuthkit.datamodel.OsAccountInstance;
import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.Score;
@ -212,6 +215,28 @@ public final class CaseEventListener implements PropertyChangeListener {
.isPresent(); .isPresent();
} }
/**
* Sets the known status of a blackboard artifact in the central repository.
*
* @param bbArtifact The blackboard artifact to set known status.
* @param knownStatus The new known status.
*/
private static void setArtifactKnownStatus(CentralRepository dbManager, BlackboardArtifact bbArtifact, TskData.FileKnown knownStatus) {
List<CorrelationAttributeInstance> convertedArtifacts = new ArrayList<>();
if (bbArtifact instanceof DataArtifact) {
convertedArtifacts.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((DataArtifact) bbArtifact));
} else if (bbArtifact instanceof AnalysisResult) {
convertedArtifacts.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((AnalysisResult) bbArtifact));
}
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
try {
dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus);
} catch (CentralRepoException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
}
}
}
private final class ContentTagTask implements Runnable { private final class ContentTagTask implements Runnable {
private final CentralRepository dbManager; private final CentralRepository dbManager;
@ -430,9 +455,9 @@ public final class CaseEventListener implements PropertyChangeListener {
TagsManager tagsManager = openCase.getServices().getTagsManager(); TagsManager tagsManager = openCase.getServices().getTagsManager();
List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
if (hasNotableTag(tags)) { if (hasNotableTag(tags)) {
setArtifactKnownStatus(bbArtifact, TskData.FileKnown.BAD); setArtifactKnownStatus(dbManager, bbArtifact, TskData.FileKnown.BAD);
} else { } else {
setArtifactKnownStatus(bbArtifact, TskData.FileKnown.UNKNOWN); setArtifactKnownStatus(dbManager, bbArtifact, TskData.FileKnown.UNKNOWN);
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to obtain tags manager for case.", ex); LOGGER.log(Level.SEVERE, "Failed to obtain tags manager for case.", ex);
@ -450,24 +475,6 @@ public final class CaseEventListener implements PropertyChangeListener {
return ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)); return ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN));
} }
/**
* Sets the known status of a blackboard artifact in the central
* repository.
*
* @param bbArtifact The blackboard artifact to set known status.
* @param knownStatus The new known status.
*/
private void setArtifactKnownStatus(BlackboardArtifact bbArtifact, TskData.FileKnown knownStatus) {
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbArtifact);
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
try {
dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus);
} catch (CentralRepoException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
}
}
}
} }
private final class TagDefinitionChangeTask implements Runnable { private final class TagDefinitionChangeTask implements Runnable {
@ -528,12 +535,7 @@ public final class CaseEventListener implements PropertyChangeListener {
} }
//if the Correlation Attribute will have no tags with a status which would prevent the current status from being changed //if the Correlation Attribute will have no tags with a status which would prevent the current status from being changed
if (!hasTagWithConflictingKnownStatus) { if (!hasTagWithConflictingKnownStatus) {
//Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed setArtifactKnownStatus(CentralRepository.getInstance(), bbTag.getArtifact(), tagName.getKnownStatus());
//with the initial set of correlation attributes this should be a single correlation attribute
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbTag.getArtifact());
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
}
} }
} }
// Next update the files // Next update the files
@ -568,7 +570,7 @@ public final class CaseEventListener implements PropertyChangeListener {
if (!hasTagWithConflictingKnownStatus) { if (!hasTagWithConflictingKnownStatus) {
Content taggedContent = contentTag.getContent(); Content taggedContent = contentTag.getContent();
if (taggedContent instanceof AbstractFile) { if (taggedContent instanceof AbstractFile) {
final List<CorrelationAttributeInstance> eamArtifact = CorrelationAttributeUtil.makeCorrAttrsForSearch(taggedContent); final List<CorrelationAttributeInstance> eamArtifact = CorrelationAttributeUtil.makeCorrAttrsForSearch((AbstractFile) taggedContent);
if (!eamArtifact.isEmpty()) { if (!eamArtifact.isEmpty()) {
//for an abstract file the 'list' of attributes will be a single attribute or empty and is returning a list for consistency with other makeCorrAttrsForSearch methods per 7852 //for an abstract file the 'list' of attributes will be a single attribute or empty and is returning a list for consistency with other makeCorrAttrsForSearch methods per 7852
CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact.get(0), tagName.getKnownStatus()); CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact.get(0), tagName.getKnownStatus());
@ -691,8 +693,8 @@ public final class CaseEventListener implements PropertyChangeListener {
for (OsAccountInstance osAccountInstance : addedOsAccountNew) { for (OsAccountInstance osAccountInstance : addedOsAccountNew) {
try { try {
OsAccount osAccount = osAccountInstance.getOsAccount(); OsAccount osAccount = osAccountInstance.getOsAccount();
CorrelationAttributeInstance correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttr(osAccount, osAccountInstance.getDataSource()); List<CorrelationAttributeInstance> correlationAttributeInstances = CorrelationAttributeUtil.makeCorrAttrsForSearch(osAccountInstance);
if (correlationAttributeInstance == null) { if (correlationAttributeInstances.isEmpty()) {
return; return;
} }
@ -700,19 +702,21 @@ public final class CaseEventListener implements PropertyChangeListener {
try { try {
// Save to the database if requested // Save to the database if requested
if (IngestEventsListener.shouldCreateCrProperties()) { if (IngestEventsListener.shouldCreateCrProperties()) {
for (CorrelationAttributeInstance correlationAttributeInstance : correlationAttributeInstances) {
dbManager.addArtifactInstance(correlationAttributeInstance); dbManager.addArtifactInstance(correlationAttributeInstance);
} }
}
// Look up and create artifacts for previously seen accounts if requested // Look up and create artifacts for previously seen accounts if requested
if (IngestEventsListener.isFlagSeenDevices()) { if (IngestEventsListener.isFlagSeenDevices()) {
CorrelationAttributeInstance.Type osAcctType = CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID); CorrelationAttributeInstance.Type osAcctType = CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID);
List<CorrelationAttributeInstance> previousOccurences = dbManager.getArtifactInstancesByTypeValue(osAcctType, correlationAttributeInstance.getCorrelationValue()); List<CorrelationAttributeInstance> previousOccurences = dbManager.getArtifactInstancesByTypeValue(osAcctType, correlationAttributeInstances.get(0).getCorrelationValue());
for (CorrelationAttributeInstance instance : previousOccurences) { for (CorrelationAttributeInstance instance : previousOccurences) {
if (!instance.getCorrelationCase().getCaseUUID().equals(correlationAttributeInstance.getCorrelationCase().getCaseUUID())) { if (!instance.getCorrelationCase().getCaseUUID().equals(correlationAttributeInstances.get(0).getCorrelationCase().getCaseUUID())) {
SleuthkitCase tskCase = osAccount.getSleuthkitCase(); SleuthkitCase tskCase = osAccount.getSleuthkitCase();
Blackboard blackboard = tskCase.getBlackboard(); Blackboard blackboard = tskCase.getBlackboard();
List<String> caseDisplayNames = dbManager.getListCasesHavingArtifactInstances(osAcctType, correlationAttributeInstance.getCorrelationValue()); List<String> caseDisplayNames = dbManager.getListCasesHavingArtifactInstances(osAcctType, correlationAttributeInstances.get(0).getCorrelationValue());
// calculate score // calculate score
Score score; Score score;
@ -737,7 +741,7 @@ public final class CaseEventListener implements PropertyChangeListener {
osAcctType.getDisplayName()), osAcctType.getDisplayName()),
new BlackboardAttribute( new BlackboardAttribute(
TSK_CORRELATION_VALUE, MODULE_NAME, TSK_CORRELATION_VALUE, MODULE_NAME,
correlationAttributeInstance.getCorrelationValue()), correlationAttributeInstances.get(0).getCorrelationValue()),
new BlackboardAttribute( new BlackboardAttribute(
TSK_OTHER_CASES, MODULE_NAME, TSK_OTHER_CASES, MODULE_NAME,
prevCases)); prevCases));

View File

@ -62,6 +62,7 @@ import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.Score;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -229,6 +230,8 @@ public class IngestEventsListener {
* @param originalArtifact Original artifact that we want to flag * @param originalArtifact Original artifact that we want to flag
* @param caseDisplayNames List of case names artifact was previously seen * @param caseDisplayNames List of case names artifact was previously seen
* in * in
* @param aType The correlation type.
* @param value The correlation value.
*/ */
@NbBundle.Messages({"IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)", @NbBundle.Messages({"IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)",
"IngestEventsListener.prevCaseComment.text=Previous Case: "}) "IngestEventsListener.prevCaseComment.text=Previous Case: "})
@ -259,6 +262,8 @@ public class IngestEventsListener {
* @param originalArtifact the artifact to create the "previously seen" item for * @param originalArtifact the artifact to create the "previously seen" item for
* @param caseDisplayNames the case names the artifact was previously seen * @param caseDisplayNames the case names the artifact was previously seen
* in * in
* @param aType The correlation type.
* @param value The correlation value.
*/ */
@NbBundle.Messages({"IngestEventsListener.prevExists.text=Previously Seen Devices (Central Repository)", @NbBundle.Messages({"IngestEventsListener.prevExists.text=Previously Seen Devices (Central Repository)",
"# {0} - typeName", "# {0} - typeName",
@ -303,6 +308,8 @@ public class IngestEventsListener {
* *
* @param originalArtifact the artifact to create the "previously unseen" item * @param originalArtifact the artifact to create the "previously unseen" item
* for * for
* @param aType The correlation type.
* @param value The correlation value.
*/ */
static private void makeAndPostPreviouslyUnseenArtifact(BlackboardArtifact originalArtifact, CorrelationAttributeInstance.Type aType, String value) { static private void makeAndPostPreviouslyUnseenArtifact(BlackboardArtifact originalArtifact, CorrelationAttributeInstance.Type aType, String value) {
Collection<BlackboardAttribute> attributesForNewArtifact = Arrays.asList( Collection<BlackboardAttribute> attributesForNewArtifact = Arrays.asList(
@ -319,6 +326,7 @@ public class IngestEventsListener {
/** /**
* Make an artifact to flag the passed in artifact. * Make an artifact to flag the passed in artifact.
* *
* @param newArtifactType Type of artifact to create.
* @param originalArtifact Artifact in current case we want to flag * @param originalArtifact Artifact in current case we want to flag
* @param attributesForNewArtifact Attributes to assign to the new artifact * @param attributesForNewArtifact Attributes to assign to the new artifact
* @param configuration The configuration to be specified for the new artifact hit * @param configuration The configuration to be specified for the new artifact hit
@ -540,7 +548,10 @@ public class IngestEventsListener {
for (BlackboardArtifact bbArtifact : bbArtifacts) { for (BlackboardArtifact bbArtifact : bbArtifacts) {
// makeCorrAttrToSave will filter out artifacts which should not be sources of CR data. // makeCorrAttrToSave will filter out artifacts which should not be sources of CR data.
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsToSave(bbArtifact); List<CorrelationAttributeInstance> convertedArtifacts = new ArrayList<>();
if (bbArtifact instanceof DataArtifact){
convertedArtifacts.addAll(CorrelationAttributeUtil.makeCorrAttrsToSave((DataArtifact)bbArtifact));
}
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
try { try {
// Only do something with this artifact if it's unique within the job // Only do something with this artifact if it's unique within the job

View File

@ -42,11 +42,13 @@ import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactItem; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactItem;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.AnalysisResult;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -135,7 +137,7 @@ public class AnnotationUtils {
* @return The pair of artifact (or null if not present) and content (either * @return The pair of artifact (or null if not present) and content (either
* artifact parent content, the node content, or null). * artifact parent content, the node content, or null).
*/ */
private static Pair<BlackboardArtifact, Content> getDisplayContent(Node node) { static DisplayTskItems getDisplayContent(Node node) {
BlackboardArtifactItem<?> artItem = node.getLookup().lookup(BlackboardArtifactItem.class); BlackboardArtifactItem<?> artItem = node.getLookup().lookup(BlackboardArtifactItem.class);
BlackboardArtifact artifact = artItem == null ? null : artItem.getTskContent(); BlackboardArtifact artifact = artItem == null ? null : artItem.getTskContent();
@ -143,16 +145,18 @@ public class AnnotationUtils {
? artItem.getSourceContent() ? artItem.getSourceContent()
: node.getLookup().lookup(AbstractFile.class); : node.getLookup().lookup(AbstractFile.class);
return Pair.of(artifact, content); return new DisplayTskItems(artifact, content);
} }
/** /**
* Returns whether or not the node is supported by the annotation viewer. * Returns whether or not the node is supported by the annotation viewer.
*
* @param node The node to display. * @param node The node to display.
*
* @return True if the node is supported. * @return True if the node is supported.
*/ */
public static boolean isSupported(Node node) { public static boolean isSupported(Node node) {
return getDisplayContent(node).getRight() != null; return getDisplayContent(node).getContent() != null;
} }
/** /**
@ -168,9 +172,9 @@ public class AnnotationUtils {
Document html = Jsoup.parse(EMPTY_HTML); Document html = Jsoup.parse(EMPTY_HTML);
Element body = html.getElementsByTag("body").first(); Element body = html.getElementsByTag("body").first();
Pair<BlackboardArtifact, Content> displayPair = getDisplayContent(node); DisplayTskItems displayItems = getDisplayContent(node);
BlackboardArtifact artifact = displayPair.getLeft(); BlackboardArtifact artifact = displayItems.getArtifact();
Content srcContent = displayPair.getRight(); Content srcContent = displayItems.getContent();
boolean somethingWasRendered = false; boolean somethingWasRendered = false;
if (artifact != null) { if (artifact != null) {
@ -380,9 +384,14 @@ public class AnnotationUtils {
if (artifact == null) { if (artifact == null) {
return new ArrayList<>(); return new ArrayList<>();
} }
List<CorrelationAttributeInstance> instances = new ArrayList<>();
if (artifact instanceof DataArtifact) {
instances.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((DataArtifact) artifact));
} else if (artifact instanceof AnalysisResult) {
instances.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((AnalysisResult) artifact));
}
List<Pair<CorrelationAttributeInstance.Type, String>> lookupKeys = CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact) List<Pair<CorrelationAttributeInstance.Type, String>> lookupKeys = instances.stream()
.stream()
.map(cai -> Pair.of(cai.getCorrelationType(), cai.getCorrelationValue())) .map(cai -> Pair.of(cai.getCorrelationType(), cai.getCorrelationValue()))
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -677,4 +686,39 @@ public class AnnotationUtils {
} }
} }
/**
* The TSK items that are being displayed as deciphered from the netbeans
* node.
*/
static class DisplayTskItems {
private final BlackboardArtifact artifact;
private final Content content;
/**
* Main constructor.
*
* @param artifact The artifact being displayed or null.
* @param content The parent content or source file being displayed or
* null.
*/
DisplayTskItems(BlackboardArtifact artifact, Content content) {
this.artifact = artifact;
this.content = content;
}
/**
* @return The selected artifact or null if no selected artifact.
*/
BlackboardArtifact getArtifact() {
return artifact;
}
/**
* @return The parent content or source file being displayed or null.
*/
Content getContent() {
return content;
}
}
} }

View File

@ -18,10 +18,16 @@
*/ */
package org.sleuthkit.autopsy.contentviewers.annotations; package org.sleuthkit.autopsy.contentviewers.annotations;
import com.google.common.collect.ImmutableSet;
import java.awt.Component; import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumSet;
import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import org.apache.commons.lang3.tuple.Pair;
import static org.openide.util.NbBundle.Messages; import static org.openide.util.NbBundle.Messages;
import org.openide.nodes.Node; import org.openide.nodes.Node;
@ -29,8 +35,19 @@ import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.openide.util.WeakListeners;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
import org.sleuthkit.autopsy.casemodule.events.CommentChangedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
import org.sleuthkit.autopsy.contentviewers.annotations.AnnotationUtils.DisplayTskItems;
import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles; import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles;
import org.sleuthkit.autopsy.contentviewers.utils.ViewerPriority; import org.sleuthkit.autopsy.contentviewers.utils.ViewerPriority;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
/** /**
* Annotations view of file contents. * Annotations view of file contents.
@ -47,7 +64,75 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(AnnotationsContentViewer.class.getName()); private static final Logger logger = Logger.getLogger(AnnotationsContentViewer.class.getName());
private AnnotationWorker worker; private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(
Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED,
Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED,
Case.Events.CONTENT_TAG_ADDED,
Case.Events.CONTENT_TAG_DELETED,
Case.Events.CR_COMMENT_CHANGED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
private static final Set<BlackboardArtifact.Type> ARTIFACT_TYPES_OF_INTEREST = ImmutableSet.of(
BlackboardArtifact.Type.TSK_HASHSET_HIT,
BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT
);
private final PropertyChangeListener ingestEventListener = (evt) -> {
Long curArtifactId = AnnotationsContentViewer.this.curArtifactId;
Long curContentId = AnnotationsContentViewer.this.curContentId;
if (curArtifactId == null && curContentId == null) {
return;
}
// if it is a module data event
if (IngestManager.IngestModuleEvent.DATA_ADDED.toString().equals(evt.getPropertyName())
&& evt.getOldValue() instanceof ModuleDataEvent) {
ModuleDataEvent moduleDataEvent = (ModuleDataEvent) evt.getOldValue();
// if an artifact is relevant, refresh
if (ARTIFACT_TYPES_OF_INTEREST.contains(moduleDataEvent.getBlackboardArtifactType())) {
for (BlackboardArtifact artifact : moduleDataEvent.getArtifacts()) {
if ((curArtifactId != null && artifact.getArtifactID() == curArtifactId)
|| (curContentId != null && artifact.getObjectID() == curContentId)) {
refresh();
return;
}
}
}
}
};
private final PropertyChangeListener weakIngestEventListener = WeakListeners.propertyChange(ingestEventListener, null);
private final PropertyChangeListener caseEventListener = (evt) -> {
Long curArtifactId = AnnotationsContentViewer.this.curArtifactId;
Long curContentId = AnnotationsContentViewer.this.curContentId;
if (curArtifactId == null && curContentId == null) {
return;
}
Pair<Long, Long> artifactContentId = getIdsFromEvent(evt);
Long artifactId = artifactContentId.getLeft();
Long contentId = artifactContentId.getRight();
// if there is a match of content id or artifact id and the event, refresh
if ((curArtifactId != null && curArtifactId.equals(artifactId)) || (curContentId != null && curContentId.equals(contentId))) {
refresh();
}
};
private final PropertyChangeListener weakCaseEventListener = WeakListeners.propertyChange(caseEventListener, null);
private final Object updateLock = new Object();
private AnnotationWorker worker = null;
private Node node;
private Long curArtifactId;
private Long curContentId;
/** /**
* Creates an instance of AnnotationsContentViewer. * Creates an instance of AnnotationsContentViewer.
@ -55,24 +140,139 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
public AnnotationsContentViewer() { public AnnotationsContentViewer() {
initComponents(); initComponents();
ContentViewerHtmlStyles.setupHtmlJTextPane(textPanel); ContentViewerHtmlStyles.setupHtmlJTextPane(textPanel);
registerListeners();
}
/**
* Registers case event and ingest event listeners.
*/
private void registerListeners() {
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakCaseEventListener);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakIngestEventListener);
}
@Override
protected void finalize() throws Throwable {
unregisterListeners();
}
/**
* Unregisters case event and ingest event listeners.
*/
private void unregisterListeners() {
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakCaseEventListener);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakIngestEventListener);
} }
@Override @Override
public void setNode(Node node) { public void setNode(Node node) {
resetComponent(); this.node = node;
DisplayTskItems displayItems = AnnotationUtils.getDisplayContent(node);
if (worker != null) { this.curArtifactId = displayItems.getArtifact() == null ? null : displayItems.getArtifact().getArtifactID();
worker.cancel(true); this.curContentId = displayItems.getContent() == null ? null : displayItems.getContent().getId();
worker = null; updateData(this.node, true);
} }
/**
* Returns a pair of the artifact id (or null) and the content id (or null)
* for the case event.
*
* @param evt The case event.
*
* @return A pair of the artifact id (or null) and the content id (or null)
* for the case event.
*/
private static Pair<Long, Long> getIdsFromEvent(PropertyChangeEvent evt) {
Case.Events eventType = null;
try {
eventType = Case.Events.valueOf(evt.getPropertyName());
} catch (IllegalArgumentException ex) {
logger.log(Level.SEVERE, "Unknown event type: " + evt.getPropertyName(), ex);
return Pair.of(null, null);
}
Long artifactId = null;
Long contentId = null;
switch (eventType) {
case BLACKBOARD_ARTIFACT_TAG_ADDED:
if (evt instanceof BlackBoardArtifactTagAddedEvent) {
BlackboardArtifact art = ((BlackBoardArtifactTagAddedEvent) evt).getAddedTag().getArtifact();
artifactId = art.getArtifactID();
contentId = art.getObjectID();
}
break;
case BLACKBOARD_ARTIFACT_TAG_DELETED:
if (evt instanceof BlackBoardArtifactTagDeletedEvent) {
artifactId = ((BlackBoardArtifactTagDeletedEvent) evt).getDeletedTagInfo().getArtifactID();
contentId = ((BlackBoardArtifactTagDeletedEvent) evt).getDeletedTagInfo().getContentID();
}
break;
case CONTENT_TAG_ADDED:
if (evt instanceof ContentTagAddedEvent) {
contentId = ((ContentTagAddedEvent) evt).getAddedTag().getContent().getId();
}
break;
case CONTENT_TAG_DELETED:
if (evt instanceof ContentTagDeletedEvent) {
contentId = ((ContentTagDeletedEvent) evt).getDeletedTagInfo().getContentID();
}
break;
case CR_COMMENT_CHANGED:
if (evt instanceof CommentChangedEvent) {
long commentObjId = ((CommentChangedEvent) evt).getContentID();
artifactId = commentObjId;
contentId = commentObjId;
}
break;
default:
break;
};
return Pair.of(artifactId, contentId);
}
/**
* Refreshes the data displayed.
*/
private void refresh() {
if (this.isVisible()) {
updateData(this.node, false);
}
}
/**
* Updates data displayed in the viewer.
*
* @param node The node to use for data.
* @param forceReset If true, forces a reset cancelling the previous worker
* if one exists and clearing data in the component. If
* false, only submits a worker if no previous worker is
* running.
*/
private void updateData(Node node, boolean forceReset) {
if (node == null) { if (node == null) {
return; return;
} }
worker = new AnnotationWorker(node); if (forceReset) {
resetComponent();
}
synchronized (updateLock) {
if (worker != null) {
if (forceReset) {
worker.cancel(true);
worker = null;
} else {
return;
}
}
worker = new AnnotationWorker(node, forceReset);
worker.execute(); worker.execute();
} }
}
/** /**
* This method is called from within the constructor to initialize the form. * This method is called from within the constructor to initialize the form.
@ -142,6 +342,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
@Override @Override
public void resetComponent() { public void resetComponent() {
textPanel.setText(""); textPanel.setText("");
} }
/** /**
@ -151,9 +352,18 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
private class AnnotationWorker extends SwingWorker<String, Void> { private class AnnotationWorker extends SwingWorker<String, Void> {
private final Node node; private final Node node;
private final boolean resetCaretPosition;
AnnotationWorker(Node node) { /**
* Main constructor.
*
* @param node The node for which data will be fetched.
* @param resetCaretPosition Whether or not to reset the caret position
* when finished.
*/
AnnotationWorker(Node node, boolean resetCaretPosition) {
this.node = node; this.node = node;
this.resetCaretPosition = resetCaretPosition;
} }
@Override @Override
@ -173,19 +383,27 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
@Override @Override
public void done() { public void done() {
if (isCancelled()) { if (!isCancelled()) {
return;
}
try { try {
String text = get(); String text = get();
ContentViewerHtmlStyles.setStyles(textPanel); ContentViewerHtmlStyles.setStyles(textPanel);
textPanel.setText(text); textPanel.setText(text);
if (resetCaretPosition) {
textPanel.setCaretPosition(0); textPanel.setCaretPosition(0);
}
} catch (InterruptedException | ExecutionException ex) { } catch (InterruptedException | ExecutionException ex) {
logger.log(Level.SEVERE, "Failed to get annotation information for node", ex); logger.log(Level.SEVERE, "Failed to get annotation information for node", ex);
} }
} }
synchronized (updateLock) {
if (worker == this) {
worker = null;
}
}
}
} }
} }

View File

@ -334,11 +334,6 @@
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.report.modules.kml.KMLReport.getDefault"/> <attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.report.modules.kml.KMLReport.getDefault"/>
<attr name="position" intvalue="904"/> <attr name="position" intvalue="904"/>
</file> </file>
<file name="org-sleuthkit-autopsy-report-modules-stix-STIXReportModule.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.report.GeneralReportModule"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.report.modules.stix.STIXReportModule.getDefault"/>
<attr name="position" intvalue="910"/>
</file>
<file name="org-sleuthkit-autopsy-report-modules-caseuco-CaseUcoReportModule.instance"> <file name="org-sleuthkit-autopsy-report-modules-caseuco-CaseUcoReportModule.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.report.GeneralReportModule"/> <attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.report.GeneralReportModule"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.report.modules.caseuco.CaseUcoReportModule.getDefault"/> <attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.report.modules.caseuco.CaseUcoReportModule.getDefault"/>

View File

@ -18,6 +18,8 @@
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.actions.ViewArtifactAction;
import org.sleuthkit.autopsy.actions.ViewOsAccountAction;
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
@ -27,6 +29,7 @@ import java.lang.ref.WeakReference;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -37,15 +40,22 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.swing.Action; import javax.swing.Action;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.util.Utilities;
import org.openide.util.WeakListeners; import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
@ -74,17 +84,34 @@ import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.autopsy.datamodel.utils.IconsUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR; import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService; import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask; import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask;
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.AnalysisResult;
import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.sleuthkit.datamodel.BlackboardArtifact.Category;
import org.sleuthkit.datamodel.HostAddress; import org.sleuthkit.datamodel.HostAddress;
import org.sleuthkit.datamodel.OsAccount;
import org.sleuthkit.datamodel.Pool; import org.sleuthkit.datamodel.Pool;
import org.sleuthkit.datamodel.DataArtifact; import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.File;
import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.LocalDirectory;
import org.sleuthkit.datamodel.LocalFile;
import org.sleuthkit.datamodel.OsAccount;
import org.sleuthkit.datamodel.Report;
import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.Score;
import org.sleuthkit.datamodel.SlackFile;
import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.Volume;
import org.sleuthkit.datamodel.VolumeSystem; import org.sleuthkit.datamodel.VolumeSystem;
@ -130,7 +157,6 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
private Content srcContent; private Content srcContent;
private volatile String translatedSourceName; private volatile String translatedSourceName;
private final String sourceObjTypeName; private final String sourceObjTypeName;
private final String srcContentShortDescription;
/* /*
* A method has been provided to allow the injection of properties into this * A method has been provided to allow the injection of properties into this
@ -260,11 +286,8 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
logger.log(Level.WARNING, MessageFormat.format("Error getting the unique path of the source content (artifact objID={0})", artifact.getId()), ex); logger.log(Level.WARNING, MessageFormat.format("Error getting the unique path of the source content (artifact objID={0})", artifact.getId()), ex);
} }
sourceObjTypeName = getSourceObjType(srcContent); sourceObjTypeName = getSourceObjType(srcContent);
srcContentShortDescription = getContentShortDescription(srcContent); setDisplayNameBySourceContent();
setName(Long.toString(artifact.getArtifactID())); setName(Long.toString(artifact.getArtifactID()));
String displayName = srcContent.getName();
setDisplayName(displayName);
setShortDescription(displayName);
setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath); setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakListener); Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakListener);
} }
@ -308,11 +331,8 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
throw new IllegalArgumentException(MessageFormat.format("Artifact missing source content (artifact objID={0})", artifact)); throw new IllegalArgumentException(MessageFormat.format("Artifact missing source content (artifact objID={0})", artifact));
} }
sourceObjTypeName = getSourceObjType(srcContent); sourceObjTypeName = getSourceObjType(srcContent);
srcContentShortDescription = getContentShortDescription(srcContent);
setName(Long.toString(artifact.getArtifactID())); setName(Long.toString(artifact.getArtifactID()));
String displayName = srcContent.getName(); setDisplayNameBySourceContent();
setDisplayName(displayName);
setShortDescription(displayName);
String iconPath = IconsUtil.getIconFilePath(artifact.getArtifactTypeID()); String iconPath = IconsUtil.getIconFilePath(artifact.getArtifactTypeID());
setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath); setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakListener); Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakListener);
@ -484,52 +504,360 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
return this.artifact; return this.artifact;
} }
/**
* Returns a list of non null actions from the given possibly null options.
*
* @param items The items to purge of null items.
*
* @return The list of non-null actions.
*/
private List<Action> getNonNull(Action... items) {
return Stream.of(items)
.filter(i -> i != null)
.collect(Collectors.toList());
}
@Override @Override
public Action[] getActions(boolean context) { public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<>(); // groupings of actions where each group will be separated by a divider
actionsList.addAll(Arrays.asList(super.getActions(context))); List<List<Action>> actionsLists = new ArrayList<>();
/* // view artifact in timeline
* If the artifact represented by this node has a timestamp, add an actionsLists.add(getNonNull(
* action to view it in the timeline. getTimelineArtifactAction(this.artifact)
));
// view associated file (TSK_PATH_ID attr) in directory and timeline
actionsLists.add(getAssociatedFileActions(this.artifact, this.artifactType));
// view source content in directory and timeline
actionsLists.add(getNonNull(
getViewSrcContentAction(this.artifact, this.srcContent),
getTimelineSrcContentAction(this.srcContent)
));
// extract with password from encrypted file
actionsLists.add(getNonNull(
getExtractWithPasswordAction(this.srcContent)
));
// menu options for artifact with report parent
if (this.srcContent instanceof Report) {
actionsLists.add(DataModelActionsFactory.getActions(this.srcContent, false));
}
Node parentFileNode = getParentFileNode(srcContent);
int selectedFileCount = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size();
int selectedArtifactCount = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactItem.class).size();
// view source content if source content is some sort of file
actionsLists.add(getSrcContentViewerActions(parentFileNode, selectedFileCount));
// extract / export if source content is some sort of file
if (parentFileNode != null) {
actionsLists.add(Arrays.asList(ExtractAction.getInstance(), ExportCSVAction.getInstance()));
}
// file and result tagging
actionsLists.add(getTagActions(parentFileNode != null, this.artifact, selectedFileCount, selectedArtifactCount));
// menu extension items (i.e. add to central repository)
actionsLists.add(ContextMenuExtensionPoint.getActions());
// netbeans default items (i.e. properties)
actionsLists.add(Arrays.asList(super.getActions(context)));
return actionsLists.stream()
// remove any empty lists
.filter((lst) -> lst != null && !lst.isEmpty())
// add in null between each list group
.flatMap(lst -> Stream.concat(Stream.of((Action) null), lst.stream()))
// skip the first null
.skip(1)
.toArray(sz -> new Action[sz]);
}
/**
* Returns the name of the artifact based on the artifact type to be used
* with the associated file string in a right click menu.
*
* @param artifactType The artifact type.
*
* @return The artifact type name.
*/ */
try { @Messages({
if (ViewArtifactInTimelineAction.hasSupportedTimeStamp(artifact) "BlackboardArtifactNode_getAssociatedTypeStr_webCache=Cached File",
&& // don't show ViewArtifactInTimelineAction for AnalysisResults. "BlackboardArtifactNode_getAssociatedTypeStr_webDownload=Downloaded File",
(!(this.artifact instanceof AnalysisResult))) { "BlackboardArtifactNode_getAssociatedTypeStr_associated=Associated File",})
private String getAssociatedTypeStr(BlackboardArtifact.Type artifactType) {
actionsList.add(new ViewArtifactInTimelineAction(artifact)); if (BlackboardArtifact.Type.TSK_WEB_CACHE.equals(artifactType)) {
return Bundle.BlackboardArtifactNode_getAssociatedTypeStr_webCache();
} else if (BlackboardArtifact.Type.TSK_WEB_DOWNLOAD.equals(artifactType)) {
return Bundle.BlackboardArtifactNode_getAssociatedTypeStr_webDownload();
} else {
return Bundle.BlackboardArtifactNode_getAssociatedTypeStr_associated();
} }
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, MessageFormat.format("Error getting artifact timestamp (artifact objID={0})", artifact.getId()), ex); //NON-NLS
} }
/* /**
* If the artifact represented by this node is linked to a file via a * Returns the name to represent the type of the content (file, data
* TSK_PATH_ID attribute, add an action to view the file in the * artifact, os account, item).
* timeline. *
* @param content The content.
*
* @return The name of the type of content.
*/ */
try { @Messages({
AbstractFile linkedFile = findLinked(artifact); "BlackboardArtifactNode_getViewSrcContentAction_type_File=File",
if (linkedFile != null) { "BlackboardArtifactNode_getViewSrcContentAction_type_DataArtifact=Data Artifact",
actionsList.add(ViewFileInTimelineAction.createViewFileAction(linkedFile)); "BlackboardArtifactNode_getViewSrcContentAction_type_OSAccount=OS Account",
"BlackboardArtifactNode_getViewSrcContentAction_type_unknown=Item"
})
private String getContentTypeStr(Content content) {
if (content instanceof AbstractFile) {
return Bundle.BlackboardArtifactNode_getViewSrcContentAction_type_File();
} else if (content instanceof DataArtifact) {
return Bundle.BlackboardArtifactNode_getViewSrcContentAction_type_DataArtifact();
} else if (content instanceof OsAccount) {
return Bundle.BlackboardArtifactNode_getViewSrcContentAction_type_OSAccount();
} else {
return Bundle.BlackboardArtifactNode_getViewSrcContentAction_type_unknown();
} }
}
/**
* Returns actions for navigating to an associated file in the directory or
* in the timeline.
*
* @param artifact The artifact whose associated file will be
* identified.
* @param artifactType The type of artifact.
*
* @return The actions or an empty list.
*/
@Messages({
"# {0} - type",
"BlackboardArtifactNode_getAssociatedFileActions_viewAssociatedFileAction=View {0} in Directory",
"# {0} - type",
"BlackboardArtifactNode_getAssociatedFileActions_viewAssociatedFileInTimelineAction=View {0} in Timeline..."
})
private List<Action> getAssociatedFileActions(BlackboardArtifact artifact, BlackboardArtifact.Type artifactType) {
try {
AbstractFile associatedFile = findLinked(artifact);
if (associatedFile != null) {
return Arrays.asList(
new ViewContextAction(
Bundle.BlackboardArtifactNode_getAssociatedFileActions_viewAssociatedFileAction(
getAssociatedTypeStr(artifactType)),
associatedFile),
new ViewFileInTimelineAction(associatedFile,
Bundle.BlackboardArtifactNode_getAssociatedFileActions_viewAssociatedFileInTimelineAction(
getAssociatedTypeStr(artifactType)))
);
}
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, MessageFormat.format("Error getting linked file of artifact (artifact objID={0})", artifact.getId()), ex); //NON-NLS logger.log(Level.SEVERE, MessageFormat.format("Error getting linked file of artifact (artifact objID={0})", artifact.getId()), ex); //NON-NLS
}
return Collections.emptyList();
} }
/* /**
* If the source content of the artifact represented by this node is a * Creates an action to navigate to src content in tree hierarchy.
* file, add an action to view the file in the data source tree. *
* @param artifact The artifact.
* @param content The content.
*
* @return The action or null if no action derived.
*/ */
AbstractFile file = getLookup().lookup(AbstractFile.class @Messages({
); "# {0} - contentType",
if (null != file) { "BlackboardArtifactNode_getSrcContentAction_actionDisplayName=View Source {0} in Directory"
actionsList.add(ViewFileInTimelineAction.createViewSourceFileAction(file)); })
private Action getViewSrcContentAction(BlackboardArtifact artifact, Content content) {
if (content instanceof DataArtifact) {
return new ViewArtifactAction(
(BlackboardArtifact) content,
Bundle.BlackboardArtifactNode_getSrcContentAction_actionDisplayName(
getContentTypeStr(content)));
} else if (content instanceof OsAccount) {
return new ViewOsAccountAction(
(OsAccount) content,
Bundle.BlackboardArtifactNode_getSrcContentAction_actionDisplayName(
getContentTypeStr(content)));
} else if (content instanceof AbstractFile || artifact instanceof DataArtifact) {
return new ViewContextAction(
Bundle.BlackboardArtifactNode_getSrcContentAction_actionDisplayName(
getContentTypeStr(content)),
content);
} else {
return null;
}
} }
return actionsList.toArray(new Action[actionsList.size()]); /**
* Returns a Node representing the file content if the content is indeed
* some sort of file. Otherwise, return null.
*
* @param content The content.
*
* @return The file node or null if not a file.
*/
private Node getParentFileNode(Content content) {
if (content instanceof File) {
return new FileNode((AbstractFile) content);
} else if (content instanceof Directory) {
return new DirectoryNode((Directory) content);
} else if (content instanceof VirtualDirectory) {
return new VirtualDirectoryNode((VirtualDirectory) content);
} else if (content instanceof LocalDirectory) {
return new LocalDirectoryNode((LocalDirectory) content);
} else if (content instanceof LayoutFile) {
return new LayoutFileNode((LayoutFile) content);
} else if (content instanceof LocalFile || content instanceof DerivedFile) {
return new LocalFileNode((AbstractFile) content);
} else if (content instanceof SlackFile) {
return new SlackFileNode((AbstractFile) content);
} else {
return null;
}
}
/**
* Returns actions for extracting content from file or null if not possible.
*
* @param srcContent The source content.
*
* @return The action or null if not appropriate source content.
*/
private Action getExtractWithPasswordAction(Content srcContent) {
if ((srcContent instanceof AbstractFile)
&& FileTypeExtensions.getArchiveExtensions()
.contains("." + ((AbstractFile) srcContent).getNameExtension().toLowerCase())) {
try {
if (srcContent.getArtifacts(BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED.getTypeID()).size() > 0) {
return new ExtractArchiveWithPasswordAction((AbstractFile) srcContent);
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Unable to add unzip with password action to context menus", ex);
}
}
return null;
}
/**
* Returns tag actions.
*
* @param hasSrcFile Whether or not the artifact has a source
* file.
* @param artifact This artifact.
* @param selectedFileCount The count of selected files.
* @param selectedArtifactCount The count of selected artifacts.
*
* @return The tag actions.
*/
private List<Action> getTagActions(boolean hasSrcFile, BlackboardArtifact artifact, int selectedFileCount, int selectedArtifactCount) {
List<Action> actionsList = new ArrayList<>();
// don't show AddContentTagAction for data artifacts.
if (hasSrcFile && !(artifact instanceof DataArtifact)) {
actionsList.add(AddContentTagAction.getInstance());
}
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
// don't show DeleteFileContentTagAction for data artifacts.
if (hasSrcFile && (!(artifact instanceof DataArtifact)) && (selectedFileCount == 1)) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
if (selectedArtifactCount == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
return actionsList;
}
/**
* Returns actions to view src content in a different viewer or window.
*
* @param srcFileNode The source file node or null if no source file.
* @param selectedFileCount The number of selected files.
*
* @return The list of actions or an empty list.
*/
@Messages({
"BlackboardArtifactNode_getSrcContentViewerActions_viewInNewWin=View Item in New Window",
"BlackboardArtifactNode_getSrcContentViewerActions_openInExtViewer=Open in External Viewer Ctrl+E"
})
private List<Action> getSrcContentViewerActions(Node srcFileNode, int selectedFileCount) {
List<Action> actionsList = new ArrayList<>();
if (srcFileNode != null) {
actionsList.add(new NewWindowViewAction(Bundle.BlackboardArtifactNode_getSrcContentViewerActions_viewInNewWin(), srcFileNode));
if (selectedFileCount == 1) {
actionsList.add(new ExternalViewerAction(Bundle.BlackboardArtifactNode_getSrcContentViewerActions_openInExtViewer(), srcFileNode));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
}
return actionsList;
}
/**
* If the source content of the artifact represented by this node is a file,
* returns an action to view the file in the data source tree.
*
* @param srcContent The src content to navigate to in the timeline action.
*
* @return The src content navigation action or null.
*/
@NbBundle.Messages({
"# {0} - contentType",
"BlackboardArtifactNode_getTimelineSrcContentAction_actionDisplayName=View Source {0} in Timeline... "
})
private Action getTimelineSrcContentAction(Content srcContent) {
if (srcContent instanceof AbstractFile) {
return new ViewFileInTimelineAction((AbstractFile) srcContent,
Bundle.BlackboardArtifactNode_getTimelineSrcContentAction_actionDisplayName(
getContentTypeStr(srcContent)));
} else if (srcContent instanceof DataArtifact) {
try {
if (ViewArtifactInTimelineAction.hasSupportedTimeStamp((BlackboardArtifact) srcContent)) {
return new ViewArtifactInTimelineAction((BlackboardArtifact) srcContent,
Bundle.BlackboardArtifactNode_getTimelineSrcContentAction_actionDisplayName(
getContentTypeStr(srcContent)));
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, MessageFormat.format("Error getting source data artifact timestamp (artifact objID={0})", srcContent.getId()), ex); //NON-NLS
}
}
return null;
}
/**
* If the artifact represented by this node has a timestamp, an action to
* view it in the timeline.
*
* @param art The artifact for timeline navigation action.
*
* @return The action or null if no action should exist.
*/
@Messages({
"BlackboardArtifactNode_getTimelineArtifactAction_displayName=View Selected Item in Timeline... "
})
private Action getTimelineArtifactAction(BlackboardArtifact art) {
try {
// don't show ViewArtifactInTimelineAction for AnalysisResults.
if (!(art instanceof AnalysisResult) && ViewArtifactInTimelineAction.hasSupportedTimeStamp(art)) {
return new ViewArtifactInTimelineAction(art, Bundle.BlackboardArtifactNode_getTimelineArtifactAction_displayName());
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, MessageFormat.format("Error getting artifact timestamp (artifact objID={0})", art.getId()), ex); //NON-NLS
}
return null;
} }
/** /**
@ -543,8 +871,8 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
} }
@NbBundle.Messages({ @NbBundle.Messages({
"BlackboardArtifactNode.createSheet.srcFile.name=Source File", "BlackboardArtifactNode.createSheet.srcFile.name=Source Name",
"BlackboardArtifactNode.createSheet.srcFile.displayName=Source File", "BlackboardArtifactNode.createSheet.srcFile.displayName=Source Name",
"BlackboardArtifactNode.createSheet.srcFile.origName=Original Name", "BlackboardArtifactNode.createSheet.srcFile.origName=Original Name",
"BlackboardArtifactNode.createSheet.srcFile.origDisplayName=Original Name", "BlackboardArtifactNode.createSheet.srcFile.origDisplayName=Original Name",
"BlackboardArtifactNode.createSheet.artifactType.displayName=Result Type", "BlackboardArtifactNode.createSheet.artifactType.displayName=Result Type",
@ -570,13 +898,6 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
sheet.put(sheetSet); sheet.put(sheetSet);
} }
boolean scoHasBeenAdded = false;
if (artifact instanceof AnalysisResult
&& !(artifactType.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()
|| artifactType.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())) {
updateSheetForAnalysisResult((AnalysisResult) artifact, sheetSet);
scoHasBeenAdded = true;
} else {
/* /*
* Add the name of the source content of the artifact represented by * Add the name of the source content of the artifact represented by
* this node to the sheet. The value of this property is the same as * this node to the sheet. The value of this property is the same as
@ -588,6 +909,13 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
Bundle.BlackboardArtifactNode_createSheet_srcFile_displayName(), Bundle.BlackboardArtifactNode_createSheet_srcFile_displayName(),
NO_DESCR, NO_DESCR,
getDisplayName())); getDisplayName()));
boolean scoHasBeenAdded = false;
if (artifact instanceof AnalysisResult
&& !(artifactType.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()
|| artifactType.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())) {
updateSheetForAnalysisResult((AnalysisResult) artifact, sheetSet);
scoHasBeenAdded = true;
} }
if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) { if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) {
@ -624,13 +952,17 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
if (attribute != null) { if (attribute != null) {
BlackboardArtifact associatedArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong()); BlackboardArtifact associatedArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.displayName"), "BlackboardArtifactNode.createSheet.artifactType.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.artifactType.displayName"),
NO_DESCR, NO_DESCR,
associatedArtifact.getDisplayName())); associatedArtifact.getDisplayName()));
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.displayName"), "BlackboardArtifactNode.createSheet.artifactDetails.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.artifactDetails.displayName"),
NO_DESCR, NO_DESCR,
associatedArtifact.getShortDescription())); associatedArtifact.getShortDescription()));
} }
@ -680,13 +1012,17 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
} }
} }
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.displayName"), "BlackboardArtifactNode.createSheet.ext.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.ext.displayName"),
NO_DESCR, NO_DESCR,
ext)); ext));
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.displayName"), "BlackboardArtifactNode.createSheet.mimeType.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.mimeType.displayName"),
NO_DESCR, NO_DESCR,
actualMimeType)); actualMimeType));
} }
@ -706,8 +1042,10 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
if (sourcePath.isEmpty() == false) { if (sourcePath.isEmpty() == false) {
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.displayName"), "BlackboardArtifactNode.createSheet.filePath.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.filePath.displayName"),
NO_DESCR, NO_DESCR,
sourcePath)); sourcePath));
} }
@ -720,28 +1058,38 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) { if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) {
AbstractFile file = srcContent instanceof AbstractFile ? (AbstractFile) srcContent : null; AbstractFile file = srcContent instanceof AbstractFile ? (AbstractFile) srcContent : null;
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.displayName"), "ContentTagNode.createSheet.fileModifiedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileModifiedTime.displayName"),
"", "",
file == null ? "" : TimeZoneUtils.getFormattedTime(file.getMtime()))); file == null ? "" : TimeZoneUtils.getFormattedTime(file.getMtime())));
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.displayName"), "ContentTagNode.createSheet.fileChangedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileChangedTime.displayName"),
"", "",
file == null ? "" : TimeZoneUtils.getFormattedTime(file.getCtime()))); file == null ? "" : TimeZoneUtils.getFormattedTime(file.getCtime())));
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.displayName"), "ContentTagNode.createSheet.fileAccessedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileAccessedTime.displayName"),
"", "",
file == null ? "" : TimeZoneUtils.getFormattedTime(file.getAtime()))); file == null ? "" : TimeZoneUtils.getFormattedTime(file.getAtime())));
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.displayName"), "ContentTagNode.createSheet.fileCreatedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileCreatedTime.displayName"),
"", "",
file == null ? "" : TimeZoneUtils.getFormattedTime(file.getCrtime()))); file == null ? "" : TimeZoneUtils.getFormattedTime(file.getCrtime())));
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.displayName"), "ContentTagNode.createSheet.fileSize.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileSize.displayName"),
"", "",
file == null ? "" : file.getSize())); file == null ? "" : file.getSize()));
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
@ -766,8 +1114,10 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
if (dataSourceStr.isEmpty() == false) { if (dataSourceStr.isEmpty() == false) {
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.displayName"), "BlackboardArtifactNode.createSheet.dataSrc.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.dataSrc.displayName"),
NO_DESCR, NO_DESCR,
dataSourceStr)); dataSourceStr));
} }
@ -791,14 +1141,18 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
} }
} }
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.displayName"), "BlackboardArtifactNode.createSheet.fileSize.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.fileSize.displayName"),
NO_DESCR, NO_DESCR,
size)); size));
sheetSet sheetSet
.put(new NodeProperty<>( .put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.name"), NbBundle.getMessage(BlackboardArtifactNode.class,
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.displayName"), "BlackboardArtifactNode.createSheet.path.name"),
NbBundle.getMessage(BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.path.displayName"),
NO_DESCR, NO_DESCR,
path)); path));
} }
@ -833,8 +1187,9 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* corresponding commented correlation attribute instance in the central * corresponding commented correlation attribute instance in the central
* repository. * repository.
* *
* @param tags The tags applied to the artifact and its source content. * @param tags The tags applied to the artifact and its source
* @param attribute A correlation attribute instance for the central * content.
* @param attributes A correlation attribute instance for the central
* repository lookup. * repository lookup.
* *
* @return The value of the comment property. * @return The value of the comment property.
@ -1066,12 +1421,6 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* @param sheetSet The sheetSet to add the values to. * @param sheetSet The sheetSet to add the values to.
*/ */
private void updateSheetForAnalysisResult(AnalysisResult result, Sheet.Set sheetSet) { private void updateSheetForAnalysisResult(AnalysisResult result, Sheet.Set sheetSet) {
sheetSet.put(new NodeProperty<>(
Bundle.BlackboardArtifactNode_analysisSheet_soureName_name(),
Bundle.BlackboardArtifactNode_analysisSheet_soureName_name(),
NO_DESCR,
srcContentShortDescription));
addSCOColumns(sheetSet); addSCOColumns(sheetSet);
sheetSet.put(new NodeProperty<>( sheetSet.put(new NodeProperty<>(
@ -1138,8 +1487,8 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
/** /**
* Returns a displayable type string for the given content object. * Returns a displayable type string for the given content object.
* *
* If the content object is a artifact of a custom type then this method * If the content object is a artifact of a custom type then this method may
* may cause a DB call BlackboardArtifact.getType * cause a DB call BlackboardArtifact.getType
* *
* @param source The object to determine the type of. * @param source The object to determine the type of.
* *
@ -1176,7 +1525,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* *
* @param content The content object. * @param content The content object.
* *
* @return A short description\label. * @return A short description/label.
*/ */
private String getContentShortDescription(Content content) { private String getContentShortDescription(Content content) {
if (content != null) { if (content != null) {
@ -1193,6 +1542,28 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
return ""; return "";
} }
/**
* Sets the displayName and short description for the node.
*/
private void setDisplayNameBySourceContent() {
if(srcContent instanceof BlackboardArtifact) {
try {
setDisplayName(((BlackboardArtifact)srcContent).getShortDescription());
} catch (TskCoreException ex) {
// Log the error, but set the display name to
// Content.getName so there is something visible to the user.
logger.log(Level.WARNING, "Failed to get short description for artifact id = " + srcContent.getId(), ex);
setDisplayName(srcContent.getName());
}
} else if(srcContent instanceof OsAccount) {
setDisplayName(((OsAccount)srcContent).getAddr().orElse(srcContent.getName()));
} else {
setDisplayName(srcContent.getName());
}
setShortDescription(getDisplayName());
}
/** /**
* Adds the score property for the artifact represented by this node to the * Adds the score property for the artifact represented by this node to the
* node property sheet. * node property sheet.

View File

@ -84,6 +84,24 @@ BlackboardArtifactNode_analysisSheet_justifaction_name=Justification
BlackboardArtifactNode_analysisSheet_score_name=Score BlackboardArtifactNode_analysisSheet_score_name=Score
BlackboardArtifactNode_analysisSheet_sourceType_name=Source Type BlackboardArtifactNode_analysisSheet_sourceType_name=Source Type
BlackboardArtifactNode_analysisSheet_soureName_name=Source Name BlackboardArtifactNode_analysisSheet_soureName_name=Source Name
# {0} - type
BlackboardArtifactNode_getAssociatedFileActions_viewAssociatedFileAction=View {0} in Directory
# {0} - type
BlackboardArtifactNode_getAssociatedFileActions_viewAssociatedFileInTimelineAction=View {0} in Timeline...
BlackboardArtifactNode_getAssociatedTypeStr_associated=Associated File
BlackboardArtifactNode_getAssociatedTypeStr_webCache=Cached File
BlackboardArtifactNode_getAssociatedTypeStr_webDownload=Downloaded File
# {0} - contentType
BlackboardArtifactNode_getSrcContentAction_actionDisplayName=View Source {0} in Directory
BlackboardArtifactNode_getSrcContentViewerActions_openInExtViewer=Open in External Viewer Ctrl+E
BlackboardArtifactNode_getSrcContentViewerActions_viewInNewWin=View Item in New Window
BlackboardArtifactNode_getTimelineArtifactAction_displayName=View Selected Item in Timeline...
# {0} - contentType
BlackboardArtifactNode_getTimelineSrcContentAction_actionDisplayName=View Source {0} in Timeline...
BlackboardArtifactNode_getViewSrcContentAction_type_DataArtifact=Data Artifact
BlackboardArtifactNode_getViewSrcContentAction_type_File=File
BlackboardArtifactNode_getViewSrcContentAction_type_OSAccount=OS Account
BlackboardArtifactNode_getViewSrcContentAction_type_unknown=Item
BlackboardArtifactTagNode.createSheet.userName.text=User Name BlackboardArtifactTagNode.createSheet.userName.text=User Name
BlackboardArtifactTagNode.viewSourceArtifact.text=View Source Result BlackboardArtifactTagNode.viewSourceArtifact.text=View Source Result
Category.five=CAT-5: Non-pertinent Category.five=CAT-5: Non-pertinent

View File

@ -99,7 +99,6 @@ public abstract class DisplayableItemNode extends AbstractNode {
* operation on this artifact type and return some object as the result of * operation on this artifact type and return some object as the result of
* the operation. * the operation.
* *
* @param <T> The return type.
* @param visitor The visitor, where the type parameter of the visitor is * @param visitor The visitor, where the type parameter of the visitor is
* the type of the object that will be returned as the result * the type of the object that will be returned as the result
* of the visit operation. * of the visit operation.

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
@ -29,6 +30,10 @@ import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.AnalysisResult;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataArtifact;
/** /**
* Background task to get Score, Comment and Occurrences values for an Abstract * Background task to get Score, Comment and Occurrences values for an Abstract
@ -62,7 +67,18 @@ class GetSCOTask implements Runnable {
//getting the correlation attribute and setting the comment column is done before the eamdb isEnabled check //getting the correlation attribute and setting the comment column is done before the eamdb isEnabled check
//because the Comment column will reflect the presence of comments in the CR when the CR is enabled, but reflect tag comments regardless //because the Comment column will reflect the presence of comments in the CR when the CR is enabled, but reflect tag comments regardless
String description = Bundle.GetSCOTask_occurrences_defaultDescription(); String description = Bundle.GetSCOTask_occurrences_defaultDescription();
List<CorrelationAttributeInstance> listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsForSearch(contentNode.getContent());
List<CorrelationAttributeInstance> listOfPossibleAttributes = new ArrayList<>();
Content contentFromNode = contentNode.getContent();
if (contentFromNode instanceof AbstractFile) {
listOfPossibleAttributes.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((AbstractFile) contentFromNode));
} else if (contentFromNode instanceof AnalysisResult) {
listOfPossibleAttributes.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((AnalysisResult) contentFromNode));
} else if (contentFromNode instanceof DataArtifact) {
listOfPossibleAttributes.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch((DataArtifact) contentFromNode));
} else {
//JIRA-TODO : add code for Jira-7938 OsAccounts
}
scoData.setComment(contentNode.getCommentProperty(tags, listOfPossibleAttributes)); scoData.setComment(contentNode.getCommentProperty(tags, listOfPossibleAttributes));
CorrelationAttributeInstance corInstance = null; CorrelationAttributeInstance corInstance = null;
if (CentralRepository.isEnabled()) { if (CentralRepository.isEnabled()) {

View File

@ -60,10 +60,20 @@ public final class OsAccounts implements AutopsyVisitableItem {
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/os-account.png"; private static final String ICON_PATH = "org/sleuthkit/autopsy/images/os-account.png";
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
private static final String REALM_DATA_AVAILABLE_EVENT = "REALM_DATA_AVAILABLE_EVENT"; private static final String REALM_DATA_AVAILABLE_EVENT = "REALM_DATA_AVAILABLE_EVENT";
private static final String LIST_NAME = Bundle.OsAccount_listNode_name();
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final long filteringDSObjId; private final long filteringDSObjId;
/**
* Returns the name of the OsAccountListNode to be used for id purposes.
*
* @return The name of the OsAccountListNode to be used for id purposes.
*/
public static String getListName() {
return LIST_NAME;
}
public OsAccounts(SleuthkitCase skCase) { public OsAccounts(SleuthkitCase skCase) {
this(skCase, 0); this(skCase, 0);
} }
@ -91,8 +101,8 @@ public final class OsAccounts implements AutopsyVisitableItem {
*/ */
public OsAccountListNode() { public OsAccountListNode() {
super(Children.create(new OsAccountNodeFactory(), true)); super(Children.create(new OsAccountNodeFactory(), true));
setName(Bundle.OsAccount_listNode_name()); setName(LIST_NAME);
setDisplayName(Bundle.OsAccount_listNode_name()); setDisplayName(LIST_NAME);
setIconBaseWithExtension("org/sleuthkit/autopsy/images/os-account.png"); setIconBaseWithExtension("org/sleuthkit/autopsy/images/os-account.png");
} }

View File

@ -170,7 +170,7 @@ public class TypesSummary {
* Constructor that accepts FileTypeCategory. * Constructor that accepts FileTypeCategory.
* *
* @param label The label for this slice. * @param label The label for this slice.
* @param mimeTypes The mime types associated with this slice. * @param fileCategory The category associated with this slice.
* @param color The color associated with this slice. * @param color The color associated with this slice.
*/ */
public FileTypeCategoryData(String label, FileTypeUtils.FileTypeCategory fileCategory, Color color) { public FileTypeCategoryData(String label, FileTypeUtils.FileTypeCategory fileCategory, Color color) {

View File

@ -66,7 +66,7 @@ GeolocationPanel_onNoCrIngest_message=No results will be shown because the GPX P
GeolocationPanel_unknownRow_title=Unknown GeolocationPanel_unknownRow_title=Unknown
PastCasesPanel_caseColumn_title=Case PastCasesPanel_caseColumn_title=Case
PastCasesPanel_countColumn_title=Count PastCasesPanel_countColumn_title=Count
PastCasesPanel_notableFileTable_tabName=Cases with Common Notable PastCasesPanel_notableFileTable_tabName=Cases with Common Notable Items at Time Of Ingest
PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run. PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run.
PastCasesPanel_sameIdsTable_tabName=Past Cases with the Same Devices PastCasesPanel_sameIdsTable_tabName=Past Cases with the Same Devices
RecentFilesPanel_attachmentsTable_tabName=Recent Attachments RecentFilesPanel_attachmentsTable_tabName=Recent Attachments
@ -75,7 +75,7 @@ RecentFilesPanel_col_header_domain=Domain
RecentFilesPanel_col_header_path=Path RecentFilesPanel_col_header_path=Path
RecentFilesPanel_col_header_sender=Sender RecentFilesPanel_col_header_sender=Sender
RecentFilesPanel_docsTable_tabName=Recently Opened Documents RecentFilesPanel_docsTable_tabName=Recently Opened Documents
RecentFilesPanel_downloadsTable_tabName=Recently Downloads RecentFilesPanel_downloadsTable_tabName=Recent Downloads
RecentFilesPanel_no_open_documents=No recently open documents found. RecentFilesPanel_no_open_documents=No recently open documents found.
SizeRepresentationUtil_units_bytes=bytes SizeRepresentationUtil_units_bytes=bytes
SizeRepresentationUtil_units_gigabytes=GB SizeRepresentationUtil_units_gigabytes=GB

View File

@ -41,7 +41,7 @@ import org.sleuthkit.datamodel.DataSource;
"PastCasesPanel_caseColumn_title=Case", "PastCasesPanel_caseColumn_title=Case",
"PastCasesPanel_countColumn_title=Count", "PastCasesPanel_countColumn_title=Count",
"PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run.", "PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run.",
"PastCasesPanel_notableFileTable_tabName=Cases with Common Notable", "PastCasesPanel_notableFileTable_tabName=Cases with Common Notable Items at Time Of Ingest",
"PastCasesPanel_sameIdsTable_tabName=Past Cases with the Same Devices",}) "PastCasesPanel_sameIdsTable_tabName=Past Cases with the Same Devices",})
public class PastCasesPanel extends BaseDataSourceSummaryPanel { public class PastCasesPanel extends BaseDataSourceSummaryPanel {

View File

@ -47,7 +47,7 @@ import org.sleuthkit.datamodel.DataSource;
*/ */
@Messages({ @Messages({
"RecentFilesPanel_docsTable_tabName=Recently Opened Documents", "RecentFilesPanel_docsTable_tabName=Recently Opened Documents",
"RecentFilesPanel_downloadsTable_tabName=Recently Downloads", "RecentFilesPanel_downloadsTable_tabName=Recent Downloads",
"RecentFilesPanel_attachmentsTable_tabName=Recent Attachments",}) "RecentFilesPanel_attachmentsTable_tabName=Recent Attachments",})
public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {

View File

@ -22,8 +22,7 @@ import java.awt.event.ActionEvent;
import java.beans.PropertyVetoException; import java.beans.PropertyVetoException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Arrays;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
@ -34,53 +33,25 @@ import org.openide.nodes.FilterNode;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory;
import org.sleuthkit.autopsy.datamodel.DirectoryNode; import org.sleuthkit.autopsy.datamodel.DirectoryNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.FileTypeExtensions;
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode;
import org.sleuthkit.autopsy.commonpropertiessearch.InstanceCountNode; import org.sleuthkit.autopsy.commonpropertiessearch.InstanceCountNode;
import org.sleuthkit.autopsy.commonpropertiessearch.InstanceCaseNode; import org.sleuthkit.autopsy.commonpropertiessearch.InstanceCaseNode;
import org.sleuthkit.autopsy.commonpropertiessearch.InstanceDataSourceNode; import org.sleuthkit.autopsy.commonpropertiessearch.InstanceDataSourceNode;
import org.sleuthkit.autopsy.commonpropertiessearch.CommonAttributeValueNode; import org.sleuthkit.autopsy.commonpropertiessearch.CommonAttributeValueNode;
import org.sleuthkit.autopsy.commonpropertiessearch.CentralRepoCommonAttributeInstanceNode; import org.sleuthkit.autopsy.commonpropertiessearch.CentralRepoCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
import org.sleuthkit.autopsy.datamodel.LocalFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode;
import org.sleuthkit.autopsy.datamodel.LocalDirectoryNode;
import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo; import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
import org.sleuthkit.autopsy.datamodel.Reports; import org.sleuthkit.autopsy.datamodel.Reports;
import org.sleuthkit.autopsy.datamodel.SlackFileNode;
import org.sleuthkit.autopsy.commonpropertiessearch.CaseDBCommonAttributeInstanceNode; import org.sleuthkit.autopsy.commonpropertiessearch.CaseDBCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
import static org.sleuthkit.autopsy.directorytree.Bundle.DataResultFilterNode_viewSourceArtifact_text;
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.File;
import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.LocalFile;
import org.sleuthkit.datamodel.LocalDirectory;
import org.sleuthkit.datamodel.SlackFile;
import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.Report;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
@ -265,137 +236,7 @@ public class DataResultFilterNode extends FilterNode {
@Override @Override
public List<Action> visit(BlackboardArtifactNode ban) { public List<Action> visit(BlackboardArtifactNode ban) {
//set up actions for artifact node based on its Content object return Arrays.asList(ban.getActions(true));
//TODO all actions need to be consolidated in single place!
//they should be set in individual Node subclass and using a utility to get Actions per Content sub-type
// TODO UPDATE: There is now a DataModelActionsFactory utility;
List<Action> actionsList = new ArrayList<>();
//merge predefined specific node actions if bban subclasses have their own
for (Action a : ban.getActions(true)) {
actionsList.add(a);
}
//Add seperator between the decorated actions and the actions from the node itself.
actionsList.add(null);
BlackboardArtifact ba = ban.getLookup().lookup(BlackboardArtifact.class);
final int artifactTypeID = ba.getArtifactTypeID();
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()
|| artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
if (ban.getLookup().lookup(AbstractFile.class) != null) {
// We only want the "View File in Directory" actions if we have a file...it is
// possible that we have a keyword hit on a Report.
actionsList.add(new ViewContextAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), ban));
}
} else if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
try {
if (ba.getAttribute(BlackboardAttribute.Type.TSK_ASSOCIATED_ARTIFACT) != null) {
//action to go to the source artifact
actionsList.add(new ViewSourceArtifactAction(DataResultFilterNode_viewSourceArtifact_text(), ba));
// action to go to the source file of the artifact
actionsList.add(new ViewContextAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewSrcFileInDir.text"), ban));
}
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "Error looking up attributes for artifact with ID=" + ba.getId());
}
} else {
// if the artifact links to another file, add an action to go to
// that file
Content c = findLinked(ban);
if (c != null) {
actionsList.add(new ViewContextAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), c));
}
// action to go to the source file of the artifact
Content fileContent = ban.getLookup().lookup(AbstractFile.class);
if (fileContent == null) {
Content content = ban.getLookup().lookup(Content.class);
actionsList.add(new ViewContextAction("View Source Content in Directory", content));
} else {
actionsList.add(new ViewContextAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewSrcFileInDir.text"), ban));
}
}
Content c = ban.getLookup().lookup(File.class);
Node n = null;
if (c != null) {
n = new FileNode((AbstractFile) c);
} else if ((c = ban.getLookup().lookup(Directory.class)) != null) {
n = new DirectoryNode((Directory) c);
} else if ((c = ban.getLookup().lookup(VirtualDirectory.class)) != null) {
n = new VirtualDirectoryNode((VirtualDirectory) c);
} else if ((c = ban.getLookup().lookup(LocalDirectory.class)) != null) {
n = new LocalDirectoryNode((LocalDirectory) c);
} else if ((c = ban.getLookup().lookup(LayoutFile.class)) != null) {
n = new LayoutFileNode((LayoutFile) c);
} else if ((c = ban.getLookup().lookup(LocalFile.class)) != null
|| (c = ban.getLookup().lookup(DerivedFile.class)) != null) {
n = new LocalFileNode((AbstractFile) c);
if (FileTypeExtensions.getArchiveExtensions().contains("." + ((AbstractFile) c).getNameExtension().toLowerCase())) {
try {
if (c.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED).size() > 0) {
actionsList.add(new ExtractArchiveWithPasswordAction((AbstractFile) c));
}
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "Unable to add unzip with password action to context menus", ex);
}
}
} else if ((c = ban.getLookup().lookup(SlackFile.class)) != null) {
n = new SlackFileNode((SlackFile) c);
} else if ((c = ban.getLookup().lookup(Report.class)) != null) {
actionsList.addAll(DataModelActionsFactory.getActions(c, false));
}
if (n != null) {
final Collection<AbstractFile> selectedFilesList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewInNewWin.text"), n));
if (selectedFilesList.size() == 1) {
actionsList.add(new ExternalViewerAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n));
} else {
actionsList.add(ExternalViewerShortcutAction.getInstance());
}
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(ExportCSVAction.getInstance());
actionsList.add(null); // creates a menu separator
// don't show AddContentTagAction for data artifacts.
if (!(ban.getArtifact() instanceof DataArtifact)) {
actionsList.add(AddContentTagAction.getInstance());
}
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
// don't show DeleteFileContentTagAction for data artifacts.
if ((!(ban.getArtifact() instanceof DataArtifact)) && (selectedFilesList.size() == 1)) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
} else {
// There's no specific file associated with the artifact, but
// we can still tag the artifact itself
actionsList.add(null);
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
}
final Collection<BlackboardArtifact> selectedArtifactsList
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if (selectedArtifactsList.size() == 1) {
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
}
if (n != null) {
actionsList.addAll(ContextMenuExtensionPoint.getActions());
}
return actionsList;
} }
@Override @Override
@ -411,44 +252,8 @@ public class DataResultFilterNode extends FilterNode {
@Override @Override
protected List<Action> defaultVisit(DisplayableItemNode ditem) { protected List<Action> defaultVisit(DisplayableItemNode ditem) {
//preserve the default node's actions return Arrays.asList(ditem.getActions(true));
List<Action> actions = new ArrayList<>();
for (Action action : ditem.getActions(true)) {
actions.add(action);
} }
return actions;
}
private Content findLinked(BlackboardArtifactNode ba) {
BlackboardArtifact art = ba.getLookup().lookup(BlackboardArtifact.class);
Content c = null;
try {
for (BlackboardAttribute attr : art.getAttributes()) {
if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()) {
switch (attr.getAttributeType().getValueType()) {
case INTEGER:
int i = attr.getValueInt();
if (i != -1) {
c = art.getSleuthkitCase().getContentById(i);
}
break;
case LONG:
long l = attr.getValueLong();
if (l != -1) {
c = art.getSleuthkitCase().getContentById(l);
}
break;
}
}
}
} catch (TskException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error getting linked file", ex); //NON-NLS
}
return c;
}
} }
/* /*

View File

@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -83,6 +84,7 @@ import org.sleuthkit.autopsy.datamodel.InterestingHits;
import org.sleuthkit.autopsy.datamodel.KeywordHits; import org.sleuthkit.autopsy.datamodel.KeywordHits;
import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildFactory; import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildFactory;
import org.sleuthkit.autopsy.datamodel.DataArtifacts; import org.sleuthkit.autopsy.datamodel.DataArtifacts;
import org.sleuthkit.autopsy.datamodel.OsAccounts;
import org.sleuthkit.autopsy.datamodel.PersonNode; import org.sleuthkit.autopsy.datamodel.PersonNode;
import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.ViewsNode; import org.sleuthkit.autopsy.datamodel.ViewsNode;
@ -95,6 +97,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.OsAccount;
import org.sleuthkit.datamodel.Person; import org.sleuthkit.datamodel.Person;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -1220,6 +1223,85 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
.findFirst(); .findFirst();
} }
/**
* Does depth-first search to find os account list node where the provided
* os account is a child.
*
* @param node The node.
* @param osAccount The os account.
*
* @return The parent list node of the os account if found or empty if not.
*/
private Optional<Node> getOsAccountListNode(Node node, OsAccount osAccount, Set<Host> hosts) {
if (node == null) {
return Optional.empty();
}
Host nodeHost = node.getLookup().lookup(Host.class);
if ((nodeHost != null && hosts != null && hosts.contains(nodeHost))
|| node.getLookup().lookup(DataSource.class) != null
|| node.getLookup().lookup(Person.class) != null
|| PersonNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) {
return Stream.of(node.getChildren().getNodes(true))
.map(childNode -> getOsAccountListNode(childNode, osAccount, hosts))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
}
if (OsAccounts.getListName().equals(node.getName())) {
return Optional.of(node);
}
return Optional.empty();
}
/**
* Navigates to the os account if the os account is found in the tree.
*
* @param osAccount The os account.
*/
public void viewOsAccount(OsAccount osAccount) {
Set<Host> hosts = null;
if (CasePreferences.getGroupItemsInTreeByDataSource()) {
try {
hosts = new HashSet<>(Case.getCurrentCase().getSleuthkitCase().getOsAccountManager().getHosts(osAccount));
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "Unable to get valid hosts for osAccount: " + osAccount, ex);
return;
}
}
final Set<Host> finalHosts = hosts;
Optional<Node> osAccountListNodeOpt = Stream.of(em.getRootContext().getChildren().getNodes(true))
.map(nd -> getOsAccountListNode(nd, osAccount, finalHosts))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
if (!osAccountListNodeOpt.isPresent()) {
return;
}
Node osAccountListNode = osAccountListNodeOpt.get();
DisplayableItemNode undecoratedParentNode = (DisplayableItemNode) ((DirectoryTreeFilterNode) osAccountListNode).getOriginal();
undecoratedParentNode.setChildNodeSelectionInfo((osAcctNd) -> {
OsAccount osAcctOfNd = osAcctNd.getLookup().lookup(OsAccount.class);
return osAcctOfNd != null && osAcctOfNd.getId() == osAccount.getId();
});
getTree().expandNode(osAccountListNode);
try {
em.setExploredContextAndSelection(osAccountListNode, new Node[]{osAccountListNode});
} catch (PropertyVetoException ex) {
LOGGER.log(Level.WARNING, "Property Veto: ", ex); //NON-NLS
}
}
/** /**
* Attempts to retrieve the artifact type for the given artifact type id. * Attempts to retrieve the artifact type for the given artifact type id.
* *

View File

@ -126,6 +126,7 @@ public class DomainSearch {
* @param caseDb The case database. * @param caseDb The case database.
* @param centralRepoDb The central repository database. Can be null * @param centralRepoDb The central repository database. Can be null
* if not needed. * if not needed.
* @param context The search context.
* *
* @return A LinkedHashMap grouped and sorted according to the parameters. * @return A LinkedHashMap grouped and sorted according to the parameters.
* *

View File

@ -31,6 +31,7 @@ import java.util.Collection;
import java.util.logging.Level; import java.util.logging.Level;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.ImageUtils;
@ -194,6 +195,7 @@ class SummaryHelpers {
} }
} }
@NbBundle.Messages({"SummaryHelper.documentSummary.unable.to.read=Unable to extract text from file."})
/** /**
* Get the beginning of text from the specified AbstractFile. * Get the beginning of text from the specified AbstractFile.
* *
@ -217,7 +219,7 @@ class SummaryHelpers {
} catch (IOException ex) { } catch (IOException ex) {
return Bundle.FileSearch_documentSummary_noBytes(); return Bundle.FileSearch_documentSummary_noBytes();
} catch (TextExtractor.InitReaderException ex) { } catch (TextExtractor.InitReaderException ex) {
return Bundle.FileSearch_documentSummary_noPreview(); return Bundle.SummaryHelper_documentSummary_unable_to_read();
} }
} }

View File

@ -54,7 +54,7 @@ ExportIngestHistory_startTimeColumn=Start Time
ExportIngestHistory_versionColumn=Module Version ExportIngestHistory_versionColumn=Module Version
ExportPastCases_caseColumn_title=Case ExportPastCases_caseColumn_title=Case
ExportPastCases_countColumn_title=Count ExportPastCases_countColumn_title=Count
ExportPastCases_notableFileTable_tabName=Cases with Common Notable ExportPastCases_notableFileTable_tabName=Cases with Common Notable Items at Time Of Ingest
ExportPastCases_sameIdsTable_tabName=Past Cases with the Same Devices ExportPastCases_sameIdsTable_tabName=Past Cases with the Same Devices
ExportRecentFiles_attachmentsTable_tabName=Recent Attachments ExportRecentFiles_attachmentsTable_tabName=Recent Attachments
ExportRecentFiles_col_head_date=Date ExportRecentFiles_col_head_date=Date

View File

@ -37,7 +37,7 @@ import org.sleuthkit.datamodel.DataSource;
@Messages({ @Messages({
"ExportPastCases_caseColumn_title=Case", "ExportPastCases_caseColumn_title=Case",
"ExportPastCases_countColumn_title=Count", "ExportPastCases_countColumn_title=Count",
"ExportPastCases_notableFileTable_tabName=Cases with Common Notable", "ExportPastCases_notableFileTable_tabName=Cases with Common Notable Items at Time Of Ingest",
"ExportPastCases_sameIdsTable_tabName=Past Cases with the Same Devices",}) "ExportPastCases_sameIdsTable_tabName=Past Cases with the Same Devices",})
class ExportPastCases { class ExportPastCases {

View File

@ -1,15 +0,0 @@
OpenIDE-Module-Name=stixModule
STIXReportModule.getName.text=STIX
STIXReportModule.getDesc.text=Generate a report by running a collection of STIX (Structured Threat Information eXpression) files against the data sources. Also creates artifacts under Interesting Files.
STIXReportModule.progress.readSTIX=Parsing STIX files
STIXReportModuleConfigPanel.jLabel2.text=Select a STIX file or directory of STIX files
STIXReportModuleConfigPanel.jButton1.text=Choose file
STIXReportModuleConfigPanel.jCheckBox1.text=Include results for false indicators in output file
STIXReportModule.notifyMsg.unableToOpenReportFile=Unable to complete STIX report.
STIXReportModule.progress.completedWithErrors=Completed with errors
STIXReportModule.notifyMsg.unableToOpenFileDir=Unable to open STIX file/directory {0}
STIXReportModule.progress.couldNotOpenFileDir=Could not open file/directory {0}
STIXReportModule.notifyMsg.tooManyArtifactsgt1000=Too many STIX-related artifacts generated for "{0}". Only saving first 1000.
STIXReportModule.notifyErr.noFildDirProvided=No STIX file/directory provided
STIXReportModule.progress.noFildDirProvided=No STIX file/directory provided
STIXReportModuleConfigPanel.jStixFileTextField.text=

View File

@ -1,18 +0,0 @@
OpenIDE-Module-Name=stixModule
StixArtifactData.indexError.message=Failed to index STIX interesting file hit artifact for keyword search.
StixArtifactData.noOpenCase.errMsg=No open case available.
STIXReportModule.getName.text=STIX
STIXReportModule.getDesc.text=Generate a report by running a collection of STIX (Structured Threat Information eXpression) files against the data sources. Also creates artifacts under Interesting Files.
STIXReportModule.progress.readSTIX=Parsing STIX files
STIXReportModule.srcModuleName.text=STIX Report
STIXReportModuleConfigPanel.jLabel2.text=Select a STIX file or directory of STIX files
STIXReportModuleConfigPanel.jButton1.text=Choose file
STIXReportModuleConfigPanel.jCheckBox1.text=Include results for false indicators in output file
STIXReportModule.notifyMsg.unableToOpenReportFile=Unable to complete STIX report.
STIXReportModule.progress.completedWithErrors=Completed with errors
STIXReportModule.notifyMsg.unableToOpenFileDir=Unable to open STIX file/directory {0}
STIXReportModule.progress.couldNotOpenFileDir=Could not open file/directory {0}
STIXReportModule.notifyMsg.tooManyArtifactsgt1000=Too many STIX-related artifacts generated for "{0}". Only saving first 1000.
STIXReportModule.notifyErr.noFildDirProvided=No STIX file/directory provided
STIXReportModule.progress.noFildDirProvided=No STIX file/directory provided
STIXReportModuleConfigPanel.jStixFileTextField.text=

View File

@ -1,18 +0,0 @@
#Mon Jul 12 13:22:00 UTC 2021
OpenIDE-Module-Name=stix\u30e2\u30b8\u30e5\u30fc\u30eb
STIXReportModule.getDesc.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u306b\u5bfe\u3057\u3066\u5e7e\u3064\u304b\u306eSTIX\uff08Structured Threat Information eXpression\uff1b\u8105\u5a01\u60c5\u5831\u69cb\u9020\u5316\u8a18\u8ff0\u5f62\u5f0f\uff09\u30d5\u30a1\u30a4\u30eb\u3092\u5b9f\u884c\u3057\u3001\u30ec\u30dd\u30fc\u30c8\u3092\u751f\u6210\u3057\u307e\u3059\u3002\u307e\u305f\u3001\u7591\u308f\u3057\u3044\u30d5\u30a1\u30a4\u30eb\u5185\u306b\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u3092\u4f5c\u6210\u3002
STIXReportModule.getName.text=STIX
STIXReportModule.notifyErr.noFildDirProvided=STIX\u30d5\u30a1\u30a4\u30eb\uff0f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u304c\u63d0\u4f9b\u3055\u308c\u3066\u3044\u307e\u305b\u3093
STIXReportModule.notifyMsg.tooManyArtifactsgt1000="{0}"\u7528\u306b\u751f\u6210\u3055\u308c\u305fSTIX\u95a2\u9023\u306e\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u304c\u591a\u3059\u304e\u307e\u3059\u3002\u6700\u521d\u306e1000\u306e\u307f\u4fdd\u5b58\u3055\u308c\u307e\u3059\u3002
STIXReportModule.notifyMsg.unableToOpenFileDir=STIX\u30d5\u30a1\u30a4\u30eb\uff0f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea{0}\u3092\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f
STIXReportModule.notifyMsg.unableToOpenReportFile=STIX\u30ec\u30dd\u30fc\u30c8\u3092\u5b8c\u4e86\u3067\u304d\u307e\u305b\u3093\u3002
STIXReportModule.progress.completedWithErrors=\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u304c\u3001\u5b8c\u4e86\u3057\u307e\u3057\u305f
STIXReportModule.progress.couldNotOpenFileDir=\u30d5\u30a1\u30a4\u30eb\uff0f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea{0}\u3092\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f
STIXReportModule.progress.noFildDirProvided=STIX\u30d5\u30a1\u30a4\u30eb\uff0f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u304c\u63d0\u4f9b\u3055\u308c\u3066\u3044\u307e\u305b\u3093
STIXReportModule.progress.readSTIX=STIX\u30d5\u30a1\u30a4\u30eb\u3092\u30d1\u30fc\u30b9\u4e2d
STIXReportModule.srcModuleName.text=STIX\u30ec\u30dd\u30fc\u30c8
STIXReportModuleConfigPanel.jButton1.text=\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e
STIXReportModuleConfigPanel.jCheckBox1.text=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a1\u30a4\u30eb\u306e\u8aa4\u3063\u305f\u30a4\u30f3\u30b8\u30b1\u30fc\u30bf\u30fc\u306e\u7d50\u679c\u3082\u542b\u3080
STIXReportModuleConfigPanel.jLabel2.text=STIX\u30d5\u30a1\u30a4\u30eb\u307e\u305f\u306fSTIX\u30d5\u30a1\u30a4\u30eb\u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u9078\u629e
StixArtifactData.indexError.message=\u30ad\u30fc\u30ef\u30fc\u30c9\u691c\u7d22\u7528\u306eSTIX\u8208\u5473\u6df1\u3044\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u4f5c\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002
StixArtifactData.noOpenCase.errMsg=\u30aa\u30fc\u30d7\u30f3\u30b1\u30fc\u30b9\u306f\u3042\u308a\u307e\u305b\u3093\u3002

View File

@ -1,227 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import java.util.List;
import java.util.ArrayList;
import org.mitre.cybox.objects.AccountObjectType;
import org.mitre.cybox.objects.UserAccountObjectType;
import org.mitre.cybox.objects.WindowsUserAccount;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
/**
*
*/
class EvalAccountObj extends EvaluatableObject {
private final AccountObjectType obj;
EvalAccountObj(AccountObjectType a_obj, String a_id, String a_spacing) {
obj = a_obj;
id = a_id;
spacing = a_spacing;
}
@SuppressWarnings( "deprecation" )
@Override
public synchronized ObservableResult evaluate() {
setWarnings("");
// Fields we can search for:
// UserAccount: Home_Directory, Username
// WinUserAccount: SID
if (!(obj instanceof UserAccountObjectType)) {
return new ObservableResult(id, "AccountObject: Can not process \"Account\" - need a User_Account or Windows_User_Account", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
// For displaying what we were looking for in the results
String searchString = "";
// Check which fields are present and record them
boolean haveHomeDir = false;
boolean haveUsername = false;
boolean haveSID = false;
UserAccountObjectType userAccountObj = (UserAccountObjectType) obj;
if (userAccountObj.getHomeDirectory() != null) {
haveHomeDir = true;
searchString = "HomeDir \"" + userAccountObj.getHomeDirectory().getValue().toString() + "\""; //NON-NLS
}
if (userAccountObj.getUsername() != null) {
haveUsername = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "Username \"" + userAccountObj.getUsername().getValue().toString() + "\""; //NON-NLS
}
WindowsUserAccount winUserObj = null;
if (obj instanceof WindowsUserAccount) {
winUserObj = (WindowsUserAccount) obj;
if (winUserObj.getSecurityID() != null) {
haveSID = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "SID \"" + winUserObj.getSecurityID().getValue().toString() + "\""; //NON-NLS
}
}
if (!(haveHomeDir || haveUsername || haveSID)) {
return new ObservableResult(id, "AccountObject: No evaluatable fields found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
// Set warnings for any unsupported fields
setUnsupportedFieldWarnings();
// The assumption here is that there aren't going to be too many network shares, so we
// can cycle through all of them.
try {
List<BlackboardArtifact> finalHits = new ArrayList<>();
Case case1 = Case.getCurrentCaseThrows();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
List<BlackboardArtifact> artList
= sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT);
for (BlackboardArtifact art : artList) {
boolean foundHomeDirMatch = false;
boolean foundUsernameMatch = false;
boolean foundSIDMatch = false;
for (BlackboardAttribute attr : art.getAttributes()) {
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID())
&& (haveHomeDir)) {
foundHomeDirMatch = compareStringObject(userAccountObj.getHomeDirectory(), attr.getValueString());
}
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME.getTypeID())
&& (haveUsername)) {
foundUsernameMatch = compareStringObject(userAccountObj.getUsername(), attr.getValueString());
}
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID.getTypeID())
&& (haveSID) && (winUserObj != null)) {
foundSIDMatch = compareStringObject(winUserObj.getSecurityID(), attr.getValueString());
}
}
if (((!haveHomeDir) || foundHomeDirMatch)
&& ((!haveUsername) || foundUsernameMatch)
&& ((!haveSID) || foundSIDMatch)) {
finalHits.add(art);
}
}
// Check if we found any matches
if (!finalHits.isEmpty()) {
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
for (BlackboardArtifact a : finalHits) {
artData.add(new StixArtifactData(a.getObjectID(), id, "Account")); //NON-NLS
}
return new ObservableResult(id, "AccountObject: Found a match for " + searchString, //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
}
// Didn't find any matches
return new ObservableResult(id, "AccountObject: No matches found for " + searchString, //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
} catch (TskCoreException | NoCurrentCaseException ex) {
return new ObservableResult(id, "AccountObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
}
/**
* Set up the warning for any fields in the object that aren't supported.
*/
private void setUnsupportedFieldWarnings() {
List<String> fieldNames = new ArrayList<String>();
if (obj.getDescription() != null) {
fieldNames.add("Description"); //NON-NLS
}
if (obj.getDomain() != null) {
fieldNames.add("Domain"); //NON-NLS
}
if (obj.getAuthentications() != null) {
fieldNames.add("Authentication"); //NON-NLS
}
if (obj.getCreationDate() != null) {
fieldNames.add("Creation_Date"); //NON-NLS
}
if (obj.getModifiedDate() != null) {
fieldNames.add("Modified_Date"); //NON-NLS
}
if (obj.getLastAccessedTime() != null) {
fieldNames.add("Last_Accessed_Time"); //NON-NLS
}
if (obj instanceof UserAccountObjectType) {
UserAccountObjectType userAccountObj = (UserAccountObjectType) obj;
if (userAccountObj.getFullName() != null) {
fieldNames.add("Full_Name"); //NON-NLS
}
if (userAccountObj.getGroupList() != null) {
fieldNames.add("Group_List"); //NON-NLS
}
if (userAccountObj.getLastLogin() != null) {
fieldNames.add("Last_Login"); //NON-NLS
}
if (userAccountObj.getPrivilegeList() != null) {
fieldNames.add("Privilege_List"); //NON-NLS
}
if (userAccountObj.getScriptPath() != null) {
fieldNames.add("Script_Path"); //NON-NLS
}
if (userAccountObj.getUserPasswordAge() != null) {
fieldNames.add("User_Password_Age"); //NON-NLS
}
}
if (obj instanceof WindowsUserAccount) {
WindowsUserAccount winUserObj = (WindowsUserAccount) obj;
if (winUserObj.getSecurityType() != null) {
fieldNames.add("Security_Type"); //NON-NLS
}
}
String warningStr = "";
for (String name : fieldNames) {
if (!warningStr.isEmpty()) {
warningStr += ", ";
}
warningStr += name;
}
addWarning("Unsupported field(s): " + warningStr); //NON-NLS
}
}

View File

@ -1,194 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import java.util.List;
import java.util.ArrayList;
import org.mitre.cybox.common_2.ConditionApplicationEnum;
import org.mitre.cybox.common_2.ConditionTypeEnum;
import org.mitre.cybox.objects.Address;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
/**
*
*/
class EvalAddressObj extends EvaluatableObject {
private final Address obj;
public EvalAddressObj(Address a_obj, String a_id, String a_spacing) {
obj = a_obj;
id = a_id;
spacing = a_spacing;
}
@Override
public synchronized ObservableResult evaluate() {
setWarnings("");
if (obj.getAddressValue() == null) {
return new ObservableResult(id, "AddressObject: No address value field found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
Case case1;
try {
case1 = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
return new ObservableResult(id, "Exception while getting open case.", //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
}
String origAddressStr = obj.getAddressValue().getValue().toString();
// For now, we don't support "NONE" because it honestly doesn't seem like it
// would ever appear in practice.
if (((obj.getAddressValue().getApplyCondition() != null)
&& (obj.getAddressValue().getApplyCondition() == ConditionApplicationEnum.NONE))) {
return new ObservableResult(id, "AddressObject: Can not process apply condition " + obj.getAddressValue().getApplyCondition().toString() //NON-NLS
+ " on Address object", spacing, ObservableResult.ObservableState.INDETERMINATE, null); //NON-NLS
}
// Set warnings for any unsupported fields
setUnsupportedFieldWarnings();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
try {
// Need to check that every part of the string had at least one match
// in the AND case
boolean everyPartMatched = true;
List<BlackboardArtifact> combinedArts = new ArrayList<BlackboardArtifact>();
String searchString = "";
String[] parts = origAddressStr.split("##comma##"); //NON-NLS
for (String addressStr : parts) {
// Update the string to show in the results
if (!searchString.isEmpty()) {
if ((obj.getAddressValue().getApplyCondition() != null)
&& (obj.getAddressValue().getApplyCondition() == ConditionApplicationEnum.ALL)) {
searchString += " AND "; //NON-NLS
} else {
searchString += " OR "; //NON-NLS
}
}
searchString += addressStr;
if ((obj.getAddressValue().getCondition() == null)
|| (obj.getAddressValue().getCondition() == ConditionTypeEnum.EQUALS)) {
List<BlackboardArtifact> arts = sleuthkitCase.getBlackboardArtifacts(
BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT,
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD,
addressStr);
if (arts.isEmpty()) {
everyPartMatched = false;
} else {
combinedArts.addAll(arts);
}
} else {
// This is inefficient, but the easiest way to do it.
List<BlackboardArtifact> finalHits = new ArrayList<BlackboardArtifact>();
// Get all the URL artifacts
List<BlackboardArtifact> artList
= sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT);
for (BlackboardArtifact art : artList) {
for (BlackboardAttribute attr : art.getAttributes()) {
if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
if (compareStringObject(addressStr, obj.getAddressValue().getCondition(),
obj.getAddressValue().getApplyCondition(), attr.getValueString())) {
finalHits.add(art);
}
}
}
}
if (finalHits.isEmpty()) {
everyPartMatched = false;
} else {
combinedArts.addAll(finalHits);
}
}
}
// If we're in the ALL case, make sure every piece matched
if ((obj.getAddressValue().getApplyCondition() != null)
&& (obj.getAddressValue().getApplyCondition() == ConditionApplicationEnum.ALL)
&& (!everyPartMatched)) {
return new ObservableResult(id, "AddressObject: No matches for " + searchString, //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
}
if (!combinedArts.isEmpty()) {
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
for (BlackboardArtifact a : combinedArts) {
artData.add(new StixArtifactData(a.getObjectID(), id, "AddressObject")); //NON-NLS
}
return new ObservableResult(id, "AddressObject: Found a match for " + searchString, //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
}
return new ObservableResult(id, "AddressObject: Found no matches for " + searchString, //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
} catch (TskCoreException ex) {
return new ObservableResult(id, "AddressObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
}
/**
* Set up the warning for any fields in the object that aren't supported.
*/
private void setUnsupportedFieldWarnings() {
List<String> fieldNames = new ArrayList<String>();
if (obj.getVLANName() != null) {
fieldNames.add("VLAN_Name"); //NON-NLS
}
if (obj.getVLANName() != null) {
fieldNames.add("VLAN_Num"); //NON-NLS
}
String warningStr = "";
for (String name : fieldNames) {
if (!warningStr.isEmpty()) {
warningStr += ", ";
}
warningStr += name;
}
addWarning("Unsupported field(s): " + warningStr); //NON-NLS
}
}

View File

@ -1,123 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import java.util.ArrayList;
import java.util.List;
import org.mitre.cybox.common_2.ConditionApplicationEnum;
import org.mitre.cybox.common_2.ConditionTypeEnum;
import org.mitre.cybox.objects.DomainName;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.datamodel.SleuthkitCase;
/**
*
*/
class EvalDomainObj extends EvaluatableObject {
private final DomainName obj;
public EvalDomainObj(DomainName a_obj, String a_id, String a_spacing) {
obj = a_obj;
id = a_id;
spacing = a_spacing;
}
@Override
public synchronized ObservableResult evaluate() {
setWarnings("");
if (obj.getValue() == null) {
return new ObservableResult(id, "DomainObject: No domain value field found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
Case case1;
try {
case1 = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
return new ObservableResult(id, "Exception while getting open case.", //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
}
// Since we have single URL artifacts, ALL and NONE conditions probably don't make sense to test
if (!((obj.getValue().getApplyCondition() == null)
|| (obj.getValue().getApplyCondition() == ConditionApplicationEnum.ANY))) {
return new ObservableResult(id, "DomainObject: Can not process apply condition " + obj.getValue().getApplyCondition().toString() //NON-NLS
+ " on Domain object", spacing, ObservableResult.ObservableState.INDETERMINATE, null); //NON-NLS
}
// If the condition is not "CONTAINS", add a warning that it's being ignored
if ((obj.getValue().getCondition() != null)
&& (obj.getValue().getCondition() != ConditionTypeEnum.CONTAINS)) {
addWarning("Warning: Ignoring condition " + obj.getValue().getCondition().toString() //NON-NLS
+ " on DomainName - using substring comparison"); //NON-NLS
}
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
try {
// Set up the list of matching artifacts
List<BlackboardArtifact> finalHits = new ArrayList<BlackboardArtifact>();
// Get all the URL artifacts
List<BlackboardArtifact> artList
= sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT);
for (BlackboardArtifact art : artList) {
for (BlackboardAttribute attr : art.getAttributes()) {
if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
String url = attr.getValueString();
// Check whether the domain name is a substring of the URL (regardless
// of the condition on the domain name object)
if (compareStringObject(obj.getValue().getValue().toString(), ConditionTypeEnum.CONTAINS,
obj.getValue().getApplyCondition(), url)) {
finalHits.add(art);
}
}
}
}
if (!finalHits.isEmpty()) {
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
for (BlackboardArtifact a : finalHits) {
artData.add(new StixArtifactData(a.getObjectID(), id, "DomainNameObject")); //NON-NLS
}
return new ObservableResult(id, "DomainNameObject: Found a match for " + obj.getValue().getValue().toString() //NON-NLS
+ " " + getPrintableWarnings(),
spacing, ObservableResult.ObservableState.TRUE, artData);
}
return new ObservableResult(id, "DomainNameObject: Found no matches for " + obj.getValue().getValue().toString() //NON-NLS
+ " " + getPrintableWarnings(),
spacing, ObservableResult.ObservableState.FALSE, null);
} catch (TskCoreException ex) {
return new ObservableResult(id, "DomainNameObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
}
}

View File

@ -1,274 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import java.util.List;
import java.util.ArrayList;
import org.mitre.cybox.objects.EmailMessage;
import org.mitre.cybox.objects.Address;
/**
*
*/
class EvalEmailObj extends EvaluatableObject {
private final EmailMessage obj;
private List<BlackboardArtifact> finalHits;
public EvalEmailObj(EmailMessage a_obj, String a_id, String a_spacing) {
obj = a_obj;
id = a_id;
spacing = a_spacing;
finalHits = null;
}
@Override
public synchronized ObservableResult evaluate() {
setWarnings("");
List<BlackboardArtifact> toHits = null;
boolean hadToFields = false;
List<BlackboardArtifact> ccHits = null;
boolean hadCcFields = false;
List<BlackboardArtifact> fromHits = null;
boolean hadFromField = false;
List<BlackboardArtifact> subjectHits = null;
boolean hadSubjectField = false;
if (obj.getHeader() != null) {
if ((obj.getHeader().getTo() != null)
&& (obj.getHeader().getTo().getRecipients() != null)
&& (!obj.getHeader().getTo().getRecipients().isEmpty())) {
for (Address addr : obj.getHeader().getTo().getRecipients()) {
if (addr.getAddressValue() != null) {
hadToFields = true;
try {
toHits = findArtifactsBySubstring(addr.getAddressValue(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO);
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
}
}
}
if ((obj.getHeader().getCC() != null)
&& (obj.getHeader().getCC().getRecipients() != null)
&& (!obj.getHeader().getCC().getRecipients().isEmpty())) {
for (Address addr : obj.getHeader().getCC().getRecipients()) {
if (addr.getAddressValue() != null) {
hadCcFields = true;
try {
ccHits = findArtifactsBySubstring(addr.getAddressValue(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CC);
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
}
}
}
if ((obj.getHeader().getFrom() != null)
&& (obj.getHeader().getFrom().getAddressValue() != null)) {
hadFromField = true;
try {
fromHits = findArtifactsBySubstring(obj.getHeader().getFrom().getAddressValue(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM);
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
}
if ((obj.getHeader().getSubject() != null)
&& (obj.getHeader().getSubject().getValue() != null)) {
hadSubjectField = true;
try {
subjectHits = findArtifactsBySubstring(obj.getHeader().getSubject(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT);
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
}
}
// Make sure at least one test had some data
if ((!hadToFields) && (!hadFromField) && (!hadCcFields) && (!hadSubjectField)) {
return new ObservableResult(id, "EmailMessage: Could not find any parsable EmailMessage fields " //NON-NLS
+ getPrintableWarnings(),
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
// Check if there were more fields that aren't currently supported
String fieldNames = getListOfUnsupportedFields();
if (fieldNames.length() > 0) {
addWarning("Unsupported field(s) found: " + fieldNames); //NON-NLS
}
// Find the artifacts that matched all of the fields
finalHits = null;
boolean finalHitsStarted = false;
if (hadToFields) {
combineHits(toHits, finalHitsStarted);
finalHitsStarted = true;
}
if (hadCcFields) {
combineHits(ccHits, finalHitsStarted);
finalHitsStarted = true;
}
if (hadFromField) {
combineHits(fromHits, finalHitsStarted);
finalHitsStarted = true;
}
if (hadSubjectField) {
combineHits(subjectHits, finalHitsStarted);
finalHitsStarted = true;
}
if (!finalHitsStarted) {
// We didn't find any fields that could be evaluated
return new ObservableResult(id, "EmailMessage: EmailObj parsing incomplete " + getPrintableWarnings(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
// If there are any artifacts left in finalHits, we have a match
if (finalHits.size() > 0) {
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
for (BlackboardArtifact a : finalHits) {
artData.add(new StixArtifactData(a.getObjectID(), id, "EmailMessage")); //NON-NLS
}
return new ObservableResult(id, "EmailMessage: " + finalHits.size() + " matching artifacts found " + getPrintableWarnings(), //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
} else {
return new ObservableResult(id, "EmailMessage: No matching artifacts found " + getPrintableWarnings(), //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
}
}
/**
* Add a set of hits to the final set of hits. Removes any artifacts that
* aren't found in the new set. The final list is the artifacts found in all
* sets.
*
* @param newHits The new hits to add to the list
* @param finalHitsStarted Whether we've started the list or not
*/
private void combineHits(List<BlackboardArtifact> newHits, boolean finalHitsStarted) {
if (finalHitsStarted && (finalHits != null)) {
finalHits.retainAll(newHits);
} else {
finalHits = newHits;
}
}
/**
* Test to see if the Email Object has any fields set that we don't support
* right now.
*
* @return a list of unsupported fields found.
*/
private String getListOfUnsupportedFields() {
String fieldNames = "";
if (obj.getHeader() != null) {
if (obj.getHeader().getReceivedLines() != null) {
fieldNames += "Received_Lines "; //NON-NLS
}
if (obj.getHeader().getBCC() != null) {
fieldNames += "BCC "; //NON-NLS
}
if (obj.getHeader().getInReplyTo() != null) {
fieldNames += "In_Reply_To "; //NON-NLS
}
if (obj.getHeader().getDate() != null) {
fieldNames += "Date "; //NON-NLS
}
if (obj.getHeader().getMessageID() != null) {
fieldNames += "Message_ID "; //NON-NLS
}
if (obj.getHeader().getSender() != null) {
fieldNames += "Sender "; //NON-NLS
}
if (obj.getHeader().getReplyTo() != null) {
fieldNames += "Reply_To "; //NON-NLS
}
if (obj.getHeader().getErrorsTo() != null) {
fieldNames += "Errors_To "; //NON-NLS
}
if (obj.getHeader().getBoundary() != null) {
fieldNames += "Boundary "; //NON-NLS
}
if (obj.getHeader().getContentType() != null) {
fieldNames += "Content_Type "; //NON-NLS
}
if (obj.getHeader().getMIMEVersion() != null) {
fieldNames += "MIME_Version "; //NON-NLS
}
if (obj.getHeader().getPrecedence() != null) {
fieldNames += "Precedence "; //NON-NLS
}
if (obj.getHeader().getUserAgent() != null) {
fieldNames += "User_Agent "; //NON-NLS
}
if (obj.getHeader().getXMailer() != null) {
fieldNames += "X_Mailer "; //NON-NLS
}
if (obj.getHeader().getXOriginatingIP() != null) {
fieldNames += "X_Originiating_IP "; //NON-NLS
}
if (obj.getHeader().getXPriority() != null) {
fieldNames += "X_Priority "; //NON-NLS
}
}
if (obj.getEmailServer() != null) {
fieldNames += "Email_Server "; //NON-NLS
}
if (obj.getRawBody() != null) {
fieldNames += "Raw_Body "; //NON-NLS
}
if (obj.getRawHeader() != null) {
fieldNames += "Raw_Header "; //NON-NLS
}
if (obj.getAttachments() != null) {
fieldNames += "Attachments "; //NON-NLS
}
if (obj.getLinks() != null) {
fieldNames += "Links "; //NON-NLS
}
return fieldNames;
}
}

View File

@ -1,699 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import java.util.List;
import java.util.ArrayList;
import java.util.Date;
import java.util.TimeZone;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.mitre.cybox.common_2.ConditionApplicationEnum;
import org.mitre.cybox.objects.FileObjectType;
import org.mitre.cybox.objects.WindowsExecutableFileObjectType;
import org.mitre.cybox.common_2.ConditionTypeEnum;
import org.mitre.cybox.common_2.DatatypeEnum;
import org.mitre.cybox.common_2.HashType;
import org.mitre.cybox.common_2.DateTimeObjectPropertyType;
import org.mitre.cybox.common_2.StringObjectPropertyType;
import org.mitre.cybox.common_2.UnsignedLongObjectPropertyType;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
/**
*
*/
class EvalFileObj extends EvaluatableObject {
private final FileObjectType obj;
public EvalFileObj(FileObjectType a_obj, String a_id, String a_spacing) {
obj = a_obj;
id = a_id;
spacing = a_spacing;
}
@Override
@SuppressWarnings("deprecation")
public synchronized ObservableResult evaluate() {
Case case1;
try {
case1 = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
return new ObservableResult(id, "Exception while getting open case.", //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
}
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
setWarnings("");
String whereClause = "";
if (obj.getSizeInBytes() != null) {
try {
String newClause = processULongObject(obj.getSizeInBytes(), "size"); //NON-NLS
whereClause = addClause(whereClause, newClause);
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
}
if (obj.getFileName() != null) {
try {
String newClause = processStringObject(obj.getFileName(), "name"); //NON-NLS
whereClause = addClause(whereClause, newClause);
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
}
if (obj.getFileExtension() != null) {
if ((obj.getFileExtension().getCondition() == null)
|| (obj.getFileExtension().getCondition() == ConditionTypeEnum.EQUALS)) {
String newClause = "LOWER(name) LIKE LOWER(\'%" + obj.getFileExtension().getValue() + "\')"; //NON-NLS
whereClause = addClause(whereClause, newClause);
} else {
addWarning(
"Could not process condition " + obj.getFileExtension().getCondition().value() + " on file extension"); //NON-NLS
}
}
if (obj.getFilePath() != null) {
try {
String[] parts = obj.getFilePath().getValue().toString().split("##comma##"); //NON-NLS
String finalPathStr = "";
for (String filePath : parts) {
// First, we need to normalize the path
String currentFilePath = filePath;
// Remove the drive letter
if (currentFilePath.matches("^[A-Za-z]:.*")) {
currentFilePath = currentFilePath.substring(2);
}
// Change any backslashes to forward slashes
currentFilePath = currentFilePath.replace("\\", "/");
// The path needs to start with a slash
if (!currentFilePath.startsWith("/")) {
currentFilePath = "/" + currentFilePath;
}
// If the path does not end in a slash, the final part should be the file name.
if (!currentFilePath.endsWith("/")) {
int lastSlash = currentFilePath.lastIndexOf('/');
if (lastSlash >= 0) {
currentFilePath = currentFilePath.substring(0, lastSlash + 1);
}
}
// Reconstruct the path string (which may be multi-part)
if (!finalPathStr.isEmpty()) {
finalPathStr += "##comma##"; //NON-NLS
}
finalPathStr += currentFilePath;
}
String newClause = processStringObject(finalPathStr, obj.getFilePath().getCondition(),
obj.getFilePath().getApplyCondition(), "parent_path"); //NON-NLS
whereClause = addClause(whereClause, newClause);
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
}
if (obj.getCreatedTime() != null) {
try {
String newClause = processTimestampObject(obj.getCreatedTime(), "crtime"); //NON-NLS
whereClause = addClause(whereClause, newClause);
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
}
if (obj.getModifiedTime() != null) {
try {
String newClause = processTimestampObject(obj.getModifiedTime(), "mtime"); //NON-NLS
whereClause = addClause(whereClause, newClause);
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
}
if (obj.getAccessedTime() != null) {
try {
String newClause = processTimestampObject(obj.getAccessedTime(), "atime"); //NON-NLS
whereClause = addClause(whereClause, newClause);
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
}
if (obj.getHashes() != null) {
for (HashType h : obj.getHashes().getHashes()) {
if (h.getSimpleHashValue() != null) {
if (h.getType().getValue().equals("MD5")) { //NON-NLS
String newClause = "";
if (h.getSimpleHashValue().getValue().toString().toLowerCase().contains("##comma##")) { //NON-NLS
String[] parts = h.getSimpleHashValue().getValue().toString().toLowerCase().split("##comma##"); //NON-NLS
String hashList = "";
for (String s : parts) {
if (!hashList.isEmpty()) {
hashList += ", ";
}
hashList += "\'" + s + "\'";
}
newClause = "md5 IN (" + hashList + ")"; //NON-NLS
} else {
newClause = "md5=\'" + h.getSimpleHashValue().getValue().toString().toLowerCase() + "\'"; //NON-NLS
}
whereClause = addClause(whereClause, newClause);
} else {
addWarning("Could not process hash type " + h.getType().getValue().toString()); //NON-NLS
}
} else {
addWarning("Could not process non-simple hash value"); //NON-NLS
}
}
}
if (obj instanceof WindowsExecutableFileObjectType) {
WindowsExecutableFileObjectType winExe = (WindowsExecutableFileObjectType) obj;
if (winExe.getHeaders() != null) {
if (winExe.getHeaders().getFileHeader() != null) {
if (winExe.getHeaders().getFileHeader().getTimeDateStamp() != null) {
try {
String result = convertTimestampString(winExe.getHeaders().getFileHeader().getTimeDateStamp().getValue().toString());
String newClause = processNumericFields(result,
winExe.getHeaders().getFileHeader().getTimeDateStamp().getCondition(),
winExe.getHeaders().getFileHeader().getTimeDateStamp().getApplyCondition(),
"crtime"); //NON-NLS
whereClause = addClause(whereClause, newClause);
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
}
}
}
}
String unsupportedFields = listUnsupportedFields();
if (!unsupportedFields.isEmpty()) {
addWarning("Unsupported fields: " + unsupportedFields); //NON-NLS
}
if (whereClause.length() > 0) {
try {
List<AbstractFile> matchingFiles = sleuthkitCase.findAllFilesWhere(whereClause);
if (!matchingFiles.isEmpty()) {
if (listSecondaryFields().isEmpty()) {
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
for (AbstractFile a : matchingFiles) {
artData.add(new StixArtifactData(a, id, "FileObject")); //NON-NLS
}
return new ObservableResult(id, "FileObject: Found " + matchingFiles.size() + " matches for " + whereClause + getPrintableWarnings(), //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
} else {
// We need to tag the matching files in Autopsy, so keep track of them
List<AbstractFile> secondaryHits = new ArrayList<AbstractFile>();
for (AbstractFile file : matchingFiles) {
boolean passedTests = true;
if (obj.isIsMasqueraded() != null) {
List<BlackboardArtifact> arts = file.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED);
boolean isMasq = false;
if (!arts.isEmpty()) {
isMasq = true;
}
if (obj.isIsMasqueraded() != isMasq) {
passedTests = false;
}
}
if (obj.getFileFormat() != null) {
String formatsFound = file.getMIMEType();
if (formatsFound != null) {
if (!(formatsFound.equalsIgnoreCase(obj.getFileFormat().getValue().toString()))) {
addWarning("Warning: Did not match File_Format field " + obj.getFileFormat().getValue().toString() //NON-NLS
+ " against " + formatsFound); //NON-NLS
}
} else {
addWarning("Warning: Did not match File_Format field " + obj.getFileFormat().getValue().toString() //NON-NLS
+ " (no file formats found)"); //NON-NLS
}
// It looks like the STIX file formats can be different than what Autopsy stores
// (mime vs. unix file), so don't kill a file based on this field not matching.
//if (!foundMatch) {
// passedTests = false;
//}
}
if (passedTests) {
secondaryHits.add(file);
}
}
if (secondaryHits.isEmpty()) {
return new ObservableResult(id, "FileObject: Found " + matchingFiles.size() + " matches for " + whereClause //NON-NLS
+ " but none for secondary tests on " + listSecondaryFields() + getPrintableWarnings(), //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
} else {
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
for (AbstractFile a : secondaryHits) {
artData.add(new StixArtifactData(a, id, "FileObject")); //NON-NLS
}
return new ObservableResult(id, "FileObject: Found " + secondaryHits.size() + " matches for " + whereClause //NON-NLS
+ " and secondary tests on " + listSecondaryFields() + getPrintableWarnings(), //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
}
}
} else {
return new ObservableResult(id, "FileObject: Found no matches for " + whereClause + getPrintableWarnings(), //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
}
} catch (TskCoreException ex) {
return new ObservableResult(id, "FileObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
} else {
}
return new ObservableResult(id, "FileObject: No evaluatable fields " + getPrintableWarnings(), spacing, //NON-NLS
ObservableResult.ObservableState.INDETERMINATE, null);
}
/**
* Create a list of secondary fields. These are the ones that we only test
* on the matches for the primary fields.
*
* @return List of secondary fields
*/
private String listSecondaryFields() {
String secondaryFields = "";
if (obj.isIsMasqueraded() != null) {
secondaryFields += "is_masqueraded "; //NON-NLS
}
if (obj.getFileFormat() != null) {
secondaryFields += "File_Format "; //NON-NLS
}
return secondaryFields;
}
/**
* List unsupported fields found in the object.
*
* @return List of unsupported fields
*/
private String listUnsupportedFields() {
String unsupportedFields = "";
if (obj.isIsPacked() != null) {
unsupportedFields += "is_packed "; //NON-NLS
}
if (obj.getDevicePath() != null) {
unsupportedFields += "Device_Path "; //NON-NLS
}
if (obj.getFullPath() != null) {
unsupportedFields += "Full_Path "; //NON-NLS
}
if (obj.getMagicNumber() != null) {
unsupportedFields += "Magic_Number "; //NON-NLS
}
if (obj.getDigitalSignatures() != null) {
unsupportedFields += "Digital_Signatures "; //NON-NLS
}
if (obj.getFileAttributesList() != null) {
unsupportedFields += "File_Attributes_List "; //NON-NLS
}
if (obj.getPermissions() != null) {
unsupportedFields += "Permissions "; //NON-NLS
}
if (obj.getUserOwner() != null) {
unsupportedFields += "User_Owner "; //NON-NLS
}
if (obj.getPackerList() != null) {
unsupportedFields += "Packer_List "; //NON-NLS
}
if (obj.getPeakEntropy() != null) {
unsupportedFields += "Peak_Entropy "; //NON-NLS
}
if (obj.getSymLinks() != null) {
unsupportedFields += "Sym_Links "; //NON-NLS
}
if (obj.getByteRuns() != null) {
unsupportedFields += "Bytes_Runs "; //NON-NLS
}
if (obj.getExtractedFeatures() != null) {
unsupportedFields += "Extracted_Features "; //NON-NLS
}
if (obj.getEncryptionAlgorithm() != null) {
unsupportedFields += "Encryption_Algorithm "; //NON-NLS
}
if (obj.getDecryptionKey() != null) {
unsupportedFields += "Decryption_Key "; //NON-NLS
}
if (obj.getCompressionMethod() != null) {
unsupportedFields += "Compression_Method "; //NON-NLS
}
if (obj.getCompressionVersion() != null) {
unsupportedFields += "Compression_Version "; //NON-NLS
}
if (obj.getCompressionComment() != null) {
unsupportedFields += "Compression_Comment "; //NON-NLS
}
return unsupportedFields;
}
/**
* Convert timestamp string into a long.
*
* @param timeStr
*
* @return
*
* @throws ParseException
*/
private static long convertTimestamp(String timeStr) throws ParseException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); //NON-NLS
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); //NON-NLS
Date parsedDate = dateFormat.parse(timeStr);
Long unixTime = parsedDate.getTime() / 1000;
return unixTime;
}
/**
* Return the SQL clause for an unsigned long object. Splits into fields and
* call the more generic version of the function.
*
* @param longObj The Cybox UnsignedLong object
* @param fieldName Name of the field to test against
*
* @return SQL clause
*
* @throws TskCoreException
*/
private static String processULongObject(UnsignedLongObjectPropertyType longObj, String fieldName)
throws TskCoreException {
return processNumericFields(longObj.getValue().toString(), longObj.getCondition(),
longObj.getApplyCondition(), fieldName);
}
/**
* Return the SQL clause for a numeric object.
*
* @param valueStr Value (as string)
* @param typeCondition Cybox condition
* @param applyCondition Cybox apply_condition
* @param fieldName Name of the field to test against
*
* @return SQL clause
*
* @throws TskCoreException
*/
private static String processNumericFields(String valueStr, ConditionTypeEnum typeCondition,
ConditionApplicationEnum applyCondition, String fieldName)
throws TskCoreException {
if ((typeCondition == null)
|| ((typeCondition != ConditionTypeEnum.INCLUSIVE_BETWEEN)
&& (typeCondition != ConditionTypeEnum.EXCLUSIVE_BETWEEN))) {
String fullClause = "";
if (valueStr.isEmpty()) {
throw new TskCoreException("Empty value field"); //NON-NLS
}
String[] parts = valueStr.split("##comma##"); //NON-NLS
for (String valuePart : parts) {
String partialClause;
if ((typeCondition == null)
|| (typeCondition == ConditionTypeEnum.EQUALS)) {
partialClause = fieldName + "=" + valuePart;
} else if (typeCondition == ConditionTypeEnum.DOES_NOT_EQUAL) {
partialClause = fieldName + "!=" + valuePart;
} else if (typeCondition == ConditionTypeEnum.GREATER_THAN) {
partialClause = fieldName + ">" + valuePart;
} else if (typeCondition == ConditionTypeEnum.GREATER_THAN_OR_EQUAL) {
partialClause = fieldName + ">=" + valuePart;
} else if (typeCondition == ConditionTypeEnum.LESS_THAN) {
partialClause = fieldName + "<" + valuePart;
} else if (typeCondition == ConditionTypeEnum.LESS_THAN_OR_EQUAL) {
partialClause = fieldName + "<=" + valuePart;
} else {
throw new TskCoreException("Could not process condition " + typeCondition.value() + " on " + fieldName); //NON-NLS
}
if (fullClause.isEmpty()) {
if (parts.length > 1) {
fullClause += "( ";
}
if (applyCondition == ConditionApplicationEnum.NONE) {
fullClause += " NOT "; //NON-NLS
}
fullClause += partialClause;
} else {
if (applyCondition == ConditionApplicationEnum.ALL) {
fullClause += " AND " + partialClause; //NON-NLS
} else if (applyCondition == ConditionApplicationEnum.NONE) {
fullClause += " AND NOT " + partialClause; //NON-NLS
} else {
fullClause += " OR " + partialClause; //NON-NLS
}
}
}
if (parts.length > 1) {
fullClause += " )";
}
return fullClause;
} else {
// I don't think apply conditions make sense for these two.
if (typeCondition == ConditionTypeEnum.INCLUSIVE_BETWEEN) {
String[] parts = valueStr.split("##comma##"); //NON-NLS
if (parts.length != 2) {
throw new TskCoreException("Unexpected number of arguments in INCLUSIVE_BETWEEN on " + fieldName //NON-NLS
+ "(" + valueStr + ")");
}
return (fieldName + ">=" + parts[0] + " AND " + fieldName + "<=" + parts[1]); //NON-NLS
} else {
String[] parts = valueStr.split("##comma##"); //NON-NLS
if (parts.length != 2) {
throw new TskCoreException("Unexpected number of arguments in EXCLUSIVE_BETWEEN on " + fieldName //NON-NLS
+ "(" + valueStr + ")");
}
return (fieldName + ">" + parts[0] + " AND " + fieldName + "<" + parts[1]); //NON-NLS
}
}
}
/**
* Return the SQL clause for a String object
*
* @param stringObj The full Cybox String object
* @param fieldName Name of the field we're testing against
*
* @return SQL clause
*
* @throws TskCoreException
*/
private static String processStringObject(StringObjectPropertyType stringObj, String fieldName)
throws TskCoreException {
return processStringObject(stringObj.getValue().toString(), stringObj.getCondition(),
stringObj.getApplyCondition(), fieldName);
}
/**
* Return the SQL clause for a String object
*
* @param valueStr Value as a string
* @param condition Cybox condition
* @param applyCondition Cybox apply_condition
* @param fieldName Name of the field we're testing against
*
* @return SQL clause
*
* @throws TskCoreException
*/
public static String processStringObject(String valueStr, ConditionTypeEnum condition,
ConditionApplicationEnum applyCondition, String fieldName)
throws TskCoreException {
String fullClause = "";
String lowerFieldName = "lower(" + fieldName + ")"; //NON-NLS
if (valueStr.isEmpty()) {
throw new TskCoreException("Empty value field"); //NON-NLS
}
String[] parts = valueStr.split("##comma##"); //NON-NLS
for (String value : parts) {
String lowerValue = value.toLowerCase();
String partialClause;
if ((condition == null)
|| (condition == ConditionTypeEnum.EQUALS)) {
partialClause = lowerFieldName + "=\'" + lowerValue + "\'";
} else if (condition == ConditionTypeEnum.DOES_NOT_EQUAL) {
partialClause = lowerFieldName + " !=\'%" + lowerValue + "%\'";
} else if (condition == ConditionTypeEnum.CONTAINS) {
partialClause = lowerFieldName + " LIKE \'%" + lowerValue + "%\'"; //NON-NLS
} else if (condition == ConditionTypeEnum.DOES_NOT_CONTAIN) {
partialClause = lowerFieldName + " NOT LIKE \'%" + lowerValue + "%\'"; //NON-NLS
} else if (condition == ConditionTypeEnum.STARTS_WITH) {
partialClause = lowerFieldName + " LIKE \'" + lowerValue + "%\'"; //NON-NLS
} else if (condition == ConditionTypeEnum.ENDS_WITH) {
partialClause = lowerFieldName + " LIKE \'%" + lowerValue + "\'"; //NON-NLS
} else {
throw new TskCoreException("Could not process condition " + condition.value() + " on " + fieldName); //NON-NLS
}
if (fullClause.isEmpty()) {
if (parts.length > 1) {
fullClause += "( ";
}
if (applyCondition == ConditionApplicationEnum.NONE) {
fullClause += " NOT "; //NON-NLS
}
fullClause += partialClause;
} else {
if (applyCondition == ConditionApplicationEnum.ALL) {
fullClause += " AND " + partialClause; //NON-NLS
} else if (applyCondition == ConditionApplicationEnum.NONE) {
fullClause += " AND NOT " + partialClause; //NON-NLS
} else {
fullClause += " OR " + partialClause; //NON-NLS
}
}
}
if (parts.length > 1) {
fullClause += " )";
}
return fullClause;
}
/**
* Create the SQL clause for a timestamp object. Converts the time into a
* numeric field and then creates the clause from that.
*
* @param dateObj Cybox DateTimeObject
* @param fieldName Name of the field we're testing against
*
* @return SQL clause
*
* @throws TskCoreException
*/
private static String processTimestampObject(DateTimeObjectPropertyType dateObj, String fieldName)
throws TskCoreException {
if (DatatypeEnum.DATE_TIME == dateObj.getDatatype()) {
// Change the string into unix timestamps
String result = convertTimestampString(dateObj.getValue().toString());
return processNumericFields(result, dateObj.getCondition(), dateObj.getApplyCondition(), fieldName);
} else {
throw new TskCoreException("Found non DATE_TIME field on " + fieldName); //NON-NLS
}
}
/**
* Convert a timestamp string into a numeric one. Leave it as a string since
* that's what we get from other object types.
*
* @param timestampStr
*
* @return String version with timestamps replaced by numeric values
*
* @throws TskCoreException
*/
private static String convertTimestampString(String timestampStr)
throws TskCoreException {
try {
String result = "";
if (timestampStr.length() > 0) {
String[] parts = timestampStr.split("##comma##"); //NON-NLS
for (int i = 0; i < parts.length - 1; i++) {
long unixTime = convertTimestamp(parts[i]);
result += unixTime + "##comma##"; //NON-NLS
}
result += convertTimestamp(parts[parts.length - 1]);
}
return result;
} catch (java.text.ParseException ex) {
throw new TskCoreException("Error parsing timestamp string " + timestampStr); //NON-NLS
}
}
/**
* Add a new clause to the existing clause
*
* @param a_clause Current clause
* @param a_newClause New clause
*
* @return Full clause
*/
private static String addClause(String a_clause, String a_newClause) {
if ((a_clause == null) || a_clause.isEmpty()) {
return a_newClause;
}
return (a_clause + " AND " + a_newClause); //NON-NLS
}
}

View File

@ -1,162 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import java.util.ArrayList;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import java.util.List;
import org.mitre.cybox.common_2.ConditionApplicationEnum;
import org.mitre.cybox.objects.WindowsNetworkShare;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
/**
*
*/
class EvalNetworkShareObj extends EvaluatableObject {
private final WindowsNetworkShare obj;
public EvalNetworkShareObj(WindowsNetworkShare a_obj, String a_id, String a_spacing) {
obj = a_obj;
id = a_id;
spacing = a_spacing;
}
@Override
public synchronized ObservableResult evaluate() {
setWarnings("");
if ((obj.getNetname() == null) && (obj.getLocalPath() == null)) {
return new ObservableResult(id, "NetworkShareObjet: No remote name or local path found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
// For displaying what we were looking for in the results
String searchString = "";
if (obj.getNetname() != null) {
searchString += "Netname \"" + obj.getNetname().getValue() + "\""; //NON-NLS
// The apply conditions ALL or NONE probably won't work correctly. Neither seems
// all that likely to come up in practice, so just give a warning.
if ((obj.getNetname().getApplyCondition() != null)
&& (obj.getNetname().getApplyCondition() != ConditionApplicationEnum.ANY)) {
addWarning("Apply condition " + obj.getNetname().getApplyCondition().value() //NON-NLS
+ " may not work correctly"); //NON-NLS
}
}
if (obj.getLocalPath() != null) {
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "LocalPath \"" + obj.getLocalPath().getValue() + "\""; //NON-NLS
// Same as above - the apply conditions ALL or NONE probably won't work correctly. Neither seems
// all that likely to come up in practice, so just give a warning.
if ((obj.getLocalPath().getApplyCondition() != null)
&& (obj.getLocalPath().getApplyCondition() != ConditionApplicationEnum.ANY)) {
addWarning("Apply condition " + obj.getLocalPath().getApplyCondition().value() //NON-NLS
+ " may not work correctly"); //NON-NLS
}
}
setUnsupportedFieldWarnings();
// The assumption here is that there aren't going to be too many network shares, so we
// can cycle through all of them.
try {
List<BlackboardArtifact> finalHits = new ArrayList<BlackboardArtifact>();
Case case1 = Case.getCurrentCaseThrows();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
List<BlackboardArtifact> artList
= sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_REMOTE_DRIVE);
for (BlackboardArtifact art : artList) {
boolean foundRemotePathMatch = false;
boolean foundLocalPathMatch = false;
for (BlackboardAttribute attr : art.getAttributes()) {
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REMOTE_PATH.getTypeID())
&& (obj.getNetname() != null)) {
foundRemotePathMatch = compareStringObject(obj.getNetname(), attr.getValueString());
}
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCAL_PATH.getTypeID())
&& (obj.getLocalPath() != null)) {
foundLocalPathMatch = compareStringObject(obj.getLocalPath(), attr.getValueString());
}
}
// Check whether we found everything we were looking for
if (((foundRemotePathMatch) || (obj.getNetname() == null))
&& ((foundLocalPathMatch) || (obj.getLocalPath() == null))) {
finalHits.add(art);
}
}
// Check if we found any matches
if (!finalHits.isEmpty()) {
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
for (BlackboardArtifact a : finalHits) {
artData.add(new StixArtifactData(a.getObjectID(), id, "NetworkShare")); //NON-NLS
}
return new ObservableResult(id, "NetworkShareObject: Found a match for " + searchString, //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
}
// Didn't find any matches
return new ObservableResult(id, "NetworkObject: No matches found for " + searchString, //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
} catch (TskCoreException | NoCurrentCaseException ex) {
return new ObservableResult(id, "NetworkObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
}
private void setUnsupportedFieldWarnings() {
List<String> fieldNames = new ArrayList<String>();
if (obj.getCurrentUses() != null) {
fieldNames.add("Current_Uses"); //NON-NLS
}
if (obj.getMaxUses() != null) {
fieldNames.add("Max_Uses"); //NON-NLS
}
if (obj.getType() != null) {
fieldNames.add("Type"); //NON-NLS
}
String warningStr = "";
for (String name : fieldNames) {
if (!warningStr.isEmpty()) {
warningStr += ", ";
}
warningStr += name;
}
addWarning("Unsupported field(s): " + warningStr); //NON-NLS
}
}

View File

@ -1,485 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import com.williballenthin.rejistry.RegistryHiveFile;
import com.williballenthin.rejistry.RegistryKey;
import com.williballenthin.rejistry.RegistryParseException;
import com.williballenthin.rejistry.RegistryValue;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.AbstractFile;
import java.util.List;
import java.util.ArrayList;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.File;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import org.mitre.cybox.objects.WindowsRegistryKey;
import org.mitre.cybox.common_2.ConditionTypeEnum;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
/**
*
*/
class EvalRegistryObj extends EvaluatableObject {
private final WindowsRegistryKey obj;
private final List<RegistryFileInfo> regFiles = new ArrayList<>();
EvalRegistryObj(WindowsRegistryKey a_obj, String a_id, String a_spacing, List<RegistryFileInfo> a_regFiles) {
obj = a_obj;
id = a_id;
spacing = a_spacing;
regFiles.addAll(a_regFiles);
}
private EvalRegistryObj() {
obj = null;
id = null;
spacing = "";
}
@Override
public synchronized ObservableResult evaluate() {
setWarnings("");
// Key name is required
if (obj.getKey() == null) {
return new ObservableResult(id, "RegistryObject: No key found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
// For now, only support a full string match
if (!((obj.getKey().getCondition() == null)
|| (obj.getKey().getCondition() == ConditionTypeEnum.EQUALS))) {
return new ObservableResult(id, "RegistryObject: Can not support condition " + obj.getKey().getCondition() //NON-NLS
+ " on Key field", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
setUnsupportedFieldWarnings();
// Make a list of hives to test
List<RegistryFileInfo> hiveList = new ArrayList<>();
if (obj.getHive() == null) {
// If the hive field is missing, add everything
hiveList.addAll(regFiles);
} else if (obj.getHive().getValue().toString().startsWith("HKEY")) { //NON-NLS
// If the hive name is HKEY_LOCAL_MACHINE, add the ones from the config directory.
// Otherwise, add the others
for (RegistryFileInfo regFile : regFiles) {
if (regFile.getAbstractFile().getParentPath() != null) {
Pattern pattern = Pattern.compile("system32", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(regFile.getAbstractFile().getParentPath());
if (matcher.find()) {
// Looking for system files and found one, so add it to the list
if (obj.getHive().getValue().toString().equalsIgnoreCase("HKEY_LOCAL_MACHINE")) { //NON-NLS
hiveList.add(regFile);
}
} else {
// Looking for non-system files and found one, so add it to the list
if (!obj.getHive().getValue().toString().equalsIgnoreCase("HKEY_LOCAL_MACHINE")) { //NON-NLS
hiveList.add(regFile);
}
}
}
}
} else {
// Otherwise, try to match the name
String stixHiveName = obj.getHive().getValue().toString();
// The temp files will end \Temp\STIX\(hive)_(number)
Pattern pattern = Pattern.compile("Temp.STIX." + stixHiveName, Pattern.CASE_INSENSITIVE);
for (RegistryFileInfo hive : regFiles) {
Matcher matcher = pattern.matcher(hive.getTempFileName());
if (matcher.find()) {
hiveList.add(hive);
}
}
// If nothing matched, add all the files
if (hiveList.isEmpty()) {
hiveList.addAll(regFiles);
}
}
// This is unlikely to happen unless we have no registry files to test against
if (hiveList.isEmpty()) {
return new ObservableResult(id, "RegistryObject: No matching registry hives found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
for (RegistryFileInfo hive : hiveList) {
try {
ObservableResult result = testRegistryFile(hive);
if (result.isTrue()) {
return result;
}
} catch (Exception ex) {
// The registry parser seems to throw lots of different types of exceptions,
// so make sure to catch them all by this point. Malformed registry files
// in particular cause problems.
addWarning("Error processing registry file " + hive); //NON-NLS
}
}
if (obj.getHive() == null) {
return new ObservableResult(id, "RegistryObject: Could not find key " + obj.getKey().getValue(), //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
}
return new ObservableResult(id, "RegistryObject: Could not find key " + obj.getKey().getValue() //NON-NLS
+ " in hive " + obj.getHive().getValue(), //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
}
/**
* Test the Registry object against one registry file.
*
* @param a_regInfo The registry file
*
* @return Result of the test
*/
private ObservableResult testRegistryFile(RegistryFileInfo a_regInfo) {
try {
RegistryKey root = openRegistry(a_regInfo.getTempFileName());
RegistryKey result = findKey(root, obj.getKey().getValue().toString());
if (result == null) {
// Take another shot looking for the key minus the first part of the path (sometimes the
// hive file name is here). This should only happen if the hive name started
// with "HKEY"
if ((obj.getHive() != null)
&& obj.getHive().getValue().toString().startsWith("HKEY")) { //NON-NLS
String[] parts = obj.getKey().getValue().toString().split("\\\\");
String newKey = "";
for (int i = 1; i < parts.length; i++) {
if (newKey.length() > 0) {
newKey += "\\";
}
newKey += parts[i];
}
result = findKey(root, newKey);
}
if (result == null) {
return new ObservableResult(id, "RegistryObject: Could not find key " + obj.getKey().getValue(), //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
}
}
if ((obj.getValues() == null) || (obj.getValues().getValues().isEmpty())) {
// No values to test
List<StixArtifactData> artData = new ArrayList<>();
artData.add(new StixArtifactData(a_regInfo.getAbstractFile().getId(), id, "Registry")); //NON-NLS
return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue(), //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
}
// Test all the values
for (org.mitre.cybox.objects.RegistryValueType stixRegValue : obj.getValues().getValues()) {
try {
for (RegistryValue valFromFile : result.getValueList()) {
// Test if the name field matches (if present)
boolean nameSuccess = true; // True if the name matches or isn't present
if (stixRegValue.getName() != null) {
try {
nameSuccess = compareStringObject(stixRegValue.getName(), valFromFile.getName());
} catch (UnsupportedEncodingException ex) {
nameSuccess = false;
}
}
boolean valueSuccess = true;
if (nameSuccess && (stixRegValue.getData() != null)) {
switch (valFromFile.getValueType()) {
case REG_SZ:
case REG_EXPAND_SZ:
try {
valueSuccess = compareStringObject(stixRegValue.getData(),
valFromFile.getValue().getAsString());
} catch (UnsupportedEncodingException ex) {
valueSuccess = false;
}
break;
case REG_DWORD:
case REG_BIG_ENDIAN:
case REG_QWORD:
// Only support "equals" for now.
if ((stixRegValue.getData().getCondition() == null)
|| (stixRegValue.getData().getCondition() == ConditionTypeEnum.EQUALS)) {
// Try to convert the STIX string to a long
try {
long stixValue = Long.decode(stixRegValue.getData().getValue().toString());
try {
valueSuccess = (stixValue == valFromFile.getValue().getAsNumber());
} catch (UnsupportedEncodingException ex) {
valueSuccess = false;
}
} catch (NumberFormatException ex) {
// We probably weren't looking at a numeric field to begin with,
// so getting this exception isn't really an error.
valueSuccess = false;
}
} else {
valueSuccess = false;
}
break;
default:
// Nothing to do here. These are the types we don't handle:
// REG_BIN, REG_FULL_RESOURCE_DESCRIPTOR, REG_LINK, REG_MULTI_SZ, REG_NONE,
// REG_RESOURCE_LIST, REG_RESOURCE_REQUIREMENTS_LIST
}
}
if (nameSuccess && valueSuccess) {
// Found a match for all values
List<StixArtifactData> artData = new ArrayList<>();
artData.add(new StixArtifactData(a_regInfo.getAbstractFile().getId(), id, "Registry")); //NON-NLS
return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue() //NON-NLS
+ " and value " + stixRegValue.getName().getValue().toString() //NON-NLS
+ " = " + stixRegValue.getData().getValue().toString(),
spacing, ObservableResult.ObservableState.TRUE, artData);
}
}
} catch (Exception ex) {
// Broad catch here becase the registry parser can create all kinds of exceptions beyond what it reports.
return new ObservableResult(id, "RegistryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
}
} catch (TskCoreException ex) {
return new ObservableResult(id, "RegistryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
return new ObservableResult(id, "RegistryObject: Not done", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
public RegistryKey openRegistry(String hive) throws TskCoreException {
try {
RegistryHiveFile regFile = new RegistryHiveFile(new File(hive));
RegistryKey root = regFile.getRoot();
return root;
} catch (IOException ex) {
throw new TskCoreException("Error opening registry file - " + ex.getLocalizedMessage()); //NON-NLS
} catch (RegistryParseException ex) {
throw new TskCoreException("Error opening root node of registry - " + ex.getLocalizedMessage()); //NON-NLS
}
}
/**
* Go down the registry tree to find a key with the given name.
*
* @param root Root of the registry hive
* @param name Name of the subkey to seach for
*
* @return The matching subkey or null if not found
*/
public RegistryKey findKey(RegistryKey root, String name) {
RegistryKey currentKey = root;
// Split the key name into parts
String[] parts = name.split("\\\\");
for (String part : parts) {
if (part.length() > 0) {
try {
currentKey = currentKey.getSubkey(part);
} catch (Exception ex) {
// We get an exception if the value wasn't found (not a RegistryParseException).
// There doesn't seem to be a cleaner way to test for existance without cycling though
// everything ourselves. (Broad catch because things other than RegistryParseException
// can happen)
return null;
}
}
}
// If we make it this far, we've found it
return currentKey;
}
/**
* Copy all registry hives to the temp directory and return the list of
* created files.
*
* @return Paths to copied registry files.
*/
public static List<RegistryFileInfo> copyRegistryFiles() throws TskCoreException {
// First get all the abstract files
List<AbstractFile> regFilesAbstract = findRegistryFiles();
// List to hold all the extracted file names plus their abstract file
List<RegistryFileInfo> regFilesLocal = new ArrayList<>();
// Make the temp directory
String tmpDir;
try {
tmpDir = Case.getCurrentCaseThrows().getTempDirectory() + File.separator + "STIX"; //NON-NLS
} catch (NoCurrentCaseException ex) {
throw new TskCoreException(ex.getLocalizedMessage());
}
File dir = new File(tmpDir);
if (dir.exists() == false) {
dir.mkdirs();
}
long index = 1;
for (AbstractFile regFile : regFilesAbstract) {
String regFileName = regFile.getName();
String regFileNameLocal = tmpDir + File.separator + regFileName + "_" + index;
File regFileNameLocalFile = new File(regFileNameLocal);
try {
// Don't save any unallocated versions
if (regFile.getMetaFlagsAsString().contains("Allocated")) { //NON-NLS
ContentUtils.writeToFile(regFile, regFileNameLocalFile);
regFilesLocal.add(new EvalRegistryObj().new RegistryFileInfo(regFile, regFileNameLocal));
}
} catch (IOException ex) {
throw new TskCoreException(ex.getLocalizedMessage());
}
index++;
}
return regFilesLocal;
}
/**
* Search for the registry hives on the system. Mostly copied from
* RecentActivity
*/
private static List<AbstractFile> findRegistryFiles() throws TskCoreException {
List<AbstractFile> registryFiles = new ArrayList<>();
Case openCase;
try {
openCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
throw new TskCoreException(ex.getLocalizedMessage());
}
org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = openCase.getServices().getFileManager();
for (Content ds : openCase.getDataSources()) {
// find the user-specific ntuser-dat files
registryFiles.addAll(fileManager.findFiles(ds, "ntuser.dat")); //NON-NLS
// find the system hives
String[] regFileNames = new String[]{"system", "software", "security", "sam"}; //NON-NLS
for (String regFileName : regFileNames) {
List<AbstractFile> allRegistryFiles = fileManager.findFiles(ds, regFileName, "/system32/config"); //NON-NLS
for (AbstractFile regFile : allRegistryFiles) {
// Don't want anything from regback
if (!regFile.getParentPath().contains("RegBack")) { //NON-NLS
registryFiles.add(regFile);
}
}
}
}
return registryFiles;
}
private void setUnsupportedFieldWarnings() {
List<String> fieldNames = new ArrayList<>();
if (obj.getNumberValues() != null) {
fieldNames.add("Number_Values"); //NON-NLS
}
if (obj.getModifiedTime() != null) {
fieldNames.add("Modified_Time"); //NON-NLS
}
if (obj.getCreatorUsername() != null) {
fieldNames.add("Creator_Username"); //NON-NLS
}
if (obj.getHandleList() != null) {
fieldNames.add("Handle_List"); //NON-NLS
}
if (obj.getNumberSubkeys() != null) {
fieldNames.add("Number_Subkeys"); //NON-NLS
}
if (obj.getSubkeys() != null) {
fieldNames.add("Subkeys"); //NON-NLS
}
if (obj.getByteRuns() != null) {
fieldNames.add("Byte_Runs"); //NON-NLS
}
String warningStr = "";
for (String name : fieldNames) {
if (!warningStr.isEmpty()) {
warningStr += ", ";
}
warningStr += name;
}
addWarning("Unsupported field(s): " + warningStr); //NON-NLS
}
/**
* Class to keep track of the abstract file and temp file that goes with
* each registry hive.
*/
public class RegistryFileInfo {
private final AbstractFile abstractFile;
private final String tempFileName;
public RegistryFileInfo(AbstractFile a_abstractFile, String a_tempFileName) {
abstractFile = a_abstractFile;
tempFileName = a_tempFileName;
}
/**
* Get the AbstractFile for this RegistryFileInfo
*
* @return the abstractFile
*/
AbstractFile getAbstractFile() {
return abstractFile;
}
/**
* Get the Temporary file name for this RegistryFileInfo
*
* @return the tempFileName
*/
String getTempFileName() {
return tempFileName;
}
}
}

View File

@ -1,303 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.OSInfo;
import org.sleuthkit.datamodel.OSUtility;
import java.util.List;
import java.util.ArrayList;
import org.mitre.cybox.objects.SystemObjectType;
import org.mitre.cybox.objects.WindowsSystem;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
/**
*
*/
class EvalSystemObj extends EvaluatableObject {
private final SystemObjectType obj;
public EvalSystemObj(SystemObjectType a_obj, String a_id, String a_spacing) {
obj = a_obj;
id = a_id;
spacing = a_spacing;
}
@Override
public synchronized ObservableResult evaluate() {
setWarnings("");
// For displaying what we were looking for in the results
String searchString = "";
// Check which fields are present and record them
boolean haveHostname = false;
// boolean haveDomain = false;
boolean haveProcArch = false;
boolean haveTempDir = false;
boolean haveProductName = false;
boolean haveSystemRoot = false;
boolean haveProductID = false;
boolean haveOwner = false;
boolean haveOrganization = false;
if (obj.getHostname() != null) {
haveHostname = true;
searchString = "Hostname \"" + obj.getHostname().getValue().toString() + "\""; //NON-NLS
}
if (obj.getProcessorArchitecture() != null) {
haveProcArch = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "Processor architecture \"" + obj.getProcessorArchitecture().getValue().toString() + "\""; //NON-NLS
}
WindowsSystem winSysObj = null;
if (obj instanceof WindowsSystem) {
winSysObj = (WindowsSystem) obj;
if (winSysObj.getProductID() != null) {
haveProductID = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "Product ID \"" + winSysObj.getProductID().getValue().toString() + "\""; //NON-NLS
}
if (winSysObj.getProductName() != null) {
haveProductName = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "Product Name \"" + winSysObj.getProductName().getValue().toString() + "\""; //NON-NLS
}
if (winSysObj.getRegisteredOrganization() != null) {
haveOrganization = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "Registered Org \"" + winSysObj.getRegisteredOrganization().getValue().toString() + "\""; //NON-NLS
}
if (winSysObj.getRegisteredOwner() != null) {
haveOwner = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "Registered Owner \"" + winSysObj.getRegisteredOwner().getValue().toString() + "\""; //NON-NLS
}
if (winSysObj.getWindowsSystemDirectory() != null) {
haveSystemRoot = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "System root \"" + winSysObj.getWindowsSystemDirectory().getValue().toString() + "\""; //NON-NLS
}
if (winSysObj.getWindowsTempDirectory() != null) {
haveTempDir = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "Temp dir \"" + winSysObj.getWindowsTempDirectory().getValue().toString() + "\""; //NON-NLS
}
}
// Return if we have nothing to search for
if (!(haveHostname || haveProcArch
|| haveTempDir || haveProductName || haveSystemRoot || haveProductID
|| haveOwner || haveOrganization)) {
return new ObservableResult(id, "SystemObject: No evaluatable fields found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
setUnsupportedFieldWarnings();
try {
Case case1 = Case.getCurrentCaseThrows();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
List<OSInfo> osInfoList = OSUtility.getOSInfo(sleuthkitCase);
List<BlackboardArtifact> finalHits = new ArrayList<BlackboardArtifact>();
if (!osInfoList.isEmpty()) {
for (OSInfo info : osInfoList) {
boolean foundHostnameMatch = false;
//boolean foundDomainMatch = false;
boolean foundProcArchMatch = false;
boolean foundTempDirMatch = false;
boolean foundProductNameMatch = false;
boolean foundSystemRootMatch = false;
boolean foundProductIDMatch = false;
boolean foundOwnerMatch = false;
boolean foundOrganizationMatch = false;
if (haveHostname) {
foundHostnameMatch = compareStringObject(obj.getHostname(), info.getCompName());
}
if (haveProcArch) {
foundProcArchMatch = compareStringObject(obj.getProcessorArchitecture().getValue().toString(),
obj.getProcessorArchitecture().getCondition(),
obj.getProcessorArchitecture().getApplyCondition(),
info.getAttributeValue(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE));
}
if (haveTempDir && (winSysObj != null)) {
foundTempDirMatch = compareStringObject(winSysObj.getWindowsTempDirectory(),
info.getAttributeValue(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEMP_DIR));
}
if (haveProductName && (winSysObj != null)) {
foundProductNameMatch = compareStringObject(winSysObj.getProductName(),
info.getAttributeValue(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME));
}
if (haveSystemRoot && (winSysObj != null)) {
foundSystemRootMatch = compareStringObject(winSysObj.getWindowsSystemDirectory(),
info.getAttributeValue(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH));
}
if (haveProductID && (winSysObj != null)) {
foundProductIDMatch = compareStringObject(winSysObj.getProductID(),
info.getAttributeValue(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PRODUCT_ID));
}
if (haveOwner && (winSysObj != null)) {
foundOwnerMatch = compareStringObject(winSysObj.getRegisteredOwner(),
info.getAttributeValue(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_OWNER));
}
if (haveOrganization && (winSysObj != null)) {
foundOrganizationMatch = compareStringObject(winSysObj.getRegisteredOrganization(),
info.getAttributeValue(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ORGANIZATION));
}
if (((!haveHostname) || foundHostnameMatch)
&& ((!haveProcArch) || foundProcArchMatch)
&& ((!haveTempDir) || foundTempDirMatch)
&& ((!haveProductName) || foundProductNameMatch)
&& ((!haveSystemRoot) || foundSystemRootMatch)
&& ((!haveProductID) || foundProductIDMatch)
&& ((!haveOwner) || foundOwnerMatch)
&& ((!haveOrganization) || foundOrganizationMatch)) {
finalHits.addAll(info.getArtifacts());
}
}
if (!finalHits.isEmpty()) {
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
for (BlackboardArtifact a : finalHits) {
artData.add(new StixArtifactData(a.getObjectID(), id, "System")); //NON-NLS
}
return new ObservableResult(id, "SystemObject: Found a match for " + searchString, //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
}
// Didn't find any matches
return new ObservableResult(id, "SystemObject: No matches found for " + searchString, //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
} else {
return new ObservableResult(id, "SystemObject: No OS artifacts found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
} catch (TskCoreException | NoCurrentCaseException ex) {
return new ObservableResult(id, "SystemObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
}
/**
* Set up the warning for any fields in the object that aren't supported.
*/
private void setUnsupportedFieldWarnings() {
List<String> fieldNames = new ArrayList<String>();
if (obj.getAvailablePhysicalMemory() != null) {
fieldNames.add("Available_Physical_Memory"); //NON-NLS
}
if (obj.getBIOSInfo() != null) {
fieldNames.add("BIOS_Info"); //NON-NLS
}
if (obj.getDate() != null) {
fieldNames.add("Date"); //NON-NLS
}
if (obj.getLocalTime() != null) {
fieldNames.add("Local_Time"); //NON-NLS
}
if (obj.getNetworkInterfaceList() != null) {
fieldNames.add("Network_Interface_List"); //NON-NLS
}
if (obj.getOS() != null) {
fieldNames.add("OS"); //NON-NLS
}
if (obj.getProcessor() != null) {
fieldNames.add("Processor"); //NON-NLS
}
if (obj.getSystemTime() != null) {
fieldNames.add("System_Time"); //NON-NLS
}
if (obj.getTimezoneDST() != null) {
fieldNames.add("Timezone_DST"); //NON-NLS
}
if (obj.getTimezoneStandard() != null) {
fieldNames.add("Timezone_Standard"); //NON-NLS
}
if (obj.getTotalPhysicalMemory() != null) {
fieldNames.add("Total_Physical_Memory"); //NON-NLS
}
if (obj.getUptime() != null) {
fieldNames.add("Uptime"); //NON-NLS
}
if (obj.getUsername() != null) {
fieldNames.add("Username"); //NON-NLS
}
if (obj instanceof WindowsSystem) {
WindowsSystem winSysObj = (WindowsSystem) obj;
if (winSysObj.getDomains() != null) {
fieldNames.add("Domain"); //NON-NLS
}
if (winSysObj.getGlobalFlagList() != null) {
fieldNames.add("Global_Flag_List"); //NON-NLS
}
if (winSysObj.getNetBIOSName() != null) {
fieldNames.add("NetBIOS_Name"); //NON-NLS
}
if (winSysObj.getOpenHandleList() != null) {
fieldNames.add("Open_Handle_List"); //NON-NLS
}
if (winSysObj.getWindowsDirectory() != null) {
fieldNames.add("Windows_Directory"); //NON-NLS
}
}
String warningStr = "";
for (String name : fieldNames) {
if (!warningStr.isEmpty()) {
warningStr += ", ";
}
warningStr += name;
}
addWarning("Unsupported field(s): " + warningStr); //NON-NLS
}
}

View File

@ -1,158 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import java.util.List;
import java.util.ArrayList;
import org.mitre.cybox.common_2.ConditionApplicationEnum;
import org.mitre.cybox.objects.URIObjectType;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
/**
*
*/
class EvalURIObj extends EvaluatableObject {
private final URIObjectType obj;
public EvalURIObj(URIObjectType a_obj, String a_id, String a_spacing) {
obj = a_obj;
id = a_id;
spacing = a_spacing;
}
@Override
public synchronized ObservableResult evaluate() {
setWarnings("");
if (obj.getValue() == null) {
return new ObservableResult(id, "URIObject: No URI value field found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
Case case1;
try {
case1 = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
return new ObservableResult(id, "Exception while getting open case: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
}
String addressStr = obj.getValue().getValue().toString();
// Strip off http:// or https://
String modifiedAddressStr = addressStr.toLowerCase();
modifiedAddressStr = modifiedAddressStr.replaceAll("http(s)?://", ""); //NON-NLS
// Since we have single URL artifacts, ALL and NONE conditions probably don't make sense to test
if (!((obj.getValue().getApplyCondition() == null)
|| (obj.getValue().getApplyCondition() == ConditionApplicationEnum.ANY))) {
return new ObservableResult(id, "URIObject: Can not process apply condition " + obj.getValue().getApplyCondition().toString() //NON-NLS
+ " on URI object", spacing, ObservableResult.ObservableState.INDETERMINATE, null); //NON-NLS
}
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
try {
/*
* if ((obj.getValue().getCondition() == null) ||
* (obj.getValue().getCondition() == ConditionTypeEnum.EQUALS)) {
*
* // Old version - uses a database query but only works on full
* strings. // It will be faster to use this in the "equals" case
* String[] parts = addressStr.split("##comma##");
* List<BlackboardArtifact> arts = new
* ArrayList<BlackboardArtifact>(); for (String part : parts) {
* arts.addAll(sleuthkitCase.getBlackboardArtifacts(
* BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT,
* BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, part)); }
*
* if (!arts.isEmpty()) {
*
* List<StixArtifactData> artData = new
* ArrayList<StixArtifactData>(); for (BlackboardArtifact a : arts)
* { artData.add(new StixArtifactData(a.getObjectID(), id,
* "URIObject")); }
*
* return new ObservableResult(id, "URIObject: Found " + arts.size()
* + " matches for address = \"" + addressStr + "\"", spacing,
* ObservableResult.ObservableState.TRUE, artData);
*
* } else { return new ObservableResult(id, "URIObject: Found no
* matches for address = \"" + addressStr + "\"", spacing,
* ObservableResult.ObservableState.FALSE, null); } } else {
*/
// This is inefficient, but the easiest way to do it.
List<BlackboardArtifact> finalHits = new ArrayList<BlackboardArtifact>();
// Get all the URL artifacts
List<BlackboardArtifact> artList
= sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT);
for (BlackboardArtifact art : artList) {
for (BlackboardAttribute attr : art.getAttributes()) {
if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
String modifiedAttrString = attr.getValueString();
if (modifiedAttrString != null) {
modifiedAttrString = modifiedAttrString.toLowerCase();
modifiedAttrString = modifiedAttrString.replaceAll("http(s)?://", ""); //NON-NLS
}
if (compareStringObject(modifiedAddressStr, obj.getValue().getCondition(),
obj.getValue().getApplyCondition(), modifiedAttrString)) {
finalHits.add(art);
}
}
}
}
if (!finalHits.isEmpty()) {
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
for (BlackboardArtifact a : finalHits) {
artData.add(new StixArtifactData(a.getObjectID(), id, "UriObject")); //NON-NLS
}
return new ObservableResult(id, "UriObject: Found a match for " + addressStr, //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
}
return new ObservableResult(id, "URIObject: Found no matches for " + addressStr, //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
/*
* }
*/
} catch (TskCoreException ex) {
return new ObservableResult(id, "URIObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
}
}

View File

@ -1,320 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import java.util.List;
import java.util.ArrayList;
import org.mitre.cybox.common_2.AnyURIObjectPropertyType;
import org.mitre.cybox.objects.URLHistory;
import org.mitre.cybox.objects.URLHistoryEntryType;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
/**
*
*/
class EvalURLHistoryObj extends EvaluatableObject {
private final URLHistory obj;
public EvalURLHistoryObj(URLHistory a_obj, String a_id, String a_spacing) {
obj = a_obj;
id = a_id;
spacing = a_spacing;
}
@Override
public synchronized ObservableResult evaluate() {
setWarnings("");
if ((obj.getBrowserInformation() == null) && (obj.getURLHistoryEntries() == null)) {
return new ObservableResult(id, "URLHistoryObject: No browser info or history entries found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
// For displaying what we were looking for in the results
String baseSearchString = "";
String finalResultsStr = "";
// The browser info is the same for each entry
boolean haveBrowserName = false;
if (obj.getBrowserInformation() != null) {
if (obj.getBrowserInformation().getName() != null) {
haveBrowserName = true;
}
baseSearchString = "Browser \"" + obj.getBrowserInformation().getName() + "\""; //NON-NLS
}
// Matching artifacts
List<BlackboardArtifact> finalHits = new ArrayList<BlackboardArtifact>();
if (obj.getURLHistoryEntries() != null) {
for (URLHistoryEntryType entry : obj.getURLHistoryEntries()) {
boolean haveURL = false;
boolean haveHostname = false;
boolean haveReferrer = false;
boolean havePageTitle = false;
boolean haveUserProfile = false;
setUnsupportedEntryFieldWarnings(entry);
// At present, the search string doesn't get reported (because there could be different ones
// for multiple URL History Entries) but it's good for debugging.
String searchString = baseSearchString;
if ((entry.getURL() != null) && (entry.getURL().getValue() != null)) {
haveURL = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "URL \"" + entry.getURL().getValue().getValue() + "\""; //NON-NLS
}
if ((entry.getReferrerURL() != null) && (entry.getReferrerURL().getValue() != null)) {
haveReferrer = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "Referrer \"" + entry.getReferrerURL().getValue().getValue() + "\""; //NON-NLS
}
if (entry.getUserProfileName() != null) {
haveUserProfile = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "UserProfile \"" + entry.getUserProfileName().getValue() + "\""; //NON-NLS
}
if (entry.getPageTitle() != null) {
havePageTitle = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "Page title \"" + entry.getPageTitle().getValue() + "\""; //NON-NLS
}
if ((entry.getHostname() != null) && (entry.getHostname().getHostnameValue() != null)) {
haveHostname = true;
if (!searchString.isEmpty()) {
searchString += " and "; //NON-NLS
}
searchString += "Hostname \"" + entry.getHostname().getHostnameValue().getValue() + "\""; //NON-NLS
}
if (!finalResultsStr.isEmpty()) {
finalResultsStr += ", ";
}
finalResultsStr += searchString;
if (!(haveURL || haveHostname || haveReferrer
|| havePageTitle || haveUserProfile || haveBrowserName)) {
return new ObservableResult(id, "URLHistoryObject: No evaluatable fields found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
try {
Case case1 = Case.getCurrentCaseThrows();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
List<BlackboardArtifact> artList
= sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY);
for (BlackboardArtifact art : artList) {
boolean foundURLMatch = false;
boolean foundHostnameMatch = false;
boolean foundReferrerMatch = false;
boolean foundPageTitleMatch = false;
boolean foundUserProfileMatch = false;
boolean foundBrowserNameMatch = false;
for (BlackboardAttribute attr : art.getAttributes()) {
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL.getTypeID())
&& (haveURL)) {
if (entry.getURL().getValue() instanceof AnyURIObjectPropertyType) {
foundURLMatch = compareStringObject(entry.getURL().getValue().getValue().toString(),
entry.getURL().getValue().getCondition(),
entry.getURL().getValue().getApplyCondition(),
attr.getValueString());
} else {
addWarning("Non-AnyURIObjectPropertyType found in URL value field"); //NON-NLS
}
}
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID())
&& (haveHostname)) {
foundHostnameMatch = compareStringObject(entry.getHostname().getHostnameValue(),
attr.getValueString());
}
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REFERRER.getTypeID())
&& (haveReferrer)) {
if (entry.getReferrerURL().getValue() instanceof AnyURIObjectPropertyType) {
foundReferrerMatch = compareStringObject(entry.getReferrerURL().getValue().getValue().toString(),
entry.getURL().getValue().getCondition(),
entry.getURL().getValue().getApplyCondition(),
attr.getValueString());
} else {
addWarning("Non-AnyURIObjectPropertyType found in URL value field"); //NON-NLS
}
}
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE.getTypeID())
&& (havePageTitle)) {
foundPageTitleMatch = compareStringObject(entry.getPageTitle(),
attr.getValueString());
}
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME.getTypeID())
&& (haveUserProfile)) {
foundUserProfileMatch = compareStringObject(entry.getUserProfileName(),
attr.getValueString());
}
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())
&& (haveBrowserName)) {
foundBrowserNameMatch = compareStringObject(obj.getBrowserInformation().getName(),
null, null, attr.getValueString());
}
}
if (((!haveURL) || foundURLMatch)
&& ((!haveHostname) || foundHostnameMatch)
&& ((!haveReferrer) || foundReferrerMatch)
&& ((!havePageTitle) || foundPageTitleMatch)
&& ((!haveUserProfile) || foundUserProfileMatch)
&& ((!haveBrowserName) || foundBrowserNameMatch)) {
finalHits.add(art);
}
}
} catch (TskCoreException | NoCurrentCaseException ex) {
return new ObservableResult(id, "URLHistoryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
}
if (!finalHits.isEmpty()) {
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
for (BlackboardArtifact a : finalHits) {
artData.add(new StixArtifactData(a.getObjectID(), id, "URLHistory")); //NON-NLS
}
return new ObservableResult(id, "URLHistoryObject: Found at least one match for " + finalResultsStr, //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
}
// Didn't find any matches
return new ObservableResult(id, "URLHistoryObject: No matches found for " + finalResultsStr, //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
} else if (haveBrowserName) {
// It doesn't seem too useful, but we can just search for the browser name
// if there aren't any URL entries
try {
Case case1 = Case.getCurrentCaseThrows();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
List<BlackboardArtifact> artList
= sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY);
for (BlackboardArtifact art : artList) {
boolean foundBrowserNameMatch = false;
for (BlackboardAttribute attr : art.getAttributes()) {
if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())
&& (haveBrowserName)) {
foundBrowserNameMatch = compareStringObject(obj.getBrowserInformation().getName(),
null, null, attr.getValueString());
}
}
if (foundBrowserNameMatch) {
finalHits.add(art);
}
}
if (!finalHits.isEmpty()) {
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
for (BlackboardArtifact a : finalHits) {
artData.add(new StixArtifactData(a.getObjectID(), id, "URLHistory")); //NON-NLS
}
return new ObservableResult(id, "URLHistoryObject: Found at least one match", //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
}
// Didn't find any matches
return new ObservableResult(id, "URLHistoryObject: No matches found for " + baseSearchString, //NON-NLS
spacing, ObservableResult.ObservableState.FALSE, null);
} catch (TskCoreException | NoCurrentCaseException ex) {
return new ObservableResult(id, "URLHistoryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
} else {
// Nothing to search for
return new ObservableResult(id, "URLHistoryObject: No evaluatable fields found", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
}
/**
* Set up the warning for any fields in the URL_History_Entry object that
* aren't supported.
*/
private void setUnsupportedEntryFieldWarnings(URLHistoryEntryType entry) {
List<String> fieldNames = new ArrayList<String>();
if (entry.getUserProfileName() != null) {
fieldNames.add("User_Profile_Name"); //NON-NLS
}
if (entry.getVisitCount() != null) {
fieldNames.add("Visit_Count"); //NON-NLS
}
if (entry.getManuallyEnteredCount() != null) {
fieldNames.add("Manually_Entered_Count"); //NON-NLS
}
if (entry.getModificationDateTime() != null) {
fieldNames.add("Modification_DateTime"); //NON-NLS
}
if (entry.getExpirationDateTime() != null) {
fieldNames.add("Expiration_DateTime"); //NON-NLS
}
if (entry.getFirstVisitDateTime() != null) {
fieldNames.add("First_Visit_DateTime"); //NON-NLS
}
if (entry.getLastVisitDateTime() != null) {
fieldNames.add("Last_Visit_DateTime"); //NON-NLS
}
String warningStr = "";
for (String name : fieldNames) {
if (!warningStr.isEmpty()) {
warningStr += ", ";
}
warningStr += name;
}
addWarning("Unsupported URL_History_Entry field(s): " + warningStr); //NON-NLS
}
}

View File

@ -1,261 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import java.util.ArrayList;
import java.util.List;
import org.mitre.cybox.common_2.ConditionApplicationEnum;
import org.mitre.cybox.common_2.ConditionTypeEnum;
import org.mitre.cybox.common_2.StringObjectPropertyType;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
*
*/
abstract class EvaluatableObject {
private String warnings;
protected String id;
protected String spacing;
abstract public ObservableResult evaluate();
/**
* Set the warnings string to the given value.
*
* @param a_warnings
*/
public void setWarnings(String a_warnings) {
warnings = a_warnings;
}
/**
* Get the warnings string. This should not be used to print the final
* version of the warnings.
*
* @return
*/
public String getWarnings() {
return warnings;
}
/**
* Add to the warnings string.
*
* @param a_newWarning
*/
public void addWarning(String a_newWarning) {
if ((warnings == null) || warnings.isEmpty()) {
warnings = a_newWarning;
return;
}
warnings = warnings + ", " + a_newWarning;
}
/**
* Find a list of artifacts with the given attribute type that contain the
* String Object. All comparisons will look for substrings of the Blackboard
* artifacts that match the String Object.
*
* @param item
* @param attrType
*
* @return
*
* @throws TskCoreException
*/
public List<BlackboardArtifact> findArtifactsBySubstring(StringObjectPropertyType item,
BlackboardAttribute.ATTRIBUTE_TYPE attrType) throws TskCoreException {
if (item.getValue() == null) {
throw new TskCoreException("Error: Value field is null"); //NON-NLS
}
if (item.getCondition() == null) {
addWarning("Warning: No condition given for " + attrType.getDisplayName() + " field, using substring comparison"); //NON-NLS
} else if (item.getCondition() != ConditionTypeEnum.CONTAINS) {
addWarning("Warning: Ignoring condition " + item.getCondition() + " for " //NON-NLS
+ attrType.getDisplayName() + " field and doing substring comparison"); //NON-NLS
}
List<BlackboardArtifact> hits = null;
try {
Case case1 = Case.getCurrentCaseThrows();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
String[] parts = item.getValue().toString().split("##comma##"); //NON-NLS
if ((item.getApplyCondition() == null)
|| (item.getApplyCondition() == ConditionApplicationEnum.ANY)) {
for (String part : parts) {
if (hits == null) {
// Note that this searches for artifacts with "part" as a substring
hits = sleuthkitCase.getBlackboardArtifacts(
attrType,
part, false);
} else {
hits.addAll(sleuthkitCase.getBlackboardArtifacts(
attrType,
part, false));
}
}
} else if ((item.getApplyCondition() != null)
|| (item.getApplyCondition() == ConditionApplicationEnum.ALL)) {
boolean firstRound = true;
for (String part : parts) {
if (firstRound) {
hits = sleuthkitCase.getBlackboardArtifacts(
attrType,
part, false);
firstRound = false;
} else if (hits != null) {
hits.retainAll(sleuthkitCase.getBlackboardArtifacts(
attrType,
part, false));
} else {
// After first round; hits is still null
// I don't think this should happen but if it does we're done
return new ArrayList<BlackboardArtifact>();
}
}
} else {
throw new TskCoreException("Error: Can not apply NONE condition in search"); //NON-NLS
}
} catch (TskCoreException | NoCurrentCaseException ex) {
addWarning(ex.getLocalizedMessage());
}
return hits;
}
/**
* Compare a CybOX String Object with a given string.
*
* @param stringObj The CybOX String Object
* @param strField The string to compare against
*
* @return true if strField is a match for the CybOX object
*
* @throws TskCoreException
*/
public static boolean compareStringObject(StringObjectPropertyType stringObj, String strField)
throws TskCoreException {
if (stringObj.getValue() == null) {
throw new TskCoreException("Error: Value field is null"); //NON-NLS
}
String valueStr = stringObj.getValue().toString();
ConditionTypeEnum condition = stringObj.getCondition();
ConditionApplicationEnum applyCondition = stringObj.getApplyCondition();
return compareStringObject(valueStr, condition, applyCondition, strField);
}
/**
* Compare a string with CybOX conditions to a given string.
*
* @param valueStr The CybOX string
* @param condition EQUALS, CONTAINS, STARTS_WITH, etc
* @param applyCondition ANY, ALL, NONE
* @param strField The string to compare against
*
* @return true if strField is a match for the CybOX valueStr and conditions
*
* @throws TskCoreException
*/
public static boolean compareStringObject(String valueStr, ConditionTypeEnum condition,
ConditionApplicationEnum applyCondition, String strField)
throws TskCoreException {
if (valueStr == null) {
throw new TskCoreException("Error: Value field is null"); //NON-NLS
}
String[] parts = valueStr.split("##comma##"); //NON-NLS
String lowerFieldName = strField.toLowerCase();
for (String value : parts) {
boolean partialResult;
if ((condition == null)
|| (condition == ConditionTypeEnum.EQUALS)) {
partialResult = value.equalsIgnoreCase(strField);
} else if (condition == ConditionTypeEnum.DOES_NOT_EQUAL) {
partialResult = !value.equalsIgnoreCase(strField);
} else if (condition == ConditionTypeEnum.CONTAINS) {
partialResult = lowerFieldName.contains(value.toLowerCase());
} else if (condition == ConditionTypeEnum.DOES_NOT_CONTAIN) {
partialResult = !lowerFieldName.contains(value.toLowerCase());
} else if (condition == ConditionTypeEnum.STARTS_WITH) {
partialResult = lowerFieldName.startsWith(value.toLowerCase());
} else if (condition == ConditionTypeEnum.ENDS_WITH) {
partialResult = lowerFieldName.endsWith(value.toLowerCase());
} else {
throw new TskCoreException("Could not process condition " + condition.value() + " on " + value); //NON-NLS
}
// Do all the short-circuiting
if (applyCondition == ConditionApplicationEnum.NONE) {
if (partialResult == true) {
// Failed
return false;
}
} else if (applyCondition == ConditionApplicationEnum.ALL) {
if (partialResult == false) {
// Failed
return false;
}
} else {
// Default is "any"
if (partialResult == true) {
return true;
}
}
}
// At this point we're done and didn't short-circuit, so ALL or NONE conditions were true,
// and ANY was false
if ((applyCondition == ConditionApplicationEnum.NONE)
|| (applyCondition == ConditionApplicationEnum.ALL)) {
return true;
}
return false;
}
/**
* Format the warnings that will be printed. Basically, just put parentheses
* around them if the string isn't empty.
*
* @return
*/
public String getPrintableWarnings() {
String warningsToPrint = "";
if ((getWarnings() != null)
&& (!getWarnings().isEmpty())) {
warningsToPrint = " (" + getWarnings() + ")";
}
return warningsToPrint;
}
}

View File

@ -1,199 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import java.util.List;
import java.util.ArrayList;
import org.mitre.cybox.cybox_2.OperatorTypeEnum;
/**
*
*/
class ObservableResult {
public enum ObservableState {
TRUE("true "), //NON-NLS
FALSE("false "), //NON-NLS
INDETERMINATE("indeterminate"); //NON-NLS
private final String label;
private ObservableState(String s) {
label = s;
}
@Override
public String toString() {
return label;
}
}
private ObservableState state = null;
private String description = "";
private List<StixArtifactData> artifacts;
public ObservableResult(String a_id, String a_desc, String a_spacing,
ObservableState a_state, List<StixArtifactData> a_artifacts) {
state = a_state;
description = a_spacing + a_id + "\t" + a_state + "\t" + a_desc + "\r\n";
artifacts = a_artifacts;
}
public ObservableResult(OperatorTypeEnum a_operator, String a_spacing) {
state = ObservableState.INDETERMINATE;
description = a_spacing + a_operator + "\r\n";
artifacts = new ArrayList<StixArtifactData>();
}
public ObservableState getState() {
return state;
}
/**
* Returns true if the ObservableResult is currently true. Note: A false
* result here does not mean the state is false; it could also be
* indeterminate.
*
* @return true if the ObservableResult is true, false if it is false or
* indeterminate
*/
public boolean isTrue() {
return (state == ObservableState.TRUE);
}
/**
* Returns true if the ObservableResult is currently false. Note: A false
* result here does not mean the state is true; it could also be
* indeterminate.
*
* @return true if the ObservableResult is false, false if it is true or
* indeterminate
*/
public boolean isFalse() {
return (state == ObservableState.FALSE);
}
public String getDescription() {
return description;
}
public List<StixArtifactData> getArtifacts() {
return artifacts;
}
/**
* Add a new result to the current state
*
* @param a_result The new result to add
* @param a_operator AND or OR
*/
public void addResult(ObservableResult a_result, OperatorTypeEnum a_operator) {
addResult(a_result.getDescription(), a_result.getState(),
a_result.getArtifacts(), a_operator);
}
/**
* Add a new result to the current state.
*
* @param a_description Description of the observable and testing done
* @param a_state State of what we're adding (true, false, or
* indeterminate)
* @param a_operator AND or OR
*/
private void addResult(String a_description, ObservableState a_state,
List<StixArtifactData> a_artifacts, OperatorTypeEnum a_operator) {
addToDesc(a_description);
if (a_operator == OperatorTypeEnum.AND) {
if (a_state == ObservableState.FALSE) {
// If we now have a false, the whole thing is false regardless of previous state.
// Clear out any existing artifacts.
state = ObservableState.FALSE;
artifacts.clear();
} else if (a_state == ObservableState.INDETERMINATE) {
// Don't change the current state, and don't save the new artifacts
// (though there probably wouldn't be any)
} else {
if (state == ObservableState.FALSE) {
// Previous state false + new state true => stay false
} else if (state == ObservableState.TRUE) {
// Previous state true + new state true => stay true and add artifacts
if ((artifacts == null) && (a_artifacts != null)) {
artifacts = new ArrayList<StixArtifactData>();
}
if (a_artifacts != null) {
artifacts.addAll(a_artifacts);
}
} else {
// If the previous state was indeterminate, change it to true and add artifacts
state = ObservableState.TRUE;
if ((artifacts == null) && (a_artifacts != null)) {
artifacts = new ArrayList<StixArtifactData>();
}
if (a_artifacts != null) {
artifacts.addAll(a_artifacts);
}
}
}
} else {
if (a_state == ObservableState.TRUE) {
// If we now have a true, the whole thing is true regardless of previous state.
// Add the new artifacts.
state = ObservableState.TRUE;
if ((artifacts == null) && (a_artifacts != null)) {
artifacts = new ArrayList<StixArtifactData>();
}
if (a_artifacts != null) {
artifacts.addAll(a_artifacts);
}
} else if (a_state == ObservableState.INDETERMINATE) {
// Don't change the current state and don't record it to the
// description string (later we should save these in some way)
} else {
if (state == ObservableState.FALSE) {
// Previous state false + new state false => stay false
} else if (state == ObservableState.TRUE) {
// Previous state true + new state false => stay true
} else {
// Previous state indeterminate + new state false => change to false
state = ObservableState.FALSE;
}
}
}
}
/**
* Add to the description string. Mostly just to make things cleaner by not
* testing for null all over the place.
*
* @param a_desc New part of the description to add
*/
private void addToDesc(String a_desc) {
if (description == null) {
description = a_desc;
} else {
description += a_desc;
}
}
}

View File

@ -1,699 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 - 2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.swing.JPanel;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import org.mitre.cybox.cybox_2.ObjectType;
import org.mitre.cybox.cybox_2.Observable;
import org.mitre.cybox.cybox_2.ObservableCompositionType;
import org.mitre.cybox.cybox_2.OperatorTypeEnum;
import org.mitre.cybox.objects.AccountObjectType;
import org.mitre.cybox.objects.Address;
import org.mitre.cybox.objects.DomainName;
import org.mitre.cybox.objects.EmailMessage;
import org.mitre.cybox.objects.FileObjectType;
import org.mitre.cybox.objects.SystemObjectType;
import org.mitre.cybox.objects.URIObjectType;
import org.mitre.cybox.objects.URLHistory;
import org.mitre.cybox.objects.WindowsNetworkShare;
import org.mitre.cybox.objects.WindowsRegistryKey;
import org.mitre.stix.common_1.IndicatorBaseType;
import org.mitre.stix.indicator_2.Indicator;
import org.mitre.stix.stix_1.STIXPackage;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.report.GeneralReportModule;
import org.sleuthkit.autopsy.report.GeneralReportSettings;
import org.sleuthkit.autopsy.report.NoReportModuleSettings;
import org.sleuthkit.autopsy.report.ReportModuleSettings;
import org.sleuthkit.autopsy.report.ReportProgressPanel;
import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus;
import org.sleuthkit.datamodel.TskCoreException;
/**
*
*/
public class STIXReportModule implements GeneralReportModule {
private static final Logger logger = Logger.getLogger(STIXReportModule.class.getName());
private STIXReportModuleConfigPanel configPanel;
private static STIXReportModule instance = null;
private String reportPath;
private boolean reportAllResults;
private Map<String, ObjectType> idToObjectMap = new HashMap<>();
private Map<String, ObservableResult> idToResult = new HashMap<>();
private List<EvalRegistryObj.RegistryFileInfo> registryFileData = null;
private final boolean skipShortCircuit = true;
// Hidden constructor for the report
private STIXReportModule() {
}
// Get the default implementation of this report
public static synchronized STIXReportModule getDefault() {
if (instance == null) {
instance = new STIXReportModule();
}
return instance;
}
/**
* @param settings Report settings.
* @param progressPanel panel to update the report's progress
*/
@Override
@Messages({"STIXReportModule.srcModuleName.text=STIX Report"})
public void generateReport(GeneralReportSettings settings, ReportProgressPanel progressPanel) {
// Start the progress bar and setup the report
progressPanel.setIndeterminate(false);
progressPanel.start();
String baseReportDir = settings.getReportDirectoryPath();
progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.readSTIX"));
reportPath = baseReportDir + getRelativeFilePath();
File reportFile = new File(reportPath);
// Check if the user wants to display all output or just hits
reportAllResults = configPanel.getShowAllResults();
// Keep track of whether any errors occur during processing
boolean hadErrors = false;
// Process the file/directory name entry
String stixFileName = configPanel.getStixFile();
if (stixFileName == null) {
logger.log(Level.SEVERE, "STIXReportModuleConfigPanel.stixFile not initialized "); //NON-NLS
progressPanel.complete(ReportStatus.ERROR, NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.noFildDirProvided"));
new File(baseReportDir).delete();
return;
}
if (stixFileName.isEmpty()) {
logger.log(Level.SEVERE, "No STIX file/directory provided "); //NON-NLS
progressPanel.complete(ReportStatus.ERROR, NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.noFildDirProvided"));
new File(baseReportDir).delete();
return;
}
File stixFile = new File(stixFileName);
if (!stixFile.exists()) {
logger.log(Level.SEVERE, String.format("Unable to open STIX file/directory %s", stixFileName)); //NON-NLS
progressPanel.complete(ReportStatus.ERROR, NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.couldNotOpenFileDir", stixFileName));
new File(baseReportDir).delete();
return;
}
try (BufferedWriter output = new BufferedWriter(new FileWriter(reportFile))) {
// Create array of stix file(s)
File[] stixFiles;
if (stixFile.isFile()) {
stixFiles = new File[1];
stixFiles[0] = stixFile;
} else {
stixFiles = stixFile.listFiles();
}
// Set the length of the progress bar - we increment twice for each file
progressPanel.setMaximumProgress(stixFiles.length * 2 + 1);
// Process each STIX file
for (File file : stixFiles) {
if (progressPanel.getStatus() == ReportStatus.CANCELED) {
return;
}
try {
processFile(file.getAbsolutePath(), progressPanel, output);
} catch (TskCoreException | JAXBException ex) {
String errMsg = String.format("Unable to process STIX file %s", file);
logger.log(Level.SEVERE, errMsg, ex); //NON-NLS
progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), errMsg));
hadErrors = true;
break;
}
// Clear out the ID maps before loading the next file
idToObjectMap = new HashMap<>();
idToResult = new HashMap<>();
}
// Set the progress bar to done. If any errors occurred along the way, modify
// the "complete" message to indicate this.
Case.getCurrentCaseThrows().addReport(reportPath, Bundle.STIXReportModule_srcModuleName_text(), "");
if (hadErrors) {
progressPanel.complete(ReportStatus.ERROR, NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.completedWithErrors"));
} else {
progressPanel.complete(ReportStatus.COMPLETE);
}
} catch (IOException ex) {
logger.log(Level.SEVERE, "Unable to complete STIX report.", ex); //NON-NLS
progressPanel.complete(ReportStatus.ERROR, NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.completedWithErrors"));
} catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Unable to add report to database.", ex);
}
}
/**
* Process a STIX file.
*
* @param stixFile - Name of the file
* @param progressPanel - Progress panel (for updating)
* @param output
*
* @throws JAXBException
* @throws TskCoreException
*/
private void processFile(String stixFile, ReportProgressPanel progressPanel, BufferedWriter output) throws
JAXBException, TskCoreException {
// Load the STIX file
STIXPackage stix;
stix = loadSTIXFile(stixFile);
printFileHeader(stixFile, output);
// Save any observables listed up front
processObservables(stix);
progressPanel.increment();
// Make copies of the registry files
registryFileData = EvalRegistryObj.copyRegistryFiles();
// Process the indicators
processIndicators(stix, output, progressPanel);
progressPanel.increment();
}
/**
* Load a STIX-formatted XML file into a STIXPackage object.
*
* @param stixFileName Name of the STIX file to unmarshal
*
* @return Unmarshalled file contents
*
* @throws JAXBException
*/
private STIXPackage loadSTIXFile(String stixFileName) throws JAXBException {
// Create STIXPackage object from xml.
// See JIRA-6958 for details about class loading and jaxb.
ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(STIXReportModule.class.getClassLoader());
File file = new File(stixFileName);
JAXBContext jaxbContext = JAXBContext.newInstance("org.mitre.stix.stix_1:org.mitre.stix.common_1:org.mitre.stix.indicator_2:" //NON-NLS
+ "org.mitre.cybox.objects:org.mitre.cybox.cybox_2:org.mitre.cybox.common_2"); //NON-NLS
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
STIXPackage stix = (STIXPackage) jaxbUnmarshaller.unmarshal(file);
return stix;
} finally {
Thread.currentThread().setContextClassLoader(original);
}
}
/**
* Do the initial processing of the list of observables. For each
* observable, save it in a map using the ID as key.
*
* @param stix STIXPackage
*/
private void processObservables(STIXPackage stix) {
if (stix.getObservables() != null) {
List<Observable> obs = stix.getObservables().getObservables();
for (Observable o : obs) {
if (o.getId() != null) {
saveToObjectMap(o);
}
}
}
}
/**
* Process all STIX indicators and save results to output file and create
* artifacts.
*
* @param stix STIXPackage
* @param output
* @param progressPanel
*/
private void processIndicators(STIXPackage stix, BufferedWriter output, ReportProgressPanel progressPanel) throws TskCoreException {
if (stix.getIndicators() != null) {
List<IndicatorBaseType> s = stix.getIndicators().getIndicators();
for (IndicatorBaseType t : s) {
if (t instanceof Indicator) {
Indicator ind = (Indicator) t;
if (ind.getObservable() != null) {
if (ind.getObservable().getObject() != null) {
ObservableResult result = evaluateSingleObservable(ind.getObservable(), "");
if (result.isTrue() || reportAllResults) {
writeResultsToFile(ind, result.getDescription(), result.isTrue(), output);
}
if (result.isTrue()) {
saveResultsAsArtifacts(ind, result, progressPanel);
}
} else if (ind.getObservable().getObservableComposition() != null) {
ObservableResult result = evaluateObservableComposition(ind.getObservable().getObservableComposition(), " ");
if (result.isTrue() || reportAllResults) {
writeResultsToFile(ind, result.getDescription(), result.isTrue(), output);
}
if (result.isTrue()) {
saveResultsAsArtifacts(ind, result, progressPanel);
}
}
}
}
}
}
}
/**
* Create the artifacts saved in the observable result.
*
* @param ind
* @param result
* @param progressPanel
*
* @throws TskCoreException
*/
private void saveResultsAsArtifacts(Indicator ind, ObservableResult result, ReportProgressPanel progressPanel) throws TskCoreException {
if (result.getArtifacts() == null) {
return;
}
// Count of how many artifacts have been created for this indicator.
int count = 0;
for (StixArtifactData s : result.getArtifacts()) {
// Figure out what name to use for this indicator. If it has a title,
// use that. Otherwise use the ID. If both are missing, use a
// generic heading.
if (ind.getTitle() != null) {
s.createArtifact(ind.getTitle());
} else if (ind.getId() != null) {
s.createArtifact(ind.getId().toString());
} else {
s.createArtifact("Unnamed indicator(s)"); //NON-NLS
}
// Trying to protect against the case where we end up with tons of artifacts
// for a single observable because the condition was not restrictive enough
count++;
if (count > 1000) {
progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(),
"STIXReportModule.notifyMsg.tooManyArtifactsgt1000"));
break;
}
}
}
/**
* Write the full results string to the output file.
*
* @param ind - Used to get the title, ID, and description of the
* indicator
* @param resultStr - Full results for this indicator
* @param found - true if the indicator was found in datasource(s)
* @param output
*/
private void writeResultsToFile(Indicator ind, String resultStr, boolean found, BufferedWriter output) {
if (output != null) {
try {
if (found) {
output.write("----------------\r\n"
+ "Found indicator:\r\n"); //NON-NLS
} else {
output.write("-----------------------\r\n"
+ "Did not find indicator:\r\n"); //NON-NLS
}
if (ind.getTitle() != null) {
output.write("Title: " + ind.getTitle() + "\r\n"); //NON-NLS
} else {
output.write("\r\n");
}
if (ind.getId() != null) {
output.write("ID: " + ind.getId() + "\r\n"); //NON-NLS
}
if (ind.getDescription() != null) {
String desc = ind.getDescription().getValue();
desc = desc.trim();
output.write("Description: " + desc + "\r\n"); //NON-NLS
}
output.write("\r\nObservable results:\r\n" + resultStr + "\r\n\r\n"); //NON-NLS
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Error writing to STIX report file %s", reportPath), ex); //NON-NLS
}
}
}
/**
* Write the a header for the current file to the output file.
*
* @param a_fileName
* @param output
*/
private void printFileHeader(String a_fileName, BufferedWriter output) {
if (output != null) {
try {
char[] chars = new char[a_fileName.length() + 8];
Arrays.fill(chars, '#');
String header = new String(chars);
output.write("\r\n" + header);
output.write("\r\n");
output.write("### " + a_fileName + " ###\r\n");
output.write(header + "\r\n\r\n");
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Error writing to STIX report file %s", reportPath), ex); //NON-NLS
}
}
}
/**
* Use the ID or ID ref to create a key into the observable map.
*
* @param obs
*
* @return
*/
private String makeMapKey(Observable obs) {
QName idQ;
if (obs.getId() != null) {
idQ = obs.getId();
} else if (obs.getIdref() != null) {
idQ = obs.getIdref();
} else {
return "";
}
return idQ.getLocalPart();
}
/**
* Save an observable in the object map.
*
* @param obs
*/
private void saveToObjectMap(Observable obs) {
if (obs.getObject() != null) {
idToObjectMap.put(makeMapKey(obs), obs.getObject());
}
}
/**
* Evaluate an observable composition. Can be called recursively.
*
* @param comp The observable composition object to evaluate
* @param spacing Used to formatting the output
*
* @return The status of the composition
*
* @throws TskCoreException
*/
private ObservableResult evaluateObservableComposition(ObservableCompositionType comp, String spacing) throws TskCoreException {
if (comp.getOperator() == null) {
throw new TskCoreException("No operator found in composition"); //NON-NLS
}
if (comp.getObservables() != null) {
List<Observable> obsList = comp.getObservables();
// Split based on the type of composition (AND vs OR)
if (comp.getOperator() == OperatorTypeEnum.AND) {
ObservableResult result = new ObservableResult(OperatorTypeEnum.AND, spacing);
for (Observable o : obsList) {
ObservableResult newResult; // The combined result for the composition
if (o.getObservableComposition() != null) {
newResult = evaluateObservableComposition(o.getObservableComposition(), spacing + " ");
if (result == null) {
result = newResult;
} else {
result.addResult(newResult, OperatorTypeEnum.AND);
}
} else {
newResult = evaluateSingleObservable(o, spacing + " ");
if (result == null) {
result = newResult;
} else {
result.addResult(newResult, OperatorTypeEnum.AND);
}
}
if ((!skipShortCircuit) && !result.isFalse()) {
// For testing purposes (and maybe in general), may not want to short-circuit
return result;
}
}
// At this point, all comparisions should have been true (or indeterminate)
if (result == null) {
// This really shouldn't happen, but if we have an empty composition,
// indeterminate seems like a reasonable result
return new ObservableResult("", "", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
return result;
} else {
ObservableResult result = new ObservableResult(OperatorTypeEnum.OR, spacing);
for (Observable o : obsList) {
ObservableResult newResult;// The combined result for the composition
if (o.getObservableComposition() != null) {
newResult = evaluateObservableComposition(o.getObservableComposition(), spacing + " ");
if (result == null) {
result = newResult;
} else {
result.addResult(newResult, OperatorTypeEnum.OR);
}
} else {
newResult = evaluateSingleObservable(o, spacing + " ");
if (result == null) {
result = newResult;
} else {
result.addResult(newResult, OperatorTypeEnum.OR);
}
}
if ((!skipShortCircuit) && result.isTrue()) {
// For testing (and maybe in general), may not want to short-circuit
return result;
}
}
// At this point, all comparisions were false (or indeterminate)
if (result == null) {
// This really shouldn't happen, but if we have an empty composition,
// indeterminate seems like a reasonable result
return new ObservableResult("", "", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
return result;
}
} else {
throw new TskCoreException("No observables found in list"); //NON-NLS
}
}
/**
* Evaluate one observable and return the result. This is at the end of the
* observable composition tree and will not be called recursively.
*
* @param obs The observable object to evaluate
* @param spacing For formatting the output
*
* @return The status of the observable
*
* @throws TskCoreException
*/
private ObservableResult evaluateSingleObservable(Observable obs, String spacing) throws TskCoreException {
// If we've already calculated this one, return the saved value
if (idToResult.containsKey(makeMapKey(obs))) {
return idToResult.get(makeMapKey(obs));
}
if (obs.getIdref() == null) {
// We should have the object data right here (as opposed to elsewhere in the STIX file).
// Save it to the map.
if (obs.getId() != null) {
saveToObjectMap(obs);
}
if (obs.getObject() != null) {
ObservableResult result = evaluateObject(obs.getObject(), spacing, makeMapKey(obs));
idToResult.put(makeMapKey(obs), result);
return result;
}
}
if (idToObjectMap.containsKey(makeMapKey(obs))) {
ObservableResult result = evaluateObject(idToObjectMap.get(makeMapKey(obs)), spacing, makeMapKey(obs));
idToResult.put(makeMapKey(obs), result);
return result;
}
throw new TskCoreException("Error loading/finding object for observable " + obs.getIdref()); //NON-NLS
}
/**
* Evaluate a STIX object.
*
*
* @param obj The object to evaluate against the datasource(s)
* @param spacing For formatting the output
* @param id
*
* @return
*/
private ObservableResult evaluateObject(ObjectType obj, String spacing, String id) {
EvaluatableObject evalObj;
if (obj.getProperties() instanceof FileObjectType) {
evalObj = new EvalFileObj((FileObjectType) obj.getProperties(), id, spacing);
} else if (obj.getProperties() instanceof Address) {
evalObj = new EvalAddressObj((Address) obj.getProperties(), id, spacing);
} else if (obj.getProperties() instanceof URIObjectType) {
evalObj = new EvalURIObj((URIObjectType) obj.getProperties(), id, spacing);
} else if (obj.getProperties() instanceof EmailMessage) {
evalObj = new EvalEmailObj((EmailMessage) obj.getProperties(), id, spacing);
} else if (obj.getProperties() instanceof WindowsNetworkShare) {
evalObj = new EvalNetworkShareObj((WindowsNetworkShare) obj.getProperties(), id, spacing);
} else if (obj.getProperties() instanceof AccountObjectType) {
evalObj = new EvalAccountObj((AccountObjectType) obj.getProperties(), id, spacing);
} else if (obj.getProperties() instanceof SystemObjectType) {
evalObj = new EvalSystemObj((SystemObjectType) obj.getProperties(), id, spacing);
} else if (obj.getProperties() instanceof URLHistory) {
evalObj = new EvalURLHistoryObj((URLHistory) obj.getProperties(), id, spacing);
} else if (obj.getProperties() instanceof DomainName) {
evalObj = new EvalDomainObj((DomainName) obj.getProperties(), id, spacing);
} else if (obj.getProperties() instanceof WindowsRegistryKey) {
evalObj = new EvalRegistryObj((WindowsRegistryKey) obj.getProperties(), id, spacing, registryFileData);
} else {
// Try to get the object type as a string
String type = obj.getProperties().toString();
type = type.substring(0, type.indexOf("@"));
if ((type.lastIndexOf(".") + 1) < type.length()) {
type = type.substring(type.lastIndexOf(".") + 1);
}
return new ObservableResult(id, type + " not supported", //NON-NLS
spacing, ObservableResult.ObservableState.INDETERMINATE, null);
}
// Evalutate the object
return evalObj.evaluate();
}
@Override
public String getName() {
String name = NbBundle.getMessage(this.getClass(), "STIXReportModule.getName.text");
return name;
}
@Override
public String getRelativeFilePath() {
return "stix.txt"; //NON-NLS
}
@Override
public String getDescription() {
String desc = NbBundle.getMessage(this.getClass(), "STIXReportModule.getDesc.text");
return desc;
}
@Override
public JPanel getConfigurationPanel() {
initializePanel();
return configPanel;
}
private void initializePanel() {
if (configPanel == null) {
configPanel = new STIXReportModuleConfigPanel();
}
}
/**
* Get default configuration for this report module.
*
* @return Object which contains default report module settings.
*/
@Override
public ReportModuleSettings getDefaultConfiguration() {
return new STIXReportModuleSettings();
}
/**
* Get current configuration for this report module.
*
* @return Object which contains current report module settings.
*/
@Override
public ReportModuleSettings getConfiguration() {
initializePanel();
return configPanel.getConfiguration();
}
/**
* Set report module configuration.
*
* @param settings Object which contains report module settings.
*/
@Override
public void setConfiguration(ReportModuleSettings settings) {
initializePanel();
if (settings == null || settings instanceof NoReportModuleSettings) {
configPanel.setConfiguration((STIXReportModuleSettings) getDefaultConfiguration());
return;
}
if (settings instanceof STIXReportModuleSettings) {
configPanel.setConfiguration((STIXReportModuleSettings) settings);
return;
}
throw new IllegalArgumentException("Expected settings argument to be an instance of STIXReportModuleSettings");
}
}

View File

@ -1,101 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="jStixFileTextField" min="-2" pref="292" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jButton1" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jCheckBox1" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="73" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jStixFileTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jButton1" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jCheckBox1" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="225" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabel2">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/report/modules/stix/Bundle.properties" key="STIXReportModuleConfigPanel.jLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextField" name="jStixFileTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/report/modules/stix/Bundle.properties" key="STIXReportModuleConfigPanel.jStixFileTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jStixFileTextFieldActionPerformed"/>
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jStixFileTextFieldKeyReleased"/>
<EventHandler event="keyTyped" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jStixFileTextFieldKeyTyped"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="jButton1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/report/modules/stix/Bundle.properties" key="STIXReportModuleConfigPanel.jButton1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="jCheckBox1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/report/modules/stix/Bundle.properties" key="STIXReportModuleConfigPanel.jCheckBox1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jCheckBox1ActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
</AuxValues>
</Component>
</SubComponents>
</Form>

View File

@ -1,179 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import java.io.File;
import javax.swing.JFileChooser;
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
/**
* Configuration panel for STIX report generation.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class STIXReportModuleConfigPanel extends javax.swing.JPanel {
String stixFile = null;
boolean showAllResults;
private final JFileChooserFactory chooserHelper;
/**
* Creates new form STIXReportModuleConfigPanel
*/
public STIXReportModuleConfigPanel() {
initComponents();
showAllResults = false;
jCheckBox1.setSelected(false);
chooserHelper = new JFileChooserFactory();
}
void setConfiguration(STIXReportModuleSettings settings) {
jStixFileTextField.setText(settings.getStixFile());
showAllResults = settings.isShowAllResults();
jCheckBox1.setSelected(settings.isShowAllResults());
}
STIXReportModuleSettings getConfiguration() {
return new STIXReportModuleSettings(jStixFileTextField.getText(), jCheckBox1.isSelected());
}
String getStixFile() {
return stixFile;
}
boolean getShowAllResults() {
return showAllResults;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jLabel2 = new javax.swing.JLabel();
jStixFileTextField = new javax.swing.JTextField();
jButton1 = new javax.swing.JButton();
jCheckBox1 = new javax.swing.JCheckBox();
jLabel2.setText(org.openide.util.NbBundle.getMessage(STIXReportModuleConfigPanel.class, "STIXReportModuleConfigPanel.jLabel2.text")); // NOI18N
jStixFileTextField.setText(org.openide.util.NbBundle.getMessage(STIXReportModuleConfigPanel.class, "STIXReportModuleConfigPanel.jStixFileTextField.text")); // NOI18N
jStixFileTextField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jStixFileTextFieldActionPerformed(evt);
}
});
jStixFileTextField.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
jStixFileTextFieldKeyReleased(evt);
}
public void keyTyped(java.awt.event.KeyEvent evt) {
jStixFileTextFieldKeyTyped(evt);
}
});
jButton1.setText(org.openide.util.NbBundle.getMessage(STIXReportModuleConfigPanel.class, "STIXReportModuleConfigPanel.jButton1.text")); // NOI18N
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jCheckBox1.setText(org.openide.util.NbBundle.getMessage(STIXReportModuleConfigPanel.class, "STIXReportModuleConfigPanel.jCheckBox1.text")); // NOI18N
jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jCheckBox1ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2)
.addGroup(layout.createSequentialGroup()
.addComponent(jStixFileTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jButton1))
.addComponent(jCheckBox1))
.addContainerGap(73, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jStixFileTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jButton1))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jCheckBox1)
.addContainerGap(225, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void jStixFileTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jStixFileTextFieldActionPerformed
}//GEN-LAST:event_jStixFileTextFieldActionPerformed
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
JFileChooser fileChooser = chooserHelper.getChooser();
fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
File currentSelection = new File(jStixFileTextField.getText());
if (currentSelection.exists()) {
fileChooser.setCurrentDirectory(currentSelection);
}
int result = fileChooser.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
stixFile = fileChooser.getSelectedFile().getAbsolutePath();
jStixFileTextField.setText(stixFile);
}
}//GEN-LAST:event_jButton1ActionPerformed
private void jStixFileTextFieldKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jStixFileTextFieldKeyTyped
}//GEN-LAST:event_jStixFileTextFieldKeyTyped
private void jStixFileTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jStixFileTextFieldKeyReleased
stixFile = jStixFileTextField.getText();
}//GEN-LAST:event_jStixFileTextFieldKeyReleased
private void jCheckBox1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBox1ActionPerformed
showAllResults = jCheckBox1.isSelected();
}//GEN-LAST:event_jCheckBox1ActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton jButton1;
private javax.swing.JCheckBox jCheckBox1;
private javax.swing.JLabel jLabel2;
private javax.swing.JTextField jStixFileTextField;
// End of variables declaration//GEN-END:variables
}

View File

@ -1,62 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import org.sleuthkit.autopsy.report.ReportModuleSettings;
/**
* Settings for the STIX report module.
*/
class STIXReportModuleSettings implements ReportModuleSettings {
private static final long serialVersionUID = 1L;
private final String stixFile;
private final boolean showAllResults;
STIXReportModuleSettings() {
stixFile = null;
showAllResults = false;
}
STIXReportModuleSettings(String stixFile, boolean showAllResults) {
this.stixFile = stixFile;
this.showAllResults = showAllResults;
}
@Override
public long getVersionNumber() {
return serialVersionUID;
}
/**
* @return the stixFile
*/
String getStixFile() {
return stixFile;
}
/**
* @return the showAllResults
*/
boolean isShowAllResults() {
return showAllResults;
}
}

View File

@ -1,107 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.stix;
import java.util.Arrays;
import java.util.Collection;
import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT;
import org.sleuthkit.datamodel.BlackboardAttribute;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE;
import org.sleuthkit.datamodel.Score;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
*
*/
class StixArtifactData {
private static final String MODULE_NAME = "Stix";
private AbstractFile file;
private final String observableId;
private final String objType;
private static final Logger logger = Logger.getLogger(StixArtifactData.class.getName());
StixArtifactData(AbstractFile a_file, String a_observableId, String a_objType) {
file = a_file;
observableId = a_observableId;
objType = a_objType;
}
StixArtifactData(long a_objId, String a_observableId, String a_objType) {
try {
Case case1 = Case.getCurrentCaseThrows();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
file = sleuthkitCase.getAbstractFileById(a_objId);
} catch (TskCoreException | NoCurrentCaseException ex) {
file = null;
}
observableId = a_observableId;
objType = a_objType;
}
@Messages({"StixArtifactData.indexError.message=Failed to index STIX interesting file hit artifact for keyword search.",
"StixArtifactData.noOpenCase.errMsg=No open case available."})
void createArtifact(String a_title) throws TskCoreException {
Blackboard blackboard;
try {
blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard();
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
return;
}
String setName = "STIX Indicator - " + StringUtils.defaultIfBlank(a_title, "(no title)"); //NON-NLS
Collection<BlackboardAttribute> attributes = Arrays.asList(
new BlackboardAttribute(TSK_SET_NAME, MODULE_NAME, setName),
new BlackboardAttribute(TSK_TITLE, MODULE_NAME, observableId),
new BlackboardAttribute(TSK_CATEGORY, MODULE_NAME, objType));
// Create artifact if it doesn't already exist.
if (!blackboard.artifactExists(file, TSK_INTERESTING_FILE_HIT, attributes)) {
BlackboardArtifact bba = file.newAnalysisResult(
BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, Score.SCORE_LIKELY_NOTABLE,
null, setName, null,
attributes)
.getAnalysisResult();
try {
/*
* post the artifact which will index the artifact for keyword
* search, and fire an event to notify UI of this new artifact
*/
blackboard.postArtifact(bba, MODULE_NAME);
} catch (Blackboard.BlackboardException ex) {
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
}
}
}
}

View File

@ -40,9 +40,22 @@ public final class ViewArtifactInTimelineAction extends AbstractAction {
private final BlackboardArtifact artifact; private final BlackboardArtifact artifact;
/**
* Constructor.
* @param artifact The artifact to navigate to in the timeline.
*/
@NbBundle.Messages({"ViewArtifactInTimelineAction.displayName=View Result in Timeline... "}) @NbBundle.Messages({"ViewArtifactInTimelineAction.displayName=View Result in Timeline... "})
public ViewArtifactInTimelineAction(BlackboardArtifact artifact) { public ViewArtifactInTimelineAction(BlackboardArtifact artifact) {
super(Bundle.ViewArtifactInTimelineAction_displayName()); this(artifact, Bundle.ViewArtifactInTimelineAction_displayName());
}
/**
* Constructor.
* @param artifact The artifact to navigate to in the timeline.
* @param displayName The display name for the action.
*/
public ViewArtifactInTimelineAction(BlackboardArtifact artifact, String displayName) {
super(displayName);
this.artifact = artifact; this.artifact = artifact;
// If timeline functionality is not available this action is disabled. // If timeline functionality is not available this action is disabled.
if ("false".equals(ModuleSettings.getConfigSetting("timeline", "enable_timeline"))) { if ("false".equals(ModuleSettings.getConfigSetting("timeline", "enable_timeline"))) {

View File

@ -43,7 +43,12 @@ public final class ViewFileInTimelineAction extends AbstractAction {
private final AbstractFile file; private final AbstractFile file;
private ViewFileInTimelineAction(AbstractFile file, String displayName) { /**
* Constructor.
* @param file The file to view in the timeline.
* @param displayName The display name of the action.
*/
public ViewFileInTimelineAction(AbstractFile file, String displayName) {
super(displayName); super(displayName);
this.file = file; this.file = file;

View File

@ -384,6 +384,20 @@ final class RegexQuery implements KeywordSearchQuery {
} }
// Replace all non numeric at the end of the hit. // Replace all non numeric at the end of the hit.
hit = hit.replaceAll("[^0-9]$", ""); hit = hit.replaceAll("[^0-9]$", "");
if (offset > 1) {
/*
* NOTE: our IP and phone number regex patterns look for
* boundary characters immediately before and after
* the keyword hit. After a match, Java pattern
* mather re-starts at the first character not
* matched by the previous match. This basically
* requires two boundary characters to be present
* between each pattern match. To mitigate this we
* are resetting the offest one character back.
*/
offset--;
}
} }
/** /**

View File

@ -5,6 +5,10 @@ ChromeCacheExtract_adding_artifacts_msg=Chrome Cache: Adding %d artifacts for an
ChromeCacheExtract_adding_extracted_files_msg=Chrome Cache: Adding %d extracted files for analysis. ChromeCacheExtract_adding_extracted_files_msg=Chrome Cache: Adding %d extracted files for analysis.
ChromeCacheExtract_loading_files_msg=Chrome Cache: Loading files from %s. ChromeCacheExtract_loading_files_msg=Chrome Cache: Loading files from %s.
ChromeCacheExtractor.moduleName=ChromeCacheExtractor ChromeCacheExtractor.moduleName=ChromeCacheExtractor
# {0} - module name
# {1} - row number
# {2} - table length
# {3} - cache path
ChromeCacheExtractor.progressMsg={0}: Extracting cache entry {1} of {2} entries from {3} ChromeCacheExtractor.progressMsg={0}: Extracting cache entry {1} of {2} entries from {3}
DataSourceUsage_AndroidMedia=Android Media Card DataSourceUsage_AndroidMedia=Android Media Card
DataSourceUsage_DJU_Drone_DAT=DJI Internal SD Card DataSourceUsage_DJU_Drone_DAT=DJI Internal SD Card
@ -152,13 +156,19 @@ Firefox.getDlV24.errMsg.errAnalyzeFile={0}: Error while trying to analyze file:{
Firefox.getDlV24.errMsg.errParsingArtifacts={0}: Error parsing {1} Firefox web download artifacts. Firefox.getDlV24.errMsg.errParsingArtifacts={0}: Error parsing {1} Firefox web download artifacts.
Progress_Message_Analyze_Registry=Analyzing Registry Files Progress_Message_Analyze_Registry=Analyzing Registry Files
Progress_Message_Analyze_Usage=Data Sources Usage Analysis Progress_Message_Analyze_Usage=Data Sources Usage Analysis
# {0} - browserName
Progress_Message_Chrome_AutoFill=Chrome Auto Fill Browser {0} Progress_Message_Chrome_AutoFill=Chrome Auto Fill Browser {0}
# {0} - browserName
Progress_Message_Chrome_Bookmarks=Chrome Bookmarks Browser {0} Progress_Message_Chrome_Bookmarks=Chrome Bookmarks Browser {0}
Progress_Message_Chrome_Cache=Chrome Cache Progress_Message_Chrome_Cache=Chrome Cache
# {0} - browserName
Progress_Message_Chrome_Cookies=Chrome Cookies Browser {0} Progress_Message_Chrome_Cookies=Chrome Cookies Browser {0}
# {0} - browserName
Progress_Message_Chrome_Downloads=Chrome Downloads Browser {0} Progress_Message_Chrome_Downloads=Chrome Downloads Browser {0}
Progress_Message_Chrome_FormHistory=Chrome Form History Progress_Message_Chrome_FormHistory=Chrome Form History
# {0} - browserName
Progress_Message_Chrome_History=Chrome History Browser {0} Progress_Message_Chrome_History=Chrome History Browser {0}
# {0} - browserName
Progress_Message_Chrome_Logins=Chrome Logins Browser {0} Progress_Message_Chrome_Logins=Chrome Logins Browser {0}
Progress_Message_Edge_Bookmarks=Microsoft Edge Bookmarks Progress_Message_Edge_Bookmarks=Microsoft Edge Bookmarks
Progress_Message_Edge_Cookies=Microsoft Edge Cookies Progress_Message_Edge_Cookies=Microsoft Edge Cookies

View File

@ -592,9 +592,14 @@ final class ChromeCacheExtractor {
// see if it is cached // see if it is cached
String fileTableKey = cacheFolderName + cacheFileName; String fileTableKey = cacheFolderName + cacheFileName;
if (cacheFileName != null) {
if (cacheFileName.startsWith("f_") && externalFilesTable.containsKey(fileTableKey)) { if (cacheFileName.startsWith("f_") && externalFilesTable.containsKey(fileTableKey)) {
return Optional.of(externalFilesTable.get(fileTableKey)); return Optional.of(externalFilesTable.get(fileTableKey));
} }
} else {
return Optional.empty();
}
if (fileCopyCache.containsKey(fileTableKey)) { if (fileCopyCache.containsKey(fileTableKey)) {
return Optional.of(fileCopyCache.get(fileTableKey).getAbstractFile()); return Optional.of(fileCopyCache.get(fileTableKey).getAbstractFile());
@ -1306,7 +1311,7 @@ final class ChromeCacheExtractor {
private String key; // Key may be found within the entry or may be external private String key; // Key may be found within the entry or may be external
CacheEntry(CacheAddress cacheAdress, FileWrapper cacheFileCopy ) throws TskCoreException { CacheEntry(CacheAddress cacheAdress, FileWrapper cacheFileCopy ) throws TskCoreException, IngestModuleException {
this.selfAddress = cacheAdress; this.selfAddress = cacheAdress;
this.cacheFileCopy = cacheFileCopy; this.cacheFileCopy = cacheFileCopy;
@ -1315,7 +1320,11 @@ final class ChromeCacheExtractor {
int entryOffset = DATAFILE_HDR_SIZE + cacheAdress.getStartBlock() * cacheAdress.getBlockSize(); int entryOffset = DATAFILE_HDR_SIZE + cacheAdress.getStartBlock() * cacheAdress.getBlockSize();
// reposition the buffer to the the correct offset // reposition the buffer to the the correct offset
if (entryOffset < fileROBuf.capacity()) {
fileROBuf.position(entryOffset); fileROBuf.position(entryOffset);
} else {
throw new IngestModuleException("Position seeked in Buffer to big"); // NON-NLS
}
hash = fileROBuf.getInt() & UINT32_MASK; hash = fileROBuf.getInt() & UINT32_MASK;
@ -1364,8 +1373,10 @@ final class ChromeCacheExtractor {
if (longKeyAddresses != null) { if (longKeyAddresses != null) {
// Key is stored outside of the entry // Key is stored outside of the entry
try { try {
if (longKeyAddresses.getFilename() != null) {
CacheDataSegment data = new CacheDataSegment(longKeyAddresses, this.keyLen, true); CacheDataSegment data = new CacheDataSegment(longKeyAddresses, this.keyLen, true);
key = data.getDataString(); key = data.getDataString();
}
} catch (TskCoreException | IngestModuleException ex) { } catch (TskCoreException | IngestModuleException ex) {
throw new TskCoreException(String.format("Failed to get external key from address %s", longKeyAddresses)); //NON-NLS throw new TskCoreException(String.format("Failed to get external key from address %s", longKeyAddresses)); //NON-NLS
} }

View File

@ -318,7 +318,13 @@ final class ExtractZoneIdentifier extends Extract {
*/ */
ZoneIdentifierInfo(AbstractFile zoneFile) throws IOException { ZoneIdentifierInfo(AbstractFile zoneFile) throws IOException {
fileName = zoneFile.getName(); fileName = zoneFile.getName();
// properties.load will throw IllegalArgument if unicode characters are found in the zone file.
try {
properties.load(new ReadContentInputStream(zoneFile)); properties.load(new ReadContentInputStream(zoneFile));
} catch (IllegalArgumentException ex) {
String message = String.format("Unable to parse Zone Id for File %s", fileName); //NON-NLS
LOG.log(Level.WARNING, message);
}
} }
/** /**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -71,7 +71,6 @@ The following topics are available here:
- \subpage ui_quick_search - \subpage ui_quick_search
- \subpage file_search_page - \subpage file_search_page
- \subpage ad_hoc_keyword_search_page - \subpage ad_hoc_keyword_search_page
- \subpage stix_page
- \subpage common_properties_page - \subpage common_properties_page
- \subpage search_all_cases_page - \subpage search_all_cases_page

View File

@ -101,11 +101,6 @@ This report module generates a KML file from any GPS data in the case. This file
This report module generates a new Autopsy case that includes tagged and/or interesting items. See the \ref portable_case_page page for additional information. This report module generates a new Autopsy case that includes tagged and/or interesting items. See the \ref portable_case_page page for additional information.
\subsection report_stix STIX
The STIX module allows you to generate a report and Interesting File artifacts by running a STIX file (or files) against the data sources in the case.
For more information see the \ref stix_page page.
\subsection report_body_file TSK Body File \subsection report_body_file TSK Body File
This module generates a <a href="https://wiki.sleuthkit.org/index.php?title=Body_file">TSK Body File</a> from the files in your case, which looks similar to the following: This module generates a <a href="https://wiki.sleuthkit.org/index.php?title=Body_file">TSK Body File</a> from the files in your case, which looks similar to the following:

View File

@ -1,104 +0,0 @@
/*! \page stix_page STIX
[TOC]
Overview
========
This document outlines the use of the STIX feature of Autopsy. This feature allows one or more Structured Threat Information Exchange (STIX) files to be run against a data source, reporting which indicators were found in the data source. More information about STIX can be found at https://stix.mitre.org/.
This document assumes basic familiarity with Autopsy.
Quick Start
===========
-# Create a case as normal and add a disk image (or folder of files) as a data source. To get the most out of the STIX module, ensure that the following ingest modules are selected:
- Recent Activity
- Hash Lookup (Check box to calculate MD5 hashes even with no database selected)
- File Type Identification
- Keyword Search (URL, IP, and Email addresses)
- Email Parser
- Extension Mismatch Detector
-# After the image has been added and ingest is complete, click the Report button then select STIX. Next choose either a single STIX file or a directory of STIX files to run against the image. It is possible to do this while ingest is running but the results will be incomplete.
-# Once the STIX report module is complete, there will be two sets of results:
- Entries will be created under Interesting Items in the Autopsy tree, under a subheading for each indicator.
- A log of which indicators/observables were found is generated by the report module (Follow the link on the Report Generation Progress window)
Supported CybOX Objects
=======================
- Address Object
- Address_Value
- Domain Name Object
- Value
- Email Message Object
- To
- CC
- From
- Subject
- File Object
- Size_In_Bytes
- File_Name
- File_Path
- File_Extension
- Modified_Time
- Accessed_Time
- Created_Time
- Hashes (MD5 only)
- File_Format
- is_masqueraded
- URI Object
- Value
- URL History Object
- Browser_Information (Name)
- URL
- Hostname
- Referrer_URL
- Page_Title
- User_Profile_Name
- User Account Object
- Home_Directory
- Username
- Win Executable File Object
- Time_Date_Stamp
- Windows Network Share Object
- Local_Path
- Netname
- Win Registry Key Object
- Key (Required)
- Hive
- Values
- System Object
- Hostname
- Processor_Architecture
- Win System Object
- Product_ID
- Product_Name
- Registered_Owner
- Registered_Organization
- Windows_System_Directory
- Windows_Temp_Directory
- Win User Account Object
- SID
See http://cybox.mitre.org for more information on CybOX Objects.
Limitations
===========
- As shown in the list above, not all CybOX objects/fields are currently supported. When an unsupported object/field is found in an observable, its status is set to "indeterminate" instead of true or false. These indeterminate fields will not change the result of the observable composition (i.e., if the rest is true, the overall result will stay as true).
- Not all ConditionTypeEnum values are supported. It varies by field, but generally on String fields the following work: EQUALS, DOES_NOT_EQUAL, CONTAINS, DOES_NOT_CONTAIN, STARTS_WITH, ENDS_WITH. If a condition type is not supported there will be a warning in the log file.
- Related objects are not processed
*/