23 package org.sleuthkit.autopsy.recentactivity;
25 import java.io.BufferedReader;
27 import org.openide.util.NbBundle;
30 import java.io.FileInputStream;
31 import java.io.FileNotFoundException;
32 import java.io.IOException;
33 import java.io.InputStreamReader;
34 import java.text.ParseException;
35 import java.text.SimpleDateFormat;
36 import java.util.ArrayList;
37 import java.util.List;
39 import java.util.HashSet;
40 import java.util.logging.Level;
42 import java.util.Collection;
43 import java.util.Scanner;
44 import java.util.stream.Collectors;
45 import org.openide.modules.InstalledFileLocator;
64 class ExtractIE
extends Extract {
66 private static final Logger logger = Logger.getLogger(ExtractIE.class.getName());
67 private final IngestServices services = IngestServices.getInstance();
68 private final String moduleTempResultsDir;
69 private String PASCO_LIB_PATH;
70 private final String JAVA_PATH;
71 private static final SimpleDateFormat dateFormatter =
new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
73 private IngestJobContext context;
76 moduleName = NbBundle.getMessage(ExtractIE.class,
"ExtractIE.moduleName.text");
77 moduleTempResultsDir = RAImageIngestModule.getRATempPath(Case.getCurrentCase(),
"IE") +
File.separator +
"results";
78 JAVA_PATH = PlatformUtil.getJavaPath();
82 public void process(
Content dataSource, IngestJobContext context) {
83 this.dataSource = dataSource;
84 this.context = context;
94 private void getBookmark() {
96 List<AbstractFile> favoritesFiles;
98 favoritesFiles = fileManager.
findFiles(dataSource,
"%.url",
"Favorites");
100 logger.log(Level.WARNING,
"Error fetching 'url' files for Internet Explorer bookmarks.", ex);
101 this.addErrorMessage(
102 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getBookmark.errMsg.errGettingBookmarks",
107 if (favoritesFiles.isEmpty()) {
108 logger.log(Level.INFO,
"Didn't find any IE bookmark files.");
113 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
115 if (fav.getSize() == 0) {
119 if (context.dataSourceIngestIsCancelled()) {
123 String url = getURLFromIEBookmarkFile(fav);
125 String name = fav.getName();
126 Long datetime = fav.getCrtime();
127 String Tempdate = datetime.toString();
128 datetime = Long.valueOf(Tempdate);
129 String domain = Util.extractDomain(url);
131 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
133 NbBundle.getMessage(
this.getClass(),
134 "ExtractIE.parentModuleName.noSpace"), url));
136 NbBundle.getMessage(
this.getClass(),
137 "ExtractIE.parentModuleName.noSpace"), name));
139 NbBundle.getMessage(
this.getClass(),
140 "ExtractIE.parentModuleName.noSpace"), datetime));
142 NbBundle.getMessage(
this.getClass(),
143 "ExtractIE.parentModuleName.noSpace"),
144 NbBundle.getMessage(
this.getClass(),
"ExtractIE.moduleName.text")));
146 NbBundle.getMessage(
this.getClass(),
147 "ExtractIE.parentModuleName.noSpace"), domain));
149 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK, fav, bbattributes);
151 bbartifacts.add(bbart);
154 services.fireModuleDataEvent(
new ModuleDataEvent(
155 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parentModuleName"),
159 private String getURLFromIEBookmarkFile(
AbstractFile fav) {
161 String line, url =
"";
163 line = reader.readLine();
164 while (null != line) {
167 if (line.startsWith(
"URL")) {
168 url = line.substring(line.indexOf(
"=") + 1);
171 line = reader.readLine();
173 }
catch (IOException ex) {
174 logger.log(Level.WARNING,
"Failed to read from content: " + fav.
getName(), ex);
175 this.addErrorMessage(
176 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getURLFromIEBmkFile.errMsg", this.getName(),
178 }
catch (IndexOutOfBoundsException ex) {
179 logger.log(Level.WARNING,
"Failed while getting URL of IE bookmark. Unexpected format of the bookmark file: " + fav.
getName(), ex);
180 this.addErrorMessage(
181 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getURLFromIEBmkFile.errMsg2", this.getName(),
186 }
catch (IOException ex) {
187 logger.log(Level.WARNING,
"Failed to close reader.", ex);
197 private void getCookie() {
199 List<AbstractFile> cookiesFiles;
201 cookiesFiles = fileManager.
findFiles(dataSource,
"%.txt",
"Cookies");
203 logger.log(Level.WARNING,
"Error getting cookie files for IE");
204 this.addErrorMessage(
205 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getCookie.errMsg.errGettingFile", this.getName()));
209 if (cookiesFiles.isEmpty()) {
210 logger.log(Level.INFO,
"Didn't find any IE cookies files.");
215 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
217 if (context.dataSourceIngestIsCancelled()) {
220 if (cookiesFile.getSize() == 0) {
224 byte[] t =
new byte[(int) cookiesFile.getSize()];
226 final int bytesRead = cookiesFile.read(t, 0, cookiesFile.getSize());
228 logger.log(Level.WARNING,
"Error reading bytes of Internet Explorer cookie.", ex);
229 this.addErrorMessage(
230 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getCookie.errMsg.errReadingIECookie",
231 this.getName(), cookiesFile.getName()));
234 String cookieString =
new String(t);
235 String[] values = cookieString.split(
"\n");
236 String url = values.length > 2 ? values[2] :
"";
237 String value = values.length > 1 ? values[1] :
"";
238 String name = values.length > 0 ? values[0] :
"";
239 Long datetime = cookiesFile.getCrtime();
240 String tempDate = datetime.toString();
241 datetime = Long.valueOf(tempDate);
242 String domain = Util.extractDomain(url);
244 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
246 NbBundle.getMessage(
this.getClass(),
247 "ExtractIE.parentModuleName.noSpace"), url));
249 NbBundle.getMessage(
this.getClass(),
250 "ExtractIE.parentModuleName.noSpace"), datetime));
252 NbBundle.getMessage(
this.getClass(),
253 "ExtractIE.parentModuleName.noSpace"), (name != null) ? name :
""));
255 NbBundle.getMessage(
this.getClass(),
256 "ExtractIE.parentModuleName.noSpace"), value));
258 NbBundle.getMessage(
this.getClass(),
259 "ExtractIE.parentModuleName.noSpace"),
260 NbBundle.getMessage(
this.getClass(),
"ExtractIE.moduleName.text")));
262 NbBundle.getMessage(
this.getClass(),
263 "ExtractIE.parentModuleName.noSpace"), domain));
264 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes);
266 bbartifacts.add(bbart);
269 services.fireModuleDataEvent(
new ModuleDataEvent(
270 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parentModuleName"),
277 private void getHistory() {
278 logger.log(Level.INFO,
"Pasco results path: {0}", moduleTempResultsDir);
279 boolean foundHistory =
false;
281 final File pascoRoot = InstalledFileLocator.getDefault().locate(
"pasco2", ExtractIE.class.getPackage().getName(),
false);
282 if (pascoRoot == null) {
283 this.addErrorMessage(
284 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.unableToGetHist", this.getName()));
285 logger.log(Level.SEVERE,
"Error finding pasco program ");
289 final String pascoHome = pascoRoot.getAbsolutePath();
290 logger.log(Level.INFO,
"Pasco2 home: {0}", pascoHome);
292 PASCO_LIB_PATH = pascoHome +
File.separator +
"pasco2.jar" +
File.pathSeparator
293 + pascoHome +
File.separator +
"*";
295 File resultsDir =
new File(moduleTempResultsDir);
300 List<AbstractFile> indexFiles;
302 indexFiles = fileManager.
findFiles(dataSource,
"index.dat");
304 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.errGettingHistFiles",
306 logger.log(Level.WARNING,
"Error fetching 'index.data' files for Internet Explorer history.");
310 if (indexFiles.isEmpty()) {
311 String msg = NbBundle.getMessage(this.getClass(),
"ExtractIE.getHistory.errMsg.noHistFiles");
312 logger.log(Level.INFO, msg);
317 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
319 String indexFileName;
326 indexFileName =
"index" + Integer.toString((
int) indexFile.getId()) +
".dat";
328 temps = RAImageIngestModule.getRATempPath(currentCase,
"IE") +
File.separator + indexFileName;
330 if (context.dataSourceIngestIsCancelled()) {
334 ContentUtils.writeToFile(indexFile, datFile, context::dataSourceIngestIsCancelled);
335 }
catch (IOException e) {
336 logger.log(Level.WARNING,
"Error while trying to write index.dat file " + datFile.getAbsolutePath(), e);
337 this.addErrorMessage(
338 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.errWriteFile", this.getName(),
339 datFile.getAbsolutePath()));
343 String filename =
"pasco2Result." + indexFile.getId() +
".txt";
344 boolean bPascProcSuccess = executePasco(temps, filename);
345 if (context.dataSourceIngestIsCancelled()) {
351 if (bPascProcSuccess) {
353 bbartifacts.addAll(parsePascoOutput(indexFile, filename).stream()
354 .filter(bbart -> bbart.
getArtifactTypeID() == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID())
355 .collect(Collectors.toList()));
361 logger.log(Level.WARNING,
"pasco execution failed on: {0}",
this.getName());
362 this.addErrorMessage(
363 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.errProcHist", this.getName()));
368 services.fireModuleDataEvent(
new ModuleDataEvent(
369 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parentModuleName"),
382 private boolean executePasco(String indexFilePath, String outputFileName) {
383 boolean success =
true;
385 final String outputFileFullPath = moduleTempResultsDir +
File.separator + outputFileName;
386 final String errFileFullPath = moduleTempResultsDir +
File.separator + outputFileName +
".err";
387 logger.log(Level.INFO,
"Writing pasco results to: {0}", outputFileFullPath);
388 List<String> commandLine =
new ArrayList<>();
389 commandLine.add(JAVA_PATH);
390 commandLine.add(
"-cp");
391 commandLine.add(PASCO_LIB_PATH);
392 commandLine.add(
"isi.pasco2.Main");
393 commandLine.add(
"-T");
394 commandLine.add(
"history");
395 commandLine.add(indexFilePath);
396 ProcessBuilder processBuilder =
new ProcessBuilder(commandLine);
397 processBuilder.redirectOutput(
new File(outputFileFullPath));
398 processBuilder.redirectError(
new File(errFileFullPath));
408 ExecUtil.execute(processBuilder,
new DataSourceIngestModuleProcessTerminator(context));
410 }
catch (IOException ex) {
412 logger.log(Level.SEVERE,
"Unable to execute Pasco to process Internet Explorer web history.", ex);
426 private Collection<BlackboardArtifact> parsePascoOutput(
AbstractFile origFile, String pascoOutputFileName) {
428 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
429 String fnAbs = moduleTempResultsDir +
File.separator + pascoOutputFileName;
432 if (file.
exists() ==
false) {
433 this.addErrorMessage(
434 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parsePascoOutput.errMsg.notFound", this.getName(),
436 logger.log(Level.WARNING,
"Pasco Output not found: {0}", file.getPath());
442 if (file.length() == 0) {
448 fileScanner =
new Scanner(
new FileInputStream(file.
toString()));
449 }
catch (FileNotFoundException ex) {
450 this.addErrorMessage(
451 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parsePascoOutput.errMsg.errParsing", this.getName(),
453 logger.log(Level.WARNING,
"Unable to find the Pasco file at " + file.getPath(), ex);
458 Set<String> reportedUserAccounts =
new HashSet<>();
460 while (fileScanner.hasNext()) {
461 String line = fileScanner.nextLine();
462 if (!line.startsWith(
"URL")) {
466 String[] lineBuff = line.split(
"\\t");
468 if (lineBuff.length < 4) {
469 logger.log(Level.INFO,
"Found unrecognized IE history format.");
473 String actime = lineBuff[3];
474 Long ftime = (long) 0;
483 if (lineBuff[1].contains(
"@")) {
484 String url[] = lineBuff[1].split(
"@", 2);
486 user = user.replace(
"Visited:",
"");
487 user = user.replace(
":Host:",
"");
488 user = user.replaceAll(
"(:)(.*?)(:)",
"");
491 realurl = realurl.replace(
"Visited:",
"");
492 realurl = realurl.replaceAll(
":(.*?):",
"");
493 realurl = realurl.replace(
":Host:",
"");
494 realurl = realurl.trim();
497 realurl = lineBuff[1].trim();
500 domain = Util.extractDomain(realurl);
502 if (!actime.isEmpty()) {
504 Long epochtime = dateFormatter.parse(actime).getTime();
505 ftime = epochtime / 1000;
506 }
catch (ParseException e) {
507 this.addErrorMessage(
508 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parsePascoOutput.errMsg.errParsingEntry",
510 logger.log(Level.WARNING, String.format(
"Error parsing Pasco results, may have partial processing of corrupt file (id=%d)", origFile.
getId()), e);
516 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
518 NbBundle.getMessage(
this.getClass(),
519 "ExtractIE.parentModuleName.noSpace"), realurl));
523 NbBundle.getMessage(
this.getClass(),
524 "ExtractIE.parentModuleName.noSpace"), ftime));
526 NbBundle.getMessage(
this.getClass(),
527 "ExtractIE.parentModuleName.noSpace"),
""));
530 NbBundle.getMessage(
this.getClass(),
531 "ExtractIE.parentModuleName.noSpace"),
532 NbBundle.getMessage(
this.getClass(),
533 "ExtractIE.moduleName.text")));
535 NbBundle.getMessage(
this.getClass(),
536 "ExtractIE.parentModuleName.noSpace"), domain));
538 NbBundle.getMessage(
this.getClass(),
539 "ExtractIE.parentModuleName.noSpace"), user));
543 this.indexArtifact(bbart);
544 bbartifacts.add(bbart);
546 if ((!user.isEmpty()) && (!reportedUserAccounts.contains(user))) {
549 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parentModuleName.noSpace"), user));
552 this.indexArtifact(osAttr);
553 bbartifacts.add(osAttr);
555 reportedUserAccounts.add(user);
558 logger.log(Level.SEVERE,
"Error writing Internet Explorer web history artifact to the blackboard.", ex);
void addAttributes(Collection< BlackboardAttribute > attributes)
void addAttribute(BlackboardAttribute attr)
BlackboardArtifact newArtifact(int artifactTypeID)
synchronized List< AbstractFile > findFiles(String fileName)
String toString(boolean preserveState)