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;
76 private Map<String, ObservableResult>
idToResult =
new HashMap<>();
88 if (instance == null) {
99 @Messages({
"STIXReportModule.srcModuleName.text=STIX Report"})
103 progressPanel.
start();
104 progressPanel.
updateStatusLabel(NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.readSTIX"));
106 File reportFile =
new File(reportPath);
108 reportAllResults = configPanel.getShowAllResults();
111 boolean hadErrors =
false;
114 String stixFileName = configPanel.getStixFile();
116 if (stixFileName == null) {
117 logger.log(Level.SEVERE,
"STIXReportModuleConfigPanel.stixFile not initialized ");
118 progressPanel.
complete(
ReportStatus.
ERROR, NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.noFildDirProvided"));
119 new File(baseReportDir).delete();
122 if (stixFileName.isEmpty()) {
123 logger.log(Level.SEVERE,
"No STIX file/directory provided ");
124 progressPanel.
complete(
ReportStatus.
ERROR, NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.noFildDirProvided"));
125 new File(baseReportDir).delete();
128 File stixFile =
new File(stixFileName);
130 if (!stixFile.exists()) {
131 logger.log(Level.SEVERE, String.format(
"Unable to open STIX file/directory %s", stixFileName));
132 progressPanel.
complete(
ReportStatus.
ERROR, NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.couldNotOpenFileDir", stixFileName));
133 new File(baseReportDir).delete();
137 try (BufferedWriter output =
new BufferedWriter(
new FileWriter(reportFile))) {
141 if (stixFile.isFile()) {
142 stixFiles =
new File[1];
143 stixFiles[0] = stixFile;
145 stixFiles = stixFile.listFiles();
152 for (File file : stixFiles) {
157 processFile(file.getAbsolutePath(), progressPanel, output);
158 }
catch (TskCoreException | JAXBException ex) {
159 String errMsg = String.format(
"Unable to process STIX file %s", file);
160 logger.log(Level.SEVERE, errMsg, ex);
166 idToObjectMap =
new HashMap<>();
167 idToResult =
new HashMap<>();
174 progressPanel.
complete(
ReportStatus.
ERROR, NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.completedWithErrors"));
178 }
catch (IOException ex) {
179 logger.log(Level.SEVERE,
"Unable to complete STIX report.", ex);
180 progressPanel.
complete(
ReportStatus.
ERROR, NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.completedWithErrors"));
182 logger.log(Level.SEVERE,
"Unable to add report to database.", ex);
197 JAXBException, TskCoreException {
227 private STIXPackage
loadSTIXFile(String stixFileName)
throws JAXBException {
229 File file =
new File(stixFileName);
230 JAXBContext jaxbContext = JAXBContext.newInstance(
"org.mitre.stix.stix_1:org.mitre.stix.common_1:org.mitre.stix.indicator_2:"
231 +
"org.mitre.cybox.objects:org.mitre.cybox.cybox_2:org.mitre.cybox.common_2");
232 Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
233 STIXPackage stix = (STIXPackage) jaxbUnmarshaller.unmarshal(file);
244 if (stix.getObservables() != null) {
245 List<Observable> obs = stix.getObservables().getObservables();
246 for (Observable o : obs) {
247 if (o.getId() != null) {
263 if (stix.getIndicators() != null) {
264 List<IndicatorBaseType> s = stix.getIndicators().getIndicators();
265 for (IndicatorBaseType t : s) {
266 if (t instanceof Indicator) {
267 Indicator ind = (Indicator) t;
268 if (ind.getObservable() != null) {
269 if (ind.getObservable().getObject() != null) {
274 if (result.isTrue()) {
277 }
else if (ind.getObservable().getObservableComposition() != null) {
283 if (result.isTrue()) {
304 if (result.getArtifacts() == null) {
311 for (StixArtifactData s : result.getArtifacts()) {
316 if (ind.getTitle() != null) {
317 s.createArtifact(ind.getTitle());
318 }
else if (ind.getId() != null) {
319 s.createArtifact(ind.getId().toString());
321 s.createArtifact(
"Unnamed indicator(s)");
329 "STIXReportModule.notifyMsg.tooManyArtifactsgt1000"));
345 private void writeResultsToFile(Indicator ind, String resultStr,
boolean found, BufferedWriter output) {
346 if (output != null) {
349 output.write(
"----------------\r\n"
350 +
"Found indicator:\r\n");
352 output.write(
"-----------------------\r\n"
353 +
"Did not find indicator:\r\n");
355 if (ind.getTitle() != null) {
356 output.write(
"Title: " + ind.getTitle() +
"\r\n");
358 output.write(
"\r\n");
360 if (ind.getId() != null) {
361 output.write(
"ID: " + ind.getId() +
"\r\n");
364 if (ind.getDescription() != null) {
365 String desc = ind.getDescription().getValue();
367 output.write(
"Description: " + desc +
"\r\n");
369 output.write(
"\r\nObservable results:\r\n" + resultStr +
"\r\n\r\n");
370 }
catch (IOException ex) {
371 logger.log(Level.SEVERE, String.format(
"Error writing to STIX report file %s", reportPath), ex);
383 if (output != null) {
385 char[] chars =
new char[a_fileName.length() + 8];
386 Arrays.fill(chars,
'#');
387 String header =
new String(chars);
388 output.write(
"\r\n" + header);
389 output.write(
"\r\n");
390 output.write(
"### " + a_fileName +
" ###\r\n");
391 output.write(header +
"\r\n\r\n");
392 }
catch (IOException ex) {
393 logger.log(Level.SEVERE, String.format(
"Error writing to STIX report file %s", reportPath), ex);
409 if (obs.getId() != null) {
411 }
else if (obs.getIdref() != null) {
412 idQ = obs.getIdref();
417 return idQ.getLocalPart();
427 if (obs.getObject() != null) {
428 idToObjectMap.put(
makeMapKey(obs), obs.getObject());
443 if (comp.getOperator() == null) {
444 throw new TskCoreException(
"No operator found in composition");
447 if (comp.getObservables() != null) {
448 List<Observable> obsList = comp.getObservables();
451 if (comp.getOperator() == OperatorTypeEnum.AND) {
452 ObservableResult result =
new ObservableResult(OperatorTypeEnum.AND, spacing);
453 for (Observable o : obsList) {
455 ObservableResult newResult;
456 if (o.getObservableComposition() != null) {
458 if (result == null) {
461 result.addResult(newResult, OperatorTypeEnum.AND);
465 if (result == null) {
468 result.addResult(newResult, OperatorTypeEnum.AND);
472 if ((!skipShortCircuit) && !result.isFalse()) {
478 if (result == null) {
481 return new ObservableResult(
"",
"", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
487 ObservableResult result =
new ObservableResult(OperatorTypeEnum.OR, spacing);
488 for (Observable o : obsList) {
490 ObservableResult newResult;
492 if (o.getObservableComposition() != null) {
494 if (result == null) {
497 result.addResult(newResult, OperatorTypeEnum.OR);
501 if (result == null) {
504 result.addResult(newResult, OperatorTypeEnum.OR);
508 if ((!skipShortCircuit) && result.isTrue()) {
514 if (result == null) {
517 return new ObservableResult(
"",
"", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
523 throw new TskCoreException(
"No observables found in list");
541 if (idToResult.containsKey(
makeMapKey(obs))) {
545 if (obs.getIdref() == null) {
549 if (obs.getId() != null) {
553 if (obs.getObject() != null) {
561 if (idToObjectMap.containsKey(
makeMapKey(obs))) {
567 throw new TskCoreException(
"Error loading/finding object for observable " + obs.getIdref());
580 private ObservableResult
evaluateObject(ObjectType obj, String spacing, String
id) {
582 EvaluatableObject evalObj;
584 if (obj.getProperties() instanceof FileObjectType) {
585 evalObj =
new EvalFileObj((FileObjectType) obj.getProperties(), id, spacing);
586 }
else if (obj.getProperties() instanceof Address) {
587 evalObj =
new EvalAddressObj((Address) obj.getProperties(), id, spacing);
588 }
else if (obj.getProperties() instanceof URIObjectType) {
589 evalObj =
new EvalURIObj((URIObjectType) obj.getProperties(), id, spacing);
590 }
else if (obj.getProperties() instanceof EmailMessage) {
591 evalObj =
new EvalEmailObj((EmailMessage) obj.getProperties(), id, spacing);
592 }
else if (obj.getProperties() instanceof WindowsNetworkShare) {
593 evalObj =
new EvalNetworkShareObj((WindowsNetworkShare) obj.getProperties(), id, spacing);
594 }
else if (obj.getProperties() instanceof AccountObjectType) {
595 evalObj =
new EvalAccountObj((AccountObjectType) obj.getProperties(), id, spacing);
596 }
else if (obj.getProperties() instanceof SystemObjectType) {
597 evalObj =
new EvalSystemObj((SystemObjectType) obj.getProperties(), id, spacing);
598 }
else if (obj.getProperties() instanceof URLHistory) {
599 evalObj =
new EvalURLHistoryObj((URLHistory) obj.getProperties(), id, spacing);
600 }
else if (obj.getProperties() instanceof DomainName) {
601 evalObj =
new EvalDomainObj((DomainName) obj.getProperties(), id, spacing);
602 }
else if (obj.getProperties() instanceof WindowsRegistryKey) {
603 evalObj =
new EvalRegistryObj((WindowsRegistryKey) obj.getProperties(), id, spacing,
registryFileData);
606 String type = obj.getProperties().toString();
607 type = type.substring(0, type.indexOf(
"@"));
608 if ((type.lastIndexOf(
".") + 1) < type.length()) {
609 type = type.substring(type.lastIndexOf(
".") + 1);
611 return new ObservableResult(
id, type +
" not supported",
612 spacing, ObservableResult.ObservableState.INDETERMINATE, null);
616 return evalObj.evaluate();
621 String name = NbBundle.getMessage(this.getClass(),
"STIXReportModule.getName.text");
632 String desc = NbBundle.getMessage(this.getClass(),
"STIXReportModule.getDesc.text");
643 if (configPanel == null) {
655 return new STIXReportModuleSettings();
666 return configPanel.getConfiguration();
682 if (settings instanceof STIXReportModuleSettings) {
683 configPanel.setConfiguration((STIXReportModuleSettings) settings);
687 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 generateReport(String baseReportDir, 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)
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 makeMapKey(Observable obs)