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;
74 private Map<String, ObjectType>
idToObjectMap =
new HashMap<String, ObjectType>();
75 private Map<String, ObservableResult>
idToResult =
new HashMap<String, ObservableResult>();
87 if (instance == null) {
98 @Messages({
"STIXReportModule.srcModuleName.text=STIX Report"})
102 progressPanel.
start();
103 progressPanel.
updateStatusLabel(NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.readSTIX"));
105 File reportFile =
new File(reportPath);
110 boolean hadErrors =
false;
115 if (stixFileName == null) {
116 logger.log(Level.SEVERE,
"STIXReportModuleConfigPanel.stixFile not initialized ");
118 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.notifyErr.noFildDirProvided"));
121 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.noFildDirProvided"));
122 new File(baseReportDir).delete();
125 if (stixFileName.isEmpty()) {
126 logger.log(Level.SEVERE,
"No STIX file/directory provided ");
128 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.notifyErr.noFildDirProvided"));
131 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.noFildDirProvided"));
132 new File(baseReportDir).delete();
135 File stixFile =
new File(stixFileName);
137 if (!stixFile.exists()) {
138 logger.log(Level.SEVERE, String.format(
"Unable to open STIX file/directory %s", stixFileName));
140 "STIXReportModule.notifyMsg.unableToOpenFileDir",
144 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.couldNotOpenFileDir", stixFileName));
145 new File(baseReportDir).delete();
149 try (BufferedWriter output =
new BufferedWriter(
new FileWriter(reportFile))) {
155 if (stixFile.isFile()) {
156 stixFiles =
new File[1];
157 stixFiles[0] = stixFile;
159 stixFiles = stixFile.listFiles();
166 for (File file : stixFiles) {
171 processFile(file.getAbsolutePath(), progressPanel, output);
173 String errMsg = String.format(
"Unable to process STIX file %s", file);
174 logger.log(Level.SEVERE, errMsg, ex);
182 idToObjectMap =
new HashMap<String, ObjectType>();
183 idToResult =
new HashMap<String, ObservableResult>();
192 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.completedWithErrors"));
196 }
catch (IOException ex) {
197 logger.log(Level.SEVERE,
"Unable to complete STIX report.", ex);
199 NbBundle.getMessage(
this.getClass(),
200 "STIXReportModule.notifyMsg.unableToOpenReportFile"),
204 NbBundle.getMessage(
this.getClass(),
"STIXReportModule.progress.completedWithErrors"));
206 logger.log(Level.SEVERE,
"Unable to add report to database.", ex);
251 private STIXPackage
loadSTIXFile(String stixFileName)
throws JAXBException {
253 File file =
new File(stixFileName);
254 JAXBContext jaxbContext = JAXBContext.newInstance(
"org.mitre.stix.stix_1:org.mitre.stix.common_1:org.mitre.stix.indicator_2:"
255 +
"org.mitre.cybox.objects:org.mitre.cybox.cybox_2:org.mitre.cybox.common_2");
256 Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
257 STIXPackage stix = (STIXPackage) jaxbUnmarshaller.unmarshal(file);
268 if (stix.getObservables() != null) {
269 List<Observable> obs = stix.getObservables().getObservables();
270 for (Observable o : obs) {
271 if (o.getId() != null) {
286 if (stix.getIndicators() != null) {
287 List<IndicatorBaseType> s = stix.getIndicators().getIndicators();
288 for (IndicatorBaseType t : s) {
289 if (t instanceof Indicator) {
290 Indicator ind = (Indicator) t;
291 if (ind.getObservable() != null) {
292 if (ind.getObservable().getObject() != null) {
297 if (result.isTrue()) {
300 }
else if (ind.getObservable().getObservableComposition() != null) {
306 if (result.isTrue()) {
326 if (result.getArtifacts() == null) {
333 for (StixArtifactData s : result.getArtifacts()) {
338 if (ind.getTitle() != null) {
339 s.createArtifact(ind.getTitle());
340 }
else if (ind.getId() != null) {
341 s.createArtifact(ind.getId().toString());
343 s.createArtifact(
"Unnamed indicator(s)");
351 NbBundle.getMessage(
this.getClass(),
352 "STIXReportModule.notifyMsg.tooManyArtifactsgt1000",
370 private void writeResultsToFile(Indicator ind, String resultStr,
boolean found, BufferedWriter output) {
371 if (output != null) {
374 output.write(
"----------------\r\n"
375 +
"Found indicator:\r\n");
377 output.write(
"-----------------------\r\n"
378 +
"Did not find indicator:\r\n");
380 if (ind.getTitle() != null) {
381 output.write(
"Title: " + ind.getTitle() +
"\r\n");
383 output.write(
"\r\n");
385 if (ind.getId() != null) {
386 output.write(
"ID: " + ind.getId() +
"\r\n");
389 if (ind.getDescription() != null) {
390 String desc = ind.getDescription().getValue();
392 output.write(
"Description: " + desc +
"\r\n");
394 output.write(
"\r\nObservable results:\r\n" + resultStr +
"\r\n\r\n");
395 }
catch (IOException ex) {
396 logger.log(Level.SEVERE, String.format(
"Error writing to STIX report file %s", reportPath), ex);
408 if (output != null) {
410 char[] chars =
new char[a_fileName.length() + 8];
411 Arrays.fill(chars,
'#');
412 String header =
new String(chars);
413 output.write(
"\r\n" + header);
414 output.write(
"\r\n");
415 output.write(
"### " + a_fileName +
" ###\r\n");
416 output.write(header +
"\r\n\r\n");
417 }
catch (IOException ex) {
418 logger.log(Level.SEVERE, String.format(
"Error writing to STIX report file %s", reportPath), ex);
434 if (obs.getId() != null) {
436 }
else if (obs.getIdref() != null) {
437 idQ = obs.getIdref();
442 return idQ.getLocalPart();
452 if (obs.getObject() != null) {
453 idToObjectMap.put(
makeMapKey(obs), obs.getObject());
468 if (comp.getOperator() == null) {
472 if (comp.getObservables() != null) {
473 List<Observable> obsList = comp.getObservables();
476 if (comp.getOperator() == OperatorTypeEnum.AND) {
477 ObservableResult result =
new ObservableResult(OperatorTypeEnum.AND, spacing);
478 for (Observable o : obsList) {
480 ObservableResult newResult;
481 if (o.getObservableComposition() != null) {
483 if (result == null) {
486 result.addResult(newResult, OperatorTypeEnum.AND);
490 if (result == null) {
493 result.addResult(newResult, OperatorTypeEnum.AND);
497 if ((!skipShortCircuit) && !result.isFalse()) {
503 if (result == null) {
506 return new ObservableResult(
"",
"", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
512 ObservableResult result =
new ObservableResult(OperatorTypeEnum.OR, spacing);
513 for (Observable o : obsList) {
515 ObservableResult newResult;
517 if (o.getObservableComposition() != null) {
519 if (result == null) {
522 result.addResult(newResult, OperatorTypeEnum.OR);
526 if (result == null) {
529 result.addResult(newResult, OperatorTypeEnum.OR);
533 if ((!skipShortCircuit) && result.isTrue()) {
539 if (result == null) {
542 return new ObservableResult(
"",
"", spacing, ObservableResult.ObservableState.INDETERMINATE, null);
566 if (idToResult.containsKey(
makeMapKey(obs))) {
570 if (obs.getIdref() == null) {
574 if (obs.getId() != null) {
578 if (obs.getObject() != null) {
586 if (idToObjectMap.containsKey(
makeMapKey(obs))) {
592 throw new TskCoreException(
"Error loading/finding object for observable " + obs.getIdref());
605 private ObservableResult
evaluateObject(ObjectType obj, String spacing, String
id) {
607 EvaluatableObject evalObj;
609 if (obj.getProperties() instanceof FileObjectType) {
610 evalObj =
new EvalFileObj((FileObjectType) obj.getProperties(), id, spacing);
611 }
else if (obj.getProperties() instanceof Address) {
612 evalObj =
new EvalAddressObj((Address) obj.getProperties(), id, spacing);
613 }
else if (obj.getProperties() instanceof URIObjectType) {
614 evalObj =
new EvalURIObj((URIObjectType) obj.getProperties(), id, spacing);
615 }
else if (obj.getProperties() instanceof EmailMessage) {
616 evalObj =
new EvalEmailObj((EmailMessage) obj.getProperties(), id, spacing);
617 }
else if (obj.getProperties() instanceof WindowsNetworkShare) {
618 evalObj =
new EvalNetworkShareObj((WindowsNetworkShare) obj.getProperties(), id, spacing);
619 }
else if (obj.getProperties() instanceof AccountObjectType) {
620 evalObj =
new EvalAccountObj((AccountObjectType) obj.getProperties(), id, spacing);
621 }
else if (obj.getProperties() instanceof SystemObjectType) {
622 evalObj =
new EvalSystemObj((SystemObjectType) obj.getProperties(), id, spacing);
623 }
else if (obj.getProperties() instanceof URLHistory) {
624 evalObj =
new EvalURLHistoryObj((URLHistory) obj.getProperties(), id, spacing);
625 }
else if (obj.getProperties() instanceof DomainName) {
626 evalObj =
new EvalDomainObj((DomainName) obj.getProperties(), id, spacing);
627 }
else if (obj.getProperties() instanceof WindowsRegistryKey) {
628 evalObj =
new EvalRegistryObj((WindowsRegistryKey) obj.getProperties(), id, spacing,
registryFileData);
631 String type = obj.getProperties().toString();
632 type = type.substring(0, type.indexOf(
"@"));
633 if ((type.lastIndexOf(
".") + 1) < type.length()) {
634 type = type.substring(type.lastIndexOf(
".") + 1);
636 return new ObservableResult(
id, type +
" not supported",
637 spacing, ObservableResult.ObservableState.INDETERMINATE, null);
641 return evalObj.evaluate();
646 String name = NbBundle.getMessage(this.getClass(),
"STIXReportModule.getName.text");
657 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
static Case getCurrentCase()
synchronized static Logger getLogger(String name)
static void show(String title, String message, MessageType type, ActionListener actionListener)
void updateStatusLabel(String statusMessage)
Map< String, ObservableResult > idToResult
static void error(String message)
boolean getShowAllResults()
void processIndicators(STIXPackage stix, BufferedWriter output)