Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
CentralRepoIngestModuleUtils.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2021-2021 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.centralrepository.ingestmodule;
20
21import java.util.ArrayList;
22import java.util.Arrays;
23import java.util.Collection;
24import java.util.Iterator;
25import java.util.List;
26import java.util.Optional;
27import java.util.Set;
28import java.util.logging.Level;
29import java.util.stream.Collectors;
30import org.openide.util.NbBundle;
31import org.sleuthkit.autopsy.casemodule.Case;
32import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
33import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
34import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
35import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
36import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
37import org.sleuthkit.autopsy.coreutils.Logger;
38import org.sleuthkit.autopsy.ingest.IngestMessage;
39import org.sleuthkit.autopsy.ingest.IngestServices;
40import org.sleuthkit.datamodel.AbstractFile;
41import org.sleuthkit.datamodel.AnalysisResult;
42import org.sleuthkit.datamodel.Blackboard;
43import org.sleuthkit.datamodel.BlackboardArtifact;
44import org.sleuthkit.datamodel.BlackboardAttribute;
45import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_TYPE;
46import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_VALUE;
47import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_OTHER_CASES;
48import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
49import org.sleuthkit.datamodel.Content;
50import org.sleuthkit.datamodel.DataArtifact;
51import org.sleuthkit.datamodel.Score;
52import org.sleuthkit.datamodel.TskCoreException;
53
57class CentralRepoIngestModuleUtils {
58
59 private static final Logger LOGGER = Logger.getLogger(CentralRepoDataArtifactIngestModule.class.getName());
60 private static final int MAX_PREV_CASES_FOR_NOTABLE_SCORE = 10;
61 private static final int MAX_PREV_CASES_FOR_PREV_SEEN = 20;
62 private final static String MODULE_NAME = CentralRepoIngestModuleFactory.getModuleName();
63
72 static List<CorrelationAttributeInstance> getOccurrencesInOtherCases(CorrelationAttributeInstance corrAttr, long ingestJobId) {
73 List<CorrelationAttributeInstance> previousOccurrences = new ArrayList<>();
74 try {
75 CentralRepository centralRepo = CentralRepository.getInstance();
76 previousOccurrences = centralRepo.getArtifactInstancesByTypeValue(corrAttr.getCorrelationType(), corrAttr.getCorrelationValue());
77 for (Iterator<CorrelationAttributeInstance> iterator = previousOccurrences.iterator(); iterator.hasNext();) {
78 CorrelationAttributeInstance prevOccurrence = iterator.next();
79 if (prevOccurrence.getCorrelationCase().getCaseUUID().equals(corrAttr.getCorrelationCase().getCaseUUID())) {
80 iterator.remove();
81 }
82 }
83 } catch (CorrelationAttributeNormalizationException ex) {
84 LOGGER.log(Level.WARNING, String.format("Error normalizing correlation attribute value for 's' (job ID=%d)", corrAttr, ingestJobId), ex); // NON-NLS
85 } catch (CentralRepoException ex) {
86 LOGGER.log(Level.SEVERE, String.format("Error getting previous occurences of correlation attribute 's' (job ID=%d)", corrAttr, ingestJobId), ex); // NON-NLS
87 }
88 return previousOccurrences;
89 }
90
102 @NbBundle.Messages({
103 "CentralRepoIngestModule_notableSetName=Previously Tagged As Notable (Central Repository)",
104 "# {0} - list of cases",
105 "CentralRepoIngestModule_notableJustification=Previously marked as notable in cases {0}"
106 })
107 static void makePrevNotableAnalysisResult(Content content, Set<String> previousCases, CorrelationAttributeInstance.Type corrAttrType, String corrAttrValue, long dataSourceObjId, long ingestJobId) {
108 String prevCases = previousCases.stream().collect(Collectors.joining(","));
109 String justification = Bundle.CentralRepoIngestModule_notableJustification(prevCases);
110 Collection<BlackboardAttribute> attributes = Arrays.asList(
111 new BlackboardAttribute(TSK_SET_NAME, MODULE_NAME, Bundle.CentralRepoIngestModule_notableSetName()),
112 new BlackboardAttribute(TSK_CORRELATION_TYPE, MODULE_NAME, corrAttrType.getDisplayName()),
113 new BlackboardAttribute(TSK_CORRELATION_VALUE, MODULE_NAME, corrAttrValue),
114 new BlackboardAttribute(TSK_OTHER_CASES, MODULE_NAME, prevCases));
115 Optional<AnalysisResult> result = makeAndPostAnalysisResult(content, BlackboardArtifact.Type.TSK_PREVIOUSLY_NOTABLE, attributes, "", Score.SCORE_NOTABLE, justification, dataSourceObjId, ingestJobId);
116 if (result.isPresent()) {
117 postNotableMessage(content, previousCases, corrAttrValue, result.get());
118 }
119 }
120
133 @NbBundle.Messages({
134 "CentralRepoIngestModule_prevSeenSetName=Previously Seen (Central Repository)",
135 "# {0} - list of cases",
136 "CentralRepoIngestModule_prevSeenJustification=Previously seen in cases {0}"
137 })
138 static void makePrevSeenAnalysisResult(Content content, Set<String> previousCases, CorrelationAttributeInstance.Type corrAttrType, String corrAttrValue, long dataSourceObjId, long ingestJobId) {
139 Optional<Score> score = calculateScore(previousCases.size());
140 if (score.isPresent()) {
141 String prevCases = previousCases.stream().collect(Collectors.joining(","));
142 String justification = Bundle.CentralRepoIngestModule_prevSeenJustification(prevCases);
143 Collection<BlackboardAttribute> analysisResultAttributes = Arrays.asList(
144 new BlackboardAttribute(TSK_SET_NAME, MODULE_NAME, Bundle.CentralRepoIngestModule_prevSeenSetName()),
145 new BlackboardAttribute(TSK_CORRELATION_TYPE, MODULE_NAME, corrAttrType.getDisplayName()),
146 new BlackboardAttribute(TSK_CORRELATION_VALUE, MODULE_NAME, corrAttrValue),
147 new BlackboardAttribute(TSK_OTHER_CASES, MODULE_NAME, prevCases));
148 makeAndPostAnalysisResult(content, BlackboardArtifact.Type.TSK_PREVIOUSLY_SEEN, analysisResultAttributes, "", score.get(), justification, dataSourceObjId, ingestJobId);
149 }
150 }
151
161 @NbBundle.Messages({
162 "CentralRepoIngestModule_prevUnseenJustification=Previously seen in zero cases"
163 })
164 static void makePrevUnseenAnalysisResult(Content content, CorrelationAttributeInstance.Type corrAttrType, String corrAttrValue, long dataSourceObjId, long ingestJobId) {
165 Collection<BlackboardAttribute> attributesForNewArtifact = Arrays.asList(
166 new BlackboardAttribute(TSK_CORRELATION_TYPE, MODULE_NAME, corrAttrType.getDisplayName()),
167 new BlackboardAttribute(TSK_CORRELATION_VALUE, MODULE_NAME, corrAttrValue));
168 makeAndPostAnalysisResult(content, BlackboardArtifact.Type.TSK_PREVIOUSLY_UNSEEN, attributesForNewArtifact, "", Score.SCORE_LIKELY_NOTABLE, Bundle.CentralRepoIngestModule_prevUnseenJustification(), dataSourceObjId, ingestJobId);
169 }
170
180 static Optional<Score> calculateScore(int numPreviousCases) {
181 Score score = null;
182 if (numPreviousCases <= MAX_PREV_CASES_FOR_NOTABLE_SCORE) {
183 score = Score.SCORE_LIKELY_NOTABLE;
184 } else if (numPreviousCases > MAX_PREV_CASES_FOR_NOTABLE_SCORE && numPreviousCases <= MAX_PREV_CASES_FOR_PREV_SEEN) {
185 score = Score.SCORE_NONE;
186 }
187 return Optional.ofNullable(score);
188 }
189
206 private static Optional<AnalysisResult> makeAndPostAnalysisResult(Content content, BlackboardArtifact.Type analysisResultType, Collection<BlackboardAttribute> analysisResultAttrs, String configuration, Score score, String justification, long dataSourceObjId, long ingestJobId) {
207 AnalysisResult analysisResult = null;
208 try {
209 Blackboard blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard();
210 if (!blackboard.artifactExists(content, analysisResultType, analysisResultAttrs)) {
211 analysisResult = content.newAnalysisResult(analysisResultType, score, null, configuration, justification, analysisResultAttrs, dataSourceObjId).getAnalysisResult();
212 try {
213 blackboard.postArtifact(analysisResult, MODULE_NAME, ingestJobId);
214 } catch (Blackboard.BlackboardException ex) {
215 LOGGER.log(Level.SEVERE, String.format("Error posting analysis result '%s' to blackboard for content 's' (job ID=%d)", analysisResult, content, ingestJobId), ex); //NON-NLS
216 }
217 }
218 } catch (NoCurrentCaseException | TskCoreException ex) {
219 LOGGER.log(Level.SEVERE, String.format("Error creating %s analysis result for content '%s' (job ID=%d)", analysisResultType, content, ingestJobId), ex); // NON-NLS
220 }
221 return Optional.ofNullable(analysisResult);
222 }
223
237 @NbBundle.Messages({
238 "# {0} - Name of item that is Notable",
239 "CentralRepoIngestModule_notable_inbox_msg_subject=Notable: {0}"
240 })
241 private static void postNotableMessage(Content content, Set<String> otherCases, String corrAttrValue, AnalysisResult analysisResult) {
242 String msgSubject = null;
243 String msgDetails = null;
244 String msgKey = corrAttrValue;
245 if (content instanceof AbstractFile) {
246 AbstractFile file = (AbstractFile) content;
247 msgSubject = Bundle.CentralRepoIngestModule_notable_inbox_msg_subject(file.getName());
248 msgDetails = makeNotableFileMessage(file, otherCases);
249 } else if (content instanceof DataArtifact) {
250 DataArtifact artifact = (DataArtifact) content;
251 msgSubject = Bundle.CentralRepoIngestModule_notable_inbox_msg_subject(artifact.getDisplayName());
252 msgDetails = makeNotableDataArtifactMessage(artifact, corrAttrValue, otherCases);
253 } else {
254 LOGGER.log(Level.SEVERE, "Unsupported Content, cannot post ingest inbox message");
255 }
256 if (msgSubject != null && msgDetails != null) {
257 IngestServices.getInstance().postMessage(
258 IngestMessage.createDataMessage(
259 MODULE_NAME,
260 msgSubject,
261 msgDetails,
262 msgKey,
263 analysisResult));
264 }
265 }
266
277 @NbBundle.Messages({
278 "CentralRepoIngestModule_filename_inbox_msg_header=File Name",
279 "CentralRepoIngestModule_md5Hash_inbox_msg_header=MD5 Hash",
280 "CentralRepoIngestModule_prev_cases_inbox_msg_header=Previous Cases"
281 })
282 private static String makeNotableFileMessage(AbstractFile file, Set<String> otherCases) {
283 StringBuilder message = new StringBuilder(1024);
284 message.append("<table border='0' cellpadding='4' width='280'>"); //NON-NLS
285 addTableRowMarkup(message, Bundle.CentralRepoIngestModule_filename_inbox_msg_header(), file.getName());
286 addTableRowMarkup(message, Bundle.CentralRepoIngestModule_md5Hash_inbox_msg_header(), file.getMd5Hash());
287 addTableRowMarkup(message, Bundle.CentralRepoIngestModule_prev_cases_inbox_msg_header(), otherCases.stream().collect(Collectors.joining(",")));
288 return message.toString();
289 }
290
302 @NbBundle.Messages({
303 "CentralRepoIngestModule_artifact_type_inbox_msg_header=Artifact Type",
304 "CentralRepoIngestModule_notable_attr_inbox_msg_header=Notable Attribute"
305 })
306 private static String makeNotableDataArtifactMessage(DataArtifact artifact, String corrAttrValue, Set<String> otherCases) {
307 StringBuilder message = new StringBuilder(1024);
308 message.append("<table border='0' cellpadding='4' width='280'>"); //NON-NLS
309 addTableRowMarkup(message, Bundle.CentralRepoIngestModule_artifact_type_inbox_msg_header(), artifact.getDisplayName());
310 addTableRowMarkup(message, Bundle.CentralRepoIngestModule_notable_attr_inbox_msg_header(), corrAttrValue);
311 addTableRowMarkup(message, Bundle.CentralRepoIngestModule_prev_cases_inbox_msg_header(), otherCases.stream().collect(Collectors.joining(",")));
312 message.append("</table>"); //NON-NLS
313 return message.toString();
314 }
315
323 private static void addTableRowMarkup(StringBuilder message, String headerText, String cellText) {
324 message.append("<tr>"); //NON-NLS
325 message.append("<th>").append(headerText).append("</th>"); //NON-NLS
326 message.append("<td>").append(cellText).append("</td>"); //NON-NLS
327 message.append("</tr>"); //NON-NLS
328 }
329
330 /*
331 * Prevents instatiation of this utility class.
332 */
333 private CentralRepoIngestModuleUtils() {
334 }
335
336}

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.