This commit is contained in:
Greg DiCristofaro 2023-07-05 16:17:30 -04:00
parent 5c9f9ca64c
commit a4a3e0f42e
6 changed files with 91 additions and 51 deletions

View File

@ -105,6 +105,13 @@ ReportsRowDTO_reportFilePath_displayName=Report File Path
ReportsRowDTO_reportName_displayName=Report Name
ReportsRowDTO_sourceModuleName_displayName=Source Module Name
ResultTag.name.text=Result Tag
ScoreDAO_columns_createdDateLbl=Created Date
ScoreDAO_columns_noDescription=No Description
ScoreDAO_columns_pathLbl=Path
ScoreDAO_columns_sourceLbl=Source
ScoreDAO_columns_typeLbl=Type
ScoreDAO_mainNode_displayName=Score
ScoreDAO_types_filelbl=File
ScoreViewFilter_bad_name=Bad Items
ScoreViewFilter_suspicious_name=Suspicious Items
TagsDAO.fileColumns.accessTimeColLbl=Accessed Time

View File

@ -27,6 +27,7 @@ import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
@ -44,6 +45,7 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
@ -68,6 +70,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.Category;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.Score;
import org.sleuthkit.datamodel.Score.Priority;
import org.sleuthkit.datamodel.Score.Significance;
import org.sleuthkit.datamodel.SleuthkitCase;
@ -118,6 +121,15 @@ public class ScoreDAO extends AbstractDAO {
private static final String SCORE_TYPE_ID = ScoreDAO.class.getName() + "_SIGNATURE_ID";
private static final String BASE_AGGR_SCORE_QUERY
= "FROM tsk_aggregate_score aggr_score\n"
+ "INNER JOIN (\n"
+ " SELECT obj_id, data_source_obj_id, 'f' AS type FROM tsk_files\n"
+ " UNION SELECT artifact_obj_id AS obj_id, data_source_obj_id, 'a' AS type FROM blackboard_artifacts\n"
+ " WHERE blackboard_artifacts.artifact_type_id IN\n"
+ " (SELECT artifact_type_id FROM blackboard_artifact_types WHERE category_type = " + Category.DATA_ARTIFACT.getID() + ")\n"
+ ") art_files ON aggr_score.obj_id = art_files.obj_id\n";
private static ScoreDAO instance = null;
synchronized static ScoreDAO getInstance() {
@ -167,19 +179,6 @@ public class ScoreDAO extends AbstractDAO {
|| Objects.equals(paramsDsId, evtDsId));
}
private static String getScoreFilter(ScoreViewFilter filter) throws IllegalArgumentException {
switch (filter) {
case SUSPICIOUS:
return " tsk_aggregate_score.significance = " + Significance.LIKELY_NOTABLE.getId()
+ " AND (tsk_aggregate_score.priority = " + Priority.NORMAL.getId() + " OR tsk_aggregate_score.priority = " + Priority.OVERRIDE.getId() + " )";
case BAD:
return " tsk_aggregate_score.significance = " + Significance.NOTABLE.getId()
+ " AND (tsk_aggregate_score.priority = " + Priority.NORMAL.getId() + " OR tsk_aggregate_score.priority = " + Priority.OVERRIDE.getId() + " )";
default:
throw new IllegalArgumentException(MessageFormat.format("Unsupported filter type to get suspect content: {0}", filter));
}
}
/**
* Returns counts for deleted content categories.
*
@ -208,17 +207,28 @@ public class ScoreDAO extends AbstractDAO {
}
}
String queryStr = Stream.of(ScoreViewFilter.values())
.map((filter) -> {
return " SELECT COUNT(tsk_aggregate_score.obj_id) AS " + filter.name() + " FROM tsk_aggregate_score WHERE\n"
+ getScoreFilter(filter) + "\n"
+ ((dataSourceId == null) ? "AND tsk_aggregate_score.data_source_obj_id = " + dataSourceId + "\n" : "")
+ " AND tsk_aggregate_score.obj_id IN\n"
+ " (SELECT tsk_files.obj_id AS obj_id FROM tsk_files UNION\n"
+ " SELECT blackboard_artifacts.artifact_obj_id AS obj_id FROM blackboard_artifacts WHERE blackboard_artifacts.artifact_type_id IN\n"
+ " (SELECT artifact_type_id FROM blackboard_artifact_types WHERE category_type = " + Category.DATA_ARTIFACT.getID() + ")) ";
String dsClause = getDsFilter(dataSourceId);
String queryStrSelects = Stream.of(ScoreViewFilter.values())
.map((filter) -> Pair.of(filter.name(), getScoreFilter(filter.getScores())))
.map((filterSqlPair) -> {
String filterSql = Stream.of(filterSqlPair.getRight(), dsClause)
.filter(StringUtils::isNotBlank)
.collect(Collectors.joining("\nAND "));
if (StringUtils.isNotBlank(filterSql)) {
filterSql = "\n WHERE " + filterSql;
}
return "(SELECT COUNT(aggr_score.obj_id) "
+ BASE_AGGR_SCORE_QUERY
+ filterSql
+ ") AS "
+ filterSqlPair.getLeft();
})
.collect(Collectors.joining(", \n"));
.collect(Collectors.joining(",\n"));
String queryStr = "\n" + queryStrSelects;
try {
SleuthkitCase skCase = getCase();
@ -256,24 +266,39 @@ public class ScoreDAO extends AbstractDAO {
displayCount);
}
private SearchResultsDTO fetchScoreSearchResultsDTOs(ScoreViewFilter filter, Long dataSourceId, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException {
String scoreWhereClause = filter.getScores().stream()
private static String getScoreFilter(Collection<Score> scores) {
if (CollectionUtils.isEmpty(scores)) {
return null;
} else {
return "("
+ scores.stream()
.map(s -> MessageFormat.format(
" (aggr_score.significance = {0} AND aggr_score.priority = {1}) ",
s.getSignificance().getId(),
s.getPriority().getId()))
.collect(Collectors.joining(" OR "));
.collect(Collectors.joining(" OR "))
+ ")";
}
}
String baseQuery
= "FROM tsk_aggregate_score aggr_score\n"
+ "INNER JOIN (\n"
+ " SELECT obj_id, data_source_obj_id, 'f' AS type FROM tsk_files\n"
+ " UNION SELECT artifact_obj_id AS obj_id, data_source_obj_id, 'a' AS type FROM blackboard_artifacts\n"
+ " WHERE blackboard_artifacts.artifact_type_id IN "
+ " (SELECT artifact_type_id FROM blackboard_artifact_types WHERE category_type = " + Category.DATA_ARTIFACT.getID() + ")\n"
+ ") art_files ON aggr_score.obj_id = art_files.obj_id\n"
+ "WHERE (" + scoreWhereClause + ")\n"
+ ((dataSourceId != null && dataSourceId > 0) ? "AND art_files.data_source_obj_id = " + dataSourceId + "\n" : "")
private static String getDsFilter(Long dataSourceId) {
return (dataSourceId == null || dataSourceId <= 0)
? null
: "aggr_score.data_source_obj_id = " + dataSourceId;
}
private SearchResultsDTO fetchScoreSearchResultsDTOs(ScoreViewFilter filter, Long dataSourceId, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException {
String scoreClause = getScoreFilter(filter.getScores());
String dsClause = getDsFilter(dataSourceId);
String filterSql = Stream.of(scoreClause, dsClause)
.filter(str -> str != null)
.collect(Collectors.joining(" AND "));
filterSql = StringUtils.isNotEmpty(filterSql) ? " WHERE " + filterSql + "\n" : "";
String baseQuery = BASE_AGGR_SCORE_QUERY
+ filterSql
+ "ORDER BY art_files.obj_id";
String countQuery = " COUNT(art_files.obj_id) AS count\n" + baseQuery;
@ -299,9 +324,7 @@ public class ScoreDAO extends AbstractDAO {
sqlEx);
}
String objIdQuery = " art_files.obj_id, art_files.type\n" + baseQuery
+ "\n"
+ "ORDER BY obj_id ASC"
String objIdQuery = " art_files.obj_id, art_files.type\n" + baseQuery + "\n"
+ (maxResultCount != null && maxResultCount > 0 ? " LIMIT " + maxResultCount : "")
+ (startItem > 0 ? " OFFSET " + startItem : "");;
@ -367,7 +390,7 @@ public class ScoreDAO extends AbstractDAO {
.map(l -> Long.toString(l))
.collect(Collectors.joining(", "));
List<DataArtifact> dataArtifacts = getCase().getBlackboard().getDataArtifactsWhere("obj_id IN (" + joinedArtifactIds + ")");
List<DataArtifact> dataArtifacts = getCase().getBlackboard().getDataArtifactsWhere("artifacts.artifact_obj_id IN (" + joinedArtifactIds + ")");
TableData artTableData = MainDAO.getInstance().getDataArtifactsDAO().createTableData(null, dataArtifacts);
// all rows should be data artifact rows, and can be appended accordingly

View File

@ -22,6 +22,7 @@ RootFactory_OsAccountsRootNode_displayName=OS Accounts
RootFactory_ReportsRootNode_displayName=Reports
RootFactory_TagsRootNode_displayName=Tags
RootFactory_ViewsRootNode_displayName=Views
ScoreTypeFactory_ScoreParentNode_displayName=Score
SearchResultRootNode_createSheet_childCount_displayName=Child Count
SearchResultRootNode_createSheet_childCount_name=Child Count
SearchResultRootNode_createSheet_type_displayName=Name
@ -31,6 +32,5 @@ ViewsTypeFactory_DeletedParentNode_displayName=Deleted Files
ViewsTypeFactory_ExtensionParentNode_displayName=By Extension
ViewsTypeFactory_FileTypesParentNode_displayName=File Types
ViewsTypeFactory_MimeParentNode_displayName=By MIME Type
ViewsTypeFactory_ScoreParentNode_displayName=Score
ViewsTypeFactory_SizeParentNode_displayName=File Size
VolumnNode_ExtractUnallocAction_text=Extract Unallocated Space to Single Files

View File

@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.mainui.datamodel.DataArtifactRowDTO;
import org.sleuthkit.autopsy.mainui.datamodel.DataArtifactTableSearchResultsDTO;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.autopsy.mainui.datamodel.DataArtifactTableSearchResultsDTO.CommAccoutTableSearchResultsDTO;
import org.sleuthkit.autopsy.mainui.datamodel.SearchResultsDTO;
import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TskCoreException;
@ -57,7 +58,7 @@ public class DataArtifactNode extends ArtifactNode<DataArtifact, DataArtifactRow
this(tableData, artifactRow, getIconFilePath(tableData), backgroundTasksPool);
}
public DataArtifactNode(DataArtifactTableSearchResultsDTO tableData, DataArtifactRowDTO artifactRow, String iconPath, ExecutorService backgroundTasksPool) {
public DataArtifactNode(SearchResultsDTO tableData, DataArtifactRowDTO artifactRow, String iconPath, ExecutorService backgroundTasksPool) {
super(tableData, artifactRow, tableData.getColumns(), createLookup(artifactRow), iconPath, backgroundTasksPool);
}

View File

@ -195,7 +195,7 @@ public class RootFactory {
new AnalysisResultsRootNode(null),
new OsAccountsRootNode(null),
new TagsRootNode(null),
new ScoreParentNode(null),
new ReportsRootNode()
));
}

View File

@ -27,6 +27,7 @@ import java.util.stream.Collectors;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.utils.IconsUtil;
import org.sleuthkit.autopsy.mainui.datamodel.AnalysisResultRowDTO;
import org.sleuthkit.autopsy.mainui.datamodel.AnalysisResultTableSearchResultsDTO;
import org.sleuthkit.autopsy.mainui.datamodel.BlackboardArtifactTagsRowDTO;
@ -49,6 +50,7 @@ import org.sleuthkit.autopsy.mainui.datamodel.RowDTO;
import org.sleuthkit.autopsy.mainui.datamodel.ContentRowDTO.VolumeRowDTO;
import org.sleuthkit.autopsy.mainui.datamodel.CreditCardByFileRowDTO;
import org.sleuthkit.autopsy.mainui.datamodel.ReportsRowDTO;
import org.sleuthkit.autopsy.mainui.datamodel.ScoreResultRowDTO;
import org.sleuthkit.autopsy.mainui.nodes.FileNode.LayoutFileNode;
import org.sleuthkit.autopsy.mainui.nodes.FileNode.SlackFileNode;
import org.sleuthkit.autopsy.mainui.nodes.SpecialDirectoryNode.LocalDirectoryNode;
@ -89,7 +91,14 @@ public class SearchResultChildFactory extends ChildFactory<ChildKey> {
protected Node createNodeForKey(ChildKey key) {
String typeId = key.getRow().getTypeId();
try {
if (DataArtifactRowDTO.getTypeIdForClass().equals(typeId)) {
if (ScoreResultRowDTO.getTypeIdForClass().equals(typeId) && key.getRow() instanceof ScoreResultRowDTO scoreRow) {
if (scoreRow.getArtifactDTO() != null) {
String iconPath = IconsUtil.getIconFilePath(scoreRow.getArtifactTypeId());
return new DataArtifactNode(key.getSearchResults(), scoreRow.getArtifactDTO(), iconPath, nodeThreadPool);
} else if (scoreRow.getFileDTO() != null) {
return new FileNode(key.getSearchResults(), scoreRow.getFileDTO(), true, nodeThreadPool);
}
} else if (DataArtifactRowDTO.getTypeIdForClass().equals(typeId)) {
return new DataArtifactNode((DataArtifactTableSearchResultsDTO) key.getSearchResults(), (DataArtifactRowDTO) key.getRow(), nodeThreadPool);
} else if (FileRowDTO.getTypeIdForClass().equals(typeId)) {
return new FileNode(key.getSearchResults(), (FileRowDTO) key.getRow(), true, nodeThreadPool);