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;
36 import java.io.FileNotFoundException;
37 import java.io.FileReader;
38 import java.io.IOException;
39 import java.util.Collection;
40 import java.util.List;
42 import java.util.HashMap;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import org.apache.commons.io.FilenameUtils;
46 import org.openide.util.NbBundle.Messages;
58 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
60 import org.
sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
64 import org.
sleuthkit.datamodel.blackboardutils.WebBrowserArtifactsHelper;
69 class Chromium
extends Extract {
71 private static final String HISTORY_QUERY =
"SELECT urls.url, urls.title, urls.visit_count, urls.typed_count, "
72 +
"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";
73 private static final String COOKIE_QUERY =
"SELECT name, value, host_key, expires_utc,last_access_utc, creation_utc FROM cookies";
74 private static final String DOWNLOAD_QUERY =
"SELECT full_path, url, start_time, received_bytes FROM downloads";
75 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";
76 private static final String LOGIN_QUERY =
"SELECT origin_url, username_value, date_created, signon_realm from logins";
77 private static final String AUTOFILL_QUERY =
"SELECT name, value, count, date_created "
78 +
" FROM autofill, autofill_dates "
79 +
" WHERE autofill.pair_id = autofill_dates.pair_id";
80 private static final String AUTOFILL_QUERY_V8X =
"SELECT name, value, count, date_created, date_last_used from autofill";
81 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 "
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";
85 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"
86 +
" FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones"
87 +
" WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
88 private static final String HISTORY_FILE_NAME =
"History";
89 private static final String BOOKMARK_FILE_NAME =
"Bookmarks";
90 private static final String COOKIE_FILE_NAME =
"Cookies";
91 private static final String LOGIN_DATA_FILE_NAME =
"Login Data";
92 private static final String WEB_DATA_FILE_NAME =
"Web Data";
93 private static final String UC_BROWSER_NAME =
"UC Browser";
94 private static final String ENCRYPTED_FIELD_MESSAGE =
"The data was encrypted.";
96 private Boolean databaseEncrypted =
false;
97 private Boolean fieldEncrypted =
false;
99 private final Logger logger = Logger.getLogger(this.getClass().getName());
100 private Content dataSource;
101 private final IngestJobContext context;
103 private static final Map<String, String> BROWSERS_MAP = ImmutableMap.<String, String>builder()
104 .put(
"Microsoft Edge",
"Microsoft/Edge/User Data/Default")
105 .put(
"Yandex",
"YandexBrowser/User Data/Default")
106 .put(
"Opera",
"Opera Software/Opera Stable")
107 .put(
"SalamWeb",
"SalamWeb/User Data/Default")
108 .put(
"UC Browser",
"UCBrowser/User Data%/Default")
109 .put(
"Brave",
"BraveSoftware/Brave-Browser/User Data/Default")
110 .put(
"Google Chrome",
"Chrome/User Data/Default")
113 @Messages({
"# {0} - browserName",
114 "Progress_Message_Chrome_History=Chrome History Browser {0}",
115 "# {0} - browserName",
116 "Progress_Message_Chrome_Bookmarks=Chrome Bookmarks Browser {0}",
117 "# {0} - browserName",
118 "Progress_Message_Chrome_Cookies=Chrome Cookies Browser {0}",
119 "# {0} - browserName",
120 "Progress_Message_Chrome_Downloads=Chrome Downloads Browser {0}",
121 "Progress_Message_Chrome_FormHistory=Chrome Form History",
122 "# {0} - browserName",
123 "Progress_Message_Chrome_AutoFill=Chrome Auto Fill Browser {0}",
124 "# {0} - browserName",
125 "Progress_Message_Chrome_Logins=Chrome Logins Browser {0}",
126 "Progress_Message_Chrome_Cache=Chrome Cache",})
128 Chromium(IngestJobContext context) {
129 super(NbBundle.getMessage(Chromium.class,
"Chrome.moduleName"), context);
130 this.context = context;
134 public void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
135 this.dataSource = dataSource;
137 long ingestJobId = context.getJobId();
139 for (Map.Entry<String, String> browser : BROWSERS_MAP.entrySet()) {
140 String browserName = browser.getKey();
141 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_History", browserName));
142 this.getHistory(browser.getKey(), browser.getValue(), ingestJobId);
143 if (context.dataSourceIngestIsCancelled()) {
147 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Bookmarks", browserName));
148 this.getBookmark(browser.getKey(), browser.getValue(), ingestJobId);
149 if (context.dataSourceIngestIsCancelled()) {
153 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Cookies", browserName));
154 this.getCookie(browser.getKey(), browser.getValue(), ingestJobId);
155 if (context.dataSourceIngestIsCancelled()) {
159 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Logins", browserName));
160 this.getLogins(browser.getKey(), browser.getValue(), ingestJobId);
161 if (context.dataSourceIngestIsCancelled()) {
165 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_AutoFill", browserName));
166 this.getAutofill(browser.getKey(), browser.getValue(), ingestJobId);
167 if (context.dataSourceIngestIsCancelled()) {
171 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Downloads", browserName));
172 this.getDownload(browser.getKey(), browser.getValue(), ingestJobId);
173 if (context.dataSourceIngestIsCancelled()) {
178 progressBar.progress(Bundle.Progress_Message_Chrome_Cache());
179 ChromeCacheExtractor chromeCacheExtractor =
new ChromeCacheExtractor(dataSource, context, progressBar);
180 chromeCacheExtractor.processCaches();
190 private void getHistory(String browser, String browserLocation,
long ingestJobId) {
191 FileManager fileManager = currentCase.getServices().getFileManager();
192 List<AbstractFile> historyFiles;
193 String historyFileName = HISTORY_FILE_NAME;
194 if (browser.equals(UC_BROWSER_NAME)) {
195 historyFileName = HISTORY_FILE_NAME +
"%";
198 historyFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation);
199 }
catch (TskCoreException ex) {
200 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getHistory.errMsg.errGettingFiles");
201 logger.log(Level.SEVERE, msg, ex);
202 this.addErrorMessage(this.getDisplayName() +
": " + msg);
207 List<AbstractFile> allocatedHistoryFiles =
new ArrayList<>();
208 for (AbstractFile historyFile : historyFiles) {
209 if (historyFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
210 allocatedHistoryFiles.add(historyFile);
215 if (allocatedHistoryFiles.isEmpty()) {
216 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getHistory.errMsg.couldntFindAnyFiles");
217 logger.log(Level.INFO, msg);
222 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
224 while (j < allocatedHistoryFiles.size()) {
225 String temps = RAImageIngestModule.getRATempPath(currentCase, browser, ingestJobId) + File.separator + allocatedHistoryFiles.get(j).getName() + j +
".db";
226 final AbstractFile historyFile = allocatedHistoryFiles.get(j++);
227 if ((historyFile.getSize() == 0) || (historyFile.getName().toLowerCase().contains(
"-slack"))
228 || (historyFile.getName().toLowerCase().contains(
"cache")) || (historyFile.getName().toLowerCase().contains(
"media"))
229 || (historyFile.getName().toLowerCase().contains(
"index"))) {
233 ContentUtils.writeToFile(historyFile,
new File(temps), context::dataSourceIngestIsCancelled);
234 }
catch (ReadContentInputStreamException ex) {
235 logger.log(Level.WARNING, String.format(
"Error reading Chrome web history artifacts file '%s' (id=%d).",
236 historyFile.getName(), historyFile.getId()), ex);
237 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getHistory.errMsg.errAnalyzingFile",
238 this.getDisplayName(), historyFile.getName()));
240 }
catch (IOException ex) {
241 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome web history artifacts file '%s' (id=%d).",
242 temps, historyFile.getName(), historyFile.getId()), ex);
243 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getHistory.errMsg.errAnalyzingFile",
244 this.getDisplayName(), historyFile.getName()));
247 File dbFile =
new File(temps);
248 if (context.dataSourceIngestIsCancelled()) {
252 List<HashMap<String, Object>> tempList;
253 tempList = this.querySQLiteDb(temps, HISTORY_QUERY);
254 logger.log(Level.INFO,
"{0}- Now getting history from {1} with {2} artifacts identified.",
new Object[]{getDisplayName(), temps, tempList.size()});
255 for (HashMap<String, Object> result : tempList) {
256 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
257 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
258 RecentActivityExtracterModuleFactory.getModuleName(),
259 ((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"")));
260 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
261 RecentActivityExtracterModuleFactory.getModuleName(),
262 (Long.valueOf(result.get(
"last_visit_time").toString()) / 1000000) - Long.valueOf(
"11644473600")));
263 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER,
264 RecentActivityExtracterModuleFactory.getModuleName(),
265 ((result.get(
"from_visit").toString() != null) ? result.get(
"from_visit").toString() :
"")));
266 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
267 RecentActivityExtracterModuleFactory.getModuleName(),
268 ((result.get(
"title").toString() != null) ? result.get(
"title").toString() :
"")));
269 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
270 RecentActivityExtracterModuleFactory.getModuleName(), browser));
271 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
272 RecentActivityExtracterModuleFactory.getModuleName(),
273 (NetworkUtils.extractDomain((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
""))));
276 bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_HISTORY, historyFile, bbattributes));
277 }
catch (TskCoreException ex) {
278 logger.log(Level.SEVERE, String.format(
"Failed to create history artifact for file (%d)", historyFile.getId()), ex);
284 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
285 postArtifacts(bbartifacts);
296 private void getBookmark(String browser, String browserLocation,
long ingestJobId) {
297 FileManager fileManager = currentCase.getServices().getFileManager();
298 List<AbstractFile> bookmarkFiles;
299 String bookmarkFileName = BOOKMARK_FILE_NAME;
300 if (browser.equals(UC_BROWSER_NAME)) {
301 bookmarkFileName = BOOKMARK_FILE_NAME +
"%";
304 bookmarkFiles = fileManager.findFiles(dataSource, bookmarkFileName, browserLocation);
305 }
catch (TskCoreException ex) {
306 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getBookmark.errMsg.errGettingFiles");
307 logger.log(Level.SEVERE, msg, ex);
308 this.addErrorMessage(this.getDisplayName() +
": " + msg);
312 if (bookmarkFiles.isEmpty()) {
313 logger.log(Level.INFO,
"Didn't find any Chrome bookmark files.");
318 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
320 while (j < bookmarkFiles.size()) {
321 AbstractFile bookmarkFile = bookmarkFiles.get(j++);
322 if ((bookmarkFile.getSize() == 0) || (bookmarkFile.getName().toLowerCase().contains(
"-slack"))
323 || (bookmarkFile.getName().toLowerCase().contains(
"extras")) || (bookmarkFile.getName().toLowerCase().contains(
"log"))
324 || (bookmarkFile.getName().toLowerCase().contains(
"backup")) || (bookmarkFile.getName().toLowerCase().contains(
"visualized"))
325 || (bookmarkFile.getName().toLowerCase().contains(
"bak")) || (bookmarkFile.getParentPath().toLowerCase().contains(
"backup"))) {
328 String temps = RAImageIngestModule.getRATempPath(currentCase, browser, ingestJobId) + File.separator + bookmarkFile.getName() + j +
".db";
330 ContentUtils.writeToFile(bookmarkFile,
new File(temps), context::dataSourceIngestIsCancelled);
331 }
catch (ReadContentInputStreamException ex) {
332 logger.log(Level.WARNING, String.format(
"Error reading Chrome bookmark artifacts file '%s' (id=%d).",
333 bookmarkFile.getName(), bookmarkFile.getId()), ex);
334 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile",
335 this.getDisplayName(), bookmarkFile.getName()));
337 }
catch (IOException ex) {
338 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome bookmark artifacts file '%s' (id=%d).",
339 temps, bookmarkFile.getName(), bookmarkFile.getId()), ex);
340 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile",
341 this.getDisplayName(), bookmarkFile.getName()));
345 logger.log(Level.INFO,
"{0}- Now getting Bookmarks from {1}",
new Object[]{getDisplayName(), temps});
346 File dbFile =
new File(temps);
347 if (context.dataSourceIngestIsCancelled()) {
352 FileReader tempReader;
354 tempReader =
new FileReader(temps);
355 }
catch (FileNotFoundException ex) {
356 logger.log(Level.WARNING,
"Error while trying to read into the Bookmarks for Chrome.", ex);
360 final JsonParser parser =
new JsonParser();
361 JsonElement jsonElement;
362 JsonObject jElement, jRoot, jBookmark;
363 JsonArray jBookmarkArray;
366 jsonElement = parser.parse(tempReader);
367 jElement = jsonElement.getAsJsonObject();
368 jRoot = jElement.get(
"roots").getAsJsonObject();
369 jBookmark = jRoot.get(
"bookmark_bar").getAsJsonObject();
370 jBookmarkArray = jBookmark.getAsJsonArray(
"children");
371 }
catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
372 logger.log(Level.WARNING,
"Error parsing Json from Chrome Bookmark.", ex);
373 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile3",
374 this.getDisplayName(), bookmarkFile.getName()));
378 for (JsonElement result : jBookmarkArray) {
379 JsonObject address = result.getAsJsonObject();
380 if (address == null) {
383 JsonElement urlEl = address.get(
"url");
386 url = urlEl.getAsString();
391 JsonElement nameEl = address.get(
"name");
392 if (nameEl != null) {
393 name = nameEl.getAsString();
398 JsonElement dateEl = address.get(
"date_added");
399 if (dateEl != null) {
400 date = dateEl.getAsLong();
402 date = Long.valueOf(0);
404 String domain = NetworkUtils.extractDomain(url);
405 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
407 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
408 RecentActivityExtracterModuleFactory.getModuleName(), url));
409 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
410 RecentActivityExtracterModuleFactory.getModuleName(), name));
411 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
412 RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf(
"11644473600")));
413 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
414 RecentActivityExtracterModuleFactory.getModuleName(), browser));
415 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
416 RecentActivityExtracterModuleFactory.getModuleName(), domain));
419 bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes));
420 }
catch (TskCoreException ex) {
421 logger.log(Level.SEVERE, String.format(
"Failed to create bookmark artifact for file (%d)", bookmarkFile.getId()), ex);
426 if (!context.dataSourceIngestIsCancelled()) {
427 postArtifacts(bbartifacts);
441 private void getCookie(String browser, String browserLocation,
long ingestJobId) {
443 FileManager fileManager = currentCase.getServices().getFileManager();
444 List<AbstractFile> cookiesFiles;
445 String cookieFileName = COOKIE_FILE_NAME;
446 if (browser.equals(UC_BROWSER_NAME)) {
449 cookieFileName =
"%" + COOKIE_FILE_NAME +
"%";
452 cookiesFiles = fileManager.findFiles(dataSource, cookieFileName, browserLocation);
453 }
catch (TskCoreException ex) {
454 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getCookie.errMsg.errGettingFiles");
455 logger.log(Level.SEVERE, msg, ex);
456 this.addErrorMessage(this.getDisplayName() +
": " + msg);
460 if (cookiesFiles.isEmpty()) {
461 logger.log(Level.INFO,
"Didn't find any Chrome cookies files.");
466 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
468 while (j < cookiesFiles.size()) {
469 AbstractFile cookiesFile = cookiesFiles.get(j++);
470 if ((cookiesFile.getSize() == 0) || (cookiesFile.getName().toLowerCase().contains(
"-slack"))) {
473 String temps = RAImageIngestModule.getRATempPath(currentCase, browser, ingestJobId) + File.separator + cookiesFile.getName() + j +
".db";
475 ContentUtils.writeToFile(cookiesFile,
new File(temps), context::dataSourceIngestIsCancelled);
476 }
catch (ReadContentInputStreamException ex) {
477 logger.log(Level.WARNING, String.format(
"Error reading Chrome cookie artifacts file '%s' (id=%d).",
478 cookiesFile.getName(), cookiesFile.getId()), ex);
479 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getCookie.errMsg.errAnalyzeFile",
480 this.getDisplayName(), cookiesFile.getName()));
482 }
catch (IOException ex) {
483 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome cookie artifacts file '%s' (id=%d).",
484 temps, cookiesFile.getName(), cookiesFile.getId()), ex);
485 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getCookie.errMsg.errAnalyzeFile",
486 this.getDisplayName(), cookiesFile.getName()));
489 File dbFile =
new File(temps);
490 if (context.dataSourceIngestIsCancelled()) {
495 List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, COOKIE_QUERY);
496 logger.log(Level.INFO,
"{0}- Now getting cookies from {1} with {2} artifacts identified.",
new Object[]{getDisplayName(), temps, tempList.size()});
497 for (HashMap<String, Object> result : tempList) {
498 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
499 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
500 RecentActivityExtracterModuleFactory.getModuleName(),
501 ((result.get(
"host_key").toString() != null) ? result.get(
"host_key").toString() :
"")));
502 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
503 RecentActivityExtracterModuleFactory.getModuleName(),
504 (Long.valueOf(result.get(
"last_access_utc").toString()) / 1000000) - Long.valueOf(
"11644473600")));
506 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
507 RecentActivityExtracterModuleFactory.getModuleName(),
508 ((result.get(
"name").toString() != null) ? result.get(
"name").toString() :
"")));
509 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
510 RecentActivityExtracterModuleFactory.getModuleName(),
511 ((result.get(
"value").toString() != null) ? result.get(
"value").toString() :
"")));
512 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
513 RecentActivityExtracterModuleFactory.getModuleName(), browser));
514 String domain = result.get(
"host_key").toString();
515 domain = domain.replaceFirst(
"^\\.+(?!$)",
"");
516 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
517 RecentActivityExtracterModuleFactory.getModuleName(), domain));
520 bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_COOKIE, cookiesFile, bbattributes));
521 }
catch (TskCoreException ex) {
522 logger.log(Level.SEVERE, String.format(
"Failed to create cookie artifact for file (%d)", cookiesFile.getId()), ex);
529 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
530 postArtifacts(bbartifacts);
541 private void getDownload(String browser, String browserLocation,
long ingestJobId) {
542 FileManager fileManager = currentCase.getServices().getFileManager();
543 List<AbstractFile> downloadFiles;
544 String historyFileName = HISTORY_FILE_NAME;
545 if (browser.equals(UC_BROWSER_NAME)) {
546 historyFileName = HISTORY_FILE_NAME +
"%";
549 downloadFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation);
550 }
catch (TskCoreException ex) {
551 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getDownload.errMsg.errGettingFiles");
552 logger.log(Level.SEVERE, msg, ex);
553 this.addErrorMessage(this.getDisplayName() +
": " + msg);
557 if (downloadFiles.isEmpty()) {
558 logger.log(Level.INFO,
"Didn't find any Chrome download files.");
563 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
565 while (j < downloadFiles.size()) {
566 AbstractFile downloadFile = downloadFiles.get(j++);
567 if ((downloadFile.getSize() == 0) || (downloadFile.getName().toLowerCase().contains(
"-slack"))
568 || (downloadFile.getName().toLowerCase().contains(
"cache")) || (downloadFile.getName().toLowerCase().contains(
"index"))) {
572 String temps = RAImageIngestModule.getRATempPath(currentCase, browser, ingestJobId) + File.separator + downloadFile.getName() + j +
".db";
574 ContentUtils.writeToFile(downloadFile,
new File(temps), context::dataSourceIngestIsCancelled);
575 }
catch (ReadContentInputStreamException ex) {
576 logger.log(Level.WARNING, String.format(
"Error reading Chrome download artifacts file '%s' (id=%d).",
577 downloadFile.getName(), downloadFile.getId()), ex);
578 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getDownload.errMsg.errAnalyzeFiles1",
579 this.getDisplayName(), downloadFile.getName()));
581 }
catch (IOException ex) {
582 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome download artifacts file '%s' (id=%d).",
583 temps, downloadFile.getName(), downloadFile.getId()), ex);
584 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getDownload.errMsg.errAnalyzeFiles1",
585 this.getDisplayName(), downloadFile.getName()));
588 File dbFile =
new File(temps);
589 if (context.dataSourceIngestIsCancelled()) {
594 List<HashMap<String, Object>> tempList;
596 if (isChromePreVersion30(temps)) {
597 tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY);
599 tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY_V30);
602 logger.log(Level.INFO,
"{0}- Now getting downloads from {1} with {2} artifacts identified.",
new Object[]{getDisplayName(), temps, tempList.size()});
603 for (HashMap<String, Object> result : tempList) {
604 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
605 String fullPath = result.get(
"full_path").toString();
606 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
607 RecentActivityExtracterModuleFactory.getModuleName(), fullPath));
608 long pathID = Util.findID(dataSource, fullPath);
610 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
611 NbBundle.getMessage(
this.getClass(),
612 "Chrome.parentModuleName"), pathID));
614 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
615 RecentActivityExtracterModuleFactory.getModuleName(),
616 ((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"")));
618 Long time = (Long.valueOf(result.get(
"start_time").toString()) / 1000000) - Long.valueOf(
"11644473600");
622 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
623 RecentActivityExtracterModuleFactory.getModuleName(), time));
624 String domain = NetworkUtils.extractDomain((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"");
625 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
626 RecentActivityExtracterModuleFactory.getModuleName(), domain));
627 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
628 RecentActivityExtracterModuleFactory.getModuleName(), browser));
632 BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_DOWNLOAD, downloadFile, bbattributes);
633 bbartifacts.add(webDownloadArtifact);
634 String normalizedFullPath = FilenameUtils.normalize(fullPath,
true);
635 for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, FilenameUtils.getName(normalizedFullPath), FilenameUtils.getPath(normalizedFullPath))) {
636 bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact));
639 }
catch (TskCoreException ex) {
640 logger.log(Level.SEVERE, String.format(
"Error creating associated object artifact for file '%s'", fullPath), ex);
647 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
648 postArtifacts(bbartifacts);
659 private void getLogins(String browser, String browserLocation,
long ingestJobId) {
661 FileManager fileManager = currentCase.getServices().getFileManager();
662 List<AbstractFile> loginDataFiles;
663 String loginDataFileName = LOGIN_DATA_FILE_NAME;
664 if (browser.equals(UC_BROWSER_NAME)) {
665 loginDataFileName = LOGIN_DATA_FILE_NAME +
"%";
669 loginDataFiles = fileManager.findFiles(dataSource, loginDataFileName, browserLocation);
670 }
catch (TskCoreException ex) {
671 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getLogin.errMsg.errGettingFiles");
672 logger.log(Level.SEVERE, msg, ex);
673 this.addErrorMessage(this.getDisplayName() +
": " + msg);
677 if (loginDataFiles.isEmpty()) {
678 logger.log(Level.INFO,
"Didn't find any Chrome Login Data files.");
683 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
685 while (j < loginDataFiles.size()) {
686 AbstractFile loginDataFile = loginDataFiles.get(j++);
687 if ((loginDataFile.getSize() == 0) || (loginDataFile.getName().toLowerCase().contains(
"-slack"))) {
690 String temps = RAImageIngestModule.getRATempPath(currentCase, browser, ingestJobId) + File.separator + loginDataFile.getName() + j +
".db";
692 ContentUtils.writeToFile(loginDataFile,
new File(temps), context::dataSourceIngestIsCancelled);
693 }
catch (ReadContentInputStreamException ex) {
694 logger.log(Level.WARNING, String.format(
"Error reading Chrome login artifacts file '%s' (id=%d).",
695 loginDataFile.getName(), loginDataFile.getId()), ex);
696 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
697 this.getDisplayName(), loginDataFile.getName()));
699 }
catch (IOException ex) {
700 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome login artifacts file '%s' (id=%d).",
701 temps, loginDataFile.getName(), loginDataFile.getId()), ex);
702 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
703 this.getDisplayName(), loginDataFile.getName()));
706 File dbFile =
new File(temps);
707 if (context.dataSourceIngestIsCancelled()) {
711 List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, LOGIN_QUERY);
712 logger.log(Level.INFO,
"{0}- Now getting login information from {1} with {2} artifacts identified.",
new Object[]{getDisplayName(), temps, tempList.size()});
713 for (HashMap<String, Object> result : tempList) {
714 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
716 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
717 RecentActivityExtracterModuleFactory.getModuleName(),
718 ((result.get(
"origin_url").toString() != null) ? result.get(
"origin_url").toString() :
"")));
720 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
721 RecentActivityExtracterModuleFactory.getModuleName(),
722 (Long.valueOf(result.get(
"date_created").toString()) / 1000000) - Long.valueOf(
"11644473600")));
724 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
725 RecentActivityExtracterModuleFactory.getModuleName(),
726 (NetworkUtils.extractDomain((result.get(
"origin_url").toString() != null) ? result.get(
"origin_url").toString() :
""))));
728 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
729 RecentActivityExtracterModuleFactory.getModuleName(),
730 ((result.get(
"username_value").toString() != null) ? result.get(
"username_value").toString().replaceAll(
"'",
"''") :
"")));
732 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REALM,
733 RecentActivityExtracterModuleFactory.getModuleName(),
734 ((result.get(
"signon_realm") != null && result.get(
"signon_realm").toString() != null) ? result.get(
"signon_realm").toString() :
"")));
736 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
737 RecentActivityExtracterModuleFactory.getModuleName(),
738 result.containsKey(
"signon_realm") ? NetworkUtils.extractDomain(result.get(
"signon_realm").toString()) :
""));
740 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
741 RecentActivityExtracterModuleFactory.getModuleName(), browser));
744 bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_SERVICE_ACCOUNT, loginDataFile, bbattributes));
745 }
catch (TskCoreException ex) {
746 logger.log(Level.SEVERE, String.format(
"Failed to create service account artifact for file (%d)", loginDataFile.getId()), ex);
753 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
754 postArtifacts(bbartifacts);
766 private void getAutofill(String browser, String browserLocation,
long ingestJobId) {
768 FileManager fileManager = currentCase.getServices().getFileManager();
769 List<AbstractFile> webDataFiles;
770 String webDataFileName = WEB_DATA_FILE_NAME;
771 if (browser.equals(UC_BROWSER_NAME)) {
772 webDataFileName = WEB_DATA_FILE_NAME +
"%";
776 webDataFiles = fileManager.findFiles(dataSource, webDataFileName, browserLocation);
777 }
catch (TskCoreException ex) {
778 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getAutofills.errMsg.errGettingFiles");
779 logger.log(Level.SEVERE, msg, ex);
780 this.addErrorMessage(this.getDisplayName() +
": " + msg);
784 if (webDataFiles.isEmpty()) {
785 logger.log(Level.INFO,
"Didn't find any Chrome Web Data files.");
790 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
792 while (j < webDataFiles.size()) {
793 databaseEncrypted =
false;
794 AbstractFile webDataFile = webDataFiles.get(j++);
795 if ((webDataFile.getSize() == 0) || (webDataFile.getName().toLowerCase().contains(
"-slack"))) {
798 String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, browser, ingestJobId) + File.separator + webDataFile.getName() + j +
".db";
800 ContentUtils.writeToFile(webDataFile,
new File(tempFilePath), context::dataSourceIngestIsCancelled);
801 }
catch (ReadContentInputStreamException ex) {
802 logger.log(Level.WARNING, String.format(
"Error reading Chrome Autofill artifacts file '%s' (id=%d).",
803 webDataFile.getName(), webDataFile.getId()), ex);
804 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getAutofill.errMsg.errAnalyzingFiles",
805 this.getDisplayName(), webDataFile.getName()));
807 }
catch (IOException ex) {
808 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome Web data file '%s' (id=%d).",
809 tempFilePath, webDataFile.getName(), webDataFile.getId()), ex);
810 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
811 this.getDisplayName(), webDataFile.getName()));
814 File dbFile =
new File(tempFilePath);
815 if (context.dataSourceIngestIsCancelled()) {
821 boolean isSchemaV8X = Util.checkColumn(
"date_created",
"autofill", tempFilePath);
824 bbartifacts.addAll(getFormAutofillArtifacts(webDataFile, tempFilePath, isSchemaV8X, browser));
827 getFormAddressArtifacts(webDataFile, tempFilePath, isSchemaV8X);
828 if (databaseEncrypted) {
829 String comment = String.format(
"%s Autofill Database Encryption Detected", browser);
830 Collection<BlackboardAttribute> bbattributes = Arrays.asList(
831 new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
832 RecentActivityExtracterModuleFactory.getModuleName(), comment));
835 webDataFile.newAnalysisResult(
836 BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, Score.SCORE_NOTABLE,
837 null, null, comment, bbattributes).getAnalysisResult());
839 }
catch (NoCurrentCaseException | TskCoreException | Blackboard.BlackboardException ex) {
840 logger.log(Level.SEVERE, String.format(
"Error adding artifacts to the case database "
841 +
"for chrome file %s [objId=%d]", webDataFile.getName(), webDataFile.getId()), ex);
847 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
848 postArtifacts(bbartifacts);
862 private Collection<BlackboardArtifact> getFormAutofillArtifacts(AbstractFile webDataFile, String dbFilePath,
boolean isSchemaV8X, String browser) {
864 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
867 String autoFillquery = (isSchemaV8X) ? AUTOFILL_QUERY_V8X
870 List<HashMap<String, Object>> autofills = this.querySQLiteDb(dbFilePath, autoFillquery);
871 logger.log(Level.INFO,
"{0}- Now getting Autofill information from {1} with {2} artifacts identified.",
new Object[]{getDisplayName(), dbFilePath, autofills.size()});
872 for (HashMap<String, Object> result : autofills) {
873 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
876 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
877 NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"),
878 ((result.get(
"name").toString() != null) ? result.get(
"name").toString() :
"")));
880 fieldEncrypted =
false;
881 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
882 RecentActivityExtracterModuleFactory.getModuleName(),
883 processFields(result.get(
"value"))));
885 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
886 RecentActivityExtracterModuleFactory.getModuleName(),
887 (Integer.valueOf(result.get(
"count").toString()))));
889 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
890 RecentActivityExtracterModuleFactory.getModuleName(),
891 Long.valueOf(result.get(
"date_created").toString())));
895 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
896 RecentActivityExtracterModuleFactory.getModuleName(),
897 Long.valueOf(result.get(
"date_last_used").toString())));
900 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
901 RecentActivityExtracterModuleFactory.getModuleName(), browser));
902 if (fieldEncrypted) {
903 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
904 RecentActivityExtracterModuleFactory.getModuleName(), ENCRYPTED_FIELD_MESSAGE));
909 bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_FORM_AUTOFILL, webDataFile, bbattributes));
910 }
catch (TskCoreException ex) {
911 logger.log(Level.SEVERE, String.format(
"Failed to create web form autopfill artifact for file (%d)", webDataFile.getId()), ex);
930 private void getFormAddressArtifacts(AbstractFile webDataFile, String dbFilePath,
boolean isSchemaV8X)
throws NoCurrentCaseException,
931 TskCoreException, Blackboard.BlackboardException {
933 String webformAddressQuery = (isSchemaV8X) ? WEBFORM_ADDRESS_QUERY_V8X
934 : WEBFORM_ADDRESS_QUERY;
937 WebBrowserArtifactsHelper helper =
new WebBrowserArtifactsHelper(
938 Case.getCurrentCaseThrows().getSleuthkitCase(),
939 NbBundle.getMessage(this.getClass(),
"Chrome.parentModuleName"),
940 webDataFile, context.getJobId()
944 List<HashMap<String, Object>> addresses = this.querySQLiteDb(dbFilePath, webformAddressQuery);
945 logger.log(Level.INFO,
"{0}- Now getting Web form addresses from {1} with {2} artifacts identified.",
new Object[]{getDisplayName(), dbFilePath, addresses.size()});
946 for (HashMap<String, Object> result : addresses) {
948 fieldEncrypted =
false;
950 String first_name = processFields(result.get(
"first_name"));
951 String middle_name = processFields(result.get(
"middle_name"));
952 String last_name = processFields(result.get(
"last_name"));
955 String email_Addr = processFields(result.get(
"email"));
956 String phone_number = processFields(result.get(
"number"));
959 String city = processFields(result.get(
"city"));
960 String state = processFields(result.get(
"state"));
961 String zipcode = processFields(result.get(
"zipcode"));
962 String country_code = processFields(result.get(
"country_code"));
965 String full_name =
"";
966 String street_address =
"";
967 long date_modified = 0;
973 full_name = processFields(result.get(
"full_name"));
974 street_address = processFields(result.get(
"street_address"));
975 date_modified = result.get(
"date_modified").toString() != null ? Long.valueOf(result.get(
"date_modified").toString()) : 0;
976 use_count = result.get(
"use_count").toString() != null ? Integer.valueOf(result.get(
"use_count").toString()) : 0;
977 use_date = result.get(
"use_date").toString() != null ? Long.valueOf(result.get(
"use_date").toString()) : 0;
979 String address_line_1 = processFields(result.get(
"address_line_1"));
980 String address_line_2 = processFields(result.get(
"address_line_2"));
981 street_address = String.join(
" ", address_line_1, address_line_2);
985 if (full_name == null || full_name.isEmpty()) {
986 full_name = String.join(
" ", first_name, middle_name, last_name);
989 String locationAddress = String.join(
", ", street_address, city, state, zipcode, country_code);
991 List<BlackboardAttribute> otherAttributes =
new ArrayList<>();
992 if (date_modified > 0) {
993 otherAttributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
994 RecentActivityExtracterModuleFactory.getModuleName(),
996 if (fieldEncrypted) {
997 otherAttributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
998 RecentActivityExtracterModuleFactory.getModuleName(), ENCRYPTED_FIELD_MESSAGE));
1003 helper.addWebFormAddress(
1004 full_name, email_Addr, phone_number,
1005 locationAddress, 0, use_date,
1006 use_count, otherAttributes);
1019 private String processFields(Object dataValue) {
1021 if (dataValue instanceof byte[]) {
1022 fieldEncrypted =
true;
1023 databaseEncrypted =
true;
1026 return dataValue.toString() != null ? dataValue.toString() :
"";
1030 private boolean isChromePreVersion30(String temps) {
1031 String query =
"PRAGMA table_info(downloads)";
1032 List<HashMap<String, Object>> columns = this.querySQLiteDb(temps, query);
1033 for (HashMap<String, Object> col : columns) {
1034 if (col.get(
"name").equals(
"url")) {