|
|
|
@ -1,7 +1,7 @@
|
|
|
|
|
/*
|
|
|
|
|
* Central Repository
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2015-2020 Basis Technology Corp.
|
|
|
|
|
* Copyright 2017-2020 Basis Technology Corp.
|
|
|
|
|
* Contact: carrier <at> sleuthkit <dot> org
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
@ -30,176 +30,280 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
|
|
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
|
|
|
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
|
|
|
|
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
|
|
|
|
import org.sleuthkit.datamodel.Content;
|
|
|
|
|
import org.sleuthkit.datamodel.HashUtility;
|
|
|
|
|
import org.sleuthkit.datamodel.TskCoreException;
|
|
|
|
|
import org.sleuthkit.datamodel.TskData;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Utility class for correlation attributes in the central repository
|
|
|
|
|
* Utility class for working with correlation attributes in the central
|
|
|
|
|
* repository.
|
|
|
|
|
*/
|
|
|
|
|
public class CorrelationAttributeUtil {
|
|
|
|
|
|
|
|
|
|
private static final Logger logger = Logger.getLogger(CorrelationAttributeUtil.class.getName());
|
|
|
|
|
|
|
|
|
|
@Messages({"EamArtifactUtil.emailaddresses.text=Email Addresses"})
|
|
|
|
|
public static String getEmailAddressAttrString() {
|
|
|
|
|
return Bundle.EamArtifactUtil_emailaddresses_text();
|
|
|
|
|
/**
|
|
|
|
|
* Gets a string that is expected to be the same string that is stored in
|
|
|
|
|
* the correlation_types table in the central repository as the display name
|
|
|
|
|
* for the email address correlation attribute type. This string is
|
|
|
|
|
* duplicated in the CorrelationAttributeInstance class.
|
|
|
|
|
*
|
|
|
|
|
* TODO (Jira-6088): We should not have multiple deifnitions of this string.
|
|
|
|
|
*
|
|
|
|
|
* @return The display name of the email address correlation attribute type.
|
|
|
|
|
*/
|
|
|
|
|
@Messages({"CorrelationAttributeUtil.emailaddresses.text=Email Addresses"})
|
|
|
|
|
private static String getEmailAddressAttrDisplayName() {
|
|
|
|
|
return Bundle.CorrelationAttributeUtil_emailaddresses_text();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Static factory method to examine a BlackboardArtifact to determine if it
|
|
|
|
|
* has contents that can be used for Correlation. If so, return a
|
|
|
|
|
* EamArtifact with a single EamArtifactInstance within. If not, return
|
|
|
|
|
* null.
|
|
|
|
|
* Makes zero to many correlation attribute instances from the attributes of
|
|
|
|
|
* an artifact.
|
|
|
|
|
*
|
|
|
|
|
* @param artifact BlackboardArtifact to examine
|
|
|
|
|
* @param checkEnabled If true, only create a CorrelationAttribute if it is
|
|
|
|
|
* enabled
|
|
|
|
|
* IMPORTANT: The correlation attribute instances are NOT added to the
|
|
|
|
|
* central repository by this method.
|
|
|
|
|
*
|
|
|
|
|
* @return List of EamArtifacts
|
|
|
|
|
* TODO (Jira-6088): The methods in this low-level, utility class should
|
|
|
|
|
* 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 artifact An artifact.
|
|
|
|
|
*
|
|
|
|
|
* @return A list, possibly empty, of correlation attribute instances for
|
|
|
|
|
* the artifact.
|
|
|
|
|
*/
|
|
|
|
|
public static List<CorrelationAttributeInstance> makeInstancesFromBlackboardArtifact(BlackboardArtifact artifact,
|
|
|
|
|
boolean checkEnabled) {
|
|
|
|
|
List<CorrelationAttributeInstance> eamArtifacts = new ArrayList<>();
|
|
|
|
|
public static List<CorrelationAttributeInstance> makeCorrAttrsFromArtifact(BlackboardArtifact artifact) {
|
|
|
|
|
List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>();
|
|
|
|
|
try {
|
|
|
|
|
BlackboardArtifact artifactForInstance = null;
|
|
|
|
|
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifact.getArtifactTypeID()) {
|
|
|
|
|
// Get the associated artifactForInstance
|
|
|
|
|
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
|
|
|
|
if (attribute != null) {
|
|
|
|
|
artifactForInstance = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
artifactForInstance = artifact;
|
|
|
|
|
}
|
|
|
|
|
if (artifactForInstance != null) {
|
|
|
|
|
int artifactTypeID = artifactForInstance.getArtifactTypeID();
|
|
|
|
|
BlackboardArtifact sourceArtifact = getCorrAttrSourceArtifact(artifact);
|
|
|
|
|
if (sourceArtifact != null) {
|
|
|
|
|
int artifactTypeID = sourceArtifact.getArtifactTypeID();
|
|
|
|
|
if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
|
|
|
|
BlackboardAttribute setNameAttr = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
|
|
|
|
|
if (setNameAttr != null
|
|
|
|
|
&& CorrelationAttributeUtil.getEmailAddressAttrString().equals(setNameAttr.getValueString())) {
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID);
|
|
|
|
|
BlackboardAttribute setNameAttr = sourceArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
|
|
|
|
|
if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) {
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID()
|
|
|
|
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID()
|
|
|
|
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID()
|
|
|
|
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID()) {
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID);
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID);
|
|
|
|
|
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|
|
|
|
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|
|
|
|
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) {
|
|
|
|
|
makeCorrAttrFromArtifactPhoneAttr(sourceArtifact);
|
|
|
|
|
|
|
|
|
|
String value = null;
|
|
|
|
|
if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) {
|
|
|
|
|
value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString();
|
|
|
|
|
} else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) {
|
|
|
|
|
value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString();
|
|
|
|
|
} else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) {
|
|
|
|
|
value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString();
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) {
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID);
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID);
|
|
|
|
|
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) {
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID);
|
|
|
|
|
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID()
|
|
|
|
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID()
|
|
|
|
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) {
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID);
|
|
|
|
|
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) {
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID);
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID);
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID);
|
|
|
|
|
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) {
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID);
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID);
|
|
|
|
|
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) {
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID);
|
|
|
|
|
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID);
|
|
|
|
|
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
|
|
|
|
makeCorrAttrFromAcctArtifact(correlationAttrs, sourceArtifact);
|
|
|
|
|
}
|
|
|
|
|
// Remove all non-numeric symbols to semi-normalize phone numbers, preserving leading "+" character
|
|
|
|
|
}
|
|
|
|
|
} catch (CentralRepoException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", artifact), ex); // NON-NLS
|
|
|
|
|
return correlationAttrs;
|
|
|
|
|
} catch (TskCoreException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, String.format("Error getting querying case database (%s)", artifact), ex); // NON-NLS
|
|
|
|
|
return correlationAttrs;
|
|
|
|
|
} catch (NoCurrentCaseException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS
|
|
|
|
|
return correlationAttrs;
|
|
|
|
|
}
|
|
|
|
|
return correlationAttrs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets the associated artifact of a "meta-artifact" such as an interesting
|
|
|
|
|
* artifact hit artifact.
|
|
|
|
|
*
|
|
|
|
|
* @param artifact An artifact.
|
|
|
|
|
*
|
|
|
|
|
* @return The associated artifact if the input artifact is a
|
|
|
|
|
* "meta-artifact", otherwise the input artifact.
|
|
|
|
|
*
|
|
|
|
|
* @throws NoCurrentCaseException If there is no open case.
|
|
|
|
|
* @throws TskCoreException If there is an error querying thew case
|
|
|
|
|
* database.
|
|
|
|
|
*/
|
|
|
|
|
private static BlackboardArtifact getCorrAttrSourceArtifact(BlackboardArtifact artifact) throws NoCurrentCaseException, TskCoreException {
|
|
|
|
|
BlackboardArtifact sourceArtifact = null;
|
|
|
|
|
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifact.getArtifactTypeID()) {
|
|
|
|
|
BlackboardAttribute assocArtifactAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
|
|
|
|
if (assocArtifactAttr != null) {
|
|
|
|
|
sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
sourceArtifact = artifact;
|
|
|
|
|
}
|
|
|
|
|
return sourceArtifact;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Makes a correlation attribute instance from a phone number attribute of an
|
|
|
|
|
* artifact.
|
|
|
|
|
*
|
|
|
|
|
* @param artifact An artifact with a phone number attribute.
|
|
|
|
|
*
|
|
|
|
|
* @return The correlation instance artifact or null, if the phone number is
|
|
|
|
|
* not a valid correlation attribute.
|
|
|
|
|
*
|
|
|
|
|
* @throws TskCoreException If there is an error querying the case
|
|
|
|
|
* database.
|
|
|
|
|
* @throws CentralRepoException If there is an error querying the central
|
|
|
|
|
* repository.
|
|
|
|
|
*/
|
|
|
|
|
private static CorrelationAttributeInstance makeCorrAttrFromArtifactPhoneAttr(BlackboardArtifact artifact) throws TskCoreException, CentralRepoException {
|
|
|
|
|
CorrelationAttributeInstance corrAttr = null;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Extract the phone number from the artifact attribute.
|
|
|
|
|
*/
|
|
|
|
|
String value = null;
|
|
|
|
|
if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) {
|
|
|
|
|
value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString();
|
|
|
|
|
} else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) {
|
|
|
|
|
value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString();
|
|
|
|
|
} else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) {
|
|
|
|
|
value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Normalize the phone number.
|
|
|
|
|
*/
|
|
|
|
|
if (value != null) {
|
|
|
|
|
String newValue = value.replaceAll("\\D", "");
|
|
|
|
|
if (value.startsWith("+")) {
|
|
|
|
|
newValue = "+" + newValue;
|
|
|
|
|
}
|
|
|
|
|
value = newValue;
|
|
|
|
|
// Only add the correlation attribute if the resulting phone number large enough to be of use
|
|
|
|
|
// (these 3-5 digit numbers can be valid, but are not useful for correlation)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Validate the phone number. Three to five digit phone numbers may
|
|
|
|
|
* be valid, but they are too short to use as correlation
|
|
|
|
|
* attributes.
|
|
|
|
|
*/
|
|
|
|
|
if (value.length() > 5) {
|
|
|
|
|
CorrelationAttributeInstance inst = makeCorrelationAttributeInstanceUsingTypeValue(artifactForInstance, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value);
|
|
|
|
|
if (inst != null) {
|
|
|
|
|
eamArtifacts.add(inst);
|
|
|
|
|
corrAttr = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) {
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID);
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID);
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) {
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID);
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID()
|
|
|
|
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID()
|
|
|
|
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) {
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID);
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) {
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID);
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID);
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID);
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) {
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID);
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID);
|
|
|
|
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) {
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID);
|
|
|
|
|
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (CentralRepoException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, "Error getting defined correlation types.", ex); // NON-NLS
|
|
|
|
|
return eamArtifacts;
|
|
|
|
|
} catch (TskCoreException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
} catch (NoCurrentCaseException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return eamArtifacts;
|
|
|
|
|
|
|
|
|
|
return corrAttr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a CorrelationAttributeInstance of the specified type to the provided
|
|
|
|
|
* list if the artifactForInstance has an Attribute of the given type with a
|
|
|
|
|
* non empty value.
|
|
|
|
|
* Makes a correlation attribute instance for an account artifact.
|
|
|
|
|
*
|
|
|
|
|
* @param eamArtifacts the list of CorrelationAttributeInstance objects
|
|
|
|
|
* which should be added to
|
|
|
|
|
* @param artifact the blackboard artifactForInstance which we are
|
|
|
|
|
* creating a CorrelationAttributeInstance for
|
|
|
|
|
* @param bbAttributeType the type of BlackboardAttribute we expect to exist
|
|
|
|
|
* for a CorrelationAttributeInstance of this type
|
|
|
|
|
* generated from this Blackboard Artifact
|
|
|
|
|
* @param typeId the integer type id of the
|
|
|
|
|
* CorrelationAttributeInstance type
|
|
|
|
|
* IMPORTANT: The correlation attribute instance is NOT added to the central
|
|
|
|
|
* repository by this method.
|
|
|
|
|
*
|
|
|
|
|
* @throws CentralRepoException
|
|
|
|
|
* @throws TskCoreException
|
|
|
|
|
* TODO (Jira-6088): The methods in this low-level, utility class should
|
|
|
|
|
* 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 corrAttrInstances A list of correlation attribute instances.
|
|
|
|
|
* @param acctArtifact An account artifact.
|
|
|
|
|
*
|
|
|
|
|
* @return The correlation attribute instance.
|
|
|
|
|
*/
|
|
|
|
|
private static void addCorrelationAttributeToList(List<CorrelationAttributeInstance> eamArtifacts, BlackboardArtifact artifact, ATTRIBUTE_TYPE bbAttributeType, int typeId) throws CentralRepoException, TskCoreException {
|
|
|
|
|
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(bbAttributeType));
|
|
|
|
|
private static void makeCorrAttrFromAcctArtifact(List<CorrelationAttributeInstance> corrAttrInstances, BlackboardArtifact acctArtifact) {
|
|
|
|
|
// RAMAN TODO: Convert TSK_ACCOUNT_TYPE attribute to correlation attribute type
|
|
|
|
|
// RAMAN TODO: Extract TSK_ID as value
|
|
|
|
|
// CorrelationAttributeInstance corrAttr = makeCorrAttr(acctArtifact, corrType, corrAttrValue);
|
|
|
|
|
// if (corrAttr != null) {
|
|
|
|
|
// corrAttrInstances.add(corrAttr);
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Makes a correlation attribute instance from a specified attribute of an
|
|
|
|
|
* artifact. The correlation attribute instance is added to an input list.
|
|
|
|
|
*
|
|
|
|
|
* @param corrAttrInstances A list of correlation attribute instances.
|
|
|
|
|
* @param artifact An artifact.
|
|
|
|
|
* @param artAttrType The type of the atrribute of the artifact that
|
|
|
|
|
* is to be made into a correlatin attribute
|
|
|
|
|
* instance.
|
|
|
|
|
* @param typeId The type ID for the desired correlation
|
|
|
|
|
* attribute instance.
|
|
|
|
|
*
|
|
|
|
|
* @throws CentralRepoException If there is an error querying the central
|
|
|
|
|
* repository.
|
|
|
|
|
* @throws TskCoreException If there is an error querying the case
|
|
|
|
|
* database.
|
|
|
|
|
*/
|
|
|
|
|
private static void makeCorrAttrFromArtifactAttr(List<CorrelationAttributeInstance> corrAttrInstances, BlackboardArtifact artifact, ATTRIBUTE_TYPE artAttrType, int typeId) throws CentralRepoException, TskCoreException {
|
|
|
|
|
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(artAttrType));
|
|
|
|
|
if (attribute != null) {
|
|
|
|
|
String value = attribute.getValueString();
|
|
|
|
|
if ((null != value) && (value.isEmpty() == false)) {
|
|
|
|
|
CorrelationAttributeInstance inst = makeCorrelationAttributeInstanceUsingTypeValue(artifact, CentralRepository.getInstance().getCorrelationTypeById(typeId), value);
|
|
|
|
|
CorrelationAttributeInstance inst = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(typeId), value);
|
|
|
|
|
if (inst != null) {
|
|
|
|
|
eamArtifacts.add(inst);
|
|
|
|
|
corrAttrInstances.add(inst);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Uses the determined type and vallue, then looks up instance details to
|
|
|
|
|
* create proper CorrelationAttributeInstance.
|
|
|
|
|
* Makes a correlation attribute instance of a given type from an artifact.
|
|
|
|
|
*
|
|
|
|
|
* @param bbArtifact the blackboard artifactForInstance
|
|
|
|
|
* @param correlationType the given type
|
|
|
|
|
* @param value the artifactForInstance value
|
|
|
|
|
* @param artifact The artifact.
|
|
|
|
|
* @param correlationType the correlation attribute type.
|
|
|
|
|
* @param value The correlation attribute value.
|
|
|
|
|
*
|
|
|
|
|
* @return CorrelationAttributeInstance from details, or null if validation
|
|
|
|
|
* failed or another error occurred
|
|
|
|
|
* TODO (Jira-6088): The methods in this low-level, utility class should
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* @return The correlation attribute instance or null, if an error occurred.
|
|
|
|
|
*/
|
|
|
|
|
private static CorrelationAttributeInstance makeCorrelationAttributeInstanceUsingTypeValue(BlackboardArtifact bbArtifact, CorrelationAttributeInstance.Type correlationType, String value) {
|
|
|
|
|
private static CorrelationAttributeInstance makeCorrAttr(BlackboardArtifact artifact, CorrelationAttributeInstance.Type correlationType, String value) {
|
|
|
|
|
try {
|
|
|
|
|
Case currentCase = Case.getCurrentCaseThrows();
|
|
|
|
|
AbstractFile bbSourceFile = currentCase.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID());
|
|
|
|
|
AbstractFile bbSourceFile = currentCase.getSleuthkitCase().getAbstractFileById(artifact.getObjectID());
|
|
|
|
|
if (null == bbSourceFile) {
|
|
|
|
|
logger.log(Level.SEVERE, "Error creating artifact instance. Abstract File was null."); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make an instance for the BB source file
|
|
|
|
|
CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows());
|
|
|
|
|
return new CorrelationAttributeInstance(
|
|
|
|
|
correlationType,
|
|
|
|
@ -212,31 +316,34 @@ public class CorrelationAttributeUtil {
|
|
|
|
|
bbSourceFile.getId());
|
|
|
|
|
|
|
|
|
|
} catch (TskCoreException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, "Error getting AbstractFile for artifact: " + bbArtifact.toString(), ex); // NON-NLS
|
|
|
|
|
logger.log(Level.SEVERE, String.format("Error getting querying case database (%s)", artifact), ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
} catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
|
|
|
|
|
logger.log(Level.WARNING, "Error creating artifact instance for artifact: " + bbArtifact.toString(), ex); // NON-NLS
|
|
|
|
|
logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", artifact), ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
} catch (NoCurrentCaseException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS
|
|
|
|
|
logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Retrieve CorrelationAttribute from the given Content.
|
|
|
|
|
* Gets the correlation attribute instance for a file.
|
|
|
|
|
*
|
|
|
|
|
* @param content The content object
|
|
|
|
|
* @param file The file.
|
|
|
|
|
*
|
|
|
|
|
* @return The new CorrelationAttribute, or null if retrieval failed.
|
|
|
|
|
* TODO (Jira-6088): The methods in this low-level, utility class should
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* @return The correlation attribute instance or null, if no such
|
|
|
|
|
* correlation attribute instance was found or an error occurred.
|
|
|
|
|
*/
|
|
|
|
|
public static CorrelationAttributeInstance getInstanceFromContent(Content content) {
|
|
|
|
|
|
|
|
|
|
if (!(content instanceof AbstractFile)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final AbstractFile file = (AbstractFile) content;
|
|
|
|
|
public static CorrelationAttributeInstance getCorrAttrForFile(AbstractFile file) {
|
|
|
|
|
|
|
|
|
|
if (!isSupportedAbstractFileType(file)) {
|
|
|
|
|
return null;
|
|
|
|
@ -254,11 +361,14 @@ public class CorrelationAttributeUtil {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource());
|
|
|
|
|
} catch (TskCoreException | CentralRepoException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, "Error retrieving correlation attribute.", ex);
|
|
|
|
|
} catch (TskCoreException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, String.format("Error getting querying case database (%s)", file), ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
} catch (CentralRepoException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
} catch (NoCurrentCaseException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, "Case is closed.", ex);
|
|
|
|
|
logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -266,20 +376,22 @@ public class CorrelationAttributeUtil {
|
|
|
|
|
try {
|
|
|
|
|
correlationAttributeInstance = CentralRepository.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, file.getId());
|
|
|
|
|
} catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
|
|
|
|
|
logger.log(Level.WARNING, String.format(
|
|
|
|
|
"Correlation attribute could not be retrieved for '%s' (id=%d): ",
|
|
|
|
|
content.getName(), content.getId()), ex);
|
|
|
|
|
logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
//if there was no correlation attribute found for the item using object_id then check for attributes added with schema 1,1 which lack object_id
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If no correlation attribute instance was found when querying by file
|
|
|
|
|
* object ID, try searching by file path instead. This is necessary
|
|
|
|
|
* because file object IDs were not stored in the central repository in
|
|
|
|
|
* early versions of its schema.
|
|
|
|
|
*/
|
|
|
|
|
if (correlationAttributeInstance == null && file.getMd5Hash() != null) {
|
|
|
|
|
String filePath = (file.getParentPath() + file.getName()).toLowerCase();
|
|
|
|
|
try {
|
|
|
|
|
correlationAttributeInstance = CentralRepository.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, file.getMd5Hash(), filePath);
|
|
|
|
|
} catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
|
|
|
|
|
logger.log(Level.WARNING, String.format(
|
|
|
|
|
"Correlation attribute could not be retrieved for '%s' (id=%d): ",
|
|
|
|
|
content.getName(), content.getId()), ex);
|
|
|
|
|
logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -288,32 +400,31 @@ public class CorrelationAttributeUtil {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create an EamArtifact from the given Content. Will return null if an
|
|
|
|
|
* artifactForInstance can not be created - this is not necessarily an error
|
|
|
|
|
* case, it just means an artifactForInstance can't be made. If creation
|
|
|
|
|
* fails due to an error (and not that the file is the wrong type or it has
|
|
|
|
|
* no hash), the error will be logged before returning.
|
|
|
|
|
* Makes a correlation attribute instance for a file.
|
|
|
|
|
*
|
|
|
|
|
* Does not add the artifactForInstance to the database.
|
|
|
|
|
* IMPORTANT: The correlation attribute instance is NOT added to the central
|
|
|
|
|
* repository by this method.
|
|
|
|
|
*
|
|
|
|
|
* @param content The content object
|
|
|
|
|
* TODO (Jira-6088): The methods in this low-level, utility class should
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* @return The new EamArtifact or null if creation failed
|
|
|
|
|
* @param file The file.
|
|
|
|
|
*
|
|
|
|
|
* @return The correlation attribute instance or null, if an error occurred.
|
|
|
|
|
*/
|
|
|
|
|
public static CorrelationAttributeInstance makeInstanceFromContent(Content content) {
|
|
|
|
|
public static CorrelationAttributeInstance makeCorrAttrFromFile(AbstractFile file) {
|
|
|
|
|
|
|
|
|
|
if (!(content instanceof AbstractFile)) {
|
|
|
|
|
if (!isSupportedAbstractFileType(file)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final AbstractFile af = (AbstractFile) content;
|
|
|
|
|
|
|
|
|
|
if (!isSupportedAbstractFileType(af)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We need a hash to make the artifactForInstance
|
|
|
|
|
String md5 = af.getMd5Hash();
|
|
|
|
|
// We need a hash to make the correlation artifact instance.
|
|
|
|
|
String md5 = file.getMd5Hash();
|
|
|
|
|
if (md5 == null || md5.isEmpty() || HashUtility.isNoDataMd5(md5)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
@ -324,31 +435,33 @@ public class CorrelationAttributeUtil {
|
|
|
|
|
CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows());
|
|
|
|
|
return new CorrelationAttributeInstance(
|
|
|
|
|
filesType,
|
|
|
|
|
af.getMd5Hash(),
|
|
|
|
|
file.getMd5Hash(),
|
|
|
|
|
correlationCase,
|
|
|
|
|
CorrelationDataSource.fromTSKDataSource(correlationCase, af.getDataSource()),
|
|
|
|
|
af.getParentPath() + af.getName(),
|
|
|
|
|
CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource()),
|
|
|
|
|
file.getParentPath() + file.getName(),
|
|
|
|
|
"",
|
|
|
|
|
TskData.FileKnown.UNKNOWN,
|
|
|
|
|
af.getId());
|
|
|
|
|
file.getId());
|
|
|
|
|
|
|
|
|
|
} catch (TskCoreException | CentralRepoException | CorrelationAttributeNormalizationException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, "Error making correlation attribute.", ex);
|
|
|
|
|
} catch (TskCoreException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, String.format("Error querying case database (%s)", file), ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
} catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
} catch (NoCurrentCaseException ex) {
|
|
|
|
|
logger.log(Level.SEVERE, "Case is closed.", ex);
|
|
|
|
|
logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check whether the given abstract file should be processed for the central
|
|
|
|
|
* repository.
|
|
|
|
|
* Checks whether or not a file is of a type that can be added to the
|
|
|
|
|
* central repository as a correlation attribute instance.
|
|
|
|
|
*
|
|
|
|
|
* @param file The file to test
|
|
|
|
|
* @param file A file.
|
|
|
|
|
*
|
|
|
|
|
* @return true if the file should be added to the central repo, false
|
|
|
|
|
* otherwise
|
|
|
|
|
* @return True or false.
|
|
|
|
|
*/
|
|
|
|
|
public static boolean isSupportedAbstractFileType(AbstractFile file) {
|
|
|
|
|
if (file == null) {
|
|
|
|
@ -375,9 +488,9 @@ public class CorrelationAttributeUtil {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructs a new EamArtifactUtil
|
|
|
|
|
* Prevent instantiation of this utility class.
|
|
|
|
|
*/
|
|
|
|
|
private CorrelationAttributeUtil() {
|
|
|
|
|
//empty constructor
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|