From db1f0e020df05fb7cd27f1c5420e5b6d7bd404e8 Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Fri, 27 Aug 2021 02:12:17 -0400 Subject: [PATCH 01/13] Parse unicode characters in shellbags Parse Unicode characters in shellbags --- .../recentactivity/ShellBagParser.java | 6 +++-- thirdparty/rr-full/plugins/shellbags.pl | 24 +++++++++++++------ thirdparty/rr-full/plugins/shellbags_test.pl | 17 ++++++++++--- thirdparty/rr-full/plugins/shellbags_xp.pl | 17 ++++++++++--- thirdparty/rr-full/shellitems.pl | 17 ++++++++++--- 5 files changed, 63 insertions(+), 18 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java index 9d36233407..85c13c6a1d 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java @@ -22,10 +22,12 @@ package org.sleuthkit.autopsy.recentactivity; import java.io.BufferedReader; -import java.io.FileReader; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -63,7 +65,7 @@ class ShellBagParser { ShellBagParser sbparser = new ShellBagParser(); - try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(regfile), StandardCharsets.UTF_8))) { String line = reader.readLine(); while (line != null) { line = line.trim(); diff --git a/thirdparty/rr-full/plugins/shellbags.pl b/thirdparty/rr-full/plugins/shellbags.pl index f4400cb4f0..de5009a494 100644 --- a/thirdparty/rr-full/plugins/shellbags.pl +++ b/thirdparty/rr-full/plugins/shellbags.pl @@ -42,6 +42,7 @@ package shellbags; use strict; use Time::Local; +use Encode::Unicode; my %config = (hive => "USRCLASS\.DAT", hivemask => 32, @@ -779,7 +780,7 @@ sub parseFolderEntry { $tag = 0; } else { - $str .= $s; + $str .= $s; $cnt++; } } @@ -799,7 +800,7 @@ sub parseFolderEntry { $tag = 0; } else { - $str .= $s; + $str .= $s; $cnt++; } } @@ -858,13 +859,12 @@ sub parseFolderEntry { my $str = substr($data,$ofs,length($data) - 30); my $longname = (split(/\00\00/,$str,2))[0]; - $longname =~ s/\00//g; if ($longname ne "") { - $item{name} = $longname; + $item{name} = _uniToAscii($longname); } else { - $item{name} = $shortname; + $item{name} = _uniToAscii($shortname); } } return %item; @@ -957,7 +957,7 @@ sub parseFolderEntry2 { $item{name} = (split(/\00\00/,$str,2))[0]; $item{name} =~ s/\13\20/\2D\00/; - $item{name} =~ s/\00//g; + $item{name} = _uniToAscii($item{name}); return %item; } @@ -1024,7 +1024,7 @@ sub shellItem0x52 { $tag = 0; } else { - $item{name} .= $d; + $item{name} .= $d; $cnt += 2; } } @@ -1119,4 +1119,14 @@ sub getNum48 { } } +#--------------------------------------------------------------------- +# _uniToAscii() +#--------------------------------------------------------------------- +sub _uniToAscii { + my $str = $_[0]; + Encode::from_to($str,'UTF-16LE','utf8'); + $str = Encode::decode_utf8($str); + return $str; +} + 1; \ No newline at end of file diff --git a/thirdparty/rr-full/plugins/shellbags_test.pl b/thirdparty/rr-full/plugins/shellbags_test.pl index 7ff3a5a4d5..aa444d2808 100644 --- a/thirdparty/rr-full/plugins/shellbags_test.pl +++ b/thirdparty/rr-full/plugins/shellbags_test.pl @@ -8,6 +8,7 @@ #----------------------------------------------------------- package shellbags_test; use strict; +use Encode::Unicode; require 'shellitems.pl'; @@ -100,7 +101,7 @@ sub traverse { my $type = unpack("C",substr($values{$v},2,1)); my $size = unpack("v",substr($values{$v},0,2)); # probe($values{$v}); - + # Need to first check to see if the parent of the item was a zip folder # and if the 'zipsubfolder' value is set to 1 if (exists ${$parent}{zipsubfolder} && ${$parent}{zipsubfolder} == 1) { @@ -411,12 +412,22 @@ sub parseFolderItem { $longname =~ s/\x00//g; if ($longname ne "") { - $item{name} = $longname; + $item{name} = _uniToAscii($longname); } else { - $item{name} = $shortname; + $item{name} = _uniToAscii($shortname); } return %item; } +#--------------------------------------------------------------------- +# _uniToAscii() +#--------------------------------------------------------------------- +sub _uniToAscii { + my $str = $_[0]; + Encode::from_to($str,'UTF-16LE','utf8'); + $str = Encode::decode_utf8($str); + return $str; +} + 1; diff --git a/thirdparty/rr-full/plugins/shellbags_xp.pl b/thirdparty/rr-full/plugins/shellbags_xp.pl index ce90cc3e7f..d503f1ab07 100644 --- a/thirdparty/rr-full/plugins/shellbags_xp.pl +++ b/thirdparty/rr-full/plugins/shellbags_xp.pl @@ -36,6 +36,7 @@ package shellbags_xp; use strict; use Time::Local; +use Encode::Unicode; my %config = (hive => "NTUSER\.DAT", hivemask => 32, @@ -779,10 +780,10 @@ sub parseFolderEntry { $longname =~ s/\x00//g; if ($longname ne "") { - $item{name} = $longname; + $item{name} = _uniToAscii($longname); } else { - $item{name} = $shortname; + $item{name} = _uniToAscii($shortname); } return %item; } @@ -871,7 +872,7 @@ sub parseFolderEntry2 { $item{name} = (split(/\x00\x00/,$str,2))[0]; $item{name} =~ s/\x13\x20/\x2D\x00/; - $item{name} =~ s/\x00//g; + $item{name} = _uniToAscii($item{name}); return %item; } @@ -931,4 +932,14 @@ sub printData { return @display; } +#--------------------------------------------------------------------- +# _uniToAscii() +#--------------------------------------------------------------------- +sub _uniToAscii { + my $str = $_[0]; + Encode::from_to($str,'UTF-16LE','utf8'); + $str = Encode::decode_utf8($str); + return $str; +} + 1; diff --git a/thirdparty/rr-full/shellitems.pl b/thirdparty/rr-full/shellitems.pl index 5ec51cd6a2..33e03759f7 100644 --- a/thirdparty/rr-full/shellitems.pl +++ b/thirdparty/rr-full/shellitems.pl @@ -27,6 +27,7 @@ # Author: H. Carvey, keydet89@yahoo.com #----------------------------------------------------------- use Time::Local; +use Encode::Unicode; my %guids = ("{bb64f8a7-bee7-4e1a-ab8d-7d8273f7fdb6}" => "Action Center", "{7a979262-40ce-46ff-aeee-7884ac3b6136}" => "Add Hardware", @@ -634,10 +635,10 @@ sub parseFolderEntry { $longname =~ s/\x00//g; if ($longname ne "") { - $item{name} = $longname; + $item{name} = _uniToAscii($longname); } else { - $item{name} = $shortname; + $item{name} = _uniToAscii($shortname); } return %item; } @@ -716,7 +717,7 @@ sub parseFolderEntry2 { $item{name} = (split(/\x00\x00/,$str,2))[0]; $item{name} =~ s/\x13\x20/\x2D\x00/; - $item{name} =~ s/\x00//g; + $item{name} = _uniToAscii($item{name}); return %item; } @@ -837,4 +838,14 @@ sub getNum48 { } } +#--------------------------------------------------------------------- +# _uniToAscii() +#--------------------------------------------------------------------- +sub _uniToAscii { + my $str = $_[0]; + Encode::from_to($str,'UTF-16LE','utf8'); + $str = Encode::decode_utf8($str); + return $str; +} + 1; From 90bda71c1d21a0b30836232bf2288d57c5328580 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Fri, 27 Aug 2021 12:06:19 -0400 Subject: [PATCH 02/13] Initial refactor of CorrelationUtils. Not complete --- .../application/OtherOccurrences.java | 2 +- .../datamodel/CorrelationAttributeUtil.java | 285 +++++++++--------- .../eventlisteners/CaseEventListener.java | 4 +- .../application/Annotations.java | 2 +- .../autopsy/datamodel/GetSCOTask.java | 2 +- 5 files changed, 142 insertions(+), 153 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java index 80e4ada388..cd11c19438 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java @@ -116,7 +116,7 @@ public final class OtherOccurrences { // correlate on blackboard artifact attributes if they exist and supported BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node); if (bbArtifact != null && CentralRepository.isEnabled()) { - ret.addAll(CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact)); + ret.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch(bbArtifact)); } // we can correlate based on the MD5 if it is enabled diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index 6d2ff51c01..776220d880 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; import java.util.logging.Level; +import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -32,6 +33,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.Cent import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; +import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -69,7 +71,7 @@ public class CorrelationAttributeUtil { * 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. + * TODO (Jira-6088): We should not have multiple definitions of this string. * * @return The display name of the email address correlation attribute type. */ @@ -78,28 +80,6 @@ public class CorrelationAttributeUtil { return Bundle.CorrelationAttributeUtil_emailaddresses_text(); } - // Defines which artifact types act as the sources for CR data. - // Most notably, does not include KEYWORD HIT, CALLLOGS, MESSAGES, CONTACTS - // TSK_INTERESTING_ARTIFACT_HIT (See JIRA-6129 for more details on the - // interesting artifact hit). - // IMPORTANT: This set should be updated for new artifacts types that need to - // be inserted into the CR. - private static final Set SOURCE_TYPES_FOR_CR_INSERT = new HashSet() { - { - addAll(DOMAIN_ARTIFACT_TYPE_IDS); - - add(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()); - add(ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()); - add(ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID()); - add(ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID()); - add(ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()); - add(ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()); - add(ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()); - add(ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()); - add(ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()); - add(ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID()); - } - }; /** * Makes zero to many correlation attribute instances from the attributes of @@ -114,17 +94,55 @@ public class CorrelationAttributeUtil { * @return A list, possibly empty, of correlation attribute instances for * the artifact. */ - public static List makeCorrAttrsToSave(BlackboardArtifact artifact) { - if (SOURCE_TYPES_FOR_CR_INSERT.contains(artifact.getArtifactTypeID())) { - // Restrict the correlation attributes to use for saving. - // The artifacts which are suitable for saving are a subset of the - // artifacts that are suitable for correlating. - return makeCorrAttrsForCorrelation(artifact); + public static List makeCorrAttrsToSave(DataArtifact artifact) { + int artifactTypeID = artifact.getArtifactTypeID(); + // @@@ TODO Add a comment about why we do not save these. + // BC: I forget the history on these... + if (artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) { + return new ArrayList<>(); } - // Return an empty collection. + + return CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact); + } + + //public static List makeCorrAttrsToSave(AbstactFile file) { + // @@@ TODO Call into makeCorrAttrsForSearch(file) when API changes + // AND move logic that perhaps in the ingest module into here. + // return makeCorrAttrsForSearch(file); + //} + + public static List makeCorrAttrsToSave(Content content) { return new ArrayList<>(); } - + + public static List makeCorrAttrsForSearch(Content content) { + return new ArrayList<>(); + } + + public static List makeCorrAttrsForSearch(AnalysisResult artifact) { + try { + if (BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.equals(artifact.getType())) { + BlackboardAttribute assocArtifactAttr = artifact.getAttribute(BlackboardAttribute.Type.TSK_ASSOCIATED_ARTIFACT); + if (assocArtifactAttr != null) { + BlackboardArtifact sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong()); + return CorrelationAttributeUtil.makeCorrAttrsForSearch(sourceArtifact); + } + } + Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); + + return CorrelationAttributeUtil.makeCorrAttrsForSearch(content); + // @@@ TODO ADD Error Handling + } catch (TskCoreException ex) { + Exceptions.printStackTrace(ex); + } catch (NoCurrentCaseException ex) { + Exceptions.printStackTrace(ex); + } + return new ArrayList<>(); + } + + /** * Makes zero to many correlation attribute instances from the attributes of * artifacts that have correlatable data. The intention of this method is to @@ -149,91 +167,89 @@ public class CorrelationAttributeUtil { * @return A list, possibly empty, of correlation attribute instances for * the artifact. */ - public static List makeCorrAttrsForCorrelation(BlackboardArtifact artifact) { + public static List makeCorrAttrsForSearch(DataArtifact artifact) { List correlationAttrs = new ArrayList<>(); try { - BlackboardArtifact sourceArtifact = getCorrAttrSourceArtifact(artifact); - if (sourceArtifact != null) { + + List attributes = artifact.getAttributes(); - List attributes = sourceArtifact.getAttributes(); - - int artifactTypeID = sourceArtifact.getArtifactTypeID(); - if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - BlackboardAttribute setNameAttr = getAttribute(attributes, 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, attributes); - } - } else if (DOMAIN_ARTIFACT_TYPE_IDS.contains(artifactTypeID)) { - BlackboardAttribute domainAttr = getAttribute(attributes, new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN)); - if ((domainAttr != null) - && !domainsToSkip.contains(domainAttr.getValueString())) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID, attributes); - } - } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) { - // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times - Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID()); - Content dataSource = sourceContent.getDataSource(); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID, - attributes, sourceContent, dataSource); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, - attributes, sourceContent, dataSource); - - } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID, attributes); - - } 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, attributes); - - } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) { - // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times - Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID()); - Content dataSource = sourceContent.getDataSource(); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID, - attributes, sourceContent, dataSource); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID, - attributes, sourceContent, dataSource); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID, - attributes, sourceContent, dataSource); - - } else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) { - // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times - Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID()); - Content dataSource = sourceContent.getDataSource(); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID, - attributes, sourceContent, dataSource); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID, - attributes, sourceContent, dataSource); - - } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) { - // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times - Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID()); - Content dataSource = sourceContent.getDataSource(); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID, - attributes, sourceContent, dataSource); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID, - attributes, sourceContent, dataSource); - - } else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { - makeCorrAttrFromAcctArtifact(correlationAttrs, sourceArtifact); - - } else if (artifactTypeID == ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID()) { - BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH)); - String pathAttrString = null; - if (setNameAttr != null) { - pathAttrString = setNameAttr.getValueString(); - } - if (pathAttrString != null && !pathAttrString.isEmpty()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes); - } else { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes); - } - } else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() - || artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() - || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) { - makeCorrAttrsFromCommunicationArtifacts(correlationAttrs, sourceArtifact, attributes); + int artifactTypeID = artifact.getArtifactTypeID(); + //if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + // BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); + // if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) { + // makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID, attributes); + // } + //} else + if (DOMAIN_ARTIFACT_TYPE_IDS.contains(artifactTypeID)) { + BlackboardAttribute domainAttr = getAttribute(attributes, new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN)); + if ((domainAttr != null) + && !domainsToSkip.contains(domainAttr.getValueString())) { + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID, attributes); } + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) { + // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times + Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); + Content dataSource = sourceContent.getDataSource(); + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID, + attributes, sourceContent, dataSource); + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, + attributes, sourceContent, dataSource); + + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) { + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID, attributes); + + } 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, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, attributes); + + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) { + // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times + Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); + Content dataSource = sourceContent.getDataSource(); + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID, + attributes, sourceContent, dataSource); + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID, + attributes, sourceContent, dataSource); + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID, + attributes, sourceContent, dataSource); + + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) { + // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times + Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); + Content dataSource = sourceContent.getDataSource(); + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID, + attributes, sourceContent, dataSource); + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID, + attributes, sourceContent, dataSource); + + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) { + // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times + Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); + Content dataSource = sourceContent.getDataSource(); + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID, + attributes, sourceContent, dataSource); + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID, + attributes, sourceContent, dataSource); + + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + makeCorrAttrFromAcctArtifact(correlationAttrs, artifact); + + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID()) { + BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH)); + String pathAttrString = null; + if (setNameAttr != null) { + pathAttrString = setNameAttr.getValueString(); + } + if (pathAttrString != null && !pathAttrString.isEmpty()) { + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes); + } else { + makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes); + } + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) { + makeCorrAttrsFromCommunicationArtifacts(correlationAttrs, artifact, attributes); } } catch (CorrelationAttributeNormalizationException ex) { logger.log(Level.WARNING, String.format("Error normalizing correlation attribute (%s)", artifact), ex); // NON-NLS @@ -320,40 +336,7 @@ public class CorrelationAttributeUtil { } } - /** - * Gets the associated artifact of a "meta-artifact" such as an "interesting - * artifact hit" or "previously seen" 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 if (BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_SEEN.getTypeID() == artifact.getArtifactTypeID() - || BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_NOTABLE.getTypeID() == artifact.getArtifactTypeID() - || BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_UNSEEN.getTypeID() == artifact.getArtifactTypeID()) { - Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); - if (content instanceof DataArtifact) { - sourceArtifact = (BlackboardArtifact) content; - } - } - if (sourceArtifact == null) { - sourceArtifact = artifact; - } - return sourceArtifact; - } /** * Makes a correlation attribute instance for an account artifact. @@ -615,8 +598,13 @@ public class CorrelationAttributeUtil { } } + // @@@ 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. + /** - * Gets the correlation attribute instance for a file. + * Gets the correlation attribute instance for a file. This method goes to the CR + * to get an actual instance. It does not simply package the data from file + * into a generic instance object. * * @param file The file. * @@ -694,7 +682,7 @@ public class CorrelationAttributeUtil { } /** - * Makes a correlation attribute instance for a file. + * Makes a correlation attribute instance for a file. Will include the specific object ID. * * IMPORTANT: The correlation attribute instance is NOT added to the central * repository by this method. @@ -711,7 +699,8 @@ public class CorrelationAttributeUtil { * * @return The correlation attribute instance or null, if an error occurred. */ - public static CorrelationAttributeInstance makeCorrAttrFromFile(AbstractFile file) { + // @@@ TODO: Make this look like other makeCorrAttrsForSearch and return a list + public static CorrelationAttributeInstance makeCorrAttrsForSearch(AbstractFile file) { if (!isSupportedAbstractFileType(file)) { return null; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 474ac1cd85..4a1f8ae2c9 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -456,7 +456,7 @@ public final class CaseEventListener implements PropertyChangeListener { * @param knownStatus The new known status. */ private void setArtifactKnownStatus(BlackboardArtifact bbArtifact, TskData.FileKnown knownStatus) { - List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact); + List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbArtifact); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { try { dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus); @@ -528,7 +528,7 @@ public final class CaseEventListener implements PropertyChangeListener { if (!hasTagWithConflictingKnownStatus) { //Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed //with the initial set of correlation attributes this should be a single correlation attribute - List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbTag.getArtifact()); + List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbTag.getArtifact()); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java b/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java index 67124d1502..f2da95bba6 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java @@ -372,7 +372,7 @@ public class Annotations { return new ArrayList<>(); } - List> lookupKeys = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(artifact) + List> lookupKeys = CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact) .stream() .map(cai -> Pair.of(cai.getCorrelationType(), cai.getCorrelationValue())) .collect(Collectors.toList()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java index 5671ca6051..d7e56a11d7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java @@ -97,7 +97,7 @@ class GetSCOTask implements Runnable { logger.log(Level.WARNING, "Unable to get correlation type or value to determine value for O column for artifact", ex); } } else { - List listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact); + List listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbArtifact); if (listOfPossibleAttributes.size() > 1) { //Don't display anything if there is more than 1 correlation property for an artifact but let the user know description = Bundle.GetSCOTask_occurrences_multipleProperties(); From 07f39ddaa698a442768584b353ec94b6ef9a4beb Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Mon, 30 Aug 2021 13:01:17 -0400 Subject: [PATCH 03/13] Address Reviewer Comments Address Reviewer Comments --- thirdparty/rr-full/plugins/shellbags.pl | 12 ++++++------ thirdparty/rr-full/plugins/shellbags_test.pl | 14 ++------------ thirdparty/rr-full/plugins/shellbags_xp.pl | 19 ++++++------------- thirdparty/rr-full/shellitems.pl | 10 +++++----- 4 files changed, 19 insertions(+), 36 deletions(-) diff --git a/thirdparty/rr-full/plugins/shellbags.pl b/thirdparty/rr-full/plugins/shellbags.pl index de5009a494..b0e71ec299 100644 --- a/thirdparty/rr-full/plugins/shellbags.pl +++ b/thirdparty/rr-full/plugins/shellbags.pl @@ -42,7 +42,6 @@ package shellbags; use strict; use Time::Local; -use Encode::Unicode; my %config = (hive => "USRCLASS\.DAT", hivemask => 32, @@ -861,10 +860,10 @@ sub parseFolderEntry { my $longname = (split(/\00\00/,$str,2))[0]; if ($longname ne "") { - $item{name} = _uniToAscii($longname); + $item{name} = Utf16ToUtf8($longname); } else { - $item{name} = _uniToAscii($shortname); + $item{name} = UTF16ToUtf8($shortname); } } return %item; @@ -957,7 +956,7 @@ sub parseFolderEntry2 { $item{name} = (split(/\00\00/,$str,2))[0]; $item{name} =~ s/\13\20/\2D\00/; - $item{name} = _uniToAscii($item{name}); + $item{name} = Utf16ToUtf8($item{name}); return %item; } @@ -1120,13 +1119,14 @@ sub getNum48 { } #--------------------------------------------------------------------- -# _uniToAscii() +# Utf16ToUtf8() #--------------------------------------------------------------------- -sub _uniToAscii { +sub Utf16ToUtf8 { my $str = $_[0]; Encode::from_to($str,'UTF-16LE','utf8'); $str = Encode::decode_utf8($str); return $str; } + 1; \ No newline at end of file diff --git a/thirdparty/rr-full/plugins/shellbags_test.pl b/thirdparty/rr-full/plugins/shellbags_test.pl index aa444d2808..3b068ea3ac 100644 --- a/thirdparty/rr-full/plugins/shellbags_test.pl +++ b/thirdparty/rr-full/plugins/shellbags_test.pl @@ -8,7 +8,6 @@ #----------------------------------------------------------- package shellbags_test; use strict; -use Encode::Unicode; require 'shellitems.pl'; @@ -412,22 +411,13 @@ sub parseFolderItem { $longname =~ s/\x00//g; if ($longname ne "") { - $item{name} = _uniToAscii($longname); + $item{name} = Utf16ToUtf8($longname); } else { - $item{name} = _uniToAscii($shortname); + $item{name} = Utf16ToUtf8($shortname); } return %item; } -#--------------------------------------------------------------------- -# _uniToAscii() -#--------------------------------------------------------------------- -sub _uniToAscii { - my $str = $_[0]; - Encode::from_to($str,'UTF-16LE','utf8'); - $str = Encode::decode_utf8($str); - return $str; -} 1; diff --git a/thirdparty/rr-full/plugins/shellbags_xp.pl b/thirdparty/rr-full/plugins/shellbags_xp.pl index d503f1ab07..4eaea3e58d 100644 --- a/thirdparty/rr-full/plugins/shellbags_xp.pl +++ b/thirdparty/rr-full/plugins/shellbags_xp.pl @@ -36,7 +36,9 @@ package shellbags_xp; use strict; use Time::Local; -use Encode::Unicode; + +require 'shellitems.pl'; + my %config = (hive => "NTUSER\.DAT", hivemask => 32, @@ -780,10 +782,10 @@ sub parseFolderEntry { $longname =~ s/\x00//g; if ($longname ne "") { - $item{name} = _uniToAscii($longname); + $item{name} = Utf16ToUtf8($longname); } else { - $item{name} = _uniToAscii($shortname); + $item{name} = _Utf16ToUtf8($shortname); } return %item; } @@ -872,7 +874,7 @@ sub parseFolderEntry2 { $item{name} = (split(/\x00\x00/,$str,2))[0]; $item{name} =~ s/\x13\x20/\x2D\x00/; - $item{name} = _uniToAscii($item{name}); + $item{name} = Utf16ToUtf8($item{name}); return %item; } @@ -932,14 +934,5 @@ sub printData { return @display; } -#--------------------------------------------------------------------- -# _uniToAscii() -#--------------------------------------------------------------------- -sub _uniToAscii { - my $str = $_[0]; - Encode::from_to($str,'UTF-16LE','utf8'); - $str = Encode::decode_utf8($str); - return $str; -} 1; diff --git a/thirdparty/rr-full/shellitems.pl b/thirdparty/rr-full/shellitems.pl index 33e03759f7..93b71e7c20 100644 --- a/thirdparty/rr-full/shellitems.pl +++ b/thirdparty/rr-full/shellitems.pl @@ -635,10 +635,10 @@ sub parseFolderEntry { $longname =~ s/\x00//g; if ($longname ne "") { - $item{name} = _uniToAscii($longname); + $item{name} = Utf16ToUtf8($longname); } else { - $item{name} = _uniToAscii($shortname); + $item{name} = Utf16ToUtf8($shortname); } return %item; } @@ -717,7 +717,7 @@ sub parseFolderEntry2 { $item{name} = (split(/\x00\x00/,$str,2))[0]; $item{name} =~ s/\x13\x20/\x2D\x00/; - $item{name} = _uniToAscii($item{name}); + $item{name} = Utf16ToUtf8($item{name}); return %item; } @@ -839,9 +839,9 @@ sub getNum48 { } #--------------------------------------------------------------------- -# _uniToAscii() +# Utf16ToUtf8() #--------------------------------------------------------------------- -sub _uniToAscii { +sub Utf16ToUtf8 { my $str = $_[0]; Encode::from_to($str,'UTF-16LE','utf8'); $str = Encode::decode_utf8($str); From 4de91c38fc12fa6fea3223a03b2b0f77769f4f22 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 31 Aug 2021 16:21:36 -0400 Subject: [PATCH 04/13] First draft --- .../AnalysisResultsContentViewer.java | 65 ++++++++-------- .../AnalysisResultsViewModel.java | 76 +++++-------------- 2 files changed, 47 insertions(+), 94 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java index ef623f44cf..afe9387dd2 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java @@ -19,33 +19,28 @@ package org.sleuthkit.autopsy.contentviewers.analysisresults; import java.awt.Component; +import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.SwingWorker; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import org.sleuthkit.autopsy.datamodel.TskContentItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; -import org.sleuthkit.datamodel.AnalysisResult; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.datamodel.AnalysisResultItem; /** - * Displays a list of analysis results as a content viewer. + * A content viewer that displays the analysis results for a Content object. */ @ServiceProvider(service = DataContentViewer.class, position = 7) public class AnalysisResultsContentViewer implements DataContentViewer { private static final Logger logger = Logger.getLogger(AnalysisResultsContentPanel.class.getName()); - - // isPreferred value private static final int PREFERRED_VALUE = 3; - private final AnalysisResultsViewModel viewModel = new AnalysisResultsViewModel(); private final AnalysisResultsContentPanel panel = new AnalysisResultsContentPanel(); @@ -87,27 +82,35 @@ public class AnalysisResultsContentViewer implements DataContentViewer { "AnalysisResultsContentViewer_setNode_loadingMessage=Loading...", "AnalysisResultsContentViewer_setNode_errorMessage=There was an error loading results.",}) public synchronized void setNode(Node node) { - // reset the panel panel.reset(); - // if there is a worker running, cancel it if (worker != null) { worker.cancel(true); worker = null; } - // if no node, nothing to do if (node == null) { return; } + TskContentItem contentItem; + AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); + if (Objects.nonNull(analysisResultItem)) { + + } else { + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); + + } + + + // show a loading message panel.showMessage(Bundle.AnalysisResultsContentViewer_setNode_loadingMessage()); + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); - // create the worker + worker = new DataFetchWorker<>( - // load a view model from the node - (selectedNode) -> viewModel.getAnalysisResults(selectedNode), + (selectedNode) -> viewModel.getAnalysisResults(node.getLookup().lookup(TskContentItem.class), node.getLookup().lookup(AnalysisResultItem.class), (nodeAnalysisResults) -> { if (nodeAnalysisResults.getResultType() == DataFetchResult.ResultType.SUCCESS) { // if successful, display the results @@ -125,34 +128,26 @@ public class AnalysisResultsContentViewer implements DataContentViewer { @Override public boolean isSupported(Node node) { - if (node == null) { + if (Objects.isNull(node)) { return false; } - // There needs to either be a file with an AnalysisResult or an AnalysisResult in the lookup. - for (Content content : node.getLookup().lookupAll(Content.class)) { - if (content instanceof AnalysisResult) { - return true; - } + AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); + if (Objects.nonNull(analysisResultItem)) { + return true; + } + + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); + if (Objects.isNull(contentItem)) { + return false; + } - if (content == null || content instanceof BlackboardArtifact) { - continue; - } - - try { - if (Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasAnalysisResults(content.getId())) { - return true; - } - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.SEVERE, "Unable to get analysis results for file with obj id " + content.getId(), ex); - } - } - - return false; + return (contentItem.getAnalyisisResults().isEmpty() == false); } @Override public int isPreferred(Node node) { return PREFERRED_VALUE; } + } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java index 03720e0cbe..7114d1f77b 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java @@ -30,7 +30,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.Node; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.datamodel.AnalysisResultItem; +import org.sleuthkit.autopsy.datamodel.TskContentItem; import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; @@ -94,7 +97,7 @@ public class AnalysisResultsViewModel { private final List analysisResults; private final Optional selectedResult; private final Optional aggregateScore; - private final Optional content; + private final Content content; /** * Constructor. @@ -105,7 +108,7 @@ public class AnalysisResultsViewModel { * @param aggregateScore The aggregate score or empty if no score. * @param content The content associated with these results. */ - NodeResults(List analysisResults, Optional selectedResult, Optional aggregateScore, Optional content) { + NodeResults(List analysisResults, Optional selectedResult, Optional aggregateScore, Content content) { this.analysisResults = analysisResults; this.selectedResult = selectedResult; this.aggregateScore = aggregateScore; @@ -146,7 +149,7 @@ public class AnalysisResultsViewModel { * @return The content associated with these results or empty if not * present. */ - Optional getContent() { + Content getContent() { return content; } } @@ -226,6 +229,8 @@ public class AnalysisResultsViewModel { } /** + * RJCTODO + * * Returns the view model data representing the analysis results to be * displayed for the node. * @@ -233,63 +238,16 @@ public class AnalysisResultsViewModel { * * @return The analysis results view model data to display. */ - NodeResults getAnalysisResults(Node node) { - if (node == null) { - return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty(), Optional.empty()); - } - + NodeResults getAnalysisResults(TskContentItem contentItem, Optional selectedResult) { + Content content = contentItem.getTskContent(); Optional aggregateScore = Optional.empty(); - Optional nodeContent = Optional.empty(); - // maps id of analysis result to analysis result to prevent duplication - Map allAnalysisResults = new HashMap<>(); - Optional selectedResult = Optional.empty(); - - // Find first content that is not an artifact within node - for (Content content : node.getLookup().lookupAll(Content.class)) { - if (content == null || content instanceof BlackboardArtifact) { - continue; - } - - try { - nodeContent = Optional.of(content); - - // get the aggregate score of that content - aggregateScore = Optional.ofNullable(content.getAggregateScore()); - - // and add all analysis results to mapping - content.getAllAnalysisResults().stream() - .forEach((ar) -> allAnalysisResults.put(ar.getArtifactID(), ar)); - - break; - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Unable to get analysis results for content with obj id " + content.getId(), ex); - } + try { + aggregateScore = Optional.ofNullable(content.getAggregateScore()); + + } catch (TskCoreException ex) { + // RJCTODO: log error } - - // Find any analysis results in the node - Collection analysisResults = node.getLookup().lookupAll(AnalysisResult.class); - if (analysisResults.size() > 0) { - - // get any items with a score - List filteredResults = analysisResults.stream() - .collect(Collectors.toList()); - - // add them to the map to display - filteredResults.forEach((ar) -> allAnalysisResults.put(ar.getArtifactID(), ar)); - - // the selected result will be the highest scored analysis result in the node. - selectedResult = filteredResults.stream() - .max((a, b) -> a.getScore().compareTo(b.getScore())); - - // if no aggregate score determined at this point, use the selected result score. - if (!aggregateScore.isPresent()) { - aggregateScore = selectedResult.flatMap(selectedRes -> Optional.ofNullable(selectedRes.getScore())); - } - } - - // get view model representation - List displayAttributes = getOrderedDisplayAttributes(allAnalysisResults.values()); - - return new NodeResults(displayAttributes, selectedResult, aggregateScore, nodeContent); + List displayAttributes = getOrderedDisplayAttributes(contentItem.getAnalyisisResults());; + return new NodeResults(displayAttributes, selectedResult, aggregateScore, content); } } From 93c87cf7ceabc20108ce04370b65a1343e56226d Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 1 Sep 2021 12:37:26 -0400 Subject: [PATCH 05/13] 7861 Make analysis results content viewer work for data artifacts --- .../autopsy/datamodel/AnalysisResultItem.java | 51 +++++++++++++++++ .../autopsy/datamodel/TskContentItem.java | 56 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100755 Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java create mode 100755 Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java new file mode 100755 index 0000000000..442d070f5c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java @@ -0,0 +1,51 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021-2021 Basis Technology Corp. + * Contact: carrier sleuthkit 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.datamodel; + +import com.google.common.annotations.Beta; +import org.sleuthkit.datamodel.AnalysisResult; + +/** + * An Autopsy Data Model item with an underlying analysis result Sleuth Kit Data + * Model object. + */ +public class AnalysisResultItem extends TskContentItem { + + /** + * Constructs an Autopsy Data Model item with an underlying AnalysisResult + * Sleuth Kit Data Model object. + * + * @param analysisResult The analysis result. + */ + @Beta + AnalysisResultItem(AnalysisResult analysisResult) { + super(analysisResult); + } + + /** + * Gets the underlying analysis result. + * + * @return The analysis result. + */ + @Beta + public AnalysisResult getAnalysisResult() { + return (AnalysisResult) (getTskContent()); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java b/Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java new file mode 100755 index 0000000000..999474cc1d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java @@ -0,0 +1,56 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021-2021 Basis Technology Corp. + * Contact: carrier sleuthkit 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.datamodel; + +import com.google.common.annotations.Beta; +import org.sleuthkit.datamodel.Content; + +/** + * An Autopsy Data Model item with an underlying Sleuth Kit Data Model object + * that implements the Sleuth Kit Data Model's Content interface. + */ +@Beta +public class TskContentItem { + + private final Content tskContent; + + /** + * Constructs an Autopsy Data Model item with an underlying Sleuth Kit Data + * Model object that implements the Sleuth Kit Data Model's Content + * interface. + * + * @param content The underlying Sleuth Kit Data Model object. + * + */ + @Beta + TskContentItem(Content sleuthKitContent) { + this.tskContent = sleuthKitContent; + } + + /** + * Gets the underlying Sleuth Kit Data Model object. + * + * @return The Sleuth Kit Data Model object. + */ + @Beta + public Content getTskContent() { + return tskContent; + } + +} From ab61ae66638a81e909e23c668e5da499ea26e870 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 1 Sep 2021 14:53:49 -0400 Subject: [PATCH 06/13] 7852 adjust makeCorrAttrsForSearch(AbstractFile) --- .../AddEditCentralRepoCommentAction.java | 9 +++- .../Bundle.properties-MERGED | 5 +- .../application/OtherOccurrences.java | 1 - .../datamodel/Bundle.properties-MERGED | 16 +++--- .../datamodel/CorrelationAttributeUtil.java | 49 ++++++++----------- .../eventlisteners/CaseEventListener.java | 25 +++++----- 6 files changed, 50 insertions(+), 55 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index 5f47487f94..b1069ba5b9 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.centralrepository; import java.awt.event.ActionEvent; +import java.util.List; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.Action; @@ -64,7 +65,13 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { correlationAttributeInstance = CorrelationAttributeUtil.getCorrAttrForFile(file); if (correlationAttributeInstance == null) { addToDatabase = true; - correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttrFromFile(file); + final List md5CorrelationAttr = CorrelationAttributeUtil.makeCorrAttrsForSearch(file); + if (!md5CorrelationAttr.isEmpty()) { + //for an abstract file the 'list' of attributes will be a single attribute or empty and is returning a list for consistancy with other makeCorrAttrsForSearch methods per 7852 + correlationAttributeInstance = md5CorrelationAttr.get(0); + } else { + correlationAttributeInstance = null; + } } if (file.getSize() == 0) { putValue(Action.NAME, Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoCommentEmptyFile()); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties-MERGED index b4f7f835ef..b2320b5408 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties-MERGED @@ -5,10 +5,7 @@ CentralRepoCommentDialog.title.addEditCentralRepoComment=Add/Edit Central Reposi OpenIDE-Module-Name=Central Repository OpenIDE-Module-Display-Category=Ingest Module OpenIDE-Module-Short-Description=Central Repository Ingest Module -OpenIDE-Module-Long-Description=\ - Central Repository ingest module and central database. \n\n\ - The Central Repository ingest module stores attributes of artifacts matching selected correlation types into a central database.\n\ - Stored attributes are used in future cases to correlate and analyzes files and artifacts during ingest. +OpenIDE-Module-Long-Description=Central Repository ingest module and central database. \n\nThe Central Repository ingest module stores attributes of artifacts matching selected correlation types into a central database.\nStored attributes are used in future cases to correlate and analyzes files and artifacts during ingest. CentralRepoCommentDialog.commentLabel.text=Comment: CentralRepoCommentDialog.okButton.text=&OK CentralRepoCommentDialog.cancelButton.text=C&ancel diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java index cd11c19438..643f5d5de7 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java @@ -53,7 +53,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccountInstance; import org.sleuthkit.datamodel.SleuthkitCase; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED index a80f1f7d86..724758847b 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED @@ -18,18 +18,18 @@ CentralRepositoryService.serviceName=Central Repository Service CorrelationAttributeInstance.invalidName.message=Invalid database table name. Name must start with a lowercase letter and can only contain lowercase letters, numbers, and '_'. CorrelationAttributeInstance.nullName.message=Database name is null. CorrelationAttributeUtil.emailaddresses.text=Email Addresses -CorrelationType.DOMAIN.displayName=Domains -CorrelationType.EMAIL.displayName=Email Addresses -CorrelationType.FILES.displayName=Files +CorrelationType.DOMAIN.displayName=Domain +CorrelationType.EMAIL.displayName=Email Address +CorrelationType.FILES.displayName=File MD5 CorrelationType.ICCID.displayName=ICCID Number CorrelationType.IMEI.displayName=IMEI Number CorrelationType.IMSI.displayName=IMSI Number -CorrelationType.MAC.displayName=MAC Addresses +CorrelationType.MAC.displayName=MAC Address CorrelationType.OS_ACCOUNT.displayName=Os Account -CorrelationType.PHONE.displayName=Phone Numbers -CorrelationType.PROG_NAME.displayName=Installed Programs -CorrelationType.SSID.displayName=Wireless Networks -CorrelationType.USBID.displayName=USB Devices +CorrelationType.PHONE.displayName=Phone Number +CorrelationType.PROG_NAME.displayName=Installed Program +CorrelationType.SSID.displayName=Wireless Network +CorrelationType.USBID.displayName=USB Device EamArtifactInstances.knownStatus.bad=Bad EamArtifactInstances.knownStatus.known=Known EamArtifactInstances.knownStatus.unknown=Unknown diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index 776220d880..0ad1d8c6ee 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -80,7 +80,6 @@ public class CorrelationAttributeUtil { return Bundle.CorrelationAttributeUtil_emailaddresses_text(); } - /** * Makes zero to many correlation attribute instances from the attributes of * artifacts that have correlatable data. The intention of this method is to @@ -106,23 +105,22 @@ public class CorrelationAttributeUtil { return CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact); } - + //public static List makeCorrAttrsToSave(AbstactFile file) { // @@@ TODO Call into makeCorrAttrsForSearch(file) when API changes // AND move logic that perhaps in the ingest module into here. // return makeCorrAttrsForSearch(file); //} - public static List makeCorrAttrsToSave(Content content) { return new ArrayList<>(); } - + public static List makeCorrAttrsForSearch(Content content) { return new ArrayList<>(); } - + public static List makeCorrAttrsForSearch(AnalysisResult artifact) { - try { + try { if (BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.equals(artifact.getType())) { BlackboardAttribute assocArtifactAttr = artifact.getAttribute(BlackboardAttribute.Type.TSK_ASSOCIATED_ARTIFACT); if (assocArtifactAttr != null) { @@ -131,9 +129,9 @@ public class CorrelationAttributeUtil { } } Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); - + return CorrelationAttributeUtil.makeCorrAttrsForSearch(content); - // @@@ TODO ADD Error Handling + // @@@ TODO ADD Error Handling } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); } catch (NoCurrentCaseException ex) { @@ -141,8 +139,7 @@ public class CorrelationAttributeUtil { } return new ArrayList<>(); } - - + /** * Makes zero to many correlation attribute instances from the attributes of * artifacts that have correlatable data. The intention of this method is to @@ -170,7 +167,7 @@ public class CorrelationAttributeUtil { public static List makeCorrAttrsForSearch(DataArtifact artifact) { List correlationAttrs = new ArrayList<>(); try { - + List attributes = artifact.getAttributes(); int artifactTypeID = artifact.getArtifactTypeID(); @@ -336,8 +333,6 @@ public class CorrelationAttributeUtil { } } - - /** * Makes a correlation attribute instance for an account artifact. * @@ -600,11 +595,10 @@ public class CorrelationAttributeUtil { // @@@ 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. - /** - * Gets the correlation attribute instance for a file. This method goes to the CR - * to get an actual instance. It does not simply package the data from file - * into a generic instance object. + * Gets the correlation attribute instance for a file. This method goes to + * the CR to get an actual instance. It does not simply package the data + * from file into a generic instance object. * * @param file The file. * @@ -682,7 +676,8 @@ public class CorrelationAttributeUtil { } /** - * Makes a correlation attribute instance for a file. Will include the specific object ID. + * Makes a correlation attribute instance for a file. Will include the + * specific object ID. * * IMPORTANT: The correlation attribute instance is NOT added to the central * repository by this method. @@ -700,23 +695,23 @@ public class CorrelationAttributeUtil { * @return The correlation attribute instance or null, if an error occurred. */ // @@@ TODO: Make this look like other makeCorrAttrsForSearch and return a list - public static CorrelationAttributeInstance makeCorrAttrsForSearch(AbstractFile file) { - + public static List makeCorrAttrsForSearch(AbstractFile file) { + List fileTypeList = new ArrayList<>(); // will be an empty or single element list as was decided in 7852 if (!isSupportedAbstractFileType(file)) { - return null; + return fileTypeList; } // We need a hash to make the correlation artifact instance. String md5 = file.getMd5Hash(); if (md5 == null || md5.isEmpty() || HashUtility.isNoDataMd5(md5)) { - return null; + return fileTypeList; } try { CorrelationAttributeInstance.Type filesType = CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID); CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); - return new CorrelationAttributeInstance( + fileTypeList.add(new CorrelationAttributeInstance( filesType, file.getMd5Hash(), correlationCase, @@ -724,21 +719,17 @@ public class CorrelationAttributeUtil { file.getParentPath() + file.getName(), "", TskData.FileKnown.UNKNOWN, - file.getId()); - + file.getId())); } catch (TskCoreException ex) { logger.log(Level.SEVERE, String.format("Error 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 (CorrelationAttributeNormalizationException ex) { logger.log(Level.WARNING, String.format("Error creating correlation attribute instance (%s)", file), ex); // NON-NLS - return null; } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS - return null; } + return fileTypeList; } /** diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 4a1f8ae2c9..1f1bd3923f 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -311,18 +311,18 @@ public final class CaseEventListener implements PropertyChangeListener { * Sets the known status for the correlation attribute instance for the * given abstract file. * - * @param af The abstract file for which to set the correlation - * attribute instance. + * @param af The abstract file for which to set the correlation + * attribute instance. * @param knownStatus The new known status for the correlation attribute - * instance. + * instance. */ private void setContentKnownStatus(AbstractFile af, TskData.FileKnown knownStatus) { - final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile(af); - - if (eamArtifact != null) { + final List md5CorrelationAttr = CorrelationAttributeUtil.makeCorrAttrsForSearch(af); + if (!md5CorrelationAttr.isEmpty()) { + //for an abstract file the 'list' of attributes will be a single attribute or empty and is returning a list for consistancy with other makeCorrAttrsForSearch methods per 7852 // send update to Central Repository db try { - dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus); + dbManager.setAttributeInstanceKnownStatus(md5CorrelationAttr.get(0), knownStatus); } catch (CentralRepoException ex) { LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS } @@ -407,7 +407,7 @@ public final class CaseEventListener implements PropertyChangeListener { * for the item. If there are, set known status as notable. If not set * status as unknown. * - * @param content The content for the tag that was added or deleted. + * @param content The content for the tag that was added or deleted. * @param bbArtifact The artifact for the tag that was added or deleted. */ private void handleTagChange(Content content, BlackboardArtifact bbArtifact) { @@ -452,7 +452,7 @@ public final class CaseEventListener implements PropertyChangeListener { * Sets the known status of a blackboard artifact in the central * repository. * - * @param bbArtifact The blackboard artifact to set known status. + * @param bbArtifact The blackboard artifact to set known status. * @param knownStatus The new known status. */ private void setArtifactKnownStatus(BlackboardArtifact bbArtifact, TskData.FileKnown knownStatus) { @@ -566,9 +566,10 @@ public final class CaseEventListener implements PropertyChangeListener { if (!hasTagWithConflictingKnownStatus) { Content taggedContent = contentTag.getContent(); if (taggedContent instanceof AbstractFile) { - final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile((AbstractFile) taggedContent); - if (eamArtifact != null) { - CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); + final List eamArtifact = CorrelationAttributeUtil.makeCorrAttrsForSearch((AbstractFile) taggedContent); + if (!eamArtifact.isEmpty()) { + //for an abstract file the 'list' of attributes will be a single attribute or empty and is returning a list for consistancy with other makeCorrAttrsForSearch methods per 7852 + CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact.get(0), tagName.getKnownStatus()); } } } From eabef9175d51462adf502991ab8888e7d178eab3 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 1 Sep 2021 16:28:11 -0400 Subject: [PATCH 07/13] 7861 Make analysis results content viewer work for data artifacts --- .../AnalysisResultsContentViewer.java | 44 +++--- .../AnalysisResultsViewModel.java | 71 +++++++--- .../datamodel/AbstractContentNode.java | 2 +- .../datamodel/BlackboardArtifactNode.java | 128 ++++++++++-------- 4 files changed, 141 insertions(+), 104 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java index afe9387dd2..b056eb11db 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java @@ -26,12 +26,15 @@ import javax.swing.SwingWorker; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.datamodel.TskContentItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.datamodel.Content; import org.sleuthkit.autopsy.datamodel.AnalysisResultItem; +import org.sleuthkit.datamodel.TskCoreException; /** * A content viewer that displays the analysis results for a Content object. @@ -82,35 +85,27 @@ public class AnalysisResultsContentViewer implements DataContentViewer { "AnalysisResultsContentViewer_setNode_loadingMessage=Loading...", "AnalysisResultsContentViewer_setNode_errorMessage=There was an error loading results.",}) public synchronized void setNode(Node node) { + // reset the panel panel.reset(); + // if there is a worker running, cancel it if (worker != null) { worker.cancel(true); worker = null; } + // if no node, nothing to do if (node == null) { return; } - TskContentItem contentItem; - AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); - if (Objects.nonNull(analysisResultItem)) { - - } else { - TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); - - } - - - // show a loading message panel.showMessage(Bundle.AnalysisResultsContentViewer_setNode_loadingMessage()); - TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); - + // create the worker worker = new DataFetchWorker<>( - (selectedNode) -> viewModel.getAnalysisResults(node.getLookup().lookup(TskContentItem.class), node.getLookup().lookup(AnalysisResultItem.class), + // load a view model from the node + (selectedNode) -> viewModel.getAnalysisResults(selectedNode), (nodeAnalysisResults) -> { if (nodeAnalysisResults.getResultType() == DataFetchResult.ResultType.SUCCESS) { // if successful, display the results @@ -135,14 +130,21 @@ public class AnalysisResultsContentViewer implements DataContentViewer { AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); if (Objects.nonNull(analysisResultItem)) { return true; - } - - TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); - if (Objects.isNull(contentItem)) { - return false; - } + } - return (contentItem.getAnalyisisResults().isEmpty() == false); + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); + if (!Objects.isNull(contentItem)) { + Content content = contentItem.getTskContent(); + try { + if (Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasAnalysisResults(content.getId())) { + return true; + } + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error getting analysis results for Content (object ID = %d)", content.getId()), ex); + } + } + + return false; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java index 7114d1f77b..508c9966fe 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java @@ -20,9 +20,8 @@ package org.sleuthkit.autopsy.contentviewers.analysisresults; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; @@ -30,18 +29,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.Node; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.datamodel.AnalysisResultItem; import org.sleuthkit.autopsy.datamodel.TskContentItem; import org.sleuthkit.datamodel.AnalysisResult; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.TskCoreException; /** - * * Creates a representation of a list of analysis results gathered from a node. */ public class AnalysisResultsViewModel { @@ -75,7 +71,7 @@ public class AnalysisResultsViewModel { * @return The attributes to display. */ List> getAttributesToDisplay() { - return attributesToDisplay; + return Collections.unmodifiableList(attributesToDisplay); } /** @@ -97,7 +93,7 @@ public class AnalysisResultsViewModel { private final List analysisResults; private final Optional selectedResult; private final Optional aggregateScore; - private final Content content; + private final Optional content; /** * Constructor. @@ -108,7 +104,7 @@ public class AnalysisResultsViewModel { * @param aggregateScore The aggregate score or empty if no score. * @param content The content associated with these results. */ - NodeResults(List analysisResults, Optional selectedResult, Optional aggregateScore, Content content) { + NodeResults(List analysisResults, Optional selectedResult, Optional aggregateScore, Optional content) { this.analysisResults = analysisResults; this.selectedResult = selectedResult; this.aggregateScore = aggregateScore; @@ -121,7 +117,7 @@ public class AnalysisResultsViewModel { * @return The analysis results to be displayed. */ List getAnalysisResults() { - return analysisResults; + return Collections.unmodifiableList(analysisResults); } /** @@ -149,7 +145,7 @@ public class AnalysisResultsViewModel { * @return The content associated with these results or empty if not * present. */ - Content getContent() { + Optional getContent() { return content; } } @@ -229,8 +225,6 @@ public class AnalysisResultsViewModel { } /** - * RJCTODO - * * Returns the view model data representing the analysis results to be * displayed for the node. * @@ -238,16 +232,49 @@ public class AnalysisResultsViewModel { * * @return The analysis results view model data to display. */ - NodeResults getAnalysisResults(TskContentItem contentItem, Optional selectedResult) { - Content content = contentItem.getTskContent(); - Optional aggregateScore = Optional.empty(); - try { - aggregateScore = Optional.ofNullable(content.getAggregateScore()); - - } catch (TskCoreException ex) { - // RJCTODO: log error + NodeResults getAnalysisResults(Node node) { + if (node == null) { + return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty(), Optional.empty()); } - List displayAttributes = getOrderedDisplayAttributes(contentItem.getAnalyisisResults());; - return new NodeResults(displayAttributes, selectedResult, aggregateScore, content); + + Content analyzedContent = null; + AnalysisResult selectedAnalysisResult = null; + Score aggregateScore = null; + List analysisResults = Collections.emptyList(); + long selectedObjectId = 0; + try { + AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); + if (Objects.nonNull(analysisResultItem)) { + /* + * The content represented by the Node is an analysis result. + * Set this analysis result as the analysis result to be + * selected in the content viewer and get the analyzed content + * as the source of the analysis results to display. + */ + selectedAnalysisResult = analysisResultItem.getAnalysisResult(); + selectedObjectId = selectedAnalysisResult.getId(); + analyzedContent = selectedAnalysisResult.getParent(); + } else { + /* + * The content represented by the Node is something other than + * an analysis result. Use it as the source of the analysis + * results to display. + */ + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); + analyzedContent = contentItem.getTskContent(); + selectedObjectId = analyzedContent.getId(); + } + aggregateScore = analyzedContent.getAggregateScore(); + analysisResults = analyzedContent.getAllAnalysisResults(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error get analysis result data for selected Content (object ID=%d)", selectedObjectId), ex); + } + + /* + * Use the data collected above to construct the view model. + */ + List displayAttributes = getOrderedDisplayAttributes(analysisResults); + return new NodeResults(displayAttributes, Optional.ofNullable(selectedAnalysisResult), Optional.ofNullable(aggregateScore), Optional.ofNullable(analyzedContent)); } + } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index 0a43d47102..daf8cd84da 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -102,7 +102,7 @@ public abstract class AbstractContentNode extends ContentNode * @param content Underlying Content instances */ AbstractContentNode(T content) { - this(content, Lookups.singleton(content)); + this(content, Lookups.fixed(content, new TskContentItem(content))); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index e3bad44705..bf57a00caa 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -84,8 +84,8 @@ import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.sleuthkit.datamodel.Score; /** - * A BlackboardArtifactNode is an AbstractNode implementation that can be used - * to represent an artifact of any type. + * An AbstractNode implementation that can be used to represent an data artifact + * or analysis result of any type. */ public class BlackboardArtifactNode extends AbstractContentNode { @@ -219,17 +219,20 @@ public class BlackboardArtifactNode extends AbstractContentNode artifact.getSleuthkitCase().getContentById(objectID)); - if (content == null) { - return Lookups.fixed(artifact); + if (useAssociatedFile) { + content = getPathIdFile(artifact); } else { - return Lookups.fixed(artifact, content); + long srcObjectID = artifact.getObjectID(); + content = contentCache.get(srcObjectID, () -> artifact.getSleuthkitCase().getContentById(srcObjectID)); } } catch (ExecutionException ex) { - logger.log(Level.SEVERE, MessageFormat.format("Error getting source content (artifact objID={0}", artifact.getId()), ex); //NON-NLS - return Lookups.fixed(artifact); + logger.log(Level.SEVERE, MessageFormat.format("Error getting source/associated content (artifact object ID={0})", artifact.getId()), ex); //NON-NLS } - } - /** - * Creates a Lookup object for this node and populates it with both the - * artifact this node represents and its source content. - * - * @param artifact The artifact this node represents. - * @param lookupIsAssociatedFile True if the Content lookup should be made - * for the associated file instead of the - * parent file. - * - * @return The Lookup. - */ - private static Lookup createLookup(BlackboardArtifact artifact, boolean lookupIsAssociatedFile) { - Content content = null; - if (lookupIsAssociatedFile) { - try { - content = getPathIdFile(artifact); - } catch (ExecutionException ex) { - logger.log(Level.SEVERE, MessageFormat.format("Error getting source content (artifact objID={0}", artifact.getId()), ex); //NON-NLS - content = null; - } - if (content == null) { - return Lookups.fixed(artifact); - } else { - return Lookups.fixed(artifact, content); - } + /* + * Make an Autopsy Data Model wrapper for the artifact. + * + * NOTE: The creation of an Autopsy Data Model independent of the + * NetBeans nodes is a work in progress. At the time this comment is + * being written, this object is only used by the analysis content + * viewer. + */ + TskContentItem artifactItem; + if (artifact instanceof AnalysisResult) { + artifactItem = new AnalysisResultItem((AnalysisResult) artifact); } else { - return createLookup(artifact); + artifactItem = new TskContentItem(artifact); } + /* + * Create the Lookup. + */ + if (content == null) { + return Lookups.fixed(artifact, artifactItem); + } else { + return Lookups.fixed(artifact, artifactItem, content); + } } /** @@ -447,10 +455,10 @@ public class BlackboardArtifactNode extends AbstractContentNode Date: Wed, 1 Sep 2021 16:58:59 -0400 Subject: [PATCH 08/13] 7861 Make analysis results content viewer work for data artifacts --- .../analysisresults/AnalysisResultsViewModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java index 508c9966fe..37e4114168 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java @@ -267,7 +267,7 @@ public class AnalysisResultsViewModel { aggregateScore = analyzedContent.getAggregateScore(); analysisResults = analyzedContent.getAllAnalysisResults(); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, String.format("Error get analysis result data for selected Content (object ID=%d)", selectedObjectId), ex); + logger.log(Level.SEVERE, String.format("Error getting analysis result data for selected Content (object ID=%d)", selectedObjectId), ex); } /* From 417c432a216e8a9d7ab9044feda5eac05ddb90d7 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 3 Sep 2021 12:46:17 -0400 Subject: [PATCH 09/13] 7963 format IngestEventsListener.java --- .../eventlisteners/IngestEventsListener.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 7aa229949e..04275f0e98 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -70,6 +70,7 @@ import org.sleuthkit.datamodel.Score; */ @NbBundle.Messages({"IngestEventsListener.ingestmodule.name=Central Repository"}) public class IngestEventsListener { + private static final Logger LOGGER = Logger.getLogger(CorrelationAttributeInstance.class.getName()); private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(DATA_ADDED); @@ -246,15 +247,15 @@ public class IngestEventsListener { originalArtifact.getArtifactID())); makeAndPostInterestingArtifact(originalArtifact, attributesForNewArtifact, Bundle.IngestEventsListener_prevExists_text()); } - - + /** * Make an interesting item artifact to flag the passed in artifact. * * @param originalArtifact Artifact in current case we want to flag * @param attributesForNewArtifact Attributes to assign to the new * Interesting items artifact - * @param configuration The configuration to be specified for the new interesting artifact hit + * @param configuration The configuration to be specified for the + * new interesting artifact hit */ private static void makeAndPostInterestingArtifact(BlackboardArtifact originalArtifact, Collection attributesForNewArtifact, String configuration) { try { @@ -263,8 +264,8 @@ public class IngestEventsListener { Blackboard blackboard = tskCase.getBlackboard(); // Create artifact if it doesn't already exist. if (!blackboard.artifactExists(abstractFile, TSK_INTERESTING_ARTIFACT_HIT, attributesForNewArtifact)) { - BlackboardArtifact newInterestingArtifact = abstractFile.newAnalysisResult( - BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, Score.SCORE_LIKELY_NOTABLE, + BlackboardArtifact newInterestingArtifact = abstractFile.newAnalysisResult( + BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, Score.SCORE_LIKELY_NOTABLE, null, configuration, null, attributesForNewArtifact) .getAnalysisResult(); @@ -368,8 +369,8 @@ public class IngestEventsListener { try { dataSource = ((DataSourceAnalysisEvent) event).getDataSource(); /* - * We only care about Images for the purpose of - * updating hash values. + * We only care about Images for the purpose of updating hash + * values. */ if (!(dataSource instanceof Image)) { return; From 753d1c80376cef837c2b177a9bbf494a86829b3b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Sep 2021 15:23:40 -0400 Subject: [PATCH 10/13] 7852 clean up --- .../datamodel/CorrelationAttributeUtil.java | 131 +++++++++--------- 1 file changed, 66 insertions(+), 65 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index 0ad1d8c6ee..1d891b5db5 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2017-2020 Basis Technology Corp. + * Copyright 2017-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +25,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; import java.util.logging.Level; -import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -43,7 +42,6 @@ import org.sleuthkit.datamodel.DataArtifact; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.InvalidAccountIDException; import org.sleuthkit.datamodel.OsAccount; -import org.sleuthkit.datamodel.OsAccountInstance; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -57,7 +55,7 @@ public class CorrelationAttributeUtil { private static final List domainsToSkip = Arrays.asList("localhost", "127.0.0.1"); // artifact ids that specifically have a TSK_DOMAIN attribute that should be handled by CR - private static Set DOMAIN_ARTIFACT_TYPE_IDS = new HashSet<>(Arrays.asList( + private static final Set DOMAIN_ARTIFACT_TYPE_IDS = new HashSet<>(Arrays.asList( ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID(), ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID(), ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(), @@ -80,64 +78,78 @@ public class CorrelationAttributeUtil { return Bundle.CorrelationAttributeUtil_emailaddresses_text(); } - /** - * Makes zero to many correlation attribute instances from the attributes of - * artifacts that have correlatable data. The intention of this method is to - * use the results to save to the CR, not to correlate with them. If you - * want to correlate, please use makeCorrAttrsForCorrelation. An artifact - * that can have correlatable data != An artifact that should be the source - * of data in the CR, so results may be un-necessarily incomplete. - * - * @param artifact An artifact. - * - * @return A list, possibly empty, of correlation attribute instances for - * the artifact. - */ - public static List makeCorrAttrsToSave(DataArtifact artifact) { + private static List makeCorrAttrsToSave(DataArtifact artifact) { int artifactTypeID = artifact.getArtifactTypeID(); - // @@@ TODO Add a comment about why we do not save these. - // BC: I forget the history on these... + //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() || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) { return new ArrayList<>(); } - return CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact); } - //public static List makeCorrAttrsToSave(AbstactFile file) { - // @@@ TODO Call into makeCorrAttrsForSearch(file) when API changes - // AND move logic that perhaps in the ingest module into here. - // return makeCorrAttrsForSearch(file); - //} + /** + * Makes zero to many correlation attribute instances from the attributes of + * content objects that have correlatable data. The intention of this method + * is to use the results to save to the CR, not to correlate with them. If + * you want to correlate, please use makeCorrAttrsForSearch. An artifact + * that can have correlatable data != An artifact that should be the source + * of data in the CR, so results may be un-necessarily incomplete. + * + * @param content A Content object. + * + * @return A list, possibly empty, of correlation attribute instances for + * the content. + */ public static List makeCorrAttrsToSave(Content content) { - return new ArrayList<>(); + if (content instanceof DataArtifact) { + return makeCorrAttrsToSave((DataArtifact) content); + } else if (!(content instanceof AnalysisResult)) { + return makeCorrAttrsForSearch(content); + } else { + return new ArrayList<>(); + } } public static List makeCorrAttrsForSearch(Content content) { - return new ArrayList<>(); + 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<>(); + } } - public static List makeCorrAttrsForSearch(AnalysisResult artifact) { + private static List makeCorrAttrsForSearch(AnalysisResult analysisResult) { + List correlationAttrs = new ArrayList<>(); try { - if (BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.equals(artifact.getType())) { - BlackboardAttribute assocArtifactAttr = artifact.getAttribute(BlackboardAttribute.Type.TSK_ASSOCIATED_ARTIFACT); + int artifactTypeID = analysisResult.getArtifactTypeID(); + 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())) { + 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); if (assocArtifactAttr != null) { BlackboardArtifact sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong()); return CorrelationAttributeUtil.makeCorrAttrsForSearch(sourceArtifact); } } - Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); - - return CorrelationAttributeUtil.makeCorrAttrsForSearch(content); - // @@@ TODO ADD Error Handling + Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(analysisResult.getObjectID()); + correlationAttrs.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch(content)); } catch (TskCoreException ex) { - Exceptions.printStackTrace(ex); + logger.log(Level.SEVERE, "Failed to get information regarding correlation attributes from AnalysisResult", ex); } catch (NoCurrentCaseException ex) { - Exceptions.printStackTrace(ex); + logger.log(Level.SEVERE, "Attempted to retrieve correlation attributes for search with no currently open case.", ex); + } catch (CentralRepoException ex) { + logger.log(Level.SEVERE, "Failed to get correlation type from central repository.", ex); } - return new ArrayList<>(); + return correlationAttrs; } /** @@ -164,19 +176,13 @@ public class CorrelationAttributeUtil { * @return A list, possibly empty, of correlation attribute instances for * the artifact. */ - public static List makeCorrAttrsForSearch(DataArtifact artifact) { + private static List makeCorrAttrsForSearch(DataArtifact artifact) { List correlationAttrs = new ArrayList<>(); try { List attributes = artifact.getAttributes(); int artifactTypeID = artifact.getArtifactTypeID(); - //if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - // BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); - // if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) { - // makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID, attributes); - // } - //} else if (DOMAIN_ARTIFACT_TYPE_IDS.contains(artifactTypeID)) { BlackboardAttribute domainAttr = getAttribute(attributes, new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN)); if ((domainAttr != null) @@ -305,8 +311,6 @@ public class CorrelationAttributeUtil { */ private static void makeCorrAttrsFromCommunicationArtifacts(List corrAttrInstances, BlackboardArtifact artifact, List attributes) throws TskCoreException, CentralRepoException, CorrelationAttributeNormalizationException { - CorrelationAttributeInstance corrAttr = null; - /* * Extract the phone number from the artifact attribute. */ @@ -318,15 +322,13 @@ public class CorrelationAttributeUtil { } else if (null != getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) { value = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); } - /* * Normalize the phone number. */ if (value != null && CorrelationAttributeNormalizer.isValidPhoneNumber(value)) { - value = CorrelationAttributeNormalizer.normalizePhone(value); - corrAttr = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value); + CorrelationAttributeInstance corrAttr = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value); if (corrAttr != null) { corrAttrInstances.add(corrAttr); } @@ -484,21 +486,21 @@ public class CorrelationAttributeUtil { */ private static CorrelationAttributeInstance makeCorrAttr(BlackboardArtifact artifact, CorrelationAttributeInstance.Type correlationType, String value, Content sourceContent, Content dataSource) { + Content srcContent = sourceContent; + Content dataSrc = dataSource; try { - - if (sourceContent == null) { - sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); + if (srcContent == null) { + srcContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); } - if (null == sourceContent) { + if (null == srcContent) { logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load content with ID: {1} associated with artifact with ID: {2}", new Object[]{correlationType.getDisplayName(), artifact.getObjectID(), artifact.getId()}); // NON-NLS return null; } - - if (dataSource == null) { - dataSource = sourceContent.getDataSource(); + if (dataSrc == null) { + dataSrc = srcContent.getDataSource(); } - if (dataSource == null) { + if (dataSrc == null) { logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load data source for content with ID: {1}", new Object[]{correlationType.getDisplayName(), artifact.getObjectID()}); // NON-NLS return null; @@ -510,24 +512,24 @@ public class CorrelationAttributeUtil { correlationType, value, correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource), + CorrelationDataSource.fromTSKDataSource(correlationCase, dataSrc), "", "", TskData.FileKnown.UNKNOWN, - sourceContent.getId()); + srcContent.getId()); } else { - if (!(sourceContent instanceof AbstractFile)) { + if (!(srcContent instanceof AbstractFile)) { logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Source content of artifact with ID: {1} is not an AbstractFile", new Object[]{correlationType.getDisplayName(), artifact.getId()}); return null; } - AbstractFile bbSourceFile = (AbstractFile) sourceContent; + AbstractFile bbSourceFile = (AbstractFile) srcContent; return new CorrelationAttributeInstance( correlationType, value, correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource), + CorrelationDataSource.fromTSKDataSource(correlationCase, dataSrc), bbSourceFile.getParentPath() + bbSourceFile.getName(), "", TskData.FileKnown.UNKNOWN, @@ -694,8 +696,7 @@ public class CorrelationAttributeUtil { * * @return The correlation attribute instance or null, if an error occurred. */ - // @@@ TODO: Make this look like other makeCorrAttrsForSearch and return a list - public static List makeCorrAttrsForSearch(AbstractFile file) { + private static List makeCorrAttrsForSearch(AbstractFile file) { List fileTypeList = new ArrayList<>(); // will be an empty or single element list as was decided in 7852 if (!isSupportedAbstractFileType(file)) { return fileTypeList; From a4ccf21c719c9e90a46341c2ace399b79594da6f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Sep 2021 15:31:55 -0400 Subject: [PATCH 11/13] 7852 further clean up --- .../Bundle.properties-MERGED | 5 +- .../datamodel/CorrelationAttributeUtil.java | 56 ++++++++++--------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties-MERGED index b2320b5408..b4f7f835ef 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/Bundle.properties-MERGED @@ -5,7 +5,10 @@ CentralRepoCommentDialog.title.addEditCentralRepoComment=Add/Edit Central Reposi OpenIDE-Module-Name=Central Repository OpenIDE-Module-Display-Category=Ingest Module OpenIDE-Module-Short-Description=Central Repository Ingest Module -OpenIDE-Module-Long-Description=Central Repository ingest module and central database. \n\nThe Central Repository ingest module stores attributes of artifacts matching selected correlation types into a central database.\nStored attributes are used in future cases to correlate and analyzes files and artifacts during ingest. +OpenIDE-Module-Long-Description=\ + Central Repository ingest module and central database. \n\n\ + The Central Repository ingest module stores attributes of artifacts matching selected correlation types into a central database.\n\ + Stored attributes are used in future cases to correlate and analyzes files and artifacts during ingest. CentralRepoCommentDialog.commentLabel.text=Comment: CentralRepoCommentDialog.okButton.text=&OK CentralRepoCommentDialog.cancelButton.text=C&ancel diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index 1d891b5db5..c15edbfd2d 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -105,13 +105,39 @@ public class CorrelationAttributeUtil { public static List makeCorrAttrsToSave(Content content) { if (content instanceof DataArtifact) { return makeCorrAttrsToSave((DataArtifact) content); - } else if (!(content instanceof AnalysisResult)) { - return makeCorrAttrsForSearch(content); - } else { + } 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); } } + /** + * Makes zero to many correlation attribute instances from the attributes of + * content 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 correlatable + * data != 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. + * + * 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 Content A Content object. + * + * @return A list, possibly empty, of correlation attribute instances for + * the content. + */ public static List makeCorrAttrsForSearch(Content content) { if (content instanceof DataArtifact) { return makeCorrAttrsForSearch((DataArtifact) content); @@ -152,30 +178,6 @@ public class CorrelationAttributeUtil { return correlationAttrs; } - /** - * Makes zero to many correlation attribute instances from the attributes of - * artifacts 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 correlatable - * data != 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. - * - * 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. - */ private static List makeCorrAttrsForSearch(DataArtifact artifact) { List correlationAttrs = new ArrayList<>(); try { From 7434c3fea02eee121a395b3d3d74560fadd305d6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Sep 2021 16:12:43 -0400 Subject: [PATCH 12/13] 7852 modify SCOtask logic --- .../datamodel/CorrelationAttributeUtil.java | 18 +++++- .../autopsy/datamodel/GetSCOTask.java | 58 ++++--------------- 2 files changed, 26 insertions(+), 50 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index c15edbfd2d..bebf68a874 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -63,6 +63,17 @@ public class CorrelationAttributeUtil { ARTIFACT_TYPE.TSK_WEB_CACHE.getTypeID() )); + private static final Set FILE_ARTIFACT_TYPE_IDS = new HashSet<>(Arrays.asList( + ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID(), + ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID(), + ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), + ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID(), + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(), + ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(), + ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID(), + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + )); + /** * 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 @@ -83,7 +94,8 @@ public class CorrelationAttributeUtil { //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() || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() - || artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) { + || artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() + || FILE_ARTIFACT_TYPE_IDS.contains(artifactTypeID)) { return new ArrayList<>(); } return CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact); @@ -191,6 +203,9 @@ public class CorrelationAttributeUtil { && !domainsToSkip.contains(domainAttr.getValueString())) { makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID, attributes); } + } else if (FILE_ARTIFACT_TYPE_IDS.contains(artifactTypeID) && artifact.getParent() instanceof AbstractFile) { + //if it is one of the types in this set we instead want to correlate on the parent file + correlationAttrs.addAll(makeCorrAttrsForSearch((AbstractFile) artifact.getParent())); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) { // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); @@ -199,7 +214,6 @@ public class CorrelationAttributeUtil { attributes, sourceContent, dataSource); makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, attributes, sourceContent, dataSource); - } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) { makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID, attributes); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java index d7e56a11d7..64b8aa604f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019-2020 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,19 +22,13 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.ref.WeakReference; import java.util.List; -import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Tag; -import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; /** @@ -46,7 +40,6 @@ class GetSCOTask implements Runnable { private final WeakReference> weakNodeRef; private final PropertyChangeListener listener; - private static final Logger logger = Logger.getLogger(GetSCOTask.class.getName()); GetSCOTask(WeakReference> weakContentRef, PropertyChangeListener listener) { this.weakNodeRef = weakContentRef; @@ -59,7 +52,7 @@ class GetSCOTask implements Runnable { public void run() { AbstractContentNode contentNode = weakNodeRef.get(); - //Check for stale reference or if columns are disabled + //Check for stale reference or if columns are disabled if (contentNode == null || UserPreferences.getHideSCOColumns()) { return; } @@ -72,49 +65,18 @@ class GetSCOTask implements Runnable { //because the Comment column will reflect the presence of comments in the CR when the CR is enabled, but reflect tag comments regardless CorrelationAttributeInstance fileAttribute = contentNode.getCorrelationAttributeInstance(); scoData.setComment(contentNode.getCommentProperty(tags, fileAttribute)); - if (CentralRepository.isEnabled()) { Type type = null; String value = null; String description = Bundle.GetSCOTask_occurrences_defaultDescription(); - if (contentNode instanceof BlackboardArtifactNode) { - BlackboardArtifact bbArtifact = ((BlackboardArtifactNode) contentNode).getArtifact(); - //for specific artifact types we still want to display information for the file instance correlation attribute - if (bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - try { - if (bbArtifact.getParent() instanceof AbstractFile) { - type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID); - value = ((AbstractFile) bbArtifact.getParent()).getMd5Hash(); - } - } catch (TskCoreException | CentralRepoException ex) { - logger.log(Level.WARNING, "Unable to get correlation type or value to determine value for O column for artifact", ex); - } - } else { - List listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbArtifact); - if (listOfPossibleAttributes.size() > 1) { - //Don't display anything if there is more than 1 correlation property for an artifact but let the user know - description = Bundle.GetSCOTask_occurrences_multipleProperties(); - } else if (!listOfPossibleAttributes.isEmpty()) { - //there should only be one item in the list - type = listOfPossibleAttributes.get(0).getCorrelationType(); - value = listOfPossibleAttributes.get(0).getCorrelationValue(); - } - } - } else if (contentNode.getContent() instanceof AbstractFile) { - //use the file instance correlation attribute if the node is not a BlackboardArtifactNode - try { - type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID); - value = ((AbstractFile) contentNode.getContent()).getMd5Hash(); - } catch (CentralRepoException ex) { - logger.log(Level.WARNING, "Unable to get correlation type to determine value for O column for file", ex); - } + List listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsForSearch(contentNode.getContent()); + if (listOfPossibleAttributes.size() > 1) { + //Don't display anything if there is more than 1 correlation property for an artifact but let the user know + description = Bundle.GetSCOTask_occurrences_multipleProperties(); + } else if (!listOfPossibleAttributes.isEmpty()) { + //there should only be one item in the list + type = listOfPossibleAttributes.get(0).getCorrelationType(); + value = listOfPossibleAttributes.get(0).getCorrelationValue(); } scoData.setCountAndDescription(contentNode.getCountPropertyAndDescription(type, value, description)); } From 18f7f21c0ff1fd996fb290e9c51e6eb89c8691f3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 3 Sep 2021 16:57:31 -0400 Subject: [PATCH 13/13] 7852 fix analysis results misidentified in logic as data artifacts --- .../datamodel/CorrelationAttributeUtil.java | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index bebf68a874..5e64e3994b 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -63,17 +63,6 @@ public class CorrelationAttributeUtil { ARTIFACT_TYPE.TSK_WEB_CACHE.getTypeID() )); - private static final Set FILE_ARTIFACT_TYPE_IDS = new HashSet<>(Arrays.asList( - ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID(), - ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID(), - ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), - ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID(), - ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(), - ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(), - ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID(), - ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() - )); - /** * 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 @@ -94,8 +83,7 @@ public class CorrelationAttributeUtil { //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() || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() - || artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() - || FILE_ARTIFACT_TYPE_IDS.contains(artifactTypeID)) { + || artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) { return new ArrayList<>(); } return CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact); @@ -178,8 +166,7 @@ public class CorrelationAttributeUtil { return CorrelationAttributeUtil.makeCorrAttrsForSearch(sourceArtifact); } } - Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(analysisResult.getObjectID()); - correlationAttrs.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch(content)); + correlationAttrs.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch(analysisResult.getParent())); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to get information regarding correlation attributes from AnalysisResult", ex); } catch (NoCurrentCaseException ex) { @@ -203,9 +190,6 @@ public class CorrelationAttributeUtil { && !domainsToSkip.contains(domainAttr.getValueString())) { makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID, attributes); } - } else if (FILE_ARTIFACT_TYPE_IDS.contains(artifactTypeID) && artifact.getParent() instanceof AbstractFile) { - //if it is one of the types in this set we instead want to correlate on the parent file - correlationAttrs.addAll(makeCorrAttrsForSearch((AbstractFile) artifact.getParent())); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) { // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());