Minor cleanup

This commit is contained in:
Brian Carrier 2013-10-19 13:41:30 -04:00
parent 28e6c98906
commit 003d12570b
3 changed files with 127 additions and 111 deletions

View File

@ -1,3 +1,21 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.thunderbirdparser; package org.sleuthkit.autopsy.thunderbirdparser;
import java.io.*; import java.io.*;
@ -18,6 +36,10 @@ import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.ContentHandler; import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
/**
* Parses an MBOX file.
*
*/
public class ThunderbirdEmailParser { public class ThunderbirdEmailParser {
private InputStream stream; private InputStream stream;
@ -41,6 +63,10 @@ public class ThunderbirdEmailParser {
this.tika = new Tika(); this.tika = new Tika();
} }
/**
*
* @param inStream String to MBX file
*/
public ThunderbirdEmailParser(InputStream inStream) { public ThunderbirdEmailParser(InputStream inStream) {
this.tika = new Tika(); this.tika = new Tika();
this.stream = inStream; this.stream = inStream;
@ -61,11 +87,26 @@ public class ThunderbirdEmailParser {
this.contentHandler = new BodyContentHandler(10*1024*1024); this.contentHandler = new BodyContentHandler(10*1024*1024);
} }
/**
* Parse data passed in via constructor
* @throws FileNotFoundException
* @throws IOException
* @throws SAXException
* @throws TikaException
*/
public void parse() throws FileNotFoundException, IOException, SAXException, TikaException { public void parse() throws FileNotFoundException, IOException, SAXException, TikaException {
init(); init();
parser.parse(this.stream, this.contentHandler, this.metadata, context); parser.parse(this.stream, this.contentHandler, this.metadata, context);
} }
/**
* Parse given MBX stream
* @param inStream stream of MBX file
* @throws FileNotFoundException
* @throws IOException
* @throws SAXException
* @throws TikaException
*/
public void parse(InputStream inStream) throws FileNotFoundException, IOException, SAXException, TikaException { public void parse(InputStream inStream) throws FileNotFoundException, IOException, SAXException, TikaException {
init(); init();
parser.parseMbox(inStream, this.contentHandler, this.metadata, context); parser.parseMbox(inStream, this.contentHandler, this.metadata, context);

View File

@ -18,11 +18,8 @@
*/ */
package org.sleuthkit.autopsy.thunderbirdparser; package org.sleuthkit.autopsy.thunderbirdparser;
import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@ -34,7 +31,6 @@ import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata; import org.apache.tika.metadata.Metadata;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile; import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit; import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.IngestServices;
@ -44,9 +40,7 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
@ -61,8 +55,6 @@ public class ThunderbirdMboxFileIngestModule extends IngestModuleAbstractFile {
private static final Logger logger = Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()); private static final Logger logger = Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName());
private static ThunderbirdMboxFileIngestModule instance = null; private static ThunderbirdMboxFileIngestModule instance = null;
private IngestServices services; private IngestServices services;
private static int messageId = 0;
private Case currentCase;
private static final String MODULE_NAME = "Thunderbird Parser"; private static final String MODULE_NAME = "Thunderbird Parser";
private final String hashDBModuleName = "Hash Lookup"; private final String hashDBModuleName = "Hash Lookup";
final public static String MODULE_VERSION = "1.0"; final public static String MODULE_VERSION = "1.0";
@ -76,21 +68,31 @@ public class ThunderbirdMboxFileIngestModule extends IngestModuleAbstractFile {
@Override @Override
public ProcessResult process(PipelineContext<IngestModuleAbstractFile>ingestContext, AbstractFile abstractFile) { public ProcessResult process(PipelineContext<IngestModuleAbstractFile>ingestContext, AbstractFile abstractFile) {
if (abstractFile.getKnown().equals(
TskData.FileKnown.KNOWN)) { // skip known
return ProcessResult.OK; //file is known, stop processing it if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) {
} return ProcessResult.OK;
}
//skip unalloc
if(abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
return ProcessResult.OK;
}
//file has read error, stop processing it
// @@@ I don't really like this
// we don't know if Hash was run or if it had lookup errors
IngestModuleAbstractFile.ProcessResult hashDBResult = IngestModuleAbstractFile.ProcessResult hashDBResult =
services.getAbstractFileModuleResult(hashDBModuleName); services.getAbstractFileModuleResult(hashDBModuleName);
if (hashDBResult == IngestModuleAbstractFile.ProcessResult.ERROR) { if (hashDBResult == IngestModuleAbstractFile.ProcessResult.ERROR) {
return ProcessResult.ERROR; //file has read error, stop processing it return ProcessResult.ERROR;
} }
if (abstractFile.isVirtual()) { if (abstractFile.isVirtual()) {
return ProcessResult.OK; return ProcessResult.OK;
} }
// check its signature
boolean isMbox = false; boolean isMbox = false;
try { try {
byte[] t = new byte[64]; byte[] t = new byte[64];
@ -110,102 +112,82 @@ public class ThunderbirdMboxFileIngestModule extends IngestModuleAbstractFile {
logger.log(Level.INFO, "ThunderbirdMboxFileIngestModule: Parsing {0}", abstractFile.getName()); logger.log(Level.INFO, "ThunderbirdMboxFileIngestModule: Parsing {0}", abstractFile.getName());
String mboxName = abstractFile.getName(); String mboxFileName = abstractFile.getName();
String msfName = mboxName + ".msf"; String mboxParentDir = abstractFile.getParentPath();
//Long mboxId = fsContent.getId();
String mboxPath = abstractFile.getParentPath();
Long msfId = 0L;
currentCase = Case.getCurrentCase(); // get the most updated case
SleuthkitCase tskCase = currentCase.getSleuthkitCase();
try { // Find the .msf file in the same folder
ResultSet resultset = tskCase.runQuery("SELECT obj_id FROM tsk_files WHERE parent_path = '" + mboxPath + "' and name = '" + msfName + "'"); // BC: Commented out because results are not being used Oct '13
if (!resultset.next()) { //Long msfId = 0L;
logger.log(Level.WARNING, "Could not find msf file in mbox dir: " + mboxPath + " file: " + msfName); //String msfName = mboxFileName + ".msf";
tskCase.closeRunQuery(resultset); //SleuthkitCase tskCase = currentCase.getSleuthkitCase();
return ProcessResult.OK; // @@@ We shouldn't bail out here if we dont' find it...
} else { // try {
msfId = resultset.getLong(1); // // @@@ Replace this with a call to FileManager.findFiles()
tskCase.closeRunQuery(resultset); // ResultSet resultset = tskCase.runQuery("SELECT obj_id FROM tsk_files WHERE parent_path = '" + mboxParentDir + "' and name = '" + msfName + "'");
} // if (!resultset.next()) {
// logger.log(Level.WARNING, "Could not find msf file in mbox dir: " + mboxParentDir + " file: " + msfName);
} catch (SQLException ex) { // tskCase.closeRunQuery(resultset);
logger.log(Level.WARNING, "Could not find msf file in mbox dir: " + mboxPath + " file: " + msfName); // return ProcessResult.OK;
} // } else {
// msfId = resultset.getLong(1);
try { // tskCase.closeRunQuery(resultset);
Content msfContent = tskCase.getContentById(msfId);
if (msfContent != null) {
ContentUtils.writeToFile(msfContent, new File(currentCase.getTempDirectory() + File.separator + msfName));
}
} catch (IOException ex) {
logger.log(Level.WARNING, "Unable to obtain msf file for mbox parsing:" + msfName, ex);
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Unable to obtain msf file for mbox parsing:" + msfName, ex);
}
int index = 0;
String replace = "";
boolean a = mboxPath.indexOf("/ImapMail/") > 0;
boolean b = mboxPath.indexOf("/Mail/") > 0;
if (b == true) {
index = mboxPath.indexOf("/Mail/");
replace = "/Mail";
} else if (a == true) {
index = mboxPath.indexOf("/ImapMail/");
replace = "/ImapMail";
} else {
replace = "";
}
String folderPath = mboxPath.substring(index);
folderPath = folderPath.replaceAll(replace, "");
folderPath = folderPath + mboxName;
folderPath = folderPath.replaceAll(".sbd", "");
// Reader reader = null;
// try {
// reader = new FileReader(currentCase.getTempDirectory() + File.separator + msfName);
// } catch (FileNotFoundException ex) {
// Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()).log(Level.WARNING, null, ex);
// } // }
// MorkDocument morkDocument = new MorkDocument(reader); //
// List<Dict> dicts = morkDocument.getDicts(); // } catch (SQLException ex) {
// for(Dict dict : dicts){ // logger.log(Level.WARNING, "Could not find msf file in mbox dir: " + mboxParentDir + " file: " + msfName);
// String path = dict.getValue("81").toString(); // }
// String account = dict.getValue("8D").toString(); //
// } // try {
String emailId = ""; // Content msfContent = tskCase.getContentById(msfId);
String content = ""; // if (msfContent != null) {
String from = ""; // ContentUtils.writeToFile(msfContent, new File(currentCase.getTempDirectory() + File.separator + msfName));
String to = ""; // }
String stringDate = ""; // } catch (IOException ex) {
Long date = 0L; // logger.log(Level.WARNING, "Unable to obtain msf file for mbox parsing:" + msfName, ex);
String subject = ""; // } catch (TskCoreException ex) {
String cc = ""; // logger.log(Level.WARNING, "Unable to obtain msf file for mbox parsing:" + msfName, ex);
String bcc = ""; // }
ThunderbirdEmailParser mbox = new ThunderbirdEmailParser();
// use the local path to determine the e-mail folder structure
String emailFolder = "";
// email folder is everything after "Mail" or ImapMail
if (mboxParentDir.contains("/Mail/")) {
emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/Mail/") + 5);
}
else if (mboxParentDir.contains("/ImapMail/")) {
emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/ImapMail/") + 9);
}
emailFolder = emailFolder + mboxFileName;
emailFolder = emailFolder.replaceAll(".sbd", "");
try { try {
ReadContentInputStream contentStream = new ReadContentInputStream(abstractFile); ReadContentInputStream contentStream = new ReadContentInputStream(abstractFile);
ThunderbirdEmailParser mbox = new ThunderbirdEmailParser();
mbox.parse(contentStream); mbox.parse(contentStream);
HashMap<String, Map<String, String>> emailMap = new HashMap<String, Map<String, String>>();
emailMap = mbox.getAllEmails(); HashMap<String, Map<String, String>>emailMap = mbox.getAllEmails();
for (Entry<String, Map<String, String>> entry : emailMap.entrySet()) { for (Entry<String, Map<String, String>> entry : emailMap.entrySet()) {
Map<String, String> propertyMap = new HashMap<String, String>(); /* @@@ I'd rather this code be cleaned up a bit so that we check if the value is
emailId = ((entry.getKey() != null) ? entry.getKey() : "Not Available"); * set and then directly add it to the attribute. otherwise, we end up with a bunch
propertyMap = entry.getValue(); * of "" attribute values.
content = ((propertyMap.get("content") != null) ? propertyMap.get("content") : ""); */
from = ((propertyMap.get(Metadata.AUTHOR) != null) ? propertyMap.get(Metadata.AUTHOR) : ""); Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
to = ((propertyMap.get(Metadata.MESSAGE_TO) != null) ? propertyMap.get(Metadata.MESSAGE_TO) : ""); String emailId = ((entry.getKey() != null) ? entry.getKey() : "Not Available");
stringDate = ((propertyMap.get("date") != null) ? propertyMap.get("date") : ""); Map<String, String>propertyMap = entry.getValue();
if (!"".equals(stringDate)) { String content = ((propertyMap.get("content") != null) ? propertyMap.get("content") : "");
String from = ((propertyMap.get(Metadata.AUTHOR) != null) ? propertyMap.get(Metadata.AUTHOR) : "");
String to = ((propertyMap.get(Metadata.MESSAGE_TO) != null) ? propertyMap.get(Metadata.MESSAGE_TO) : "");
String stringDate = ((propertyMap.get("date") != null) ? propertyMap.get("date") : "");
Long date = 0L;
if (stringDate.equals("") == false) {
date = mbox.getDateCreated(stringDate); date = mbox.getDateCreated(stringDate);
} }
subject = ((propertyMap.get(Metadata.SUBJECT) != null) ? propertyMap.get(Metadata.SUBJECT) : ""); String subject = ((propertyMap.get(Metadata.SUBJECT) != null) ? propertyMap.get(Metadata.SUBJECT) : "");
cc = ((propertyMap.get(Metadata.MESSAGE_CC) != null) ? propertyMap.get(Metadata.MESSAGE_CC) : ""); String cc = ((propertyMap.get(Metadata.MESSAGE_CC) != null) ? propertyMap.get(Metadata.MESSAGE_CC) : "");
bcc = ((propertyMap.get(Metadata.MESSAGE_BCC) != null) ? propertyMap.get(Metadata.MESSAGE_BCC) : ""); String bcc = ((propertyMap.get(Metadata.MESSAGE_BCC) != null) ? propertyMap.get(Metadata.MESSAGE_BCC) : "");
Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_TO.getTypeID(), MODULE_NAME, to)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_TO.getTypeID(), MODULE_NAME, to));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID(), MODULE_NAME, cc)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID(), MODULE_NAME, cc));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID(), MODULE_NAME, bcc)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID(), MODULE_NAME, bcc));
@ -217,7 +199,7 @@ public class ThunderbirdMboxFileIngestModule extends IngestModuleAbstractFile {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD.getTypeID(), MODULE_NAME, date)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD.getTypeID(), MODULE_NAME, date));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID(), MODULE_NAME, date)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID(), MODULE_NAME, date));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SUBJECT.getTypeID(), MODULE_NAME, subject)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SUBJECT.getTypeID(), MODULE_NAME, subject));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH.getTypeID(), MODULE_NAME, folderPath)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH.getTypeID(), MODULE_NAME, emailFolder));
BlackboardArtifact bbart; BlackboardArtifact bbart;
try { try {
bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG); bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
@ -240,9 +222,6 @@ public class ThunderbirdMboxFileIngestModule extends IngestModuleAbstractFile {
@Override @Override
public void complete() { public void complete() {
logger.log(Level.INFO, "complete()");
//module specific cleanup due completion here
} }
@Override @Override
@ -263,18 +242,11 @@ public class ThunderbirdMboxFileIngestModule extends IngestModuleAbstractFile {
@Override @Override
public void init(IngestModuleInit initContext) { public void init(IngestModuleInit initContext) {
logger.log(Level.INFO, "init()");
services = IngestServices.getDefault(); services = IngestServices.getDefault();
currentCase = Case.getCurrentCase();
//module specific initialization here
} }
@Override @Override
public void stop() { public void stop() {
logger.log(Level.INFO, "stop()");
//module specific cleanup due interruption here
} }
@Override @Override

View File

@ -37,6 +37,9 @@ import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.ContentHandler; import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
/**
* Contains the logic to parse an MBOX file.
*/
public class ThunderbirdMboxParser { public class ThunderbirdMboxParser {
/** Serial version UID */ /** Serial version UID */