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 {
232 ClassLoader original = Thread.currentThread().getContextClassLoader();
234 Thread.currentThread().setContextClassLoader(
STIXReportModule.class.getClassLoader());
235 File file =
new File(stixFileName);
236 JAXBContext jaxbContext = JAXBContext.newInstance(
"org.mitre.stix.stix_1:org.mitre.stix.common_1:org.mitre.stix.indicator_2:"
237 +
"org.mitre.cybox.objects:org.mitre.cybox.cybox_2:org.mitre.cybox.common_2");
238 Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
239 STIXPackage stix = (STIXPackage) jaxbUnmarshaller.unmarshal(file);
242 Thread.currentThread().setContextClassLoader(original);
253 if (stix.getObservables() != null) {
254 List<Observable> obs = stix.getObservables().getObservables();
255 for (Observable o : obs) {
256 if (o.getId() != null) {
272 if (stix.getIndicators() != null) {
273 List<IndicatorBaseType> s = stix.getIndicators().getIndicators();
274 for (IndicatorBaseType t : s) {
275 if (t instanceof Indicator) {
276 Indicator ind = (Indicator) t;
277 if (ind.getObservable() != null) {
278 if (ind.getObservable().getObject() != null) {
283 if (result.isTrue()) {
286 }
else if (ind.getObservable().getObservableComposition() != null) {
292 if (result.isTrue()) {
313 if (result.getArtifacts() == null) {
320 for (StixArtifactData s : result.getArtifacts()) {
325 if (ind.getTitle() != null) {
326 s.createArtifact(ind.getTitle());
327 }
else if (ind.getId() != null) {
328 s.createArtifact(ind.getId().toString());
330 s.createArtifact(
"Unnamed indicator(s)");
338 "STIXReportModule.notifyMsg.tooManyArtifactsgt1000"));
354 private void writeResultsToFile(Indicator ind, String resultStr,
boolean found, BufferedWriter output) {
355 if (output != null) {
358 output.write(
"----------------\r\n"
359 +
"Found indicator:\r\n");
361 output.write(
"-----------------------\r\n"
362 +
"Did not find indicator:\r\n");
364 if (ind.getTitle() != null) {
365 output.write(
"Title: " + ind.getTitle() +
"\r\n");
367 output.write(
"\r\n");
369 if (ind.getId() != null) {
370 output.write(
"ID: " + ind.getId() +
"\r\n");
373 if (ind.getDescription() != null) {
374 String desc = ind.getDescription().getValue();
376 output.write(
"Description: " + desc +
"\r\n");
378 output.write(
"\r\nObservable results:\r\n" + resultStr +
"\r\n\r\n");
379 }
catch (IOException ex) {
380 logger.log(Level.SEVERE, String.format(
"Error writing to STIX report file %s", reportPath), ex);
392 if (output != null) {
394 char[] chars =
new char[a_fileName.length() + 8];
395 Arrays.fill(chars,
'#');
396 String header =
new String(chars);
397 output.write(
"\r\n" + header);
398 output.write(
"\r\n");
399 output.write(
"### " + a_fileName +
" ###\r\n");
400 output.write(header +
"\r\n\r\n");
401 }
catch (IOException ex) {
402 logger.log(Level.SEVERE, String.format(
"Error writing to STIX report file %s", reportPath), ex);
418 if (obs.getId() != null) {
420 }
else if (obs.getIdref() != null) {
421 idQ = obs.getIdref();
426 return idQ.getLocalPart();
436 if (obs.getObject() != null) {
437 idToObjectMap.put(
makeMapKey(obs), obs.getObject());
452 if (comp.getOperator() == null) {
453 throw new TskCoreException(
"No operator found in composition");
456 if (comp.getObservables() != null) {
457 List<Observable> obsList = comp.getObservables();
460 if (comp.getOperator() == OperatorTypeEnum.AND) {
461 ObservableResult result =
new ObservableResult(OperatorTypeEnum.AND, spacing);
462 for (Observable o : obsList) {
464 ObservableResult newResult;
465 if (o.getObservableComposition() != null) {
467 if (result == null) {
470 result.addResult(newResult, OperatorTypeEnum.AND);
474 if (result == null) {
477 result.addResult(newResult, OperatorTypeEnum.AND);
481 if ((!skipShortCircuit) && !result.isFalse()) {
487 if (result == null) {
490 return new ObservableResult(
"",
"", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
496 ObservableResult result =
new ObservableResult(OperatorTypeEnum.OR, spacing);
497 for (Observable o : obsList) {
499 ObservableResult newResult;
501 if (o.getObservableComposition() != null) {
503 if (result == null) {
506 result.addResult(newResult, OperatorTypeEnum.OR);
510 if (result == null) {
513 result.addResult(newResult, OperatorTypeEnum.OR);
517 if ((!skipShortCircuit) && result.isTrue()) {
523 if (result == null) {
526 return new ObservableResult(
"",
"", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
532 throw new TskCoreException(
"No observables found in list");
550 if (idToResult.containsKey(
makeMapKey(obs))) {
554 if (obs.getIdref() == null) {
558 if (obs.getId() != null) {
562 if (obs.getObject() != null) {
570 if (idToObjectMap.containsKey(
makeMapKey(obs))) {
576 throw new TskCoreException(
"Error loading/finding object for observable " + obs.getIdref());
589 private ObservableResult
evaluateObject(ObjectType obj, String spacing, String
id) {
591 EvaluatableObject evalObj;
593 if (obj.getProperties() instanceof FileObjectType) {
594 evalObj =
new EvalFileObj((FileObjectType) obj.getProperties(), id, spacing);
595 }
else if (obj.getProperties() instanceof Address) {
596 evalObj =
new EvalAddressObj((Address) obj.getProperties(), id, spacing);
597 }
else if (obj.getProperties() instanceof URIObjectType) {
598 evalObj =
new EvalURIObj((URIObjectType) obj.getProperties(), id, spacing);
599 }
else if (obj.getProperties() instanceof EmailMessage) {
600 evalObj =
new EvalEmailObj((EmailMessage) obj.getProperties(), id, spacing);
601 }
else if (obj.getProperties() instanceof WindowsNetworkShare) {
602 evalObj =
new EvalNetworkShareObj((WindowsNetworkShare) obj.getProperties(), id, spacing);
603 }
else if (obj.getProperties() instanceof AccountObjectType) {
604 evalObj =
new EvalAccountObj((AccountObjectType) obj.getProperties(), id, spacing);
605 }
else if (obj.getProperties() instanceof SystemObjectType) {
606 evalObj =
new EvalSystemObj((SystemObjectType) obj.getProperties(), id, spacing);
607 }
else if (obj.getProperties() instanceof URLHistory) {
608 evalObj =
new EvalURLHistoryObj((URLHistory) obj.getProperties(), id, spacing);
609 }
else if (obj.getProperties() instanceof DomainName) {
610 evalObj =
new EvalDomainObj((DomainName) obj.getProperties(), id, spacing);
611 }
else if (obj.getProperties() instanceof WindowsRegistryKey) {
612 evalObj =
new EvalRegistryObj((WindowsRegistryKey) obj.getProperties(), id, spacing,
registryFileData);
615 String type = obj.getProperties().toString();
616 type = type.substring(0, type.indexOf(
"@"));
617 if ((type.lastIndexOf(
".") + 1) < type.length()) {
618 type = type.substring(type.lastIndexOf(
".") + 1);
620 return new ObservableResult(
id, type +
" not supported",
621 spacing, ObservableResult.ObservableState.INDETERMINATE, null);
625 return evalObj.evaluate();
630 String name = NbBundle.getMessage(this.getClass(),
"STIXReportModule.getName.text");
641 String desc = NbBundle.getMessage(this.getClass(),
"STIXReportModule.getDesc.text");
652 if (configPanel == null) {
664 return new STIXReportModuleSettings();
675 return configPanel.getConfiguration();
691 if (settings instanceof STIXReportModuleSettings) {
692 configPanel.setConfiguration((STIXReportModuleSettings) settings);
696 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)