19 package org.sleuthkit.autopsy.report.modules.stix;
21 import java.io.BufferedWriter;
23 import java.io.FileWriter;
24 import java.io.IOException;
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.List;
29 import java.util.logging.Level;
30 import javax.swing.JPanel;
31 import javax.xml.bind.JAXBContext;
32 import javax.xml.bind.JAXBException;
33 import javax.xml.bind.Unmarshaller;
34 import javax.xml.namespace.QName;
35 import org.mitre.cybox.cybox_2.ObjectType;
36 import org.mitre.cybox.cybox_2.Observable;
37 import org.mitre.cybox.cybox_2.ObservableCompositionType;
38 import org.mitre.cybox.cybox_2.OperatorTypeEnum;
39 import org.mitre.cybox.objects.AccountObjectType;
40 import org.mitre.cybox.objects.Address;
41 import org.mitre.cybox.objects.DomainName;
42 import org.mitre.cybox.objects.EmailMessage;
43 import org.mitre.cybox.objects.FileObjectType;
44 import org.mitre.cybox.objects.SystemObjectType;
45 import org.mitre.cybox.objects.URIObjectType;
46 import org.mitre.cybox.objects.URLHistory;
47 import org.mitre.cybox.objects.WindowsNetworkShare;
48 import org.mitre.cybox.objects.WindowsRegistryKey;
49 import org.mitre.stix.common_1.IndicatorBaseType;
50 import org.mitre.stix.indicator_2.Indicator;
51 import org.mitre.stix.stix_1.STIXPackage;
52 import org.openide.util.NbBundle;
53 import org.openide.util.NbBundle.Messages;
77 private Map<String, ObservableResult>
idToResult =
new HashMap<>();
89 if (instance == null) {
100 @Messages({
"STIXReportModule.srcModuleName.text=STIX Report"})
104 progressPanel.
start();
106 progressPanel.
updateStatusLabel(NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.readSTIX"));
108 File reportFile =
new File(reportPath);
110 reportAllResults = configPanel.getShowAllResults();
113 boolean hadErrors =
false;
116 String stixFileName = configPanel.getStixFile();
118 if (stixFileName == null) {
119 logger.log(Level.SEVERE,
"STIXReportModuleConfigPanel.stixFile not initialized ");
120 progressPanel.
complete(
ReportStatus.
ERROR, NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.noFildDirProvided"));
121 new File(baseReportDir).delete();
124 if (stixFileName.isEmpty()) {
125 logger.log(Level.SEVERE,
"No STIX file/directory provided ");
126 progressPanel.
complete(
ReportStatus.
ERROR, NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.noFildDirProvided"));
127 new File(baseReportDir).delete();
130 File stixFile =
new File(stixFileName);
132 if (!stixFile.exists()) {
133 logger.log(Level.SEVERE, String.format(
"Unable to open STIX file/directory %s", stixFileName));
134 progressPanel.
complete(
ReportStatus.
ERROR, NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.couldNotOpenFileDir", stixFileName));
135 new File(baseReportDir).delete();
139 try (BufferedWriter output =
new BufferedWriter(
new FileWriter(reportFile))) {
143 if (stixFile.isFile()) {
144 stixFiles =
new File[1];
145 stixFiles[0] = stixFile;
147 stixFiles = stixFile.listFiles();
154 for (File file : stixFiles) {
159 processFile(file.getAbsolutePath(), progressPanel, output);
160 }
catch (TskCoreException | JAXBException ex) {
161 String errMsg = String.format(
"Unable to process STIX file %s", file);
162 logger.log(Level.SEVERE, errMsg, ex);
168 idToObjectMap =
new HashMap<>();
169 idToResult =
new HashMap<>();
176 progressPanel.
complete(
ReportStatus.
ERROR, NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.completedWithErrors"));
180 }
catch (IOException ex) {
181 logger.log(Level.SEVERE,
"Unable to complete STIX report.", ex);
182 progressPanel.
complete(
ReportStatus.
ERROR, NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.completedWithErrors"));
184 logger.log(Level.SEVERE,
"Unable to add report to database.", ex);
199 JAXBException, TskCoreException {
229 private STIXPackage
loadSTIXFile(String stixFileName)
throws JAXBException {
231 File file =
new File(stixFileName);
232 JAXBContext jaxbContext = JAXBContext.newInstance(
"org.mitre.stix.stix_1:org.mitre.stix.common_1:org.mitre.stix.indicator_2:"
233 +
"org.mitre.cybox.objects:org.mitre.cybox.cybox_2:org.mitre.cybox.common_2");
234 Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
235 STIXPackage stix = (STIXPackage) jaxbUnmarshaller.unmarshal(file);
246 if (stix.getObservables() != null) {
247 List<Observable> obs = stix.getObservables().getObservables();
248 for (Observable o : obs) {
249 if (o.getId() != null) {
265 if (stix.getIndicators() != null) {
266 List<IndicatorBaseType> s = stix.getIndicators().getIndicators();
267 for (IndicatorBaseType t : s) {
268 if (t instanceof Indicator) {
269 Indicator ind = (Indicator) t;
270 if (ind.getObservable() != null) {
271 if (ind.getObservable().getObject() != null) {
276 if (result.isTrue()) {
279 }
else if (ind.getObservable().getObservableComposition() != null) {
285 if (result.isTrue()) {
306 if (result.getArtifacts() == null) {
313 for (StixArtifactData s : result.getArtifacts()) {
318 if (ind.getTitle() != null) {
319 s.createArtifact(ind.getTitle());
320 }
else if (ind.getId() != null) {
321 s.createArtifact(ind.getId().toString());
323 s.createArtifact(
"Unnamed indicator(s)");
331 "STIXReportModule.notifyMsg.tooManyArtifactsgt1000"));
347 private void writeResultsToFile(Indicator ind, String resultStr,
boolean found, BufferedWriter output) {
348 if (output != null) {
351 output.write(
"----------------\r\n"
352 +
"Found indicator:\r\n");
354 output.write(
"-----------------------\r\n"
355 +
"Did not find indicator:\r\n");
357 if (ind.getTitle() != null) {
358 output.write(
"Title: " + ind.getTitle() +
"\r\n");
360 output.write(
"\r\n");
362 if (ind.getId() != null) {
363 output.write(
"ID: " + ind.getId() +
"\r\n");
366 if (ind.getDescription() != null) {
367 String desc = ind.getDescription().getValue();
369 output.write(
"Description: " + desc +
"\r\n");
371 output.write(
"\r\nObservable results:\r\n" + resultStr +
"\r\n\r\n");
372 }
catch (IOException ex) {
373 logger.log(Level.SEVERE, String.format(
"Error writing to STIX report file %s", reportPath), ex);
385 if (output != null) {
387 char[] chars =
new char[a_fileName.length() + 8];
388 Arrays.fill(chars,
'#');
389 String header =
new String(chars);
390 output.write(
"\r\n" + header);
391 output.write(
"\r\n");
392 output.write(
"### " + a_fileName +
" ###\r\n");
393 output.write(header +
"\r\n\r\n");
394 }
catch (IOException ex) {
395 logger.log(Level.SEVERE, String.format(
"Error writing to STIX report file %s", reportPath), ex);
411 if (obs.getId() != null) {
413 }
else if (obs.getIdref() != null) {
414 idQ = obs.getIdref();
419 return idQ.getLocalPart();
429 if (obs.getObject() != null) {
430 idToObjectMap.put(
makeMapKey(obs), obs.getObject());
445 if (comp.getOperator() == null) {
446 throw new TskCoreException(
"No operator found in composition");
449 if (comp.getObservables() != null) {
450 List<Observable> obsList = comp.getObservables();
453 if (comp.getOperator() == OperatorTypeEnum.AND) {
454 ObservableResult result =
new ObservableResult(OperatorTypeEnum.AND, spacing);
455 for (Observable o : obsList) {
457 ObservableResult newResult;
458 if (o.getObservableComposition() != null) {
460 if (result == null) {
463 result.addResult(newResult, OperatorTypeEnum.AND);
467 if (result == null) {
470 result.addResult(newResult, OperatorTypeEnum.AND);
474 if ((!skipShortCircuit) && !result.isFalse()) {
480 if (result == null) {
483 return new ObservableResult(
"",
"", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
489 ObservableResult result =
new ObservableResult(OperatorTypeEnum.OR, spacing);
490 for (Observable o : obsList) {
492 ObservableResult newResult;
494 if (o.getObservableComposition() != null) {
496 if (result == null) {
499 result.addResult(newResult, OperatorTypeEnum.OR);
503 if (result == null) {
506 result.addResult(newResult, OperatorTypeEnum.OR);
510 if ((!skipShortCircuit) && result.isTrue()) {
516 if (result == null) {
519 return new ObservableResult(
"",
"", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
525 throw new TskCoreException(
"No observables found in list");
543 if (idToResult.containsKey(
makeMapKey(obs))) {
547 if (obs.getIdref() == null) {
551 if (obs.getId() != null) {
555 if (obs.getObject() != null) {
563 if (idToObjectMap.containsKey(
makeMapKey(obs))) {
569 throw new TskCoreException(
"Error loading/finding object for observable " + obs.getIdref());
582 private ObservableResult
evaluateObject(ObjectType obj, String spacing, String
id) {
584 EvaluatableObject evalObj;
586 if (obj.getProperties() instanceof FileObjectType) {
587 evalObj =
new EvalFileObj((FileObjectType) obj.getProperties(), id, spacing);
588 }
else if (obj.getProperties() instanceof Address) {
589 evalObj =
new EvalAddressObj((Address) obj.getProperties(), id, spacing);
590 }
else if (obj.getProperties() instanceof URIObjectType) {
591 evalObj =
new EvalURIObj((URIObjectType) obj.getProperties(), id, spacing);
592 }
else if (obj.getProperties() instanceof EmailMessage) {
593 evalObj =
new EvalEmailObj((EmailMessage) obj.getProperties(), id, spacing);
594 }
else if (obj.getProperties() instanceof WindowsNetworkShare) {
595 evalObj =
new EvalNetworkShareObj((WindowsNetworkShare) obj.getProperties(), id, spacing);
596 }
else if (obj.getProperties() instanceof AccountObjectType) {
597 evalObj =
new EvalAccountObj((AccountObjectType) obj.getProperties(), id, spacing);
598 }
else if (obj.getProperties() instanceof SystemObjectType) {
599 evalObj =
new EvalSystemObj((SystemObjectType) obj.getProperties(), id, spacing);
600 }
else if (obj.getProperties() instanceof URLHistory) {
601 evalObj =
new EvalURLHistoryObj((URLHistory) obj.getProperties(), id, spacing);
602 }
else if (obj.getProperties() instanceof DomainName) {
603 evalObj =
new EvalDomainObj((DomainName) obj.getProperties(), id, spacing);
604 }
else if (obj.getProperties() instanceof WindowsRegistryKey) {
605 evalObj =
new EvalRegistryObj((WindowsRegistryKey) obj.getProperties(), id, spacing,
registryFileData);
608 String type = obj.getProperties().toString();
609 type = type.substring(0, type.indexOf(
"@"));
610 if ((type.lastIndexOf(
".") + 1) < type.length()) {
611 type = type.substring(type.lastIndexOf(
".") + 1);
613 return new ObservableResult(
id, type +
" not supported",
614 spacing, ObservableResult.ObservableState.INDETERMINATE, null);
618 return evalObj.evaluate();
623 String name = NbBundle.getMessage(this.getClass(),
"STIXReportModule.getName.text");
634 String desc = NbBundle.getMessage(this.getClass(),
"STIXReportModule.getDesc.text");
645 if (configPanel == null) {
657 return new STIXReportModuleSettings();
668 return configPanel.getConfiguration();
684 if (settings instanceof STIXReportModuleSettings) {
685 configPanel.setConfiguration((STIXReportModuleSettings) settings);
689 throw new IllegalArgumentException(
"Expected settings argument to be an instance of STIXReportModuleSettings");
void processFile(String stixFile, ReportProgressPanel progressPanel, BufferedWriter output)
String getRelativeFilePath()
void processObservables(STIXPackage stix)
void saveResultsAsArtifacts(Indicator ind, ObservableResult result, ReportProgressPanel progressPanel)
void writeResultsToFile(Indicator ind, String resultStr, boolean found, BufferedWriter output)
Map< String, ObservableResult > idToResult
ReportModuleSettings getDefaultConfiguration()
STIXReportModuleConfigPanel configPanel
void complete(ReportStatus reportStatus)
ObservableResult evaluateObservableComposition(ObservableCompositionType comp, String spacing)
void printFileHeader(String a_fileName, BufferedWriter output)
static STIXReportModule instance
ObservableResult evaluateSingleObservable(Observable obs, String spacing)
STIXPackage loadSTIXFile(String stixFileName)
void addReport(String localPath, String srcModuleName, String reportName)
Map< String, ObjectType > idToObjectMap
static synchronized STIXReportModule getDefault()
void setIndeterminate(boolean indeterminate)
void generateReport(GeneralReportSettings settings, ReportProgressPanel progressPanel)
ReportModuleSettings getConfiguration()
static final Logger logger
void setConfiguration(ReportModuleSettings settings)
List< EvalRegistryObj.RegistryFileInfo > registryFileData
void setMaximumProgress(int max)
JPanel getConfigurationPanel()
void saveToObjectMap(Observable obs)
ObservableResult evaluateObject(ObjectType obj, String spacing, String id)
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
void updateStatusLabel(String statusMessage)
void processIndicators(STIXPackage stix, BufferedWriter output, ReportProgressPanel progressPanel)
final boolean skipShortCircuit
String getReportDirectoryPath()
String makeMapKey(Observable obs)