23 package org.sleuthkit.autopsy.recentactivity;
25 import java.io.BufferedReader;
26 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.nio.file.Paths;
35 import java.text.ParseException;
36 import java.text.SimpleDateFormat;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.logging.Level;
41 import java.util.Collection;
42 import java.util.Scanner;
43 import java.util.stream.Collectors;
44 import org.openide.modules.InstalledFileLocator;
45 import org.openide.util.NbBundle.Messages;
49 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
51 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
58 import static org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY;
66 class ExtractIE
extends Extract {
68 private static final Logger logger = Logger.getLogger(ExtractIE.class.getName());
69 private String PASCO_LIB_PATH;
70 private final String JAVA_PATH;
71 private static final String RESOURCE_URL_PREFIX =
"res://";
72 private static final SimpleDateFormat dateFormatter =
new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
73 private Content dataSource;
74 private final IngestJobContext context;
77 "Progress_Message_IE_History=IE History",
78 "Progress_Message_IE_Bookmarks=IE Bookmarks",
79 "Progress_Message_IE_Cookies=IE Cookies",
80 "Progress_Message_IE_Downloads=IE Downloads",
81 "Progress_Message_IE_FormHistory=IE Form History",
82 "Progress_Message_IE_AutoFill=IE Auto Fill",
83 "Progress_Message_IE_Logins=IE Logins",})
85 ExtractIE(IngestJobContext context) {
86 super(NbBundle.getMessage(ExtractIE.class,
"ExtractIE.moduleName.text"), context);
87 JAVA_PATH = PlatformUtil.getJavaPath();
88 this.context = context;
92 public void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
93 String moduleTempDir = RAImageIngestModule.getRATempPath(getCurrentCase(),
"IE", context.getJobId());
94 String moduleTempResultsDir = Paths.get(moduleTempDir,
"results").toString();
96 this.dataSource = dataSource;
99 progressBar.progress(Bundle.Progress_Message_IE_Bookmarks());
102 if (context.dataSourceIngestIsCancelled()) {
106 progressBar.progress(Bundle.Progress_Message_IE_Cookies());
109 if (context.dataSourceIngestIsCancelled()) {
113 progressBar.progress(Bundle.Progress_Message_IE_History());
114 this.getHistory(moduleTempDir, moduleTempResultsDir);
120 private void getBookmark() {
122 List<AbstractFile> favoritesFiles;
124 favoritesFiles = fileManager.
findFiles(dataSource,
"%.url",
"Favorites");
125 }
catch (TskCoreException ex) {
126 logger.log(Level.WARNING,
"Error fetching 'url' files for Internet Explorer bookmarks.", ex);
127 this.addErrorMessage(
128 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getBookmark.errMsg.errGettingBookmarks",
129 this.getDisplayName()));
133 if (favoritesFiles.isEmpty()) {
134 logger.log(Level.INFO,
"Didn't find any IE bookmark files.");
139 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
140 for (AbstractFile fav : favoritesFiles) {
141 if (fav.getSize() == 0) {
145 if (context.dataSourceIngestIsCancelled()) {
149 String url = getURLFromIEBookmarkFile(fav);
151 String name = fav.getName();
152 Long datetime = fav.getCrtime();
153 String Tempdate = datetime.toString();
154 datetime = Long.valueOf(Tempdate);
155 String domain = extractDomain(url);
157 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
158 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
159 RecentActivityExtracterModuleFactory.getModuleName(), url));
160 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
161 RecentActivityExtracterModuleFactory.getModuleName(), name));
162 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
163 RecentActivityExtracterModuleFactory.getModuleName(), datetime));
164 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
165 RecentActivityExtracterModuleFactory.getModuleName(),
166 NbBundle.getMessage(this.getClass(),
"ExtractIE.moduleName.text")));
167 if (domain != null && domain.isEmpty() ==
false) {
168 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
169 RecentActivityExtracterModuleFactory.getModuleName(), domain));
173 bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_BOOKMARK, fav, bbattributes));
174 }
catch (TskCoreException ex) {
175 logger.log(Level.SEVERE, String.format(
"Failed to create %s for file %d", ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getDisplayName(), fav.getId()), ex);
179 if (!context.dataSourceIngestIsCancelled()) {
180 postArtifacts(bbartifacts);
184 private String getURLFromIEBookmarkFile(AbstractFile fav) {
185 BufferedReader reader =
new BufferedReader(
new InputStreamReader(
new ReadContentInputStream(fav)));
186 String line, url =
"";
188 line = reader.readLine();
189 while (null != line) {
192 if (line.startsWith(
"URL")) {
193 url = line.substring(line.indexOf(
"=") + 1);
196 line = reader.readLine();
198 }
catch (IOException ex) {
199 logger.log(Level.WARNING,
"Failed to read from content: " + fav.getName(), ex);
200 this.addErrorMessage(
201 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getURLFromIEBmkFile.errMsg", this.getDisplayName(),
203 }
catch (IndexOutOfBoundsException ex) {
204 logger.log(Level.WARNING,
"Failed while getting URL of IE bookmark. Unexpected format of the bookmark file: " + fav.getName(), ex);
205 this.addErrorMessage(
206 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getURLFromIEBmkFile.errMsg2", this.getDisplayName(),
211 }
catch (IOException ex) {
212 logger.log(Level.WARNING,
"Failed to close reader.", ex);
222 private void getCookie() {
224 List<AbstractFile> cookiesFiles;
226 cookiesFiles = fileManager.
findFiles(dataSource,
"%.txt",
"Cookies");
227 }
catch (TskCoreException ex) {
228 logger.log(Level.WARNING,
"Error getting cookie files for IE");
229 this.addErrorMessage(
230 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getCookie.errMsg.errGettingFile", this.getDisplayName()));
234 if (cookiesFiles.isEmpty()) {
235 logger.log(Level.INFO,
"Didn't find any IE cookies files.");
240 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
241 for (AbstractFile cookiesFile : cookiesFiles) {
242 if (context.dataSourceIngestIsCancelled()) {
245 if (cookiesFile.getSize() == 0) {
249 byte[] t =
new byte[(int) cookiesFile.getSize()];
251 final int bytesRead = cookiesFile.read(t, 0, cookiesFile.getSize());
252 }
catch (TskCoreException ex) {
253 logger.log(Level.WARNING,
"Error reading bytes of Internet Explorer cookie.", ex);
254 this.addErrorMessage(
255 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getCookie.errMsg.errReadingIECookie",
256 this.getDisplayName(), cookiesFile.getName()));
259 String cookieString =
new String(t);
260 String[] values = cookieString.split(
"\n");
261 String url = values.length > 2 ? values[2] :
"";
262 String value = values.length > 1 ? values[1] :
"";
263 String name = values.length > 0 ? values[0] :
"";
264 Long datetime = cookiesFile.getCrtime();
265 String tempDate = datetime.toString();
266 datetime = Long.valueOf(tempDate);
267 String domain = extractDomain(url);
269 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
270 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
271 RecentActivityExtracterModuleFactory.getModuleName(), url));
272 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
273 RecentActivityExtracterModuleFactory.getModuleName(), datetime));
274 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
275 RecentActivityExtracterModuleFactory.getModuleName(), (name != null) ? name :
""));
276 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
277 RecentActivityExtracterModuleFactory.getModuleName(), value));
278 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
279 RecentActivityExtracterModuleFactory.getModuleName(),
280 NbBundle.getMessage(this.getClass(),
"ExtractIE.moduleName.text")));
281 if (domain != null && domain.isEmpty() ==
false) {
282 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
283 RecentActivityExtracterModuleFactory.getModuleName(), domain));
287 bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_COOKIE, cookiesFile, bbattributes));
288 }
catch (TskCoreException ex) {
289 logger.log(Level.SEVERE, String.format(
"Failed to create %s for file %d", BlackboardArtifact.Type.TSK_WEB_COOKIE.getDisplayName(), cookiesFile.getId()), ex);
293 if (!context.dataSourceIngestIsCancelled()) {
294 postArtifacts(bbartifacts);
305 private void getHistory(String moduleTempDir, String moduleTempResultsDir) {
306 logger.log(Level.INFO,
"Pasco results path: {0}", moduleTempResultsDir);
307 boolean foundHistory =
false;
309 final File pascoRoot = InstalledFileLocator.getDefault().locate(
"pasco2", ExtractIE.class.getPackage().getName(),
false);
310 if (pascoRoot == null) {
311 this.addErrorMessage(
312 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.unableToGetHist", this.getDisplayName()));
313 logger.log(Level.SEVERE,
"Error finding pasco program ");
317 final String pascoHome = pascoRoot.getAbsolutePath();
318 logger.log(Level.INFO,
"Pasco2 home: {0}", pascoHome);
320 PASCO_LIB_PATH = pascoHome + File.separator +
"pasco2.jar" + File.pathSeparator
321 + pascoHome + File.separator +
"*";
323 File resultsDir =
new File(moduleTempResultsDir);
327 FileManager fileManager = currentCase.getServices().getFileManager();
328 List<AbstractFile> indexFiles;
330 indexFiles = fileManager.findFiles(dataSource,
"index.dat");
331 }
catch (TskCoreException ex) {
332 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.errGettingHistFiles",
333 this.getDisplayName()));
334 logger.log(Level.WARNING,
"Error fetching 'index.data' files for Internet Explorer history.");
338 if (indexFiles.isEmpty()) {
339 String msg = NbBundle.getMessage(this.getClass(),
"ExtractIE.getHistory.errMsg.noHistFiles");
340 logger.log(Level.INFO, msg);
345 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
347 String indexFileName;
348 for (AbstractFile indexFile : indexFiles) {
355 indexFileName =
"index" + Integer.toString((
int) indexFile.getId()) +
".dat";
357 temps = moduleTempDir + File.separator + indexFileName;
358 File datFile =
new File(temps);
359 if (context.dataSourceIngestIsCancelled()) {
363 ContentUtils.writeToFile(indexFile, datFile, context::dataSourceIngestIsCancelled);
364 }
catch (IOException e) {
365 logger.log(Level.WARNING,
"Error while trying to write index.dat file " + datFile.getAbsolutePath(), e);
366 this.addErrorMessage(
367 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.errWriteFile", this.getDisplayName(),
368 datFile.getAbsolutePath()));
372 String filename =
"pasco2Result." + indexFile.getId() +
".txt";
373 boolean bPascProcSuccess = executePasco(temps, filename, moduleTempResultsDir);
374 if (context.dataSourceIngestIsCancelled()) {
380 if (bPascProcSuccess) {
382 bbartifacts.addAll(parsePascoOutput(indexFile, filename, moduleTempResultsDir).stream()
383 .filter(bbart -> bbart.getArtifactTypeID() == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID())
384 .collect(Collectors.toList()));
385 if (context.dataSourceIngestIsCancelled()) {
393 logger.log(Level.WARNING,
"pasco execution failed on: {0}", filename);
394 this.addErrorMessage(
395 NbBundle.getMessage(
this.getClass(),
"ExtractIE.getHistory.errMsg.errProcHist", this.getDisplayName()));
399 if (!context.dataSourceIngestIsCancelled()) {
400 postArtifacts(bbartifacts);
414 "# {0} - sub module name",
415 "ExtractIE_executePasco_errMsg_errorRunningPasco={0}: Error analyzing Internet Explorer web history",})
416 private boolean executePasco(String indexFilePath, String outputFileName, String moduleTempResultsDir) {
417 boolean success =
true;
419 final String outputFileFullPath = moduleTempResultsDir + File.separator + outputFileName;
420 final String errFileFullPath = moduleTempResultsDir + File.separator + outputFileName +
".err";
421 logger.log(Level.INFO,
"Writing pasco results to: {0}", outputFileFullPath);
422 List<String> commandLine =
new ArrayList<>();
423 commandLine.add(JAVA_PATH);
424 commandLine.add(
"-cp");
425 commandLine.add(PASCO_LIB_PATH);
426 commandLine.add(
"isi.pasco2.Main");
427 commandLine.add(
"-T");
428 commandLine.add(
"history");
429 commandLine.add(indexFilePath);
430 ProcessBuilder processBuilder =
new ProcessBuilder(commandLine);
431 processBuilder.redirectOutput(
new File(outputFileFullPath));
432 processBuilder.redirectError(
new File(errFileFullPath));
442 ExecUtil.execute(processBuilder,
new DataSourceIngestModuleProcessTerminator(context,
true));
444 }
catch (IOException ex) {
445 logger.log(Level.SEVERE,
"Error executing Pasco to process Internet Explorer web history", ex);
446 addErrorMessage(Bundle.ExtractIE_executePasco_errMsg_errorRunningPasco(getDisplayName()));
462 private Collection<BlackboardArtifact> parsePascoOutput(AbstractFile origFile, String pascoOutputFileName, String moduleTempResultsDir) {
464 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
465 String fnAbs = moduleTempResultsDir + File.separator + pascoOutputFileName;
467 File file =
new File(fnAbs);
468 if (file.exists() ==
false) {
469 this.addErrorMessage(
470 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parsePascoOutput.errMsg.notFound", this.getDisplayName(),
472 logger.log(Level.WARNING,
"Pasco Output not found: {0}", file.getPath());
478 if (file.length() == 0) {
484 fileScanner =
new Scanner(
new FileInputStream(file.toString()));
485 }
catch (FileNotFoundException ex) {
486 this.addErrorMessage(
487 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parsePascoOutput.errMsg.errParsing", this.getDisplayName(),
489 logger.log(Level.WARNING,
"Unable to find the Pasco file at " + file.getPath(), ex);
492 while (fileScanner.hasNext()) {
494 if (context.dataSourceIngestIsCancelled()) {
498 String line = fileScanner.nextLine();
499 if (!line.startsWith(
"URL")) {
503 String[] lineBuff = line.split(
"\\t");
505 if (lineBuff.length < 4) {
506 logger.log(Level.INFO,
"Found unrecognized IE history format.");
510 String actime = lineBuff[3];
511 Long ftime = (long) 0;
513 String realurl = null;
520 if (lineBuff[1].contains(
"@")) {
521 String url[] = lineBuff[1].split(
"@", 2);
526 domain = extractDomain(url[0]);
528 if (domain != null && domain.isEmpty() ==
false) {
532 realurl = lineBuff[1].trim();
539 user = user.replace(
"Visited:",
"");
540 user = user.replace(
":Host:",
"");
541 user = user.replaceAll(
"(:)(.*?)(:)",
"");
544 realurl = realurl.replace(
"Visited:",
"");
545 realurl = realurl.replaceAll(
":(.*?):",
"");
546 realurl = realurl.replace(
":Host:",
"");
547 realurl = realurl.trim();
548 domain = extractDomain(realurl);
554 realurl = lineBuff[1].trim();
555 domain = extractDomain(realurl);
558 if (!actime.isEmpty()) {
560 Long epochtime = dateFormatter.parse(actime).getTime();
561 ftime = epochtime / 1000;
562 }
catch (ParseException e) {
563 this.addErrorMessage(
564 NbBundle.getMessage(
this.getClass(),
"ExtractIE.parsePascoOutput.errMsg.errParsingEntry",
565 this.getDisplayName()));
566 logger.log(Level.WARNING, String.format(
"Error parsing Pasco results, may have partial processing of corrupt file (id=%d)", origFile.getId()), e);
570 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
571 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
572 RecentActivityExtracterModuleFactory.getModuleName(), realurl));
575 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
576 RecentActivityExtracterModuleFactory.getModuleName(), ftime));
577 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER,
578 RecentActivityExtracterModuleFactory.getModuleName(),
""));
580 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
581 RecentActivityExtracterModuleFactory.getModuleName(),
582 NbBundle.getMessage(this.getClass(),
583 "ExtractIE.moduleName.text")));
584 if (domain != null && domain.isEmpty() ==
false) {
585 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
586 RecentActivityExtracterModuleFactory.getModuleName(), domain));
588 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
589 RecentActivityExtracterModuleFactory.getModuleName(), user));
592 bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_HISTORY, origFile, bbattributes));
593 }
catch (TskCoreException ex) {
594 logger.log(Level.SEVERE, String.format(
"Failed to create %s for file %d", BlackboardArtifact.Type.TSK_WEB_HISTORY.getDisplayName(), origFile.getId()), ex);
609 private String extractDomain(String url) {
610 if (url == null || url.isEmpty()) {
614 if (url.toLowerCase().startsWith(RESOURCE_URL_PREFIX)) {
621 return NetworkUtils.extractDomain(url);
List< AbstractFile > findFiles(String fileName)