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;
52 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
54 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
65 class ExtractIE
extends Extract {
67 private static final Logger logger = Logger.getLogger(ExtractIE.class.getName());
68 private final IngestServices services = IngestServices.getInstance();
69 private final String moduleTempResultsDir;
70 private String PASCO_LIB_PATH;
71 private final String JAVA_PATH;
72 private static final SimpleDateFormat dateFormatter =
new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
73 private Content dataSource;
74 private IngestJobContext context;
76 ExtractIE() throws NoCurrentCaseException {
77 moduleName = NbBundle.getMessage(ExtractIE.class,
"ExtractIE.moduleName.text");
78 moduleTempResultsDir = RAImageIngestModule.getRATempPath(Case.getCurrentCaseThrows(),
"IE") + File.separator +
"results";
79 JAVA_PATH = PlatformUtil.getJavaPath();
83 public void process(Content dataSource, IngestJobContext context) {
84 this.dataSource = dataSource;
85 this.context = context;
95 private void getBookmark() {
97 List<AbstractFile> favoritesFiles;
99 favoritesFiles = fileManager.
findFiles(dataSource,
"%.url",
"Favorites");
100 }
catch (TskCoreException ex) {
101 logger.log(Level.WARNING,
"Error fetching 'url' files for Internet Explorer bookmarks.", ex);
102 this.addErrorMessage(
103 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getBookmark.errMsg.errGettingBookmarks",
108 if (favoritesFiles.isEmpty()) {
109 logger.log(Level.INFO,
"Didn't find any IE bookmark files.");
114 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
115 for (AbstractFile fav : favoritesFiles) {
116 if (fav.getSize() == 0) {
120 if (context.dataSourceIngestIsCancelled()) {
124 String url = getURLFromIEBookmarkFile(fav);
126 String name = fav.getName();
127 Long datetime = fav.getCrtime();
128 String Tempdate = datetime.toString();
129 datetime = Long.valueOf(Tempdate);
130 String domain = Util.extractDomain(url);
132 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
133 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
134 NbBundle.getMessage(
this.getClass(),
135 "ExtractIE.parentModuleName.noSpace"), url));
136 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
137 NbBundle.getMessage(
this.getClass(),
138 "ExtractIE.parentModuleName.noSpace"), name));
139 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
140 NbBundle.getMessage(
this.getClass(),
141 "ExtractIE.parentModuleName.noSpace"), datetime));
142 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
143 NbBundle.getMessage(
this.getClass(),
144 "ExtractIE.parentModuleName.noSpace"),
145 NbBundle.getMessage(
this.getClass(),
"ExtractIE.moduleName.text")));
146 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
147 NbBundle.getMessage(
this.getClass(),
148 "ExtractIE.parentModuleName.noSpace"), domain));
150 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK, fav, bbattributes);
152 bbartifacts.add(bbart);
155 services.fireModuleDataEvent(
new ModuleDataEvent(
156 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parentModuleName"),
157 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bbartifacts));
160 private String getURLFromIEBookmarkFile(AbstractFile fav) {
161 BufferedReader reader =
new BufferedReader(
new InputStreamReader(
new ReadContentInputStream(fav)));
162 String line, url =
"";
164 line = reader.readLine();
165 while (null != line) {
168 if (line.startsWith(
"URL")) {
169 url = line.substring(line.indexOf(
"=") + 1);
172 line = reader.readLine();
174 }
catch (IOException ex) {
175 logger.log(Level.WARNING,
"Failed to read from content: " + fav.getName(), ex);
176 this.addErrorMessage(
177 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getURLFromIEBmkFile.errMsg", this.getName(),
179 }
catch (IndexOutOfBoundsException ex) {
180 logger.log(Level.WARNING,
"Failed while getting URL of IE bookmark. Unexpected format of the bookmark file: " + fav.getName(), ex);
181 this.addErrorMessage(
182 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getURLFromIEBmkFile.errMsg2", this.getName(),
187 }
catch (IOException ex) {
188 logger.log(Level.WARNING,
"Failed to close reader.", ex);
198 private void getCookie() {
200 List<AbstractFile> cookiesFiles;
202 cookiesFiles = fileManager.
findFiles(dataSource,
"%.txt",
"Cookies");
203 }
catch (TskCoreException ex) {
204 logger.log(Level.WARNING,
"Error getting cookie files for IE");
205 this.addErrorMessage(
206 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getCookie.errMsg.errGettingFile", this.getName()));
210 if (cookiesFiles.isEmpty()) {
211 logger.log(Level.INFO,
"Didn't find any IE cookies files.");
216 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
217 for (AbstractFile cookiesFile : cookiesFiles) {
218 if (context.dataSourceIngestIsCancelled()) {
221 if (cookiesFile.getSize() == 0) {
225 byte[] t =
new byte[(int) cookiesFile.getSize()];
227 final int bytesRead = cookiesFile.read(t, 0, cookiesFile.getSize());
228 }
catch (TskCoreException ex) {
229 logger.log(Level.WARNING,
"Error reading bytes of Internet Explorer cookie.", ex);
230 this.addErrorMessage(
231 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getCookie.errMsg.errReadingIECookie",
232 this.getName(), cookiesFile.getName()));
235 String cookieString =
new String(t);
236 String[] values = cookieString.split(
"\n");
237 String url = values.length > 2 ? values[2] :
"";
238 String value = values.length > 1 ? values[1] :
"";
239 String name = values.length > 0 ? values[0] :
"";
240 Long datetime = cookiesFile.getCrtime();
241 String tempDate = datetime.toString();
242 datetime = Long.valueOf(tempDate);
243 String domain = Util.extractDomain(url);
245 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
246 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
247 NbBundle.getMessage(
this.getClass(),
248 "ExtractIE.parentModuleName.noSpace"), url));
249 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME,
250 NbBundle.getMessage(
this.getClass(),
251 "ExtractIE.parentModuleName.noSpace"), datetime));
252 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
253 NbBundle.getMessage(
this.getClass(),
254 "ExtractIE.parentModuleName.noSpace"), (name != null) ? name :
""));
255 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
256 NbBundle.getMessage(
this.getClass(),
257 "ExtractIE.parentModuleName.noSpace"), value));
258 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
259 NbBundle.getMessage(
this.getClass(),
260 "ExtractIE.parentModuleName.noSpace"),
261 NbBundle.getMessage(
this.getClass(),
"ExtractIE.moduleName.text")));
262 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
263 NbBundle.getMessage(
this.getClass(),
264 "ExtractIE.parentModuleName.noSpace"), domain));
265 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes);
267 bbartifacts.add(bbart);
270 services.fireModuleDataEvent(
new ModuleDataEvent(
271 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parentModuleName"),
272 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, bbartifacts));
278 private void getHistory() {
279 logger.log(Level.INFO,
"Pasco results path: {0}", moduleTempResultsDir);
280 boolean foundHistory =
false;
282 final File pascoRoot = InstalledFileLocator.getDefault().locate(
"pasco2", ExtractIE.class.getPackage().getName(),
false);
283 if (pascoRoot == null) {
284 this.addErrorMessage(
285 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.unableToGetHist", this.getName()));
286 logger.log(Level.SEVERE,
"Error finding pasco program ");
290 final String pascoHome = pascoRoot.getAbsolutePath();
291 logger.log(Level.INFO,
"Pasco2 home: {0}", pascoHome);
293 PASCO_LIB_PATH = pascoHome + File.separator +
"pasco2.jar" + File.pathSeparator
294 + pascoHome + File.separator +
"*";
296 File resultsDir =
new File(moduleTempResultsDir);
301 List<AbstractFile> indexFiles;
303 indexFiles = fileManager.
findFiles(dataSource,
"index.dat");
304 }
catch (TskCoreException ex) {
305 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.errGettingHistFiles",
307 logger.log(Level.WARNING,
"Error fetching 'index.data' files for Internet Explorer history.");
311 if (indexFiles.isEmpty()) {
312 String msg = NbBundle.getMessage(this.getClass(),
"ExtractIE.getHistory.errMsg.noHistFiles");
313 logger.log(Level.INFO, msg);
318 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
320 String indexFileName;
321 for (AbstractFile indexFile : indexFiles) {
327 indexFileName =
"index" + Integer.toString((
int) indexFile.getId()) +
".dat";
329 temps = RAImageIngestModule.getRATempPath(currentCase,
"IE") + File.separator + indexFileName;
330 File datFile =
new File(temps);
331 if (context.dataSourceIngestIsCancelled()) {
335 ContentUtils.writeToFile(indexFile, datFile, context::dataSourceIngestIsCancelled);
336 }
catch (IOException e) {
337 logger.log(Level.WARNING,
"Error while trying to write index.dat file " + datFile.getAbsolutePath(), e);
338 this.addErrorMessage(
339 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.errWriteFile", this.getName(),
340 datFile.getAbsolutePath()));
344 String filename =
"pasco2Result." + indexFile.getId() +
".txt";
345 boolean bPascProcSuccess = executePasco(temps, filename);
346 if (context.dataSourceIngestIsCancelled()) {
352 if (bPascProcSuccess) {
354 bbartifacts.addAll(parsePascoOutput(indexFile, filename).stream()
355 .filter(bbart -> bbart.getArtifactTypeID() == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID())
356 .collect(Collectors.toList()));
362 logger.log(Level.WARNING,
"pasco execution failed on: {0}",
this.getName());
363 this.addErrorMessage(
364 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.errProcHist", this.getName()));
369 services.fireModuleDataEvent(
new ModuleDataEvent(
370 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parentModuleName"),
371 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, bbartifacts));
383 private boolean executePasco(String indexFilePath, String outputFileName) {
384 boolean success =
true;
386 final String outputFileFullPath = moduleTempResultsDir + File.separator + outputFileName;
387 final String errFileFullPath = moduleTempResultsDir + File.separator + outputFileName +
".err";
388 logger.log(Level.INFO,
"Writing pasco results to: {0}", outputFileFullPath);
389 List<String> commandLine =
new ArrayList<>();
390 commandLine.add(JAVA_PATH);
391 commandLine.add(
"-cp");
392 commandLine.add(PASCO_LIB_PATH);
393 commandLine.add(
"isi.pasco2.Main");
394 commandLine.add(
"-T");
395 commandLine.add(
"history");
396 commandLine.add(indexFilePath);
397 ProcessBuilder processBuilder =
new ProcessBuilder(commandLine);
398 processBuilder.redirectOutput(
new File(outputFileFullPath));
399 processBuilder.redirectError(
new File(errFileFullPath));
409 ExecUtil.execute(processBuilder,
new DataSourceIngestModuleProcessTerminator(context));
411 }
catch (IOException ex) {
413 logger.log(Level.SEVERE,
"Unable to execute Pasco to process Internet Explorer web history.", ex);
427 private Collection<BlackboardArtifact> parsePascoOutput(AbstractFile origFile, String pascoOutputFileName) {
429 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
430 String fnAbs = moduleTempResultsDir + File.separator + pascoOutputFileName;
432 File file =
new File(fnAbs);
433 if (file.exists() ==
false) {
434 this.addErrorMessage(
435 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parsePascoOutput.errMsg.notFound", this.getName(),
437 logger.log(Level.WARNING,
"Pasco Output not found: {0}", file.getPath());
443 if (file.length() == 0) {
449 fileScanner =
new Scanner(
new FileInputStream(file.toString()));
450 }
catch (FileNotFoundException ex) {
451 this.addErrorMessage(
452 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parsePascoOutput.errMsg.errParsing", this.getName(),
454 logger.log(Level.WARNING,
"Unable to find the Pasco file at " + file.getPath(), ex);
459 Set<String> reportedUserAccounts =
new HashSet<>();
461 while (fileScanner.hasNext()) {
462 String line = fileScanner.nextLine();
463 if (!line.startsWith(
"URL")) {
467 String[] lineBuff = line.split(
"\\t");
469 if (lineBuff.length < 4) {
470 logger.log(Level.INFO,
"Found unrecognized IE history format.");
474 String actime = lineBuff[3];
475 Long ftime = (long) 0;
484 if (lineBuff[1].contains(
"@")) {
485 String url[] = lineBuff[1].split(
"@", 2);
487 user = user.replace(
"Visited:",
"");
488 user = user.replace(
":Host:",
"");
489 user = user.replaceAll(
"(:)(.*?)(:)",
"");
492 realurl = realurl.replace(
"Visited:",
"");
493 realurl = realurl.replaceAll(
":(.*?):",
"");
494 realurl = realurl.replace(
":Host:",
"");
495 realurl = realurl.trim();
498 realurl = lineBuff[1].trim();
501 domain = Util.extractDomain(realurl);
503 if (!actime.isEmpty()) {
505 Long epochtime = dateFormatter.parse(actime).getTime();
506 ftime = epochtime / 1000;
507 }
catch (ParseException e) {
508 this.addErrorMessage(
509 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parsePascoOutput.errMsg.errParsingEntry",
511 logger.log(Level.WARNING, String.format(
"Error parsing Pasco results, may have partial processing of corrupt file (id=%d)", origFile.getId()), e);
516 BlackboardArtifact bbart = origFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY);
517 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
518 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
519 NbBundle.getMessage(
this.getClass(),
520 "ExtractIE.parentModuleName.noSpace"), realurl));
523 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
524 NbBundle.getMessage(
this.getClass(),
525 "ExtractIE.parentModuleName.noSpace"), ftime));
526 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER,
527 NbBundle.getMessage(
this.getClass(),
528 "ExtractIE.parentModuleName.noSpace"),
""));
530 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
531 NbBundle.getMessage(
this.getClass(),
532 "ExtractIE.parentModuleName.noSpace"),
533 NbBundle.getMessage(
this.getClass(),
534 "ExtractIE.moduleName.text")));
535 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
536 NbBundle.getMessage(
this.getClass(),
537 "ExtractIE.parentModuleName.noSpace"), domain));
538 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
539 NbBundle.getMessage(
this.getClass(),
540 "ExtractIE.parentModuleName.noSpace"), user));
541 bbart.addAttributes(bbattributes);
544 this.indexArtifact(bbart);
545 bbartifacts.add(bbart);
547 if ((!user.isEmpty()) && (!reportedUserAccounts.contains(user))) {
548 BlackboardArtifact osAttr = origFile.newArtifact(ARTIFACT_TYPE.TSK_OS_ACCOUNT);
549 osAttr.addAttribute(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
550 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parentModuleName.noSpace"), user));
553 this.indexArtifact(osAttr);
554 bbartifacts.add(osAttr);
556 reportedUserAccounts.add(user);
558 }
catch (TskCoreException ex) {
559 logger.log(Level.SEVERE,
"Error writing Internet Explorer web history artifact to the blackboard.", ex);
synchronized List< AbstractFile > findFiles(String fileName)