19 package org.sleuthkit.autopsy.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;
75 private Map<String, ObjectType>
idToObjectMap =
new HashMap<String, ObjectType>();
76 private Map<String, ObservableResult>
idToResult =
new HashMap<String, ObservableResult>();
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);
111 boolean hadErrors =
false;
116 if (stixFileName == null) {
117 logger.log(Level.SEVERE,
"STIXReportModuleConfigPanel.stixFile not initialized ");
119 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.notifyErr.noFildDirProvided"));
122 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.noFildDirProvided"));
123 new File(baseReportDir).delete();
126 if (stixFileName.isEmpty()) {
127 logger.log(Level.SEVERE,
"No STIX file/directory provided ");
129 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.notifyErr.noFildDirProvided"));
132 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.noFildDirProvided"));
133 new File(baseReportDir).delete();
136 File stixFile =
new File(stixFileName);
138 if (!stixFile.exists()) {
139 logger.log(Level.SEVERE, String.format(
"Unable to open STIX file/directory %s", stixFileName));
141 "STIXReportModule.notifyMsg.unableToOpenFileDir",
145 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.couldNotOpenFileDir", stixFileName));
146 new File(baseReportDir).delete();
150 try (BufferedWriter output =
new BufferedWriter(
new FileWriter(reportFile))) {
156 if (stixFile.isFile()) {
157 stixFiles =
new File[1];
158 stixFiles[0] = stixFile;
160 stixFiles = stixFile.listFiles();
167 for (File file : stixFiles) {
172 processFile(file.getAbsolutePath(), progressPanel, output);
173 }
catch (TskCoreException | JAXBException ex) {
174 String errMsg = String.format(
"Unable to process STIX file %s", file);
175 logger.log(Level.SEVERE, errMsg, ex);
183 idToObjectMap =
new HashMap<String, ObjectType>();
184 idToResult =
new HashMap<String, ObservableResult>();
193 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.completedWithErrors"));
197 }
catch (IOException ex) {
198 logger.log(Level.SEVERE,
"Unable to complete STIX report.", ex);
200 NbBundle.getMessage(
this.getClass(),
201 "STIXReportModule.notifyMsg.unableToOpenReportFile"),
205 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.completedWithErrors"));
207 logger.log(Level.SEVERE,
"Unable to add report to database.", ex);
222 JAXBException, TskCoreException {
252 private STIXPackage
loadSTIXFile(String stixFileName)
throws JAXBException {
254 File file =
new File(stixFileName);
255 JAXBContext jaxbContext = JAXBContext.newInstance(
"org.mitre.stix.stix_1:org.mitre.stix.common_1:org.mitre.stix.indicator_2:"
256 +
"org.mitre.cybox.objects:org.mitre.cybox.cybox_2:org.mitre.cybox.common_2");
257 Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
258 STIXPackage stix = (STIXPackage) jaxbUnmarshaller.unmarshal(file);
269 if (stix.getObservables() != null) {
270 List<Observable> obs = stix.getObservables().getObservables();
271 for (Observable o : obs) {
272 if (o.getId() != null) {
286 private void processIndicators(STIXPackage stix, BufferedWriter output)
throws TskCoreException {
287 if (stix.getIndicators() != null) {
288 List<IndicatorBaseType> s = stix.getIndicators().getIndicators();
289 for (IndicatorBaseType t : s) {
290 if (t instanceof Indicator) {
291 Indicator ind = (Indicator) t;
292 if (ind.getObservable() != null) {
293 if (ind.getObservable().getObject() != null) {
298 if (result.isTrue()) {
301 }
else if (ind.getObservable().getObservableComposition() != null) {
307 if (result.isTrue()) {
327 if (result.getArtifacts() == null) {
334 for (StixArtifactData s : result.getArtifacts()) {
339 if (ind.getTitle() != null) {
340 s.createArtifact(ind.getTitle());
341 }
else if (ind.getId() != null) {
342 s.createArtifact(ind.getId().toString());
344 s.createArtifact(
"Unnamed indicator(s)");
352 NbBundle.getMessage(
this.getClass(),
353 "STIXReportModule.notifyMsg.tooManyArtifactsgt1000",
371 private void writeResultsToFile(Indicator ind, String resultStr,
boolean found, BufferedWriter output) {
372 if (output != null) {
375 output.write(
"----------------\r\n"
376 +
"Found indicator:\r\n");
378 output.write(
"-----------------------\r\n"
379 +
"Did not find indicator:\r\n");
381 if (ind.getTitle() != null) {
382 output.write(
"Title: " + ind.getTitle() +
"\r\n");
384 output.write(
"\r\n");
386 if (ind.getId() != null) {
387 output.write(
"ID: " + ind.getId() +
"\r\n");
390 if (ind.getDescription() != null) {
391 String desc = ind.getDescription().getValue();
393 output.write(
"Description: " + desc +
"\r\n");
395 output.write(
"\r\nObservable results:\r\n" + resultStr +
"\r\n\r\n");
396 }
catch (IOException ex) {
397 logger.log(Level.SEVERE, String.format(
"Error writing to STIX report file %s", reportPath), ex);
409 if (output != null) {
411 char[] chars =
new char[a_fileName.length() + 8];
412 Arrays.fill(chars,
'#');
413 String header =
new String(chars);
414 output.write(
"\r\n" + header);
415 output.write(
"\r\n");
416 output.write(
"### " + a_fileName +
" ###\r\n");
417 output.write(header +
"\r\n\r\n");
418 }
catch (IOException ex) {
419 logger.log(Level.SEVERE, String.format(
"Error writing to STIX report file %s", reportPath), ex);
435 if (obs.getId() != null) {
437 }
else if (obs.getIdref() != null) {
438 idQ = obs.getIdref();
443 return idQ.getLocalPart();
453 if (obs.getObject() != null) {
454 idToObjectMap.put(
makeMapKey(obs), obs.getObject());
469 if (comp.getOperator() == null) {
470 throw new TskCoreException(
"No operator found in composition");
473 if (comp.getObservables() != null) {
474 List<Observable> obsList = comp.getObservables();
477 if (comp.getOperator() == OperatorTypeEnum.AND) {
478 ObservableResult result =
new ObservableResult(OperatorTypeEnum.AND, spacing);
479 for (Observable o : obsList) {
481 ObservableResult newResult;
482 if (o.getObservableComposition() != null) {
484 if (result == null) {
487 result.addResult(newResult, OperatorTypeEnum.AND);
491 if (result == null) {
494 result.addResult(newResult, OperatorTypeEnum.AND);
498 if ((!skipShortCircuit) && !result.isFalse()) {
504 if (result == null) {
507 return new ObservableResult(
"",
"", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
513 ObservableResult result =
new ObservableResult(OperatorTypeEnum.OR, spacing);
514 for (Observable o : obsList) {
516 ObservableResult newResult;
518 if (o.getObservableComposition() != null) {
520 if (result == null) {
523 result.addResult(newResult, OperatorTypeEnum.OR);
527 if (result == null) {
530 result.addResult(newResult, OperatorTypeEnum.OR);
534 if ((!skipShortCircuit) && result.isTrue()) {
540 if (result == null) {
543 return new ObservableResult(
"",
"", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
549 throw new TskCoreException(
"No observables found in list");
567 if (idToResult.containsKey(
makeMapKey(obs))) {
571 if (obs.getIdref() == null) {
575 if (obs.getId() != null) {
579 if (obs.getObject() != null) {
587 if (idToObjectMap.containsKey(
makeMapKey(obs))) {
593 throw new TskCoreException(
"Error loading/finding object for observable " + obs.getIdref());
606 private ObservableResult
evaluateObject(ObjectType obj, String spacing, String
id) {
608 EvaluatableObject evalObj;
610 if (obj.getProperties() instanceof FileObjectType) {
611 evalObj =
new EvalFileObj((FileObjectType) obj.getProperties(), id, spacing);
612 }
else if (obj.getProperties() instanceof Address) {
613 evalObj =
new EvalAddressObj((Address) obj.getProperties(), id, spacing);
614 }
else if (obj.getProperties() instanceof URIObjectType) {
615 evalObj =
new EvalURIObj((URIObjectType) obj.getProperties(), id, spacing);
616 }
else if (obj.getProperties() instanceof EmailMessage) {
617 evalObj =
new EvalEmailObj((EmailMessage) obj.getProperties(), id, spacing);
618 }
else if (obj.getProperties() instanceof WindowsNetworkShare) {
619 evalObj =
new EvalNetworkShareObj((WindowsNetworkShare) obj.getProperties(), id, spacing);
620 }
else if (obj.getProperties() instanceof AccountObjectType) {
621 evalObj =
new EvalAccountObj((AccountObjectType) obj.getProperties(), id, spacing);
622 }
else if (obj.getProperties() instanceof SystemObjectType) {
623 evalObj =
new EvalSystemObj((SystemObjectType) obj.getProperties(), id, spacing);
624 }
else if (obj.getProperties() instanceof URLHistory) {
625 evalObj =
new EvalURLHistoryObj((URLHistory) obj.getProperties(), id, spacing);
626 }
else if (obj.getProperties() instanceof DomainName) {
627 evalObj =
new EvalDomainObj((DomainName) obj.getProperties(), id, spacing);
628 }
else if (obj.getProperties() instanceof WindowsRegistryKey) {
629 evalObj =
new EvalRegistryObj((WindowsRegistryKey) obj.getProperties(), id, spacing,
registryFileData);
632 String type = obj.getProperties().toString();
633 type = type.substring(0, type.indexOf(
"@"));
634 if ((type.lastIndexOf(
".") + 1) < type.length()) {
635 type = type.substring(type.lastIndexOf(
".") + 1);
637 return new ObservableResult(
id, type +
" not supported",
638 spacing, ObservableResult.ObservableState.INDETERMINATE, null);
642 return evalObj.evaluate();
647 String name = NbBundle.getMessage(this.getClass(),
"STIXReportModule.getName.text");
658 String desc = NbBundle.getMessage(this.getClass(),
"STIXReportModule.getDesc.text");
void saveToObjectMap(Observable obs)
ObservableResult evaluateObservableComposition(ObservableCompositionType comp, String spacing)
void generateReport(String baseReportDir, ReportProgressPanel progressPanel)
String getRelativeFilePath()
JPanel getConfigurationPanel()
ObservableResult evaluateObject(ObjectType obj, String spacing, String id)
Map< String, ObjectType > idToObjectMap
void complete(ReportStatus reportStatus)
String makeMapKey(Observable obs)
void processFile(String stixFile, ReportProgressPanel progressPanel, BufferedWriter output)
static synchronized STIXReportModule getDefault()
static final Logger logger
void addReport(String localPath, String srcModuleName, String reportName)
static STIXReportModule instance
void setIndeterminate(boolean indeterminate)
final boolean skipShortCircuit
void saveResultsAsArtifacts(Indicator ind, ObservableResult result)
void processObservables(STIXPackage stix)
STIXPackage loadSTIXFile(String stixFileName)
static synchronized void setConfigSetting(String moduleName, String settingName, String settingVal)
void printFileHeader(String a_fileName, BufferedWriter output)
void setMaximumProgress(int max)
ObservableResult evaluateSingleObservable(Observable obs, String spacing)
List< EvalRegistryObj.RegistryFileInfo > registryFileData
void writeResultsToFile(Indicator ind, String resultStr, boolean found, BufferedWriter output)
STIXReportModuleConfigPanel configPanel
synchronized static Logger getLogger(String name)
static void show(String title, String message, MessageType type, ActionListener actionListener)
static Case getCurrentCaseThrows()
void updateStatusLabel(String statusMessage)
Map< String, ObservableResult > idToResult
static void error(String message)
boolean getShowAllResults()
void processIndicators(STIXPackage stix, BufferedWriter output)