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";
75 private static final String AUTOFILL_QUERY_V8X =
"SELECT name, value, count, date_created, date_last_used from autofill";
76 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 "
77 +
" FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones"
78 +
" WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
80 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"
81 +
" FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones"
82 +
" WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
83 private static final String HISTORY_FILE_NAME =
"History";
84 private static final String BOOKMARK_FILE_NAME =
"Bookmarks";
85 private static final String COOKIE_FILE_NAME =
"Cookies";
86 private static final String LOGIN_DATA_FILE_NAME =
"Login Data";
87 private static final String WEB_DATA_FILE_NAME =
"Web Data";
88 private static final String UC_BROWSER_NAME =
"UC Browser";
90 private final Logger logger = Logger.getLogger(this.getClass().getName());
91 private Content dataSource;
92 private IngestJobContext context;
94 private static final Map<String, String> BROWSERS_MAP = ImmutableMap.<String, String>builder()
95 .put(
"Microsoft Edge",
"Microsoft/Edge/User Data/Default")
96 .put(
"Yandex",
"YandexBrowser/User Data/Default")
97 .put(
"Opera",
"Opera Software/Opera Stable")
98 .put(
"SalamWeb",
"SalamWeb/User Data/Default")
99 .put(
"UC Browser",
"UCBrowser/User Data%/Default")
100 .put(
"Brave",
"BraveSoftware/Brave-Browser/User Data/Default")
101 .put(
"Google Chrome",
"Chrome/User Data/Default")
104 @Messages({
"# {0} - browserName",
105 "Progress_Message_Chrome_History=Chrome History Browser {0}",
106 "# {0} - browserName",
107 "Progress_Message_Chrome_Bookmarks=Chrome Bookmarks Browser {0}",
108 "# {0} - browserName",
109 "Progress_Message_Chrome_Cookies=Chrome Cookies Browser {0}",
110 "# {0} - browserName",
111 "Progress_Message_Chrome_Downloads=Chrome Downloads Browser {0}",
112 "Progress_Message_Chrome_FormHistory=Chrome Form History",
113 "# {0} - browserName",
114 "Progress_Message_Chrome_AutoFill=Chrome Auto Fill Browser {0}",
115 "# {0} - browserName",
116 "Progress_Message_Chrome_Logins=Chrome Logins Browser {0}",
117 "Progress_Message_Chrome_Cache=Chrome Cache",})
120 moduleName = NbBundle.getMessage(Chromium.class,
"Chrome.moduleName");
124 public void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
125 this.dataSource = dataSource;
126 this.context = context;
129 for (Map.Entry<String, String> browser : BROWSERS_MAP.entrySet()) {
130 String browserName = browser.getKey();
131 String browserLocation = browser.getValue();
132 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_History", browserName));
133 this.getHistory(browser.getKey(), browser.getValue());
134 if (context.dataSourceIngestIsCancelled()) {
138 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Bookmarks", browserName));
139 this.getBookmark(browser.getKey(), browser.getValue());
140 if (context.dataSourceIngestIsCancelled()) {
144 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Cookies", browserName));
145 this.getCookie(browser.getKey(), browser.getValue());
146 if (context.dataSourceIngestIsCancelled()) {
150 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Logins", browserName));
151 this.getLogins(browser.getKey(), browser.getValue());
152 if (context.dataSourceIngestIsCancelled()) {
156 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_AutoFill", browserName));
157 this.getAutofill(browser.getKey(), browser.getValue());
158 if (context.dataSourceIngestIsCancelled()) {
162 progressBar.progress(NbBundle.getMessage(
this.getClass(),
"Progress_Message_Chrome_Downloads", browserName));
163 this.getDownload(browser.getKey(), browser.getValue());
164 if (context.dataSourceIngestIsCancelled()) {
169 progressBar.progress(Bundle.Progress_Message_Chrome_Cache());
170 ChromeCacheExtractor chromeCacheExtractor =
new ChromeCacheExtractor(dataSource, context, progressBar);
171 chromeCacheExtractor.processCaches();
178 private void getHistory(String browser, String browserLocation) {
179 FileManager fileManager = currentCase.getServices().getFileManager();
180 List<AbstractFile> historyFiles;
181 String historyFileName = HISTORY_FILE_NAME;
182 if (browser.equals(UC_BROWSER_NAME)) {
183 historyFileName = HISTORY_FILE_NAME +
"%";
186 historyFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation);
187 }
catch (TskCoreException ex) {
188 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getHistory.errMsg.errGettingFiles");
189 logger.log(Level.SEVERE, msg, ex);
190 this.addErrorMessage(this.getName() +
": " + msg);
195 List<AbstractFile> allocatedHistoryFiles =
new ArrayList<>();
196 for (AbstractFile historyFile : historyFiles) {
197 if (historyFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
198 allocatedHistoryFiles.add(historyFile);
203 if (allocatedHistoryFiles.isEmpty()) {
204 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getHistory.errMsg.couldntFindAnyFiles");
205 logger.log(Level.INFO, msg);
210 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
212 while (j < allocatedHistoryFiles.size()) {
213 String temps = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + allocatedHistoryFiles.get(j).getName() + j +
".db";
214 final AbstractFile historyFile = allocatedHistoryFiles.get(j++);
215 if ((historyFile.getSize() == 0) || (historyFile.getName().toLowerCase().contains(
"-slack"))
216 || (historyFile.getName().toLowerCase().contains(
"cache")) || (historyFile.getName().toLowerCase().contains(
"media"))
217 || (historyFile.getName().toLowerCase().contains(
"index"))) {
221 ContentUtils.writeToFile(historyFile,
new File(temps), context::dataSourceIngestIsCancelled);
222 }
catch (ReadContentInputStreamException ex) {
223 logger.log(Level.WARNING, String.format(
"Error reading Chrome web history artifacts file '%s' (id=%d).",
224 historyFile.getName(), historyFile.getId()), ex);
225 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getHistory.errMsg.errAnalyzingFile",
226 this.getName(), historyFile.getName()));
228 }
catch (IOException ex) {
229 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome web history artifacts file '%s' (id=%d).",
230 temps, historyFile.getName(), historyFile.getId()), ex);
231 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getHistory.errMsg.errAnalyzingFile",
232 this.getName(), historyFile.getName()));
235 File dbFile =
new File(temps);
236 if (context.dataSourceIngestIsCancelled()) {
240 List<HashMap<String, Object>> tempList;
241 tempList = this.dbConnect(temps, HISTORY_QUERY);
242 logger.log(Level.INFO,
"{0}- Now getting history from {1} with {2}artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
243 for (HashMap<String, Object> result : tempList) {
244 Collection<BlackboardAttribute> bbattributes =
new ArrayList<BlackboardAttribute>();
245 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
246 RecentActivityExtracterModuleFactory.getModuleName(),
247 ((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"")));
248 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
249 RecentActivityExtracterModuleFactory.getModuleName(),
250 (Long.valueOf(result.get(
"last_visit_time").toString()) / 1000000) - Long.valueOf(
"11644473600")));
251 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER,
252 RecentActivityExtracterModuleFactory.getModuleName(),
253 ((result.get(
"from_visit").toString() != null) ? result.get(
"from_visit").toString() :
"")));
254 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
255 RecentActivityExtracterModuleFactory.getModuleName(),
256 ((result.get(
"title").toString() != null) ? result.get(
"title").toString() :
"")));
257 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
258 RecentActivityExtracterModuleFactory.getModuleName(), browser));
259 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
260 RecentActivityExtracterModuleFactory.getModuleName(),
261 (NetworkUtils.extractDomain((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
""))));
263 BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes);
265 bbartifacts.add(bbart);
271 if (!bbartifacts.isEmpty()) {
272 postArtifacts(bbartifacts);
279 private void getBookmark(String browser, String browserLocation) {
280 FileManager fileManager = currentCase.getServices().getFileManager();
281 List<AbstractFile> bookmarkFiles;
282 String bookmarkFileName = BOOKMARK_FILE_NAME;
283 if (browser.equals(UC_BROWSER_NAME)) {
284 bookmarkFileName = BOOKMARK_FILE_NAME +
"%";
287 bookmarkFiles = fileManager.findFiles(dataSource, bookmarkFileName, browserLocation);
288 }
catch (TskCoreException ex) {
289 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getBookmark.errMsg.errGettingFiles");
290 logger.log(Level.SEVERE, msg, ex);
291 this.addErrorMessage(this.getName() +
": " + msg);
295 if (bookmarkFiles.isEmpty()) {
296 logger.log(Level.INFO,
"Didn't find any Chrome bookmark files.");
301 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
304 while (j < bookmarkFiles.size()) {
305 AbstractFile bookmarkFile = bookmarkFiles.get(j++);
306 if ((bookmarkFile.getSize() == 0) || (bookmarkFile.getName().toLowerCase().contains(
"-slack"))
307 || (bookmarkFile.getName().toLowerCase().contains(
"extras")) || (bookmarkFile.getName().toLowerCase().contains(
"log"))
308 || (bookmarkFile.getName().toLowerCase().contains(
"backup")) || (bookmarkFile.getName().toLowerCase().contains(
"visualized"))
309 || (bookmarkFile.getName().toLowerCase().contains(
"bak")) || (bookmarkFile.getParentPath().toLowerCase().contains(
"backup"))) {
312 String temps = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + bookmarkFile.getName() + j +
".db";
314 ContentUtils.writeToFile(bookmarkFile,
new File(temps), context::dataSourceIngestIsCancelled);
315 }
catch (ReadContentInputStreamException ex) {
316 logger.log(Level.WARNING, String.format(
"Error reading Chrome bookmark artifacts file '%s' (id=%d).",
317 bookmarkFile.getName(), bookmarkFile.getId()), ex);
318 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile",
319 this.getName(), bookmarkFile.getName()));
321 }
catch (IOException ex) {
322 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome bookmark artifacts file '%s' (id=%d).",
323 temps, bookmarkFile.getName(), bookmarkFile.getId()), ex);
324 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile",
325 this.getName(), bookmarkFile.getName()));
329 logger.log(Level.INFO,
"{0}- Now getting Bookmarks from {1}",
new Object[]{moduleName, temps});
330 File dbFile =
new File(temps);
331 if (context.dataSourceIngestIsCancelled()) {
336 FileReader tempReader;
338 tempReader =
new FileReader(temps);
339 }
catch (FileNotFoundException ex) {
340 logger.log(Level.WARNING,
"Error while trying to read into the Bookmarks for Chrome.", ex);
344 final JsonParser parser =
new JsonParser();
345 JsonElement jsonElement;
346 JsonObject jElement, jRoot, jBookmark;
347 JsonArray jBookmarkArray;
350 jsonElement = parser.parse(tempReader);
351 jElement = jsonElement.getAsJsonObject();
352 jRoot = jElement.get(
"roots").getAsJsonObject();
353 jBookmark = jRoot.get(
"bookmark_bar").getAsJsonObject();
354 jBookmarkArray = jBookmark.getAsJsonArray(
"children");
355 }
catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
356 logger.log(Level.WARNING,
"Error parsing Json from Chrome Bookmark.", ex);
357 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile3",
358 this.getName(), bookmarkFile.getName()));
362 for (JsonElement result : jBookmarkArray) {
363 JsonObject address = result.getAsJsonObject();
364 if (address == null) {
367 JsonElement urlEl = address.get(
"url");
370 url = urlEl.getAsString();
375 JsonElement nameEl = address.get(
"name");
376 if (nameEl != null) {
377 name = nameEl.getAsString();
382 JsonElement dateEl = address.get(
"date_added");
383 if (dateEl != null) {
384 date = dateEl.getAsLong();
386 date = Long.valueOf(0);
388 String domain = NetworkUtils.extractDomain(url);
390 BlackboardArtifact bbart = bookmarkFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
391 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
393 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
394 RecentActivityExtracterModuleFactory.getModuleName(), url));
395 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
396 RecentActivityExtracterModuleFactory.getModuleName(), name));
397 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
398 RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf(
"11644473600")));
399 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
400 RecentActivityExtracterModuleFactory.getModuleName(), browser));
401 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
402 RecentActivityExtracterModuleFactory.getModuleName(), domain));
403 bbart.addAttributes(bbattributes);
405 bbartifacts.add(bbart);
406 }
catch (TskCoreException ex) {
407 logger.log(Level.SEVERE,
"Error while trying to insert Chrome bookmark artifact{0}", ex);
408 this.addErrorMessage(
409 NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile4",
410 this.getName(), bookmarkFile.getName()));
413 postArtifacts(bbartifacts);
422 private void getCookie(String browser, String browserLocation) {
424 FileManager fileManager = currentCase.getServices().getFileManager();
425 List<AbstractFile> cookiesFiles;
426 String cookieFileName = COOKIE_FILE_NAME;
427 if (browser.equals(UC_BROWSER_NAME)) {
430 cookieFileName =
"%" + COOKIE_FILE_NAME +
"%";
433 cookiesFiles = fileManager.findFiles(dataSource, cookieFileName, browserLocation);
434 }
catch (TskCoreException ex) {
435 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getCookie.errMsg.errGettingFiles");
436 logger.log(Level.SEVERE, msg, ex);
437 this.addErrorMessage(this.getName() +
": " + msg);
441 if (cookiesFiles.isEmpty()) {
442 logger.log(Level.INFO,
"Didn't find any Chrome cookies files.");
447 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
449 while (j < cookiesFiles.size()) {
450 AbstractFile cookiesFile = cookiesFiles.get(j++);
451 if ((cookiesFile.getSize() == 0) || (cookiesFile.getName().toLowerCase().contains(
"-slack"))) {
454 String temps = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + cookiesFile.getName() + j +
".db";
456 ContentUtils.writeToFile(cookiesFile,
new File(temps), context::dataSourceIngestIsCancelled);
457 }
catch (ReadContentInputStreamException ex) {
458 logger.log(Level.WARNING, String.format(
"Error reading Chrome cookie artifacts file '%s' (id=%d).",
459 cookiesFile.getName(), cookiesFile.getId()), ex);
460 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getCookie.errMsg.errAnalyzeFile",
461 this.getName(), cookiesFile.getName()));
463 }
catch (IOException ex) {
464 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome cookie artifacts file '%s' (id=%d).",
465 temps, cookiesFile.getName(), cookiesFile.getId()), ex);
466 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getCookie.errMsg.errAnalyzeFile",
467 this.getName(), cookiesFile.getName()));
470 File dbFile =
new File(temps);
471 if (context.dataSourceIngestIsCancelled()) {
476 List<HashMap<String, Object>> tempList = this.dbConnect(temps, COOKIE_QUERY);
477 logger.log(Level.INFO,
"{0}- Now getting cookies from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
478 for (HashMap<String, Object> result : tempList) {
479 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
480 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
481 RecentActivityExtracterModuleFactory.getModuleName(),
482 ((result.get(
"host_key").toString() != null) ? result.get(
"host_key").toString() :
"")));
483 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME,
484 RecentActivityExtracterModuleFactory.getModuleName(),
485 (Long.valueOf(result.get(
"last_access_utc").toString()) / 1000000) - Long.valueOf(
"11644473600")));
487 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
488 RecentActivityExtracterModuleFactory.getModuleName(),
489 ((result.get(
"name").toString() != null) ? result.get(
"name").toString() :
"")));
490 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
491 RecentActivityExtracterModuleFactory.getModuleName(),
492 ((result.get(
"value").toString() != null) ? result.get(
"value").toString() :
"")));
493 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
494 RecentActivityExtracterModuleFactory.getModuleName(), browser));
495 String domain = result.get(
"host_key").toString();
496 domain = domain.replaceFirst(
"^\\.+(?!$)",
"");
497 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
498 RecentActivityExtracterModuleFactory.getModuleName(), domain));
500 BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes);
502 bbartifacts.add(bbart);
509 if (!bbartifacts.isEmpty()) {
510 postArtifacts(bbartifacts);
517 private void getDownload(String browser, String browserLocation) {
518 FileManager fileManager = currentCase.getServices().getFileManager();
519 List<AbstractFile> downloadFiles;
520 String historyFileName = HISTORY_FILE_NAME;
521 if (browser.equals(UC_BROWSER_NAME)) {
522 historyFileName = HISTORY_FILE_NAME +
"%";
525 downloadFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation);
526 }
catch (TskCoreException ex) {
527 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getDownload.errMsg.errGettingFiles");
528 logger.log(Level.SEVERE, msg, ex);
529 this.addErrorMessage(this.getName() +
": " + msg);
533 if (downloadFiles.isEmpty()) {
534 logger.log(Level.INFO,
"Didn't find any Chrome download files.");
539 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
541 while (j < downloadFiles.size()) {
542 AbstractFile downloadFile = downloadFiles.get(j++);
543 if ((downloadFile.getSize() == 0) || (downloadFile.getName().toLowerCase().contains(
"-slack"))
544 || (downloadFile.getName().toLowerCase().contains(
"cache")) || (downloadFile.getName().toLowerCase().contains(
"index"))) {
548 String temps = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + downloadFile.getName() + j +
".db";
550 ContentUtils.writeToFile(downloadFile,
new File(temps), context::dataSourceIngestIsCancelled);
551 }
catch (ReadContentInputStreamException ex) {
552 logger.log(Level.WARNING, String.format(
"Error reading Chrome download artifacts file '%s' (id=%d).",
553 downloadFile.getName(), downloadFile.getId()), ex);
554 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getDownload.errMsg.errAnalyzeFiles1",
555 this.getName(), downloadFile.getName()));
557 }
catch (IOException ex) {
558 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome download artifacts file '%s' (id=%d).",
559 temps, downloadFile.getName(), downloadFile.getId()), ex);
560 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getDownload.errMsg.errAnalyzeFiles1",
561 this.getName(), downloadFile.getName()));
564 File dbFile =
new File(temps);
565 if (context.dataSourceIngestIsCancelled()) {
570 List<HashMap<String, Object>> tempList;
572 if (isChromePreVersion30(temps)) {
573 tempList = this.dbConnect(temps, DOWNLOAD_QUERY);
575 tempList = this.dbConnect(temps, DOWNLOAD_QUERY_V30);
578 logger.log(Level.INFO,
"{0}- Now getting downloads from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
579 for (HashMap<String, Object> result : tempList) {
580 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
581 String fullPath = result.get(
"full_path").toString();
582 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
583 RecentActivityExtracterModuleFactory.getModuleName(), fullPath));
584 long pathID = Util.findID(dataSource, fullPath);
586 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
587 NbBundle.getMessage(
this.getClass(),
588 "Chrome.parentModuleName"), pathID));
590 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
591 RecentActivityExtracterModuleFactory.getModuleName(),
592 ((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"")));
594 Long time = (Long.valueOf(result.get(
"start_time").toString()) / 1000000) - Long.valueOf(
"11644473600");
598 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
599 RecentActivityExtracterModuleFactory.getModuleName(), time));
600 String domain = NetworkUtils.extractDomain((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"");
601 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
602 RecentActivityExtracterModuleFactory.getModuleName(), domain));
603 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
604 RecentActivityExtracterModuleFactory.getModuleName(), browser));
606 BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadFile, bbattributes);
607 if (webDownloadArtifact != null) {
608 bbartifacts.add(webDownloadArtifact);
612 String normalizedFullPath = FilenameUtils.normalize(fullPath,
true);
613 for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(normalizedFullPath), FilenameUtils.getPath(normalizedFullPath))) {
614 BlackboardArtifact associatedObjectArtifact = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT);
615 associatedObjectArtifact.addAttribute(
616 new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT,
617 RecentActivityExtracterModuleFactory.getModuleName(), webDownloadArtifact.getArtifactID()));
619 bbartifacts.add(associatedObjectArtifact);
622 }
catch (TskCoreException ex) {
623 logger.log(Level.SEVERE, String.format(
"Error creating associated object artifact for file '%s'", fullPath), ex);
631 if (!bbartifacts.isEmpty()) {
632 postArtifacts(bbartifacts);
639 private void getLogins(String browser, String browserLocation) {
641 FileManager fileManager = currentCase.getServices().getFileManager();
642 List<AbstractFile> loginDataFiles;
643 String loginDataFileName = LOGIN_DATA_FILE_NAME;
644 if (browser.equals(UC_BROWSER_NAME)) {
645 loginDataFileName = LOGIN_DATA_FILE_NAME +
"%";
649 loginDataFiles = fileManager.findFiles(dataSource, loginDataFileName, browserLocation);
650 }
catch (TskCoreException ex) {
651 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getLogin.errMsg.errGettingFiles");
652 logger.log(Level.SEVERE, msg, ex);
653 this.addErrorMessage(this.getName() +
": " + msg);
657 if (loginDataFiles.isEmpty()) {
658 logger.log(Level.INFO,
"Didn't find any Chrome Login Data files.");
663 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
665 while (j < loginDataFiles.size()) {
666 AbstractFile loginDataFile = loginDataFiles.get(j++);
667 if ((loginDataFile.getSize() == 0) || (loginDataFile.getName().toLowerCase().contains(
"-slack"))) {
670 String temps = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + loginDataFile.getName() + j +
".db";
672 ContentUtils.writeToFile(loginDataFile,
new File(temps), context::dataSourceIngestIsCancelled);
673 }
catch (ReadContentInputStreamException ex) {
674 logger.log(Level.WARNING, String.format(
"Error reading Chrome login artifacts file '%s' (id=%d).",
675 loginDataFile.getName(), loginDataFile.getId()), ex);
676 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
677 this.getName(), loginDataFile.getName()));
679 }
catch (IOException ex) {
680 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome login artifacts file '%s' (id=%d).",
681 temps, loginDataFile.getName(), loginDataFile.getId()), ex);
682 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
683 this.getName(), loginDataFile.getName()));
686 File dbFile =
new File(temps);
687 if (context.dataSourceIngestIsCancelled()) {
691 List<HashMap<String, Object>> tempList = this.dbConnect(temps, LOGIN_QUERY);
692 logger.log(Level.INFO,
"{0}- Now getting login information from {1} with {2}artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
693 for (HashMap<String, Object> result : tempList) {
694 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
696 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
697 RecentActivityExtracterModuleFactory.getModuleName(),
698 ((result.get(
"origin_url").toString() != null) ? result.get(
"origin_url").toString() :
"")));
700 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
701 RecentActivityExtracterModuleFactory.getModuleName(),
702 (Long.valueOf(result.get(
"date_created").toString()) / 1000000) - Long.valueOf(
"11644473600")));
704 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
705 RecentActivityExtracterModuleFactory.getModuleName(),
706 (NetworkUtils.extractDomain((result.get(
"origin_url").toString() != null) ? result.get(
"origin_url").toString() :
""))));
708 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
709 RecentActivityExtracterModuleFactory.getModuleName(),
710 ((result.get(
"username_value").toString() != null) ? result.get(
"username_value").toString().replaceAll(
"'",
"''") :
"")));
712 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REALM,
713 RecentActivityExtracterModuleFactory.getModuleName(),
714 ((result.get(
"signon_realm") != null && result.get(
"signon_realm").toString() != null) ? result.get(
"signon_realm").toString() :
"")));
716 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
717 RecentActivityExtracterModuleFactory.getModuleName(),
718 result.containsKey(
"signon_realm") ? NetworkUtils.extractDomain(result.get(
"signon_realm").toString()) :
""));
720 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
721 RecentActivityExtracterModuleFactory.getModuleName(), browser));
723 BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT, loginDataFile, bbattributes);
725 bbartifacts.add(bbart);
732 if (!bbartifacts.isEmpty()) {
733 postArtifacts(bbartifacts);
741 private void getAutofill(String browser, String browserLocation) {
743 FileManager fileManager = currentCase.getServices().getFileManager();
744 List<AbstractFile> webDataFiles;
745 String webDataFileName = WEB_DATA_FILE_NAME;
746 if (browser.equals(UC_BROWSER_NAME)) {
747 webDataFileName = WEB_DATA_FILE_NAME +
"%";
751 webDataFiles = fileManager.findFiles(dataSource, webDataFileName, browserLocation);
752 }
catch (TskCoreException ex) {
753 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getAutofills.errMsg.errGettingFiles");
754 logger.log(Level.SEVERE, msg, ex);
755 this.addErrorMessage(this.getName() +
": " + msg);
759 if (webDataFiles.isEmpty()) {
760 logger.log(Level.INFO,
"Didn't find any Chrome Web Data files.");
765 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
767 while (j < webDataFiles.size()) {
768 AbstractFile webDataFile = webDataFiles.get(j++);
769 if ((webDataFile.getSize() == 0) || (webDataFile.getName().toLowerCase().contains(
"-slack"))) {
772 String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, browser) + File.separator + webDataFile.getName() + j +
".db";
774 ContentUtils.writeToFile(webDataFile,
new File(tempFilePath), context::dataSourceIngestIsCancelled);
775 }
catch (ReadContentInputStreamException ex) {
776 logger.log(Level.WARNING, String.format(
"Error reading Chrome Autofill artifacts file '%s' (id=%d).",
777 webDataFile.getName(), webDataFile.getId()), ex);
778 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getAutofill.errMsg.errAnalyzingFiles",
779 this.getName(), webDataFile.getName()));
781 }
catch (IOException ex) {
782 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome Web data file '%s' (id=%d).",
783 tempFilePath, webDataFile.getName(), webDataFile.getId()), ex);
784 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
785 this.getName(), webDataFile.getName()));
788 File dbFile =
new File(tempFilePath);
789 if (context.dataSourceIngestIsCancelled()) {
795 boolean isSchemaV8X = Util.checkColumn(
"date_created",
"autofill", tempFilePath);
798 bbartifacts.addAll(getFormAutofillArtifacts(webDataFile, tempFilePath, isSchemaV8X, browser));
801 getFormAddressArtifacts(webDataFile, tempFilePath, isSchemaV8X);
802 }
catch (NoCurrentCaseException | TskCoreException | Blackboard.BlackboardException ex) {
803 logger.log(Level.SEVERE, String.format(
"Error adding artifacts to the case database "
804 +
"for chrome file %s [objId=%d]", webDataFile.getName(), webDataFile.getId()), ex);
810 if (!bbartifacts.isEmpty()) {
811 postArtifacts(bbartifacts);
825 private Collection<BlackboardArtifact> getFormAutofillArtifacts(AbstractFile webDataFile, String dbFilePath,
boolean isSchemaV8X, String browser) {
827 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
830 String autoFillquery = (isSchemaV8X) ? AUTOFILL_QUERY_V8X
833 List<HashMap<String, Object>> autofills = this.dbConnect(dbFilePath, autoFillquery);
834 logger.log(Level.INFO,
"{0}- Now getting Autofill information from {1} with {2}artifacts identified.",
new Object[]{moduleName, dbFilePath, autofills.size()});
835 for (HashMap<String, Object> result : autofills) {
836 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
839 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
840 NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"),
841 ((result.get(
"name").toString() != null) ? result.get(
"name").toString() :
"")));
843 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
844 RecentActivityExtracterModuleFactory.getModuleName(),
845 ((result.get(
"value").toString() != null) ? result.get(
"value").toString() :
"")));
847 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
848 RecentActivityExtracterModuleFactory.getModuleName(),
849 (Integer.valueOf(result.get(
"count").toString()))));
851 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
852 RecentActivityExtracterModuleFactory.getModuleName(),
853 Long.valueOf(result.get(
"date_created").toString())));
857 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
858 RecentActivityExtracterModuleFactory.getModuleName(),
859 Long.valueOf(result.get(
"date_last_used").toString())));
862 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
863 RecentActivityExtracterModuleFactory.getModuleName(), browser));
866 BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, webDataFile, bbattributes);
868 bbartifacts.add(bbart);
887 private void getFormAddressArtifacts(AbstractFile webDataFile, String dbFilePath,
boolean isSchemaV8X)
throws NoCurrentCaseException,
888 TskCoreException, Blackboard.BlackboardException {
890 String webformAddressQuery = (isSchemaV8X) ? WEBFORM_ADDRESS_QUERY_V8X
891 : WEBFORM_ADDRESS_QUERY;
894 WebBrowserArtifactsHelper helper =
new WebBrowserArtifactsHelper(
895 Case.getCurrentCaseThrows().getSleuthkitCase(),
896 NbBundle.getMessage(this.getClass(),
"Chrome.parentModuleName"),
901 List<HashMap<String, Object>> addresses = this.dbConnect(dbFilePath, webformAddressQuery);
902 logger.log(Level.INFO,
"{0}- Now getting Web form addresses from {1} with {2}artifacts identified.",
new Object[]{moduleName, dbFilePath, addresses.size()});
903 for (HashMap<String, Object> result : addresses) {
906 String first_name = result.get(
"first_name").toString() != null ? result.get(
"first_name").toString() :
"";
907 String middle_name = result.get(
"middle_name").toString() != null ? result.get(
"middle_name").toString() :
"";
908 String last_name = result.get(
"last_name").toString() != null ? result.get(
"last_name").toString() :
"";
911 String email_Addr = result.get(
"email").toString() != null ? result.get(
"email").toString() :
"";
912 String phone_number = result.get(
"number").toString() != null ? result.get(
"number").toString() :
"";
915 String city = result.get(
"city").toString() != null ? result.get(
"city").toString() :
"";
916 String state = result.get(
"state").toString() != null ? result.get(
"state").toString() :
"";
917 String zipcode = result.get(
"zipcode").toString() != null ? result.get(
"zipcode").toString() :
"";
918 String country_code = result.get(
"country_code").toString() != null ? result.get(
"country_code").toString() :
"";
921 String full_name =
"";
922 String street_address =
"";
923 long date_modified = 0;
928 full_name = result.get(
"full_name").toString() != null ? result.get(
"full_name").toString() :
"";
929 street_address = result.get(
"street_address").toString() != null ? result.get(
"street_address").toString() :
"";
930 date_modified = result.get(
"date_modified").toString() != null ? Long.valueOf(result.get(
"date_modified").toString()) : 0;
931 use_count = result.get(
"use_count").toString() != null ? Integer.valueOf(result.get(
"use_count").toString()) : 0;
932 use_date = result.get(
"use_date").toString() != null ? Long.valueOf(result.get(
"use_date").toString()) : 0;
934 String address_line_1 = result.get(
"address_line_1").toString() != null ? result.get(
"street_address").toString() :
"";
935 String address_line_2 = result.get(
"address_line_2").toString() != null ? result.get(
"address_line_2").toString() :
"";
936 street_address = String.join(
" ", address_line_1, address_line_2);
940 if (full_name == null || full_name.isEmpty()) {
941 full_name = String.join(
" ", first_name, middle_name, last_name);
944 String locationAddress = String.join(
", ", street_address, city, state, zipcode, country_code);
946 List<BlackboardAttribute> otherAttributes =
new ArrayList<>();
947 if (date_modified > 0) {
948 otherAttributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
949 RecentActivityExtracterModuleFactory.getModuleName(),
953 helper.addWebFormAddress(
954 full_name, email_Addr, phone_number,
955 locationAddress, 0, use_date,
956 use_count, otherAttributes);
960 private boolean isChromePreVersion30(String temps) {
961 String query =
"PRAGMA table_info(downloads)";
962 List<HashMap<String, Object>> columns = this.dbConnect(temps, query);
963 for (HashMap<String, Object> col : columns) {
964 if (col.get(
"name").equals(
"url")) {