23 package org.sleuthkit.autopsy.recentactivity;
25 import com.google.common.collect.ImmutableMap;
26 import com.google.gson.JsonArray;
27 import com.google.gson.JsonElement;
28 import com.google.gson.JsonIOException;
29 import com.google.gson.JsonObject;
30 import com.google.gson.JsonParser;
31 import com.google.gson.JsonSyntaxException;
32 import org.openide.util.NbBundle;
34 import java.util.logging.Level;
37 import java.io.FileNotFoundException;
38 import java.io.FileReader;
39 import java.io.IOException;
40 import org.apache.commons.io.FilenameUtils;
41 import org.openide.util.NbBundle.Messages;
52 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
54 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
56 import org.
sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
59 import org.
sleuthkit.datamodel.blackboardutils.WebBrowserArtifactsHelper;
64 class Chromium
extends Extract {
66 private static final String HISTORY_QUERY =
"SELECT urls.url, urls.title, urls.visit_count, urls.typed_count, "
67 +
"last_visit_time, urls.hidden, visits.visit_time, (SELECT urls.url FROM urls WHERE urls.id=visits.url) AS from_visit, visits.transition FROM urls, visits WHERE urls.id = visits.url";
68 private static final String COOKIE_QUERY =
"SELECT name, value, host_key, expires_utc,last_access_utc, creation_utc FROM cookies";
69 private static final String DOWNLOAD_QUERY =
"SELECT full_path, url, start_time, received_bytes FROM downloads";
70 private static final String DOWNLOAD_QUERY_V30 =
"SELECT current_path AS full_path, url, start_time, received_bytes FROM downloads, downloads_url_chains WHERE downloads.id=downloads_url_chains.id";
71 private static final String LOGIN_QUERY =
"SELECT origin_url, username_value, date_created, signon_realm from logins";
72 private static final String AUTOFILL_QUERY =
"SELECT name, value, count, date_created " +
73 " FROM autofill, autofill_dates " +
74 " WHERE autofill.pair_id = autofill_dates.pair_id"
76 private static final String AUTOFILL_QUERY_V8X =
"SELECT name, value, count, date_created, date_last_used from autofill";
77 private static final String WEBFORM_ADDRESS_QUERY =
"SELECT first_name, middle_name, last_name, address_line_1, address_line_2, city, state, zipcode, country_code, number, email, date_modified " +
78 " FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones" +
79 " WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
81 private static final String WEBFORM_ADDRESS_QUERY_V8X =
"SELECT first_name, middle_name, last_name, full_name, street_address, city, state, zipcode, country_code, number, email, date_modified, use_date, use_count" +
82 " FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones" +
83 " WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
84 private final Logger logger = Logger.getLogger(this.getClass().getName());
85 private Content dataSource;
86 private IngestJobContext context;
88 private static final Map<String, String> BROWSERS_MAP = ImmutableMap.<String, String>builder()
89 .put(NbBundle.getMessage(Chromium.class,
"Browser.name.Microsoft.Edge"),
"Microsoft/Edge")
90 .put(NbBundle.getMessage(Chromium.class,
"Browser.name.Yandex"),
"YandexBrowser")
91 .put(NbBundle.getMessage(Chromium.class,
"Browser.name.Opera"),
"Opera Software")
92 .put(NbBundle.getMessage(Chromium.class,
"Browser.name.SalamWeb"),
"SalamWeb")
93 .put(NbBundle.getMessage(Chromium.class,
"Browser.name.UC.Browser"),
"UCBrowser")
94 .put(NbBundle.getMessage(Chromium.class,
"Browser.name.Brave"),
"BraveSoftware")
95 .put(NbBundle.getMessage(Chromium.class,
"Browser.name.Google.Chrome"),
"Chrome")
99 @Messages({
"# {0} - browserName",
100 "Progress_Message_Chrome_History=Chrome History Browser {0}",
101 "# {0} - browserName",
102 "Progress_Message_Chrome_Bookmarks=Chrome Bookmarks Browser {0}",
103 "# {0} - browserName",
104 "Progress_Message_Chrome_Cookies=Chrome Cookies Browser {0}",
105 "# {0} - browserName",
106 "Progress_Message_Chrome_Downloads=Chrome Downloads Browser {0}",
107 "Progress_Message_Chrome_FormHistory=Chrome Form History",
108 "# {0} - browserName",
109 "Progress_Message_Chrome_AutoFill=Chrome Auto Fill Browser {0}",
110 "# {0} - browserName",
111 "Progress_Message_Chrome_Logins=Chrome Logins Browser {0}",
112 "Progress_Message_Chrome_Cache=Chrome Cache",
116 moduleName = NbBundle.getMessage(Chromium.class,
"Chrome.moduleName");
120 public void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
121 this.dataSource = dataSource;
122 this.context = context;
125 for (Map.Entry<String, String> browser : BROWSERS_MAP.entrySet()) {
126 String browserName = browser.getKey();
127 String browserLocation = browser.getValue();
128 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_History", browserName));
129 this.getHistory(browser.getKey(), browser.getValue());
130 if (context.dataSourceIngestIsCancelled()) {
134 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Bookmarks", browserName));
135 this.getBookmark(browser.getKey(), browser.getValue());
136 if (context.dataSourceIngestIsCancelled()) {
140 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Cookies", browserName));
141 this.getCookie(browser.getKey(), browser.getValue());
142 if (context.dataSourceIngestIsCancelled()) {
146 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Logins", browserName));
147 this.getLogins(browser.getKey(), browser.getValue());
148 if (context.dataSourceIngestIsCancelled()) {
152 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_AutoFill", browserName));
153 this.getAutofill(browser.getKey(), browser.getValue());
154 if (context.dataSourceIngestIsCancelled()) {
158 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Downloads", browserName));
159 this.getDownload(browser.getKey(), browser.getValue());
160 if (context.dataSourceIngestIsCancelled()) {
165 progressBar.progress(Bundle.Progress_Message_Chrome_Cache());
166 ChromeCacheExtractor chromeCacheExtractor =
new ChromeCacheExtractor(dataSource, context, progressBar);
167 chromeCacheExtractor.processCaches();
174 private void getHistory(String browser, String browserLocation) {
175 FileManager fileManager = currentCase.getServices().getFileManager();
176 List<AbstractFile> historyFiles;
178 historyFiles = fileManager.findFiles(dataSource,
"%History%", browserLocation);
179 }
catch (TskCoreException ex) {
180 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getHistory.errMsg.errGettingFiles");
181 logger.log(Level.SEVERE, msg, ex);
182 this.addErrorMessage(this.getName() +
": " + msg);
187 List<AbstractFile> allocatedHistoryFiles =
new ArrayList<>();
188 for (AbstractFile historyFile : historyFiles) {
189 if (historyFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
190 allocatedHistoryFiles.add(historyFile);
195 if (allocatedHistoryFiles.isEmpty()) {
196 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getHistory.errMsg.couldntFindAnyFiles");
197 logger.log(Level.INFO, msg);
202 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
204 while (j < allocatedHistoryFiles.size()) {
205 String temps = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + allocatedHistoryFiles.get(j).getName() + j +
".db";
206 final AbstractFile historyFile = allocatedHistoryFiles.get(j++);
207 if ((historyFile.getSize() == 0) || (historyFile.getName().toLowerCase().contains(
"-slack"))
208 || (historyFile.getName().toLowerCase().contains(
"cache")) || (historyFile.getName().toLowerCase().contains(
"media"))
209 || (historyFile.getName().toLowerCase().contains(
"index"))) {
213 ContentUtils.writeToFile(historyFile,
new File(temps), context::dataSourceIngestIsCancelled);
214 }
catch (ReadContentInputStreamException ex) {
215 logger.log(Level.WARNING, String.format(
"Error reading Chrome web history artifacts file '%s' (id=%d).",
216 historyFile.getName(), historyFile.getId()), ex);
217 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getHistory.errMsg.errAnalyzingFile",
218 this.getName(), historyFile.getName()));
220 }
catch (IOException ex) {
221 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome web history artifacts file '%s' (id=%d).",
222 temps, historyFile.getName(), historyFile.getId()), ex);
223 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getHistory.errMsg.errAnalyzingFile",
224 this.getName(), historyFile.getName()));
227 File dbFile =
new File(temps);
228 if (context.dataSourceIngestIsCancelled()) {
232 List<HashMap<String, Object>> tempList;
233 tempList = this.dbConnect(temps, HISTORY_QUERY);
234 logger.log(Level.INFO,
"{0}- Now getting history from {1} with {2}artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
235 for (HashMap<String, Object> result : tempList) {
236 Collection<BlackboardAttribute> bbattributes =
new ArrayList<BlackboardAttribute>();
237 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
238 RecentActivityExtracterModuleFactory.getModuleName(),
239 ((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"")));
240 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
241 RecentActivityExtracterModuleFactory.getModuleName(),
242 (Long.valueOf(result.get(
"last_visit_time").toString()) / 1000000) - Long.valueOf(
"11644473600")));
243 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER,
244 RecentActivityExtracterModuleFactory.getModuleName(),
245 ((result.get(
"from_visit").toString() != null) ? result.get(
"from_visit").toString() :
"")));
246 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
247 RecentActivityExtracterModuleFactory.getModuleName(),
248 ((result.get(
"title").toString() != null) ? result.get(
"title").toString() :
"")));
249 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
250 RecentActivityExtracterModuleFactory.getModuleName(), browser));
251 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
252 RecentActivityExtracterModuleFactory.getModuleName(),
253 (NetworkUtils.extractDomain((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
""))));
255 BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes);
257 bbartifacts.add(bbart);
263 if( !bbartifacts.isEmpty() ){
264 postArtifacts(bbartifacts);
271 private void getBookmark(String browser, String browserLocation) {
272 FileManager fileManager = currentCase.getServices().getFileManager();
273 List<AbstractFile> bookmarkFiles;
275 bookmarkFiles = fileManager.findFiles(dataSource,
"%Bookmarks%", browserLocation);
276 }
catch (TskCoreException ex) {
277 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getBookmark.errMsg.errGettingFiles");
278 logger.log(Level.SEVERE, msg, ex);
279 this.addErrorMessage(this.getName() +
": " + msg);
283 if (bookmarkFiles.isEmpty()) {
284 logger.log(Level.INFO,
"Didn't find any Chrome bookmark files.");
289 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
292 while (j < bookmarkFiles.size()) {
293 AbstractFile bookmarkFile = bookmarkFiles.get(j++);
294 if ((bookmarkFile.getSize() == 0) || (bookmarkFile.getName().toLowerCase().contains(
"-slack"))
295 || (bookmarkFile.getName().toLowerCase().contains(
"extras")) || (bookmarkFile.getName().toLowerCase().contains(
"log"))
296 || (bookmarkFile.getName().toLowerCase().contains(
"backup")) || (bookmarkFile.getName().toLowerCase().contains(
"visualized"))
297 || (bookmarkFile.getName().toLowerCase().contains(
"bak")) || (bookmarkFile.getParentPath().toLowerCase().contains(
"backup"))) {
300 String temps = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + bookmarkFile.getName() + j +
".db";
302 ContentUtils.writeToFile(bookmarkFile,
new File(temps), context::dataSourceIngestIsCancelled);
303 }
catch (ReadContentInputStreamException ex) {
304 logger.log(Level.WARNING, String.format(
"Error reading Chrome bookmark artifacts file '%s' (id=%d).",
305 bookmarkFile.getName(), bookmarkFile.getId()), ex);
306 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile",
307 this.getName(), bookmarkFile.getName()));
309 }
catch (IOException ex) {
310 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome bookmark artifacts file '%s' (id=%d).",
311 temps, bookmarkFile.getName(), bookmarkFile.getId()), ex);
312 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile",
313 this.getName(), bookmarkFile.getName()));
317 logger.log(Level.INFO,
"{0}- Now getting Bookmarks from {1}",
new Object[]{moduleName, temps});
318 File dbFile =
new File(temps);
319 if (context.dataSourceIngestIsCancelled()) {
324 FileReader tempReader;
326 tempReader =
new FileReader(temps);
327 }
catch (FileNotFoundException ex) {
328 logger.log(Level.WARNING,
"Error while trying to read into the Bookmarks for Chrome.", ex);
332 final JsonParser parser =
new JsonParser();
333 JsonElement jsonElement;
334 JsonObject jElement, jRoot, jBookmark;
335 JsonArray jBookmarkArray;
338 jsonElement = parser.parse(tempReader);
339 jElement = jsonElement.getAsJsonObject();
340 jRoot = jElement.get(
"roots").getAsJsonObject();
341 jBookmark = jRoot.get(
"bookmark_bar").getAsJsonObject();
342 jBookmarkArray = jBookmark.getAsJsonArray(
"children");
343 }
catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
344 logger.log(Level.WARNING,
"Error parsing Json from Chrome Bookmark.", ex);
345 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile3",
346 this.getName(), bookmarkFile.getName()));
350 for (JsonElement result : jBookmarkArray) {
351 JsonObject address = result.getAsJsonObject();
352 if (address == null) {
355 JsonElement urlEl = address.get(
"url");
358 url = urlEl.getAsString();
363 JsonElement nameEl = address.get(
"name");
364 if (nameEl != null) {
365 name = nameEl.getAsString();
370 JsonElement dateEl = address.get(
"date_added");
371 if (dateEl != null) {
372 date = dateEl.getAsLong();
374 date = Long.valueOf(0);
376 String domain = NetworkUtils.extractDomain(url);
378 BlackboardArtifact bbart = bookmarkFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
379 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
381 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
382 RecentActivityExtracterModuleFactory.getModuleName(), url));
383 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
384 RecentActivityExtracterModuleFactory.getModuleName(), name));
385 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
386 RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf(
"11644473600")));
387 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
388 RecentActivityExtracterModuleFactory.getModuleName(), browser));
389 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
390 RecentActivityExtracterModuleFactory.getModuleName(), domain));
391 bbart.addAttributes(bbattributes);
393 bbartifacts.add(bbart);
394 }
catch (TskCoreException ex) {
395 logger.log(Level.SEVERE,
"Error while trying to insert Chrome bookmark artifact{0}", ex);
396 this.addErrorMessage(
397 NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile4",
398 this.getName(), bookmarkFile.getName()));
401 postArtifacts(bbartifacts);
409 private void getCookie(String browser, String browserLocation) {
411 FileManager fileManager = currentCase.getServices().getFileManager();
412 List<AbstractFile> cookiesFiles;
414 cookiesFiles = fileManager.findFiles(dataSource,
"%Cookies%", browserLocation);
415 }
catch (TskCoreException ex) {
416 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getCookie.errMsg.errGettingFiles");
417 logger.log(Level.SEVERE, msg, ex);
418 this.addErrorMessage(this.getName() +
": " + msg);
422 if (cookiesFiles.isEmpty()) {
423 logger.log(Level.INFO,
"Didn't find any Chrome cookies files.");
428 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
430 while (j < cookiesFiles.size()) {
431 AbstractFile cookiesFile = cookiesFiles.get(j++);
432 if ((cookiesFile.getSize() == 0) || (cookiesFile.getName().toLowerCase().contains(
"-slack"))) {
435 String temps = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + cookiesFile.getName() + j +
".db";
437 ContentUtils.writeToFile(cookiesFile,
new File(temps), context::dataSourceIngestIsCancelled);
438 }
catch (ReadContentInputStreamException ex) {
439 logger.log(Level.WARNING, String.format(
"Error reading Chrome cookie artifacts file '%s' (id=%d).",
440 cookiesFile.getName(), cookiesFile.getId()), ex);
441 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getCookie.errMsg.errAnalyzeFile",
442 this.getName(), cookiesFile.getName()));
444 }
catch (IOException ex) {
445 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome cookie artifacts file '%s' (id=%d).",
446 temps, cookiesFile.getName(), cookiesFile.getId()), ex);
447 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getCookie.errMsg.errAnalyzeFile",
448 this.getName(), cookiesFile.getName()));
451 File dbFile =
new File(temps);
452 if (context.dataSourceIngestIsCancelled()) {
457 List<HashMap<String, Object>> tempList = this.dbConnect(temps, COOKIE_QUERY);
458 logger.log(Level.INFO,
"{0}- Now getting cookies from {1} with {2}artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
459 for (HashMap<String, Object> result : tempList) {
460 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
461 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
462 RecentActivityExtracterModuleFactory.getModuleName(),
463 ((result.get(
"host_key").toString() != null) ? result.get(
"host_key").toString() :
"")));
464 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME,
465 RecentActivityExtracterModuleFactory.getModuleName(),
466 (Long.valueOf(result.get(
"last_access_utc").toString()) / 1000000) - Long.valueOf(
"11644473600")));
468 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
469 RecentActivityExtracterModuleFactory.getModuleName(),
470 ((result.get(
"name").toString() != null) ? result.get(
"name").toString() :
"")));
471 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
472 RecentActivityExtracterModuleFactory.getModuleName(),
473 ((result.get(
"value").toString() != null) ? result.get(
"value").toString() :
"")));
474 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
475 RecentActivityExtracterModuleFactory.getModuleName(), browser));
476 String domain = result.get(
"host_key").toString();
477 domain = domain.replaceFirst(
"^\\.+(?!$)",
"");
478 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
479 RecentActivityExtracterModuleFactory.getModuleName(), domain));
481 BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes);
483 bbartifacts.add(bbart);
490 if( !bbartifacts.isEmpty() ) {
491 postArtifacts(bbartifacts);
498 private void getDownload(String browser, String browserLocation) {
499 FileManager fileManager = currentCase.getServices().getFileManager();
500 List<AbstractFile> downloadFiles;
502 downloadFiles = fileManager.findFiles(dataSource,
"%History%", browserLocation);
503 }
catch (TskCoreException ex) {
504 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getDownload.errMsg.errGettingFiles");
505 logger.log(Level.SEVERE, msg, ex);
506 this.addErrorMessage(this.getName() +
": " + msg);
510 if (downloadFiles.isEmpty()) {
511 logger.log(Level.INFO,
"Didn't find any Chrome download files.");
516 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
518 while (j < downloadFiles.size()) {
519 AbstractFile downloadFile = downloadFiles.get(j++);
520 if ((downloadFile.getSize() == 0) || (downloadFile.getName().toLowerCase().contains(
"-slack"))
521 || (downloadFile.getName().toLowerCase().contains(
"cache")) || (downloadFile.getName().toLowerCase().contains(
"index"))) {
525 String temps = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + downloadFile.getName() + j +
".db";
527 ContentUtils.writeToFile(downloadFile,
new File(temps), context::dataSourceIngestIsCancelled);
528 }
catch (ReadContentInputStreamException ex) {
529 logger.log(Level.WARNING, String.format(
"Error reading Chrome download artifacts file '%s' (id=%d).",
530 downloadFile.getName(), downloadFile.getId()), ex);
531 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getDownload.errMsg.errAnalyzeFiles1",
532 this.getName(), downloadFile.getName()));
534 }
catch (IOException ex) {
535 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome download artifacts file '%s' (id=%d).",
536 temps, downloadFile.getName(), downloadFile.getId()), ex);
537 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getDownload.errMsg.errAnalyzeFiles1",
538 this.getName(), downloadFile.getName()));
541 File dbFile =
new File(temps);
542 if (context.dataSourceIngestIsCancelled()) {
547 List<HashMap<String, Object>> tempList;
549 if (isChromePreVersion30(temps)) {
550 tempList = this.dbConnect(temps, DOWNLOAD_QUERY);
552 tempList = this.dbConnect(temps, DOWNLOAD_QUERY_V30);
555 logger.log(Level.INFO,
"{0}- Now getting downloads from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
556 for (HashMap<String, Object> result : tempList) {
557 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
558 String fullPath = result.get(
"full_path").toString();
559 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
560 RecentActivityExtracterModuleFactory.getModuleName(), fullPath));
561 long pathID = Util.findID(dataSource, fullPath);
563 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
564 NbBundle.getMessage(
this.getClass(),
565 "Chrome.parentModuleName"), pathID));
567 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
568 RecentActivityExtracterModuleFactory.getModuleName(),
569 ((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"")));
571 Long time = (Long.valueOf(result.get(
"start_time").toString()) / 1000000) - Long.valueOf(
"11644473600");
575 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
576 RecentActivityExtracterModuleFactory.getModuleName(), time));
577 String domain = NetworkUtils.extractDomain((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"");
578 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
579 RecentActivityExtracterModuleFactory.getModuleName(), domain));
580 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
581 RecentActivityExtracterModuleFactory.getModuleName(), browser));
583 BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadFile, bbattributes);
584 if (webDownloadArtifact != null) {
585 bbartifacts.add(webDownloadArtifact);
589 String normalizedFullPath = FilenameUtils.normalize(fullPath,
true);
590 for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(normalizedFullPath), FilenameUtils.getPath(normalizedFullPath))) {
591 BlackboardArtifact associatedObjectArtifact = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT);
592 associatedObjectArtifact.addAttribute(
593 new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT,
594 RecentActivityExtracterModuleFactory.getModuleName(), webDownloadArtifact.getArtifactID()));
596 bbartifacts.add(associatedObjectArtifact);
599 }
catch (TskCoreException ex) {
600 logger.log(Level.SEVERE, String.format(
"Error creating associated object artifact for file '%s'", fullPath), ex);
608 if( !bbartifacts.isEmpty() ) {
609 postArtifacts(bbartifacts);
616 private void getLogins(String browser, String browserLocation) {
618 FileManager fileManager = currentCase.getServices().getFileManager();
619 List<AbstractFile> loginDataFiles;
621 loginDataFiles = fileManager.findFiles(dataSource,
"%Login Data%", browserLocation);
622 }
catch (TskCoreException ex) {
623 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getLogin.errMsg.errGettingFiles");
624 logger.log(Level.SEVERE, msg, ex);
625 this.addErrorMessage(this.getName() +
": " + msg);
629 if (loginDataFiles.isEmpty()) {
630 logger.log(Level.INFO,
"Didn't find any Chrome Login Data files.");
635 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
637 while (j < loginDataFiles.size()) {
638 AbstractFile loginDataFile = loginDataFiles.get(j++);
639 if ((loginDataFile.getSize() == 0) || (loginDataFile.getName().toLowerCase().contains(
"-slack"))) {
642 String temps = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + loginDataFile.getName() + j +
".db";
644 ContentUtils.writeToFile(loginDataFile,
new File(temps), context::dataSourceIngestIsCancelled);
645 }
catch (ReadContentInputStreamException ex) {
646 logger.log(Level.WARNING, String.format(
"Error reading Chrome login artifacts file '%s' (id=%d).",
647 loginDataFile.getName(), loginDataFile.getId()), ex);
648 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
649 this.getName(), loginDataFile.getName()));
651 }
catch (IOException ex) {
652 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome login artifacts file '%s' (id=%d).",
653 temps, loginDataFile.getName(), loginDataFile.getId()), ex);
654 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
655 this.getName(), loginDataFile.getName()));
658 File dbFile =
new File(temps);
659 if (context.dataSourceIngestIsCancelled()) {
663 List<HashMap<String, Object>> tempList = this.dbConnect(temps, LOGIN_QUERY);
664 logger.log(Level.INFO,
"{0}- Now getting login information from {1} with {2}artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
665 for (HashMap<String, Object> result : tempList) {
666 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
668 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
669 RecentActivityExtracterModuleFactory.getModuleName(),
670 ((result.get(
"origin_url").toString() != null) ? result.get(
"origin_url").toString() :
"")));
673 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
674 RecentActivityExtracterModuleFactory.getModuleName(),
675 (Long.valueOf(result.get(
"date_created").toString()) / 1000000) - Long.valueOf(
"11644473600")));
677 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
678 RecentActivityExtracterModuleFactory.getModuleName(),
679 (NetworkUtils.extractDomain((result.get(
"origin_url").toString() != null) ? result.get(
"origin_url").toString() :
""))));
681 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
682 RecentActivityExtracterModuleFactory.getModuleName(),
683 ((result.get(
"username_value").toString() != null) ? result.get(
"username_value").toString().replaceAll(
"'",
"''") :
"")));
685 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
686 RecentActivityExtracterModuleFactory.getModuleName(),
687 ((result.get(
"signon_realm").toString() != null) ? result.get(
"signon_realm").toString() :
"")));
689 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
690 RecentActivityExtracterModuleFactory.getModuleName(), browser));
692 BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT, loginDataFile, bbattributes);
694 bbartifacts.add(bbart);
701 if( !bbartifacts.isEmpty() ) {
702 postArtifacts(bbartifacts);
710 private void getAutofill(String browser, String browserLocation) {
712 FileManager fileManager = currentCase.getServices().getFileManager();
713 List<AbstractFile> webDataFiles;
715 webDataFiles = fileManager.findFiles(dataSource,
"%Web Data%", browserLocation);
716 }
catch (TskCoreException ex) {
717 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getAutofills.errMsg.errGettingFiles");
718 logger.log(Level.SEVERE, msg, ex);
719 this.addErrorMessage(this.getName() +
": " + msg);
723 if (webDataFiles.isEmpty()) {
724 logger.log(Level.INFO,
"Didn't find any Chrome Web Data files.");
729 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
731 while (j < webDataFiles.size()) {
732 AbstractFile webDataFile = webDataFiles.get(j++);
733 if ((webDataFile.getSize() == 0) || (webDataFile.getName().toLowerCase().contains(
"-slack"))) {
736 String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + webDataFile.getName() + j +
".db";
738 ContentUtils.writeToFile(webDataFile,
new File(tempFilePath), context::dataSourceIngestIsCancelled);
739 }
catch (ReadContentInputStreamException ex) {
740 logger.log(Level.WARNING, String.format(
"Error reading Chrome Autofill artifacts file '%s' (id=%d).",
741 webDataFile.getName(), webDataFile.getId()), ex);
742 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getAutofill.errMsg.errAnalyzingFiles",
743 this.getName(), webDataFile.getName()));
745 }
catch (IOException ex) {
746 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome Web data file '%s' (id=%d).",
747 tempFilePath, webDataFile.getName(), webDataFile.getId()), ex);
748 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
749 this.getName(), webDataFile.getName()));
752 File dbFile =
new File(tempFilePath);
753 if (context.dataSourceIngestIsCancelled()) {
759 boolean isSchemaV8X = Util.checkColumn(
"date_created",
"autofill", tempFilePath);
762 bbartifacts.addAll(getFormAutofillArtifacts(webDataFile, tempFilePath, isSchemaV8X, browser));
765 getFormAddressArtifacts(webDataFile, tempFilePath, isSchemaV8X);
766 }
catch (NoCurrentCaseException | TskCoreException | Blackboard.BlackboardException ex) {
767 logger.log(Level.SEVERE, String.format(
"Error adding artifacts to the case database "
768 +
"for chrome file %s [objId=%d]", webDataFile.getName(), webDataFile.getId()), ex);
774 if( !bbartifacts.isEmpty() ){
775 postArtifacts(bbartifacts);
788 private Collection<BlackboardArtifact> getFormAutofillArtifacts (AbstractFile webDataFile, String dbFilePath ,
boolean isSchemaV8X, String browser ) {
790 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
793 String autoFillquery = (isSchemaV8X) ? AUTOFILL_QUERY_V8X
796 List<HashMap<String, Object>> autofills = this.dbConnect(dbFilePath, autoFillquery);
797 logger.log(Level.INFO,
"{0}- Now getting Autofill information from {1} with {2}artifacts identified.",
new Object[]{moduleName, dbFilePath, autofills.size()});
798 for (HashMap<String, Object> result : autofills) {
799 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
802 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
803 NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"),
804 ((result.get(
"name").toString() != null) ? result.get(
"name").toString() :
"")));
806 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
807 RecentActivityExtracterModuleFactory.getModuleName(),
808 ((result.get(
"value").toString() != null) ? result.get(
"value").toString() :
"")));
810 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
811 RecentActivityExtracterModuleFactory.getModuleName(),
812 (Integer.valueOf(result.get(
"count").toString()))));
814 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
815 RecentActivityExtracterModuleFactory.getModuleName(),
816 Long.valueOf(result.get(
"date_created").toString())));
820 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
821 RecentActivityExtracterModuleFactory.getModuleName(),
822 Long.valueOf(result.get(
"date_last_used").toString())));
825 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
826 RecentActivityExtracterModuleFactory.getModuleName(), browser));
829 BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, webDataFile, bbattributes);
831 bbartifacts.add(bbart);
848 private void getFormAddressArtifacts (AbstractFile webDataFile, String dbFilePath ,
boolean isSchemaV8X )
throws NoCurrentCaseException,
849 TskCoreException, Blackboard.BlackboardException {
851 String webformAddressQuery = (isSchemaV8X) ? WEBFORM_ADDRESS_QUERY_V8X
852 : WEBFORM_ADDRESS_QUERY;
855 WebBrowserArtifactsHelper helper =
new WebBrowserArtifactsHelper(
856 Case.getCurrentCaseThrows().getSleuthkitCase(),
857 NbBundle.getMessage(this.getClass(),
"Chrome.parentModuleName"),
862 List<HashMap<String, Object>> addresses = this.dbConnect(dbFilePath, webformAddressQuery);
863 logger.log(Level.INFO,
"{0}- Now getting Web form addresses from {1} with {2}artifacts identified.",
new Object[]{moduleName, dbFilePath, addresses.size()});
864 for (HashMap<String, Object> result : addresses) {
867 String first_name = result.get(
"first_name").toString() != null ? result.get(
"first_name").toString() :
"";
868 String middle_name = result.get(
"middle_name").toString() != null ? result.get(
"middle_name").toString() :
"";
869 String last_name = result.get(
"last_name").toString() != null ? result.get(
"last_name").toString() :
"";
872 String email_Addr = result.get(
"email").toString() != null ? result.get(
"email").toString() :
"";
873 String phone_number = result.get(
"number").toString() != null ? result.get(
"number").toString() :
"";
876 String city = result.get(
"city").toString() != null ? result.get(
"city").toString() :
"";
877 String state = result.get(
"state").toString() != null ? result.get(
"state").toString() :
"";
878 String zipcode = result.get(
"zipcode").toString() != null ? result.get(
"zipcode").toString() :
"";
879 String country_code = result.get(
"country_code").toString() != null ? result.get(
"country_code").toString() :
"";
882 String full_name =
"";
883 String street_address =
"";
884 long date_modified = 0;
889 full_name = result.get(
"full_name").toString() != null ? result.get(
"full_name").toString() :
"";
890 street_address = result.get(
"street_address").toString() != null ? result.get(
"street_address").toString() :
"";
891 date_modified = result.get(
"date_modified").toString() != null ? Long.valueOf(result.get(
"date_modified").toString()) : 0;
892 use_count = result.get(
"use_count").toString() != null ? Integer.valueOf(result.get(
"use_count").toString()) : 0;
893 use_date = result.get(
"use_date").toString() != null ? Long.valueOf(result.get(
"use_date").toString()) : 0;
895 String address_line_1 = result.get(
"address_line_1").toString() != null ? result.get(
"street_address").toString() :
"";
896 String address_line_2 = result.get(
"address_line_2").toString() != null ? result.get(
"address_line_2").toString() :
"";
897 street_address = String.join(
" ", address_line_1, address_line_2);
901 if (full_name == null || full_name.isEmpty()) {
902 full_name = String.join(
" ", first_name, middle_name, last_name);
905 String locationAddress = String.join(
", ", street_address, city, state, zipcode, country_code);
907 List<BlackboardAttribute> otherAttributes =
new ArrayList<>();
908 if (date_modified > 0) {
909 otherAttributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
910 RecentActivityExtracterModuleFactory.getModuleName(),
914 helper.addWebFormAddress(
915 full_name, email_Addr, phone_number,
916 locationAddress, 0, use_date,
917 use_count, otherAttributes);
921 private boolean isChromePreVersion30(String temps) {
922 String query =
"PRAGMA table_info(downloads)";
923 List<HashMap<String, Object>> columns = this.dbConnect(temps, query);
924 for (HashMap<String, Object> col : columns) {
925 if (col.get(
"name").equals(
"url")) {