diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/IEExtractor.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/IEExtractor.java index b8cec046f4..4bc0d6c70d 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/IEExtractor.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/IEExtractor.java @@ -22,41 +22,55 @@ */ package org.sleuthkit.autopsy.recentactivity; +import com.google.common.collect.Sets; import java.io.BufferedReader; - -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.coreutils.ExecUtil; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; +import java.nio.file.Path; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.HashSet; -import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.Scanner; +import java.util.Set; +import java.util.logging.Level; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.openide.modules.InstalledFileLocator; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; -import org.sleuthkit.datamodel.Content; +import org.sleuthkit.autopsy.casemodule.services.FileManager; +import org.sleuthkit.autopsy.coreutils.ExecUtil; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator; import org.sleuthkit.autopsy.ingest.IngestJobContext; +import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.*; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE; +import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REFERRER; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE; /** * Extracts activity from Internet Explorer browser, as well as recent documents @@ -65,17 +79,19 @@ import org.sleuthkit.datamodel.*; class IEExtractor extends Extractor { private static final Logger logger = Logger.getLogger(IEExtractor.class.getName()); + private static final String PARENT_MODULE_NAME_NO_SPACE + = NbBundle.getMessage(IEExtractor.class, "ExtractIE.parentModuleName.noSpace"); + private static final String PASCO_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; + private final IngestServices services = IngestServices.getInstance(); private final String moduleTempResultsDir; - private String PASCO_LIB_PATH; - private final String JAVA_PATH; - private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + private final String JAVA_PATH = PlatformUtil.getJavaPath(); + private Content dataSource; private IngestJobContext context; IEExtractor() throws NoCurrentCaseException { moduleTempResultsDir = RAImageIngestModule.getRATempPath(Case.getCurrentCaseThrows(), "IE") + File.separator + "results"; //NON-NLS - JAVA_PATH = PlatformUtil.getJavaPath(); } @Override @@ -96,8 +112,8 @@ class IEExtractor extends Extractor { /** * Finds the files storing bookmarks and creates artifacts */ - private void getBookmark() { - org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager(); + private void getBookmark() throws TskCoreException { + FileManager fileManager = currentCase.getServices().getFileManager(); List favoritesFiles; try { favoritesFiles = fileManager.findFiles(dataSource, "%.url", "Favorites"); //NON-NLS @@ -125,36 +141,21 @@ class IEExtractor extends Extractor { break; } - String url = getURLFromIEBookmarkFile(fav); + Collection bbattributes = Arrays.asList( + new BlackboardAttribute( + TSK_URL, PARENT_MODULE_NAME_NO_SPACE, getURLFromIEBookmarkFile(fav)), + new BlackboardAttribute( + TSK_TITLE, PARENT_MODULE_NAME_NO_SPACE, fav.getName()), + new BlackboardAttribute( + TSK_DATETIME_CREATED, PARENT_MODULE_NAME_NO_SPACE, fav.getCrtime()), + new BlackboardAttribute( + TSK_PROG_NAME, PARENT_MODULE_NAME_NO_SPACE, + NbBundle.getMessage(this.getClass(), "ExtractIE.moduleName.text")), + new BlackboardAttribute( + TSK_DOMAIN, PARENT_MODULE_NAME_NO_SPACE, Util.extractDomain(getURLFromIEBookmarkFile(fav)))); - String name = fav.getName(); - Long datetime = fav.getCrtime(); - String Tempdate = datetime.toString(); - datetime = Long.valueOf(Tempdate); - String domain = Util.extractDomain(url); + bbartifacts.add(this.addArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK, fav, bbattributes)); - Collection bbattributes = new ArrayList<>(); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), url)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), name)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), datetime)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), - NbBundle.getMessage(this.getClass(), "ExtractIE.moduleName.text"))); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), domain)); - - BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK, fav, bbattributes); - if (bbart != null) { - bbartifacts.add(bbart); - } } services.fireModuleDataEvent(new ModuleDataEvent( NbBundle.getMessage(this.getClass(), "ExtractIE.parentModuleName"), @@ -162,18 +163,14 @@ class IEExtractor extends Extractor { } private String getURLFromIEBookmarkFile(AbstractFile fav) { - BufferedReader reader = new BufferedReader(new InputStreamReader(new ReadContentInputStream(fav))); - String line, url = ""; - try { - line = reader.readLine(); - while (null != line) { + String line; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ReadContentInputStream(fav)));) { + while (null != (line = reader.readLine())) { // The actual shortcut line we are interested in is of the // form URL=http://path/to/website if (line.startsWith("URL")) { //NON-NLS - url = line.substring(line.indexOf("=") + 1); - break; + return StringUtils.substringAfter(line, "="); //NON-NLS } - line = reader.readLine(); } } catch (IOException ex) { logger.log(Level.WARNING, "Failed to read from content: " + fav.getName(), ex); //NON-NLS @@ -185,22 +182,16 @@ class IEExtractor extends Extractor { this.addErrorMessage( NbBundle.getMessage(this.getClass(), "ExtractIE.getURLFromIEBmkFile.errMsg2", this.getModuleName(), fav.getName())); - } finally { - try { - reader.close(); - } catch (IOException ex) { - logger.log(Level.WARNING, "Failed to close reader.", ex); //NON-NLS - } } - return url; + return ""; } /** * Finds files that store cookies and adds artifacts for them. */ - private void getCookie() { - org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager(); + private void getCookie() throws TskCoreException { + FileManager fileManager = currentCase.getServices().getFileManager(); List cookiesFiles; try { cookiesFiles = fileManager.findFiles(dataSource, "%.txt", "Cookies"); //NON-NLS @@ -226,9 +217,9 @@ class IEExtractor extends Extractor { continue; } - byte[] t = new byte[(int) cookiesFile.getSize()]; + byte[] cookiesBuffer = new byte[(int) cookiesFile.getSize()]; try { - final int bytesRead = cookiesFile.read(t, 0, cookiesFile.getSize()); + cookiesFile.read(cookiesBuffer, 0, cookiesFile.getSize()); } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error reading bytes of Internet Explorer cookie.", ex); //NON-NLS this.addErrorMessage( @@ -236,44 +227,33 @@ class IEExtractor extends Extractor { this.getModuleName(), cookiesFile.getName())); continue; } - String cookieString = new String(t); - String[] values = cookieString.split("\n"); - String url = values.length > 2 ? values[2] : ""; - String value = values.length > 1 ? values[1] : ""; - String name = values.length > 0 ? values[0] : ""; - Long datetime = cookiesFile.getCrtime(); - String tempDate = datetime.toString(); - datetime = Long.valueOf(tempDate); - String domain = Util.extractDomain(url); - Collection bbattributes = new ArrayList<>(); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), url)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), datetime)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), (name != null) ? name : "")); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), value)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), - NbBundle.getMessage(this.getClass(), "ExtractIE.moduleName.text"))); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), domain)); - BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes); - if (bbart != null) { - bbartifacts.add(bbart); - } + String[] values = new String(cookiesBuffer).split("\n"); + String URL = values.length > 2 ? values[2] : ""; + + Collection bbattributes = Arrays.asList(new BlackboardAttribute( + TSK_DATETIME, PARENT_MODULE_NAME_NO_SPACE, + cookiesFile.getCrtime()), + new BlackboardAttribute( + TSK_NAME, PARENT_MODULE_NAME_NO_SPACE, + values.length > 0 ? values[0] : ""), + new BlackboardAttribute( + TSK_VALUE, PARENT_MODULE_NAME_NO_SPACE, + values.length > 1 ? values[1] : ""), + new BlackboardAttribute( + TSK_URL, PARENT_MODULE_NAME_NO_SPACE, + URL), + new BlackboardAttribute( + TSK_PROG_NAME, PARENT_MODULE_NAME_NO_SPACE, + getModuleName()), + new BlackboardAttribute( + TSK_DOMAIN, PARENT_MODULE_NAME_NO_SPACE, + Util.extractDomain(URL))); + + bbartifacts.add(this.addArtifact(TSK_WEB_COOKIE, cookiesFile, bbattributes)); } services.fireModuleDataEvent(new ModuleDataEvent( - NbBundle.getMessage(this.getClass(), "ExtractIE.parentModuleName"), - BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, bbartifacts)); + NbBundle.getMessage(this.getClass(), "ExtractIE.parentModuleName"), TSK_WEB_COOKIE, bbartifacts)); } /** @@ -281,8 +261,8 @@ class IEExtractor extends Extractor { */ private void getHistory() { logger.log(Level.INFO, "Pasco results path: {0}", moduleTempResultsDir); //NON-NLS - boolean foundHistory = false; + //TODO: Why are we getting the pasoc library path for datasource we process? final File pascoRoot = InstalledFileLocator.getDefault().locate("pasco2", IEExtractor.class.getPackage().getName(), false); //NON-NLS if (pascoRoot == null) { this.addErrorMessage( @@ -294,14 +274,14 @@ class IEExtractor extends Extractor { final String pascoHome = pascoRoot.getAbsolutePath(); logger.log(Level.INFO, "Pasco2 home: {0}", pascoHome); //NON-NLS - PASCO_LIB_PATH = pascoHome + File.separator + "pasco2.jar" + File.pathSeparator //NON-NLS - + pascoHome + File.separator + "*"; + String pascoLibPath = pascoHome + File.separator + "pasco2.jar" + File.pathSeparator //NON-NLS + + pascoHome + File.separator + "*"; File resultsDir = new File(moduleTempResultsDir); resultsDir.mkdirs(); // get index.dat files - org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager(); + FileManager fileManager = currentCase.getServices().getFileManager(); List indexFiles; try { indexFiles = fileManager.findFiles(dataSource, "index.dat"); //NON-NLS @@ -319,18 +299,20 @@ class IEExtractor extends Extractor { } dataFound = true; + boolean foundHistory = false; Collection bbartifacts = new ArrayList<>(); - String temps; - String indexFileName; + for (AbstractFile indexFile : indexFiles) { - // Since each result represent an index.dat file, - // just create these files with the following notation: - // index.dat (i.e. index0.dat, index1.dat,..., indexN.dat) - // Write each index.dat file to a temp directory. - //BlackboardArtifact bbart = fsc.newArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY); - indexFileName = "index" + Integer.toString((int) indexFile.getId()) + ".dat"; //NON-NLS - //indexFileName = "index" + Long.toString(bbart.getArtifactID()) + ".dat"; - temps = RAImageIngestModule.getRATempPath(currentCase, "IE") + File.separator + indexFileName; //NON-NLS + /* Since each result represent an index.dat file, just create these + * files with the following notation: index.dat (i.e. + * index0.dat, index1.dat,..., indexN.dat) Write each index.dat file + * to a temp directory. + * + * TODO: this comment is not accurate. It implies we use an + * sequential id number but actualy we use the file id from the db. + */ + String indexFileName = "index" + indexFile.getId() + ".dat"; //NON-NLS + String temps = RAImageIngestModule.getRATempPath(currentCase, "IE") + File.separator + indexFileName; //NON-NLS File datFile = new File(temps); if (context.dataSourceIngestIsCancelled()) { break; @@ -346,13 +328,13 @@ class IEExtractor extends Extractor { } String filename = "pasco2Result." + indexFile.getId() + ".txt"; //NON-NLS - boolean bPascProcSuccess = executePasco(temps, filename); + boolean bPascProcSuccess = executePasco(pascoLibPath, temps, filename); if (context.dataSourceIngestIsCancelled()) { return; } - //At this point pasco2 proccessed the index files. - //Now fetch the results, parse them and the delete the files. + //At this point pasco2 proccessed the index file. + //Now fetch the results, parse them and the delete the file. if (bPascProcSuccess) { // Don't add TSK_OS_ACCOUNT artifacts to the ModuleDataEvent bbartifacts.addAll(parsePascoOutput(indexFile, filename).stream() @@ -360,7 +342,7 @@ class IEExtractor extends Extractor { .collect(Collectors.toList())); foundHistory = true; - //Delete index.dat file since it was succcessfully by Pasco + //Delete index.dat file since it was succcessfully parsed by Pasco datFile.delete(); } else { logger.log(Level.WARNING, "pasco execution failed on: {0}", this.getModuleName()); //NON-NLS @@ -382,22 +364,22 @@ class IEExtractor extends Extractor { * @param indexFilePath Path to local index.dat file to analyze * @param outputFileName Name of file to save output to * - * @return false on error + * @return the boolean */ - private boolean executePasco(String indexFilePath, String outputFileName) { + private boolean executePasco(String pascoLibraryPath, String indexFilePath, String outputFileName) { boolean success = true; try { final String outputFileFullPath = moduleTempResultsDir + File.separator + outputFileName; final String errFileFullPath = moduleTempResultsDir + File.separator + outputFileName + ".err"; //NON-NLS logger.log(Level.INFO, "Writing pasco results to: {0}", outputFileFullPath); //NON-NLS - List commandLine = new ArrayList<>(); - commandLine.add(JAVA_PATH); - commandLine.add("-cp"); //NON-NLS - commandLine.add(PASCO_LIB_PATH); - commandLine.add("isi.pasco2.Main"); //NON-NLS - commandLine.add("-T"); //NON-NLS - commandLine.add("history"); //NON-NLS - commandLine.add(indexFilePath); + List commandLine = Arrays.asList( + JAVA_PATH, + "-cp",//NON-NLS + pascoLibraryPath, + "isi.pasco2.Main", //NON-NLS + "-T", //NON-NLS + "history", //NON-NLS + indexFilePath); ProcessBuilder processBuilder = new ProcessBuilder(commandLine); processBuilder.redirectOutput(new File(outputFileFullPath)); processBuilder.redirectError(new File(errFileFullPath)); @@ -430,7 +412,6 @@ class IEExtractor extends Extractor { */ private Collection parsePascoOutput(AbstractFile origFile, String pascoOutputFileName) { - Collection bbartifacts = new ArrayList<>(); String fnAbs = moduleTempResultsDir + File.separator + pascoOutputFileName; File file = new File(fnAbs); @@ -439,131 +420,124 @@ class IEExtractor extends Extractor { NbBundle.getMessage(this.getClass(), "ExtractIE.parsePascoOutput.errMsg.notFound", this.getModuleName(), file.getName())); logger.log(Level.WARNING, "Pasco Output not found: {0}", file.getPath()); //NON-NLS - return bbartifacts; + return Collections.emptySet(); } // Make sure the file the is not empty or the Scanner will // throw a "No Line found" Exception if (file.length() == 0) { - return bbartifacts; + return Collections.emptySet(); } + try (Scanner fileScanner = new Scanner(new FileInputStream(file.toString()));) { - Scanner fileScanner; - try { - fileScanner = new Scanner(new FileInputStream(file.toString())); + // Keep a list of reported user accounts to avoid repeats. + // Initialize it with the empty string to represent an unknown user. + Set reportedUserAccounts = Sets.newHashSet(""); + Collection bbartifacts = new ArrayList<>(); + while (fileScanner.hasNext()) { + String line = fileScanner.nextLine(); + if (!line.startsWith("URL")) { //NON-NLS + continue; + } + + String[] lineBuff = line.split("\\t"); //NON-NLS + + if (lineBuff.length < 4) { + logger.log(Level.INFO, "Found unrecognized IE history format."); //NON-NLS + continue; + } + + String actime = lineBuff[3]; + Long ftime = (long) 0; + String user; + String realurl; + String domain; + + /* + * We've seen two types of lines: URL http://XYZ.com .... URL + * Visited: Joe@http://XYZ.com .... + */ + if (lineBuff[1].contains("@")) { + String url[] = lineBuff[1].split("@", 2); + user = url[0]; + user = user.replace("Visited:", ""); //NON-NLS + user = user.replace(":Host:", ""); //NON-NLS + user = user.replaceAll(":(.*?):", ""); + user = user.trim(); + realurl = url[1]; + realurl = realurl.replace("Visited:", ""); //NON-NLS + realurl = realurl.replaceAll(":(.*?):", ""); + realurl = realurl.replace(":Host:", ""); //NON-NLS + realurl = realurl.trim(); + } else { + user = ""; + realurl = lineBuff[1].trim(); + } + + domain = Util.extractDomain(realurl); + + if (!actime.isEmpty()) { + try { + Long epochtime = new SimpleDateFormat(PASCO_DATE_FORMAT).parse(actime).getTime(); + ftime = epochtime / 1000; + } catch (ParseException e) { + this.addErrorMessage( + NbBundle.getMessage(this.getClass(), "ExtractIE.parsePascoOutput.errMsg.errParsingEntry", + this.getModuleName())); + logger.log(Level.WARNING, String.format("Error parsing Pasco results, may have partial processing of corrupt file (id=%d)", origFile.getId()), e); //NON-NLS + } + } + + try { + BlackboardArtifact bbart = origFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY); + Collection bbattributes = Arrays.asList( + new BlackboardAttribute( + TSK_URL, PARENT_MODULE_NAME_NO_SPACE, + realurl), + new BlackboardAttribute( + TSK_DATETIME_ACCESSED, PARENT_MODULE_NAME_NO_SPACE, + ftime), + //TODO: why are we adding an attribute that is always blank? + new BlackboardAttribute( + TSK_REFERRER, PARENT_MODULE_NAME_NO_SPACE, + ""), + // @@@ NOte that other browser modules are adding TITLE in here for the title + new BlackboardAttribute( + TSK_PROG_NAME, PARENT_MODULE_NAME_NO_SPACE, + getModuleName()), + new BlackboardAttribute( + TSK_DOMAIN, PARENT_MODULE_NAME_NO_SPACE, + domain), + new BlackboardAttribute( + TSK_USER_NAME, PARENT_MODULE_NAME_NO_SPACE, + user)); + bbart.addAttributes(bbattributes); + + // index the artifact for keyword search + this.indexArtifact(bbart); + bbartifacts.add(bbart); + + if (reportedUserAccounts.contains(user) == false) { + BlackboardArtifact osAttr = origFile.newArtifact(TSK_OS_ACCOUNT); + osAttr.addAttribute(new BlackboardAttribute(TSK_USER_NAME, PARENT_MODULE_NAME_NO_SPACE, user)); + + // index the artifact for keyword search + this.indexArtifact(osAttr); + bbartifacts.add(osAttr); + + reportedUserAccounts.add(user); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error writing Internet Explorer web history artifact to the blackboard.", ex); //NON-NLS + } + } + return bbartifacts; } catch (FileNotFoundException ex) { this.addErrorMessage( NbBundle.getMessage(this.getClass(), "ExtractIE.parsePascoOutput.errMsg.errParsing", this.getModuleName(), file.getName())); logger.log(Level.WARNING, "Unable to find the Pasco file at " + file.getPath(), ex); //NON-NLS - return bbartifacts; + return Collections.emptySet(); } - - // Keep a list of reported user accounts to avoid repeats - Set reportedUserAccounts = new HashSet<>(); - - while (fileScanner.hasNext()) { - String line = fileScanner.nextLine(); - if (!line.startsWith("URL")) { //NON-NLS - continue; - } - - String[] lineBuff = line.split("\\t"); //NON-NLS - - if (lineBuff.length < 4) { - logger.log(Level.INFO, "Found unrecognized IE history format."); //NON-NLS - continue; - } - - String actime = lineBuff[3]; - Long ftime = (long) 0; - String user; - String realurl; - String domain; - - /* - * We've seen two types of lines: URL http://XYZ.com .... URL - * Visited: Joe@http://XYZ.com .... - */ - if (lineBuff[1].contains("@")) { - String url[] = lineBuff[1].split("@", 2); - user = url[0]; - user = user.replace("Visited:", ""); //NON-NLS - user = user.replace(":Host:", ""); //NON-NLS - user = user.replaceAll("(:)(.*?)(:)", ""); - user = user.trim(); - realurl = url[1]; - realurl = realurl.replace("Visited:", ""); //NON-NLS - realurl = realurl.replaceAll(":(.*?):", ""); - realurl = realurl.replace(":Host:", ""); //NON-NLS - realurl = realurl.trim(); - } else { - user = ""; - realurl = lineBuff[1].trim(); - } - - domain = Util.extractDomain(realurl); - - if (!actime.isEmpty()) { - try { - Long epochtime = dateFormatter.parse(actime).getTime(); - ftime = epochtime / 1000; - } catch (ParseException e) { - this.addErrorMessage( - NbBundle.getMessage(this.getClass(), "ExtractIE.parsePascoOutput.errMsg.errParsingEntry", - this.getModuleName())); - logger.log(Level.WARNING, String.format("Error parsing Pasco results, may have partial processing of corrupt file (id=%d)", origFile.getId()), e); //NON-NLS - } - } - - try { - BlackboardArtifact bbart = origFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY); - Collection bbattributes = new ArrayList<>(); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), realurl)); - //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", EscapeUtil.decodeURL(realurl))); - - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), ftime)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), "")); - // @@@ NOte that other browser modules are adding TITLE in hre for the title - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), - NbBundle.getMessage(this.getClass(), - "ExtractIE.moduleName.text"))); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), domain)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), user)); - bbart.addAttributes(bbattributes); - - // index the artifact for keyword search - this.indexArtifact(bbart); - bbartifacts.add(bbart); - - if ((!user.isEmpty()) && (!reportedUserAccounts.contains(user))) { - BlackboardArtifact osAttr = origFile.newArtifact(ARTIFACT_TYPE.TSK_OS_ACCOUNT); - osAttr.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, - NbBundle.getMessage(this.getClass(), "ExtractIE.parentModuleName.noSpace"), user)); - - // index the artifact for keyword search - this.indexArtifact(osAttr); - bbartifacts.add(osAttr); - - reportedUserAccounts.add(user); - } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error writing Internet Explorer web history artifact to the blackboard.", ex); //NON-NLS - } - } - fileScanner.close(); - return bbartifacts; } }